1 /* -*- mode: c++; c-basic-offset:4 -*-
2     dialogs/deletecertificatesdialog.cpp
3 
4     This file is part of Kleopatra, the KDE keymanager
5     SPDX-FileCopyrightText: 2009 Klarälvdalens Datakonsult AB
6 
7     SPDX-License-Identifier: GPL-2.0-or-later
8 */
9 
10 #include <config-kleopatra.h>
11 
12 #include "deletecertificatesdialog.h"
13 
14 #include <view/keytreeview.h>
15 
16 #include <Libkleo/KeyListModel>
17 #include <Libkleo/Stl_Util>
18 
19 #include <KLocalizedString>
20 #include <KMessageBox>
21 #include <KStandardGuiItem>
22 #include "kleopatra_debug.h"
23 #include <KConfigGroup>
24 #include <KSharedConfig>
25 
26 #include <QLabel>
27 #include <QDialogButtonBox>
28 #include <QVBoxLayout>
29 #include <QWhatsThis>
30 #include <QCursor>
31 #include <QPushButton>
32 #include <QTreeView>
33 
34 #include <gpgme++/key.h>
35 
36 
37 using namespace Kleo;
38 using namespace Kleo::Dialogs;
39 using namespace GpgME;
40 
41 class DeleteCertificatesDialog::Private
42 {
43     friend class ::Kleo::Dialogs::DeleteCertificatesDialog;
44     DeleteCertificatesDialog *const q;
45 public:
Private(DeleteCertificatesDialog * qq)46     explicit Private(DeleteCertificatesDialog *qq)
47         : q(qq),
48           ui(q)
49     {
50 
51     }
52 
slotWhatsThisRequested()53     void slotWhatsThisRequested()
54     {
55         qCDebug(KLEOPATRA_LOG);
56         if (QWidget *const widget = qobject_cast<QWidget *>(q->sender()))
57             if (!widget->whatsThis().isEmpty()) {
58                 QWhatsThis::showText(QCursor::pos(), widget->whatsThis());
59             }
60     }
61 
readConfig()62     void readConfig()
63     {
64         KConfigGroup dialog(KSharedConfig::openStateConfig(), "DeleteCertificatesDialog");
65         ui.selectedKTV.restoreLayout(dialog);
66         ui.unselectedKTV.restoreLayout(dialog);
67         const QSize size = dialog.readEntry("Size", QSize(600, 400));
68         if (size.isValid()) {
69             q->resize(size);
70         }
71     }
72 
writeConfig()73     void writeConfig()
74     {
75         KConfigGroup dialog(KSharedConfig::openStateConfig(), "DeleteCertificatesDialog");
76         ui.selectedKTV.saveLayout(dialog);
77         dialog.writeEntry("Size", q->size());
78         dialog.sync();
79     }
80 
81 private:
82     struct UI {
83         QLabel selectedLB;
84         KeyTreeView selectedKTV;
85         QLabel unselectedLB;
86         KeyTreeView unselectedKTV;
87         QDialogButtonBox buttonBox;
88         QVBoxLayout vlay;
89 
UIDeleteCertificatesDialog::Private::UI90         explicit UI(DeleteCertificatesDialog *qq)
91             : selectedLB(i18n("These are the certificates you have selected for deletion:"), qq),
92               selectedKTV(qq),
93               unselectedLB(i18n("These certificates will be deleted even though you did <b>not</b> "
94                                  "explicitly select them (<a href=\"whatsthis://\">Why?</a>):"), qq),
95               unselectedKTV(qq),
96               buttonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel),
97               vlay(qq)
98         {
99             KDAB_SET_OBJECT_NAME(selectedLB);
100             KDAB_SET_OBJECT_NAME(selectedKTV);
101             KDAB_SET_OBJECT_NAME(unselectedLB);
102             KDAB_SET_OBJECT_NAME(unselectedKTV);
103             KDAB_SET_OBJECT_NAME(buttonBox);
104             KDAB_SET_OBJECT_NAME(vlay);
105 
106             vlay.addWidget(&selectedLB);
107             vlay.addWidget(&selectedKTV, 1);
108             vlay.addWidget(&unselectedLB);
109             vlay.addWidget(&unselectedKTV, 1);
110             vlay.addWidget(&buttonBox);
111 
112             const QString unselectedWhatsThis
113                 = xi18nc("@info:whatsthis",
114                          "<title>Why do you want to delete more certificates than I selected?</title>"
115                          "<para>When you delete CA certificates (both root CAs and intermediate CAs), "
116                          "the certificates issued by them will also be deleted.</para>"
117                          "<para>This can be nicely seen in <application>Kleopatra</application>'s "
118                          "hierarchical view mode: In this mode, if you delete a certificate that has "
119                          "children, those children will also be deleted. Think of CA certificates as "
120                          "folders containing other certificates: When you delete the folder, you "
121                          "delete its contents, too.</para>");
122             unselectedLB.setContextMenuPolicy(Qt::NoContextMenu);
123             unselectedLB.setWhatsThis(unselectedWhatsThis);
124             unselectedKTV.setWhatsThis(unselectedWhatsThis);
125 
126             buttonBox.button(QDialogButtonBox::Ok)->setText(i18nc("@action:button", "Delete"));
127 
128             connect(&unselectedLB, SIGNAL(linkActivated(QString)), qq, SLOT(slotWhatsThisRequested()));
129 
130             selectedKTV.setFlatModel(AbstractKeyListModel::createFlatKeyListModel(&selectedKTV));
131             unselectedKTV.setFlatModel(AbstractKeyListModel::createFlatKeyListModel(&unselectedKTV));
132 
133             selectedKTV.setHierarchicalView(false);
134             selectedKTV.view()->setSelectionMode(QAbstractItemView::NoSelection);
135             unselectedKTV.setHierarchicalView(false);
136             unselectedKTV.view()->setSelectionMode(QAbstractItemView::NoSelection);
137 
138             connect(&buttonBox, SIGNAL(accepted()), qq, SLOT(accept()));
139             connect(&buttonBox, &QDialogButtonBox::rejected, qq, &QDialog::reject);
140         }
141     } ui;
142 };
143 
DeleteCertificatesDialog(QWidget * p)144 DeleteCertificatesDialog::DeleteCertificatesDialog(QWidget *p)
145     : QDialog(p), d(new Private(this))
146 {
147     d->readConfig();
148 }
149 
~DeleteCertificatesDialog()150 DeleteCertificatesDialog::~DeleteCertificatesDialog()
151 {
152     d->writeConfig();
153 }
154 
setSelectedKeys(const std::vector<Key> & keys)155 void DeleteCertificatesDialog::setSelectedKeys(const std::vector<Key> &keys)
156 {
157     d->ui.selectedKTV.setKeys(keys);
158 }
159 
setUnselectedKeys(const std::vector<Key> & keys)160 void DeleteCertificatesDialog::setUnselectedKeys(const std::vector<Key> &keys)
161 {
162     d->ui.unselectedLB .setVisible(!keys.empty());
163     d->ui.unselectedKTV.setVisible(!keys.empty());
164     d->ui.unselectedKTV.setKeys(keys);
165 }
166 
keys() const167 std::vector<Key> DeleteCertificatesDialog::keys() const
168 {
169     const std::vector<Key> sel = d->ui.selectedKTV.keys();
170     const std::vector<Key> uns = d->ui.unselectedKTV.keys();
171     std::vector<Key> result;
172     result.reserve(sel.size() + uns.size());
173     result.insert(result.end(), sel.begin(), sel.end());
174     result.insert(result.end(), uns.begin(), uns.end());
175     return result;
176 }
177 
accept()178 void DeleteCertificatesDialog::accept()
179 {
180 
181     const std::vector<Key> sel = d->ui.selectedKTV.keys();
182     const std::vector<Key> uns = d->ui.unselectedKTV.keys();
183 
184     const uint secret = std::count_if(sel.cbegin(), sel.cend(), std::mem_fn(&Key::hasSecret))
185                         + std::count_if(uns.cbegin(), uns.cend(), std::mem_fn(&Key::hasSecret));
186     const uint total  = sel.size() + uns.size();
187 
188     int ret = KMessageBox::Continue;
189     if (secret)
190         ret = KMessageBox::warningContinueCancel(this,
191                 secret == total
192                 ? i18np("The certificate to be deleted is your own. "
193                         "It contains private key material, "
194                         "which is needed to decrypt past communication "
195                         "encrypted to the certificate, and should therefore "
196                         "not be deleted.",
197 
198                         "All of the certificates to be deleted "
199                         "are your own. "
200                         "They contain private key material, "
201                         "which is needed to decrypt past communication "
202                         "encrypted to the certificate, and should therefore "
203                         "not be deleted.",
204 
205                         secret)
206                 : i18np("One of the certificates to be deleted "
207                         "is your own. "
208                         "It contains private key material, "
209                         "which is needed to decrypt past communication "
210                         "encrypted to the certificate, and should therefore "
211                         "not be deleted.",
212 
213                         "Some of the certificates to be deleted "
214                         "are your own. "
215                         "They contain private key material, "
216                         "which is needed to decrypt past communication "
217                         "encrypted to the certificate, and should therefore "
218                         "not be deleted.",
219 
220                         secret),
221                 i18n("Secret Key Deletion"),
222                 KStandardGuiItem::guiItem(KStandardGuiItem::Delete),
223                 KStandardGuiItem::cancel(), QString(), KMessageBox::Notify | KMessageBox::Dangerous);
224 
225     if (ret == KMessageBox::Continue) {
226         QDialog::accept();
227     } else {
228         QDialog::reject();
229     }
230 }
231 
232 #include "moc_deletecertificatesdialog.cpp"
233