File indexing completed on 2024-12-01 03:41:21
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(QStringLiteral("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(QStringLiteral("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 QWidget *parent) 0376 { 0377 if (d->gotPersistentUserReply(type, 0378 KSharedConfig::openConfig(QStringLiteral("kioslaverc"))->group(QStringLiteral("Notification Messages")), 0379 dontAskAgainName)) { 0380 return; 0381 } 0382 0383 const KGuiItem primaryActionButton(primaryActionText, primaryActionIconName); 0384 const KGuiItem secondaryActionButton(secondaryActionText, secondaryActionIconName); 0385 0386 // It's "Do not ask again" every where except with Information 0387 QString dontAskAgainText = i18nc("@option:check", "Do not ask again"); 0388 0389 KMessageDialog::Type dlgType; 0390 bool hasCancelButton = false; 0391 0392 switch (type) { 0393 case AskUserActionInterface::QuestionTwoActions: 0394 dlgType = KMessageDialog::QuestionTwoActions; 0395 break; 0396 case AskUserActionInterface::QuestionTwoActionsCancel: 0397 dlgType = KMessageDialog::QuestionTwoActionsCancel; 0398 hasCancelButton = true; 0399 break; 0400 case AskUserActionInterface::WarningTwoActions: 0401 dlgType = KMessageDialog::WarningTwoActions; 0402 break; 0403 case AskUserActionInterface::WarningTwoActionsCancel: 0404 dlgType = KMessageDialog::WarningTwoActionsCancel; 0405 hasCancelButton = true; 0406 break; 0407 case AskUserActionInterface::WarningContinueCancel: 0408 dlgType = KMessageDialog::WarningContinueCancel; 0409 hasCancelButton = true; 0410 break; 0411 case AskUserActionInterface::Information: 0412 dlgType = KMessageDialog::Information; 0413 dontAskAgainText = i18nc("@option:check", "Do not show this message again"); 0414 break; 0415 case AskUserActionInterface::Error: 0416 dlgType = KMessageDialog::Error; 0417 dontAskAgainText = QString{}; // No dontAskAgain checkbox 0418 break; 0419 default: 0420 qCWarning(KIO_WIDGETS) << "Unknown message dialog type" << type; 0421 return; 0422 } 0423 0424 QMetaObject::invokeMethod(qGuiApp, [=]() { 0425 auto cancelButton = hasCancelButton ? KStandardGuiItem::cancel() : KGuiItem(); 0426 auto *dialog = new KMessageDialog(dlgType, text, d->getParentWidget(parent)); 0427 0428 dialog->setAttribute(Qt::WA_DeleteOnClose); 0429 dialog->setCaption(title); 0430 dialog->setIcon(QIcon{}); 0431 dialog->setButtons(primaryActionButton, secondaryActionButton, cancelButton); 0432 dialog->setDetails(details); 0433 dialog->setDontAskAgainText(dontAskAgainText); 0434 dialog->setDontAskAgainChecked(false); 0435 dialog->setOpenExternalLinks(true); // Allow opening external links in the text labels 0436 0437 connect(dialog, &QDialog::finished, this, [=](const int result) { 0438 KIO::WorkerBase::ButtonCode btnCode; 0439 switch (result) { 0440 case KMessageDialog::PrimaryAction: 0441 if (dlgType == KMessageDialog::WarningContinueCancel) { 0442 btnCode = KIO::WorkerBase::Continue; 0443 } else { 0444 btnCode = KIO::WorkerBase::PrimaryAction; 0445 } 0446 break; 0447 case KMessageDialog::SecondaryAction: 0448 btnCode = KIO::WorkerBase::SecondaryAction; 0449 break; 0450 case KMessageDialog::Cancel: 0451 btnCode = KIO::WorkerBase::Cancel; 0452 break; 0453 case KMessageDialog::Ok: 0454 btnCode = KIO::WorkerBase::Ok; 0455 break; 0456 default: 0457 qCWarning(KIO_WIDGETS) << "Unknown message dialog result" << result; 0458 return; 0459 } 0460 0461 Q_EMIT messageBoxResult(btnCode); 0462 0463 if ((result != KMessageDialog::Cancel) && dialog->isDontAskAgainChecked()) { 0464 KSharedConfigPtr reqMsgConfig = KSharedConfig::openConfig(QStringLiteral("kioslaverc")); 0465 KConfigGroup cg = reqMsgConfig->group(QStringLiteral("Notification Messages")); 0466 d->savePersistentUserReply(type, cg, dontAskAgainName, result); 0467 } 0468 }); 0469 0470 dialog->show(); 0471 }); 0472 } 0473 0474 void KIO::WidgetsAskUserActionHandler::setWindow(QWidget *window) 0475 { 0476 d->m_parentWidget = window; 0477 } 0478 0479 void KIO::WidgetsAskUserActionHandler::askIgnoreSslErrors(const QVariantMap &sslErrorData, QWidget *parent) 0480 { 0481 QWidget *parentWidget = d->getParentWidget(parent); 0482 0483 QString message = i18n("The server failed the authenticity check (%1).\n\n", sslErrorData[QLatin1String("hostname")].toString()); 0484 0485 message += sslErrorData[QLatin1String("sslError")].toString(); 0486 0487 auto *dialog = new KMessageDialog(KMessageDialog::WarningTwoActionsCancel, message, parentWidget); 0488 0489 dialog->setAttribute(Qt::WA_DeleteOnClose); 0490 dialog->setCaption(i18n("Server Authentication")); 0491 dialog->setIcon(QIcon{}); 0492 dialog->setButtons(KGuiItem{i18n("&Details"), QStringLiteral("documentinfo")}, KStandardGuiItem::cont(), KStandardGuiItem::cancel()); 0493 0494 connect(dialog, &KMessageDialog::finished, this, [this, parentWidget, sslErrorData](int result) { 0495 if (result == KMessageDialog::PrimaryAction) { 0496 showSslDetails(sslErrorData, parentWidget); 0497 } else if (result == KMessageDialog::SecondaryAction) { 0498 // continue(); 0499 Q_EMIT askIgnoreSslErrorsResult(1); 0500 } else if (result == KMessageDialog::Cancel) { 0501 // cancel(); 0502 Q_EMIT askIgnoreSslErrorsResult(0); 0503 } else { 0504 Q_UNREACHABLE(); 0505 } 0506 }); 0507 0508 dialog->show(); 0509 } 0510 0511 void KIO::WidgetsAskUserActionHandler::showSslDetails(const QVariantMap &sslErrorData, QWidget *parentWidget) 0512 { 0513 const QStringList sslList = sslErrorData[QLatin1String("peerCertChain")].toStringList(); 0514 0515 QList<QSslCertificate> certChain; 0516 bool decodedOk = true; 0517 for (const QString &str : sslList) { 0518 certChain.append(QSslCertificate(str.toUtf8())); 0519 if (certChain.last().isNull()) { 0520 decodedOk = false; 0521 break; 0522 } 0523 } 0524 0525 QMetaObject::invokeMethod(qGuiApp, [=] { 0526 if (decodedOk) { // Use KSslInfoDialog 0527 KSslInfoDialog *ksslDlg = new KSslInfoDialog(parentWidget); 0528 ksslDlg->setSslInfo( 0529 certChain, 0530 QString(), 0531 sslErrorData[QLatin1String("hostname")].toString(), 0532 sslErrorData[QLatin1String("protocol")].toString(), 0533 sslErrorData[QLatin1String("cipher")].toString(), 0534 sslErrorData[QLatin1String("usedBits")].toInt(), 0535 sslErrorData[QLatin1String("bits")].toInt(), 0536 KSslInfoDialog::certificateErrorsFromString(sslErrorData[QLatin1String("certificateErrors")].toStringList().join(QLatin1Char('\n')))); 0537 0538 // KSslInfoDialog deletes itself by setting Qt::WA_DeleteOnClose 0539 0540 QObject::connect(ksslDlg, &QDialog::finished, this, [this, sslErrorData, parentWidget]() { 0541 // KSslInfoDialog only has one button, QDialogButtonBox::Close 0542 askIgnoreSslErrors(sslErrorData, parentWidget); 0543 }); 0544 0545 ksslDlg->show(); 0546 return; 0547 } 0548 0549 // Fallback to a generic message box 0550 auto *dialog = new KMessageDialog(KMessageDialog::Information, i18n("The peer SSL certificate chain appears to be corrupt."), parentWidget); 0551 0552 dialog->setAttribute(Qt::WA_DeleteOnClose); 0553 dialog->setCaption(i18n("SSL")); 0554 dialog->setButtons(KStandardGuiItem::ok()); 0555 0556 QObject::connect(dialog, &QDialog::finished, this, [this](const int result) { 0557 Q_EMIT askIgnoreSslErrorsResult(result == KMessageDialog::Ok ? 1 : 0); 0558 }); 0559 0560 dialog->show(); 0561 }); 0562 } 0563 0564 #include "moc_widgetsaskuseractionhandler.cpp"