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