File indexing completed on 2024-04-28 15:27:33

0001 /*
0002     This file is part of the KDE libraries
0003     SPDX-FileCopyrightText: 2020 Ahmad Samir <a.samirh78@gmail.com>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0006 */
0007 
0008 #include "widgetsaskuseractionhandler.h"
0009 
0010 #include <KConfig>
0011 #include <KConfigGroup>
0012 #include <KGuiItem>
0013 #include <KIO/WorkerBase>
0014 #include <KJob>
0015 #include <KJobWidgets>
0016 #include <KLocalizedString>
0017 #include <KMessageDialog>
0018 #include <KSharedConfig>
0019 #include <KSslInfoDialog>
0020 #include <KStandardGuiItem>
0021 #include <kio_widgets_debug.h>
0022 
0023 #include <QApplication>
0024 #include <QDialogButtonBox>
0025 #include <QPointer>
0026 #include <QRegularExpression>
0027 #include <QUrl>
0028 
0029 class KIO::WidgetsAskUserActionHandlerPrivate
0030 {
0031 public:
0032     explicit WidgetsAskUserActionHandlerPrivate(WidgetsAskUserActionHandler *qq)
0033         : q(qq)
0034     {
0035     }
0036 
0037     // Creates a KSslInfoDialog or falls back to a generic Information dialog
0038     void sslMessageBox(const QString &text, const KIO::MetaData &metaData, QWidget *parent);
0039 
0040     bool gotPersistentUserReply(KIO::AskUserActionInterface::MessageDialogType type, const KConfigGroup &cg, const QString &dontAskAgainName);
0041     void savePersistentUserReply(KIO::AskUserActionInterface::MessageDialogType type, KConfigGroup &cg, const QString &dontAskAgainName, int result);
0042 
0043     WidgetsAskUserActionHandler *const q;
0044     QPointer<QWidget> m_parentWidget = nullptr;
0045 
0046     QWidget *getParentWidget(KJob *job);
0047     QWidget *getParentWidget(QWidget *widget);
0048 };
0049 
0050 bool KIO::WidgetsAskUserActionHandlerPrivate::gotPersistentUserReply(KIO::AskUserActionInterface::MessageDialogType type,
0051                                                                      const KConfigGroup &cg,
0052                                                                      const QString &dontAskAgainName)
0053 {
0054     // storage values matching the logic of FrameworkIntegration's KMessageBoxDontAskAgainConfigStorage
0055     switch (type) {
0056     case KIO::AskUserActionInterface::QuestionTwoActions:
0057     case KIO::AskUserActionInterface::QuestionTwoActionsCancel:
0058     case KIO::AskUserActionInterface::WarningTwoActions:
0059     case KIO::AskUserActionInterface::WarningTwoActionsCancel: {
0060         // storage holds "true" if persistent reply is "Yes", "false" for persistent "No",
0061         // otherwise no persistent reply is present
0062         const QString value = cg.readEntry(dontAskAgainName, QString());
0063         if ((value.compare(QLatin1String("yes"), Qt::CaseInsensitive) == 0) || (value.compare(QLatin1String("true"), Qt::CaseInsensitive) == 0)) {
0064             Q_EMIT q->messageBoxResult(KIO::WorkerBase::PrimaryAction);
0065             return true;
0066         }
0067         if ((value.compare(QLatin1String("no"), Qt::CaseInsensitive) == 0) || (value.compare(QLatin1String("false"), Qt::CaseInsensitive) == 0)) {
0068             Q_EMIT q->messageBoxResult(KIO::WorkerBase::SecondaryAction);
0069             return true;
0070         }
0071         break;
0072     }
0073     case KIO::AskUserActionInterface::WarningContinueCancel: {
0074         // storage holds "false" if persistent reply is "Continue"
0075         // otherwise no persistent reply is present
0076         const bool value = cg.readEntry(dontAskAgainName, true);
0077         if (value == false) {
0078             Q_EMIT q->messageBoxResult(KIO::WorkerBase::Continue);
0079             return true;
0080         }
0081         break;
0082     }
0083     default:
0084         break;
0085     }
0086 
0087     return false;
0088 }
0089 
0090 void KIO::WidgetsAskUserActionHandlerPrivate::savePersistentUserReply(KIO::AskUserActionInterface::MessageDialogType type,
0091                                                                       KConfigGroup &cg,
0092                                                                       const QString &dontAskAgainName,
0093                                                                       int result)
0094 {
0095     // see gotPersistentUserReply for values stored and why
0096     switch (type) {
0097     case KIO::AskUserActionInterface::QuestionTwoActions:
0098     case KIO::AskUserActionInterface::QuestionTwoActionsCancel:
0099     case KIO::AskUserActionInterface::WarningTwoActions:
0100     case KIO::AskUserActionInterface::WarningTwoActionsCancel:
0101         cg.writeEntry(dontAskAgainName, result == KIO::WorkerBase::PrimaryAction);
0102         cg.sync();
0103         break;
0104     case KIO::AskUserActionInterface::WarningContinueCancel:
0105         cg.writeEntry(dontAskAgainName, false);
0106         cg.sync();
0107         break;
0108     default:
0109         break;
0110     }
0111 }
0112 
0113 QWidget *KIO::WidgetsAskUserActionHandlerPrivate::getParentWidget(KJob *job)
0114 {
0115     // This needs to be in qpointer, otherwise copying process
0116     // will crash if done in background and dolphin is closed
0117     QPointer<QWidget> parentWidget = nullptr;
0118 
0119     if (job) {
0120         parentWidget = KJobWidgets::window(job);
0121     }
0122 
0123     return getParentWidget(parentWidget);
0124 }
0125 
0126 QWidget *KIO::WidgetsAskUserActionHandlerPrivate::getParentWidget(QWidget *widget)
0127 {
0128     // This needs to be in qpointer, otherwise copying process
0129     // will crash if done in background and dolphin is closed
0130     QPointer<QWidget> parentWidget = widget;
0131 
0132     if (!parentWidget) {
0133         parentWidget = this->m_parentWidget;
0134     }
0135 
0136     if (!parentWidget) {
0137         parentWidget = qApp->activeWindow();
0138     }
0139 
0140     return parentWidget;
0141 }
0142 
0143 KIO::WidgetsAskUserActionHandler::WidgetsAskUserActionHandler(QObject *parent)
0144     : KIO::AskUserActionInterface(parent)
0145     , d(new WidgetsAskUserActionHandlerPrivate(this))
0146 {
0147 }
0148 
0149 KIO::WidgetsAskUserActionHandler::~WidgetsAskUserActionHandler()
0150 {
0151 }
0152 
0153 void KIO::WidgetsAskUserActionHandler::askUserRename(KJob *job,
0154                                                      const QString &title,
0155                                                      const QUrl &src,
0156                                                      const QUrl &dest,
0157                                                      KIO::RenameDialog_Options options,
0158                                                      KIO::filesize_t sizeSrc,
0159                                                      KIO::filesize_t sizeDest,
0160                                                      const QDateTime &ctimeSrc,
0161                                                      const QDateTime &ctimeDest,
0162                                                      const QDateTime &mtimeSrc,
0163                                                      const QDateTime &mtimeDest)
0164 {
0165     QMetaObject::invokeMethod(qGuiApp, [=] {
0166         auto *dlg = new KIO::RenameDialog(d->getParentWidget(job), title, src, dest, options, sizeSrc, sizeDest, ctimeSrc, ctimeDest, mtimeSrc, mtimeDest);
0167 
0168         dlg->setAttribute(Qt::WA_DeleteOnClose);
0169         dlg->setWindowModality(Qt::WindowModal);
0170 
0171         connect(job, &KJob::finished, dlg, &QDialog::reject);
0172         connect(dlg, &QDialog::finished, this, [this, job, dlg](const int exitCode) {
0173             KIO::RenameDialog_Result result = static_cast<RenameDialog_Result>(exitCode);
0174             const QUrl newUrl = result == Result_AutoRename ? dlg->autoDestUrl() : dlg->newDestUrl();
0175             Q_EMIT askUserRenameResult(result, newUrl, job);
0176         });
0177 
0178         dlg->show();
0179     });
0180 }
0181 
0182 void KIO::WidgetsAskUserActionHandler::askUserSkip(KJob *job, KIO::SkipDialog_Options options, const QString &errorText)
0183 {
0184     QMetaObject::invokeMethod(qGuiApp, [=] {
0185         auto *dlg = new KIO::SkipDialog(d->getParentWidget(job), options, errorText);
0186         dlg->setAttribute(Qt::WA_DeleteOnClose);
0187         dlg->setWindowModality(Qt::WindowModal);
0188 
0189         connect(job, &KJob::finished, dlg, &QDialog::reject);
0190         connect(dlg, &QDialog::finished, this, [this, job](const int exitCode) {
0191             Q_EMIT askUserSkipResult(static_cast<KIO::SkipDialog_Result>(exitCode), job);
0192         });
0193 
0194         dlg->show();
0195     });
0196 }
0197 
0198 struct ProcessAskDeleteResult {
0199     QStringList prettyList;
0200     KMessageDialog::Type dialogType = KMessageDialog::QuestionTwoActions;
0201     KGuiItem acceptButton;
0202     QString text;
0203     QIcon icon;
0204     QString title = i18n("Delete Permanently");
0205     bool isSingleUrl = false;
0206 };
0207 
0208 using AskIface = KIO::AskUserActionInterface;
0209 static ProcessAskDeleteResult processAskDelete(const QList<QUrl> &urls, AskIface::DeletionType deletionType)
0210 {
0211     ProcessAskDeleteResult res;
0212     res.prettyList.reserve(urls.size());
0213     std::transform(urls.cbegin(), urls.cend(), std::back_inserter(res.prettyList), [](const auto &url) {
0214         if (url.scheme() == QLatin1String("trash")) {
0215             QString path = url.path();
0216             // HACK (#98983): remove "0-foo". Note that it works better than
0217             // displaying KFileItem::name(), for files under a subdir.
0218             static const QRegularExpression re(QStringLiteral("^/[0-9]+-"));
0219             path.remove(re);
0220             return path;
0221         } else {
0222             return url.toDisplayString(QUrl::PreferLocalFile);
0223         }
0224     });
0225 
0226     const int urlCount = res.prettyList.size();
0227     res.isSingleUrl = urlCount == 1;
0228 
0229     switch (deletionType) {
0230     case AskIface::Delete: {
0231         res.dialogType = KMessageDialog::QuestionTwoActions; // Using Question* so the Delete button is pre-selected. Bug 462845
0232         res.icon = QIcon::fromTheme(QStringLiteral("dialog-warning"));
0233         if (res.isSingleUrl) {
0234             res.text = xi18nc("@info",
0235                               "Do you really want to permanently delete this item?<nl/><nl/>"
0236                               "<filename>%1</filename><nl/><nl/>"
0237                               "<emphasis strong='true'>This action cannot be undone.</emphasis>",
0238                               res.prettyList.at(0));
0239         } else {
0240             res.text = xi18ncp("@info",
0241                                "Do you really want to permanently delete this %1 item?<nl/><nl/>"
0242                                "<emphasis strong='true'>This action cannot be undone.</emphasis>",
0243                                "Do you really want to permanently delete these %1 items?<nl/><nl/>"
0244                                "<emphasis strong='true'>This action cannot be undone.</emphasis>",
0245                                urlCount);
0246         }
0247         res.acceptButton = KGuiItem(i18nc("@action:button", "Delete Permanently"), QStringLiteral("edit-delete"));
0248         break;
0249     }
0250     case AskIface::DeleteInsteadOfTrash: {
0251         res.dialogType = KMessageDialog::WarningTwoActions;
0252         if (res.isSingleUrl) {
0253             res.text = xi18nc("@info",
0254                               "Moving this item to Trash failed as it is too large."
0255                               " Permanently delete it instead?<nl/><nl/>"
0256                               "<filename>%1</filename><nl/><nl/>"
0257                               "<emphasis strong='true'>This action cannot be undone.</emphasis>",
0258                               res.prettyList.at(0));
0259         } else {
0260             res.text = xi18ncp("@info",
0261                                "Moving this %1 item to Trash failed as it is too large."
0262                                " Permanently delete it instead?<nl/>"
0263                                "<emphasis strong='true'>This action cannot be undone.</emphasis>",
0264                                "Moving these %1 items to Trash failed as they are too large."
0265                                " Permanently delete them instead?<nl/><nl/>"
0266                                "<emphasis strong='true'>This action cannot be undone.</emphasis>",
0267                                urlCount);
0268         }
0269         res.acceptButton = KGuiItem(i18nc("@action:button", "Delete Permanently"), QStringLiteral("edit-delete"));
0270         break;
0271     }
0272     case AskIface::EmptyTrash: {
0273         res.dialogType = KMessageDialog::QuestionTwoActions; // Using Question* so the Delete button is pre-selected.
0274         res.icon = QIcon::fromTheme(QStringLiteral("dialog-warning"));
0275         res.text = xi18nc("@info",
0276                           "Do you want to permanently delete all items from the Trash?<nl/><nl/>"
0277                           "<emphasis strong='true'>This action cannot be undone.</emphasis>");
0278         res.acceptButton = KGuiItem(i18nc("@action:button", "Empty Trash"), QStringLiteral("user-trash"));
0279         break;
0280     }
0281     case AskIface::Trash: {
0282         if (res.isSingleUrl) {
0283             res.text = xi18nc("@info",
0284                               "Do you really want to move this item to the Trash?<nl/>"
0285                               "<filename>%1</filename>",
0286                               res.prettyList.at(0));
0287         } else {
0288             res.text =
0289                 xi18ncp("@info", "Do you really want to move this %1 item to the Trash?", "Do you really want to move these %1 items to the Trash?", urlCount);
0290         }
0291         res.title = i18n("Move to Trash");
0292         res.acceptButton = KGuiItem(res.title, QStringLiteral("user-trash"));
0293         break;
0294     }
0295     default:
0296         break;
0297     }
0298     return res;
0299 }
0300 
0301 void KIO::WidgetsAskUserActionHandler::askUserDelete(const QList<QUrl> &urls, DeletionType deletionType, ConfirmationType confirmationType, QWidget *parent)
0302 {
0303     QString keyName;
0304     bool ask = (confirmationType == ForceConfirmation);
0305     if (!ask) {
0306         // The default value for confirmations is true for delete and false
0307         // for trash. If you change this, please also update:
0308         //      dolphin/src/settings/general/confirmationssettingspage.cpp
0309         bool defaultValue = true;
0310 
0311         switch (deletionType) {
0312         case DeleteInsteadOfTrash:
0313         case Delete:
0314             keyName = QStringLiteral("ConfirmDelete");
0315             break;
0316         case Trash:
0317             keyName = QStringLiteral("ConfirmTrash");
0318             defaultValue = false;
0319             break;
0320         case EmptyTrash:
0321             keyName = QStringLiteral("ConfirmEmptyTrash");
0322             break;
0323         }
0324 
0325         KSharedConfigPtr kioConfig = KSharedConfig::openConfig(QStringLiteral("kiorc"), KConfig::NoGlobals);
0326         ask = kioConfig->group("Confirmations").readEntry(keyName, defaultValue);
0327     }
0328 
0329     if (!ask) {
0330         Q_EMIT askUserDeleteResult(true, urls, deletionType, parent);
0331         return;
0332     }
0333 
0334     QMetaObject::invokeMethod(qGuiApp, [=] {
0335         const auto &[prettyList, dialogType, acceptButton, text, icon, title, singleUrl] = processAskDelete(urls, deletionType);
0336         KMessageDialog *dlg = new KMessageDialog(dialogType, text, parent);
0337         dlg->setAttribute(Qt::WA_DeleteOnClose);
0338         dlg->setCaption(title);
0339         dlg->setIcon(icon);
0340         dlg->setButtons(acceptButton, KStandardGuiItem::cancel());
0341         if (!singleUrl) {
0342             dlg->setListWidgetItems(prettyList);
0343         }
0344         dlg->setDontAskAgainText(i18nc("@option:checkbox", "Do not ask again"));
0345         // If we get here, !ask must be false
0346         dlg->setDontAskAgainChecked(!ask);
0347 
0348         connect(dlg, &QDialog::finished, this, [=](const int buttonCode) {
0349             const bool isDelete = (buttonCode == KMessageDialog::PrimaryAction);
0350 
0351             Q_EMIT askUserDeleteResult(isDelete, urls, deletionType, parent);
0352 
0353             if (isDelete) {
0354                 KSharedConfigPtr kioConfig = KSharedConfig::openConfig(QStringLiteral("kiorc"), KConfig::NoGlobals);
0355                 KConfigGroup cg = kioConfig->group("Confirmations");
0356                 cg.writeEntry(keyName, !dlg->isDontAskAgainChecked());
0357                 cg.sync();
0358             }
0359         });
0360 
0361         dlg->setWindowModality(Qt::WindowModal);
0362         dlg->show();
0363     });
0364 }
0365 
0366 void KIO::WidgetsAskUserActionHandler::requestUserMessageBox(MessageDialogType type,
0367                                                              const QString &text,
0368                                                              const QString &title,
0369                                                              const QString &primaryActionText,
0370                                                              const QString &secondaryActionText,
0371                                                              const QString &primaryActionIconName,
0372                                                              const QString &secondaryActionIconName,
0373                                                              const QString &dontAskAgainName,
0374                                                              const QString &details,
0375                                                              const KIO::MetaData &metaData,
0376                                                              QWidget *parent)
0377 {
0378     if (d->gotPersistentUserReply(type, KSharedConfig::openConfig(QStringLiteral("kioslaverc"))->group("Notification Messages"), dontAskAgainName)) {
0379         return;
0380     }
0381 
0382     const KGuiItem primaryActionButton(primaryActionText, primaryActionIconName);
0383     const KGuiItem secondaryActionButton(secondaryActionText, secondaryActionIconName);
0384 
0385     // It's "Do not ask again" every where except with Information
0386     QString dontAskAgainText = i18nc("@option:check", "Do not ask again");
0387 
0388     KMessageDialog::Type dlgType;
0389     bool hasCancelButton = false;
0390 
0391     switch (type) {
0392     case AskUserActionInterface::QuestionTwoActions:
0393         dlgType = KMessageDialog::QuestionTwoActions;
0394         break;
0395     case AskUserActionInterface::QuestionTwoActionsCancel:
0396         dlgType = KMessageDialog::QuestionTwoActionsCancel;
0397         hasCancelButton = true;
0398         break;
0399     case AskUserActionInterface::WarningTwoActions:
0400         dlgType = KMessageDialog::WarningTwoActions;
0401         break;
0402     case AskUserActionInterface::WarningTwoActionsCancel:
0403         dlgType = KMessageDialog::WarningTwoActionsCancel;
0404         hasCancelButton = true;
0405         break;
0406     case AskUserActionInterface::WarningContinueCancel:
0407         dlgType = KMessageDialog::WarningContinueCancel;
0408         hasCancelButton = true;
0409         break;
0410     case AskUserActionInterface::SSLMessageBox:
0411         d->sslMessageBox(text, metaData, d->getParentWidget(parent));
0412         return;
0413     case AskUserActionInterface::Information:
0414         dlgType = KMessageDialog::Information;
0415         dontAskAgainText = i18nc("@option:check", "Do not show this message again");
0416         break;
0417 #if KIOCORE_BUILD_DEPRECATED_SINCE(5, 97)
0418     case AskUserActionInterface::Sorry:
0419 #if KWIDGETSADDONS_BUILD_DEPRECATED_SINCE(5, 97)
0420         QT_WARNING_PUSH
0421         QT_WARNING_DISABLE_DEPRECATED
0422         dlgType = KMessageDialog::Sorry;
0423         QT_WARNING_POP
0424         dontAskAgainText = QString{}; // No dontAskAgain checkbox
0425         break;
0426 #else
0427 #error "Cannot build KIOCore with KIO::AskUserActionInterface::Sorry with KMessageDialog::Sorry disabled"
0428 #endif
0429 #endif
0430     case AskUserActionInterface::Error:
0431         dlgType = KMessageDialog::Error;
0432         dontAskAgainText = QString{}; // No dontAskAgain checkbox
0433         break;
0434     default:
0435         qCWarning(KIO_WIDGETS) << "Unknown message dialog type" << type;
0436         return;
0437     }
0438 
0439     QMetaObject::invokeMethod(qGuiApp, [=]() {
0440         auto cancelButton = hasCancelButton ? KStandardGuiItem::cancel() : KGuiItem();
0441         auto *dialog = new KMessageDialog(dlgType, text, d->getParentWidget(parent));
0442 
0443         dialog->setAttribute(Qt::WA_DeleteOnClose);
0444         dialog->setCaption(title);
0445         dialog->setIcon(QIcon{});
0446         dialog->setButtons(primaryActionButton, secondaryActionButton, cancelButton);
0447         dialog->setDetails(details);
0448         dialog->setDontAskAgainText(dontAskAgainText);
0449         dialog->setDontAskAgainChecked(false);
0450         dialog->setOpenExternalLinks(true); // Allow opening external links in the text labels
0451 
0452         connect(dialog, &QDialog::finished, this, [=](const int result) {
0453             KIO::WorkerBase::ButtonCode btnCode;
0454             switch (result) {
0455             case KMessageDialog::PrimaryAction:
0456                 if (dlgType == KMessageDialog::WarningContinueCancel) {
0457                     btnCode = KIO::WorkerBase::Continue;
0458                 } else {
0459                     btnCode = KIO::WorkerBase::PrimaryAction;
0460                 }
0461                 break;
0462             case KMessageDialog::SecondaryAction:
0463                 btnCode = KIO::WorkerBase::SecondaryAction;
0464                 break;
0465             case KMessageDialog::Cancel:
0466                 btnCode = KIO::WorkerBase::Cancel;
0467                 break;
0468             case KMessageDialog::Ok:
0469                 btnCode = KIO::WorkerBase::Ok;
0470                 break;
0471             default:
0472                 qCWarning(KIO_WIDGETS) << "Unknown message dialog result" << result;
0473                 return;
0474             }
0475 
0476             Q_EMIT messageBoxResult(btnCode);
0477 
0478             if ((result != KMessageDialog::Cancel) && dialog->isDontAskAgainChecked()) {
0479                 KSharedConfigPtr reqMsgConfig = KSharedConfig::openConfig(QStringLiteral("kioslaverc"));
0480                 KConfigGroup cg = reqMsgConfig->group("Notification Messages");
0481                 d->savePersistentUserReply(type, cg, dontAskAgainName, result);
0482             }
0483         });
0484 
0485         dialog->show();
0486     });
0487 }
0488 
0489 void KIO::WidgetsAskUserActionHandlerPrivate::sslMessageBox(const QString &text, const KIO::MetaData &metaData, QWidget *parent)
0490 {
0491     QWidget *parentWidget = getParentWidget(parent);
0492 
0493     const QStringList sslList = metaData.value(QStringLiteral("ssl_peer_chain")).split(QLatin1Char('\x01'), Qt::SkipEmptyParts);
0494 
0495     QList<QSslCertificate> certChain;
0496     bool decodedOk = true;
0497     for (const QString &str : sslList) {
0498         certChain.append(QSslCertificate(str.toUtf8()));
0499         if (certChain.last().isNull()) {
0500             decodedOk = false;
0501             break;
0502         }
0503     }
0504 
0505     QMetaObject::invokeMethod(qGuiApp, [=] {
0506         if (decodedOk) { // Use KSslInfoDialog
0507             KSslInfoDialog *ksslDlg = new KSslInfoDialog(parentWidget);
0508             ksslDlg->setSslInfo(certChain,
0509                                 metaData.value(QStringLiteral("ssl_peer_ip")),
0510                                 text, // The URL
0511                                 metaData.value(QStringLiteral("ssl_protocol_version")),
0512                                 metaData.value(QStringLiteral("ssl_cipher")),
0513                                 metaData.value(QStringLiteral("ssl_cipher_used_bits")).toInt(),
0514                                 metaData.value(QStringLiteral("ssl_cipher_bits")).toInt(),
0515                                 KSslInfoDialog::certificateErrorsFromString(metaData.value(QStringLiteral("ssl_cert_errors"))));
0516 
0517             // KSslInfoDialog deletes itself by setting Qt::WA_DeleteOnClose
0518 
0519             QObject::connect(ksslDlg, &QDialog::finished, q, [this]() {
0520                 // KSslInfoDialog only has one button, QDialogButtonBox::Close
0521                 Q_EMIT q->messageBoxResult(KIO::WorkerBase::Cancel);
0522             });
0523 
0524             ksslDlg->show();
0525             return;
0526         }
0527 
0528         // Fallback to a generic message box
0529         auto *dialog = new KMessageDialog(KMessageDialog::Information, i18n("The peer SSL certificate chain appears to be corrupt."), parentWidget);
0530 
0531         dialog->setAttribute(Qt::WA_DeleteOnClose);
0532         dialog->setCaption(i18n("SSL"));
0533         // KMessageDialog will set a proper icon
0534         dialog->setIcon(QIcon{});
0535         dialog->setButtons(KStandardGuiItem::ok());
0536 
0537         QObject::connect(dialog, &QDialog::finished, q, [this](const int result) {
0538             Q_EMIT q->messageBoxResult(result == KMessageDialog::Ok ? KIO::WorkerBase::Ok : KIO::WorkerBase::Cancel);
0539         });
0540 
0541         dialog->show();
0542     });
0543 }
0544 
0545 void KIO::WidgetsAskUserActionHandler::setWindow(QWidget *window)
0546 {
0547     d->m_parentWidget = window;
0548 }
0549 
0550 #include "moc_widgetsaskuseractionhandler.cpp"