File indexing completed on 2024-06-23 05:14:03

0001 /* -*- mode: c++; c-basic-offset:4 -*-
0002     dialogs/deletecertificatesdialog.cpp
0003 
0004     This file is part of Kleopatra, the KDE keymanager
0005     SPDX-FileCopyrightText: 2009 Klarälvdalens Datakonsult AB
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 
0010 #include <config-kleopatra.h>
0011 
0012 #include "deletecertificatesdialog.h"
0013 
0014 #include <utils/accessibility.h>
0015 #include <view/keytreeview.h>
0016 
0017 #include <Libkleo/KeyListModel>
0018 #include <Libkleo/Stl_Util>
0019 
0020 #include "kleopatra_debug.h"
0021 #include <KConfigGroup>
0022 #include <KLocalizedString>
0023 #include <KMessageBox>
0024 #include <KSharedConfig>
0025 #include <KStandardGuiItem>
0026 
0027 #include <QCursor>
0028 #include <QDialogButtonBox>
0029 #include <QLabel>
0030 #include <QPushButton>
0031 #include <QTreeView>
0032 #include <QVBoxLayout>
0033 #include <QWhatsThis>
0034 
0035 #include <gpgme++/key.h>
0036 
0037 using namespace Kleo;
0038 using namespace Kleo::Dialogs;
0039 using namespace GpgME;
0040 
0041 class DeleteCertificatesDialog::Private
0042 {
0043     friend class ::Kleo::Dialogs::DeleteCertificatesDialog;
0044     DeleteCertificatesDialog *const q;
0045 
0046 public:
0047     explicit Private(DeleteCertificatesDialog *qq)
0048         : q(qq)
0049         , ui(q)
0050     {
0051     }
0052 
0053     void slotWhatsThisRequested()
0054     {
0055         qCDebug(KLEOPATRA_LOG);
0056         if (QWidget *const widget = qobject_cast<QWidget *>(q->sender()))
0057             if (!widget->whatsThis().isEmpty()) {
0058                 showToolTip(QCursor::pos(), widget->whatsThis(), widget);
0059             }
0060     }
0061 
0062     void readConfig()
0063     {
0064         KConfigGroup dialog(KSharedConfig::openStateConfig(), QStringLiteral("DeleteCertificatesDialog"));
0065         ui.selectedKTV.restoreLayout(dialog);
0066         ui.unselectedKTV.restoreLayout(dialog);
0067         const QSize size = dialog.readEntry("Size", QSize(600, 400));
0068         if (size.isValid()) {
0069             q->resize(size);
0070         }
0071     }
0072 
0073     void writeConfig()
0074     {
0075         KConfigGroup dialog(KSharedConfig::openStateConfig(), QStringLiteral("DeleteCertificatesDialog"));
0076         dialog.writeEntry("Size", q->size());
0077         dialog.sync();
0078     }
0079 
0080 private:
0081     struct UI {
0082         QLabel selectedLB;
0083         KeyTreeView selectedKTV;
0084         QLabel unselectedLB;
0085         KeyTreeView unselectedKTV;
0086         QDialogButtonBox buttonBox;
0087         QVBoxLayout vlay;
0088 
0089         explicit UI(DeleteCertificatesDialog *qq)
0090             : selectedLB(i18n("These are the certificates you have selected for deletion:"), qq)
0091             , selectedKTV(qq)
0092             , unselectedLB(i18n("These certificates will be deleted even though you did <b>not</b> "
0093                                 "explicitly select them (<a href=\"whatsthis://\">Why?</a>):"),
0094                            qq)
0095             , unselectedKTV(qq)
0096             , buttonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel)
0097             , vlay(qq)
0098         {
0099             KDAB_SET_OBJECT_NAME(selectedLB);
0100             KDAB_SET_OBJECT_NAME(selectedKTV);
0101             KDAB_SET_OBJECT_NAME(unselectedLB);
0102             KDAB_SET_OBJECT_NAME(unselectedKTV);
0103             KDAB_SET_OBJECT_NAME(buttonBox);
0104             KDAB_SET_OBJECT_NAME(vlay);
0105 
0106             vlay.addWidget(&selectedLB);
0107             vlay.addWidget(&selectedKTV, 1);
0108             vlay.addWidget(&unselectedLB);
0109             vlay.addWidget(&unselectedKTV, 1);
0110             vlay.addWidget(&buttonBox);
0111 
0112             const QString unselectedWhatsThis = xi18nc("@info:whatsthis",
0113                                                        "<title>Why do you want to delete more certificates than I selected?</title>"
0114                                                        "<para>When you delete CA certificates (both root CAs and intermediate CAs), "
0115                                                        "the certificates issued by them will also be deleted.</para>"
0116                                                        "<para>This can be nicely seen in <application>Kleopatra</application>'s "
0117                                                        "hierarchical view mode: In this mode, if you delete a certificate that has "
0118                                                        "children, those children will also be deleted. Think of CA certificates as "
0119                                                        "folders containing other certificates: When you delete the folder, you "
0120                                                        "delete its contents, too.</para>");
0121             unselectedLB.setContextMenuPolicy(Qt::NoContextMenu);
0122             unselectedLB.setWhatsThis(unselectedWhatsThis);
0123             unselectedKTV.setWhatsThis(unselectedWhatsThis);
0124 
0125             buttonBox.button(QDialogButtonBox::Ok)->setText(i18nc("@action:button", "Delete"));
0126 
0127             connect(&unselectedLB, SIGNAL(linkActivated(QString)), qq, SLOT(slotWhatsThisRequested()));
0128 
0129             selectedKTV.setFlatModel(AbstractKeyListModel::createFlatKeyListModel(&selectedKTV));
0130             unselectedKTV.setFlatModel(AbstractKeyListModel::createFlatKeyListModel(&unselectedKTV));
0131 
0132             selectedKTV.setHierarchicalView(false);
0133             selectedKTV.view()->setSelectionMode(QAbstractItemView::NoSelection);
0134             unselectedKTV.setHierarchicalView(false);
0135             unselectedKTV.view()->setSelectionMode(QAbstractItemView::NoSelection);
0136 
0137             connect(&buttonBox, SIGNAL(accepted()), qq, SLOT(accept()));
0138             connect(&buttonBox, &QDialogButtonBox::rejected, qq, &QDialog::reject);
0139         }
0140     } ui;
0141 };
0142 
0143 DeleteCertificatesDialog::DeleteCertificatesDialog(QWidget *p)
0144     : QDialog(p)
0145     , d(new Private(this))
0146 {
0147     d->readConfig();
0148 }
0149 
0150 DeleteCertificatesDialog::~DeleteCertificatesDialog()
0151 {
0152     d->writeConfig();
0153 }
0154 
0155 void DeleteCertificatesDialog::setSelectedKeys(const std::vector<Key> &keys)
0156 {
0157     d->ui.selectedKTV.setKeys(keys);
0158 }
0159 
0160 void DeleteCertificatesDialog::setUnselectedKeys(const std::vector<Key> &keys)
0161 {
0162     d->ui.unselectedLB.setVisible(!keys.empty());
0163     d->ui.unselectedKTV.setVisible(!keys.empty());
0164     d->ui.unselectedKTV.setKeys(keys);
0165 }
0166 
0167 std::vector<Key> DeleteCertificatesDialog::keys() const
0168 {
0169     const std::vector<Key> sel = d->ui.selectedKTV.keys();
0170     const std::vector<Key> uns = d->ui.unselectedKTV.keys();
0171     std::vector<Key> result;
0172     result.reserve(sel.size() + uns.size());
0173     result.insert(result.end(), sel.begin(), sel.end());
0174     result.insert(result.end(), uns.begin(), uns.end());
0175     return result;
0176 }
0177 
0178 void DeleteCertificatesDialog::accept()
0179 {
0180     const std::vector<Key> sel = d->ui.selectedKTV.keys();
0181     const std::vector<Key> uns = d->ui.unselectedKTV.keys();
0182 
0183     const uint secret =
0184         std::count_if(sel.cbegin(), sel.cend(), std::mem_fn(&Key::hasSecret)) + std::count_if(uns.cbegin(), uns.cend(), std::mem_fn(&Key::hasSecret));
0185     const uint total = sel.size() + uns.size();
0186 
0187     int ret = KMessageBox::Continue;
0188     if (secret)
0189         ret = KMessageBox::warningContinueCancel(this,
0190                                                  secret == total ? i18np("The certificate to be deleted is your own. "
0191                                                                          "It contains private key material, "
0192                                                                          "which is needed to decrypt past communication "
0193                                                                          "encrypted to the certificate, and should therefore "
0194                                                                          "not be deleted.",
0195 
0196                                                                          "All of the certificates to be deleted "
0197                                                                          "are your own. "
0198                                                                          "They contain private key material, "
0199                                                                          "which is needed to decrypt past communication "
0200                                                                          "encrypted to the certificate, and should therefore "
0201                                                                          "not be deleted.",
0202 
0203                                                                          secret)
0204                                                                  : i18np("One of the certificates to be deleted "
0205                                                                          "is your own. "
0206                                                                          "It contains private key material, "
0207                                                                          "which is needed to decrypt past communication "
0208                                                                          "encrypted to the certificate, and should therefore "
0209                                                                          "not be deleted.",
0210 
0211                                                                          "Some of the certificates to be deleted "
0212                                                                          "are your own. "
0213                                                                          "They contain private key material, "
0214                                                                          "which is needed to decrypt past communication "
0215                                                                          "encrypted to the certificate, and should therefore "
0216                                                                          "not be deleted.",
0217 
0218                                                                          secret),
0219                                                  i18nc("@title:window", "Secret Key Deletion"),
0220                                                  KStandardGuiItem::guiItem(KStandardGuiItem::Delete),
0221                                                  KStandardGuiItem::cancel(),
0222                                                  QString(),
0223                                                  KMessageBox::Notify | KMessageBox::Dangerous);
0224 
0225     if (ret == KMessageBox::Continue) {
0226         QDialog::accept();
0227     } else {
0228         QDialog::reject();
0229     }
0230 }
0231 
0232 #include "moc_deletecertificatesdialog.cpp"