QCA

keyselectdlg.cpp
1/*
2 Copyright (C) 2007 Justin Karneges <justin@affinix.com>
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20*/
21
22#include "keyselectdlg.h"
23
24#include "ui_keyselect.h"
25#include <QMenu>
26#include <QMessageBox>
27#include <QPushButton>
28#include <QtCore>
29#include <QtCrypto>
30#include <QtGui>
31
32#define ONLY_SHOW_KEYBUNDLE
33
35
36class KeyStoreItemShared
37{
38public:
39 KeyStoreIconset iconset;
40 QString notAvailableString;
41};
42
43class KeyStoreItem : public QStandardItem
44{
45public:
46 enum Type
47 {
48 Store = UserType,
49 Entry
50 };
51
52 enum Role
53 {
54 NameRole = Qt::UserRole,
55 SubTypeRole,
56 AvailabilityRole,
57 PositionRole
58 };
59
60 QPixmap entryTypeToIcon(QCA::KeyStoreEntry::Type type) const
61 {
62 QPixmap out;
63 if (!_shared)
64 return out;
65 const KeyStoreIconset &iconset = _shared->iconset;
66 switch (type) {
67 case QCA::KeyStoreEntry::TypeKeyBundle:
68 out = iconset[KeySelectDlg::IconKeyBundle];
69 break;
70 case QCA::KeyStoreEntry::TypeCertificate:
71 out = iconset[KeySelectDlg::IconCert];
72 break;
73 case QCA::KeyStoreEntry::TypeCRL:
74 out = iconset[KeySelectDlg::IconCrl];
75 break;
76 case QCA::KeyStoreEntry::TypePGPSecretKey:
77 out = iconset[KeySelectDlg::IconPgpSec];
78 break;
79 case QCA::KeyStoreEntry::TypePGPPublicKey:
80 out = iconset[KeySelectDlg::IconPgpPub];
81 break;
82 default:
83 break;
84 }
85 return out;
86 }
87
88 Type _type;
89 KeyStoreItemShared *_shared;
90
91 QCA::KeyStore *keyStore;
92 QCA::KeyStoreEntry keyStoreEntry;
93
94 KeyStoreItem(Type type, KeyStoreItemShared *shared)
95 : _type(type)
96 , _shared(shared)
97 {
99 }
100
101 void setStore(const QString &name, QCA::KeyStore::Type type)
102 {
103 setData(name, NameRole);
104 setData((int)type, SubTypeRole);
105 }
106
107 void setEntry(const QString &name, QCA::KeyStoreEntry::Type type, bool available, int pos)
108 {
109 setData(name, NameRole);
110 setData((int)type, SubTypeRole);
111 setData(available, AvailabilityRole);
112 setData(pos, PositionRole);
113 }
114
115 virtual QVariant data(int role) const
116 {
117 if (role == Qt::DisplayRole) {
118 if (_type == Store) {
119 return data(NameRole).toString();
120 } else if (_type == Entry) {
121 QString str = data(NameRole).toString();
122 if (_shared && !data(AvailabilityRole).toBool())
123 str += QString(" ") + _shared->notAvailableString;
124 return str;
125 } else
126 return QStandardItem::data(role);
127 } else if (role == Qt::DecorationRole) {
128 if (_type == Entry) {
130 return entryTypeToIcon(type);
131 } else
132 return QStandardItem::data(role);
133 } else
134 return QStandardItem::data(role);
135 }
136
137 virtual int type() const
138 {
139 return _type;
140 }
141
142 virtual QStandardItem *clone() const
143 {
144 return new KeyStoreItem(*this);
145 }
146};
147
148class KeyStoreModel : public QStandardItemModel
149{
151public:
152 KeyStoreItemShared shared;
153
155
156 KeyStoreModel(QObject *parent = 0)
158 , ksm(this)
159 {
160 shared.notAvailableString = tr("(not available)");
161
162 // make sure keystores are started
164
165 connect(&ksm, SIGNAL(keyStoreAvailable(const QString &)), SLOT(ks_available(const QString &)));
166 QStringList list = ksm.keyStores();
167 foreach (const QString &s, list)
168 ks_available(s);
169
170 setSortRole(KeyStoreItem::PositionRole);
171 }
172
173 KeyStoreItem *itemFromStore(QCA::KeyStore *ks) const
174 {
175 for (int n = 0; n < rowCount(); ++n) {
176 KeyStoreItem *i = (KeyStoreItem *)item(n);
177 if (i->keyStore == ks)
178 return i;
179 }
180 return 0;
181 }
182
183private Q_SLOTS:
184 void ks_available(const QString &keyStoreId)
185 {
186 QCA::KeyStore *ks = new QCA::KeyStore(keyStoreId, &ksm);
187
188#ifdef ONLY_SHOW_KEYBUNDLE
189 // only list stores containing keybundles (non-pgp identities)
190 if (!ks->holdsIdentities() || ks->type() == QCA::KeyStore::PGPKeyring)
191 return;
192#endif
193
194 connect(ks, SIGNAL(updated()), SLOT(ks_updated()));
195 connect(ks, SIGNAL(unavailable()), SLOT(ks_unavailable()));
196
197 KeyStoreItem *store_item = new KeyStoreItem(KeyStoreItem::Store, &shared);
198 store_item->setStore(ks->name(), ks->type());
199 store_item->keyStore = ks;
201 appendRow(store_item);
202 }
203
204 void ks_updated()
205 {
207 KeyStoreItem *store_item = itemFromStore(ks);
208 Q_ASSERT(store_item);
209
210 QList<QCA::KeyStoreEntry> newEntries = ks->entryList();
211
212#ifdef ONLY_SHOW_KEYBUNDLE
213 // ignore entries that are not keybundles
214 for (int n = 0; n < newEntries.count(); ++n) {
215 if (newEntries[n].type() != QCA::KeyStoreEntry::TypeKeyBundle) {
216 newEntries.removeAt(n);
217 --n; // adjust position
218 }
219 }
220#endif
221
222 // update the store item itself
223 store_item->setStore(ks->name(), ks->type());
224
225 // handle removed child entries
226 for (int n = 0; n < store_item->rowCount(); ++n) {
227 KeyStoreItem *i = (KeyStoreItem *)store_item->child(n);
228
229 // is the existing entry in the new list?
230 bool found = false;
231 foreach (const QCA::KeyStoreEntry &ne, newEntries) {
232 if (ne.id() == i->keyStoreEntry.id()) {
233 found = true;
234 break;
235 }
236 }
237
238 // if not, remove it
239 if (!found) {
240 store_item->removeRow(n);
241 --n; // adjust position
242 }
243 }
244
245 // handle added/updated child entries
246 for (int n = 0; n < newEntries.count(); ++n) {
247 const QCA::KeyStoreEntry &ne = newEntries[n];
248
249 // was this entry in the original list?
250 KeyStoreItem *entry_item = 0;
251 for (int k = 0; k < store_item->rowCount(); ++k) {
252 KeyStoreItem *i = (KeyStoreItem *)store_item->child(k);
253 if (i->keyStoreEntry.id() == ne.id()) {
254 entry_item = i;
255 break;
256 }
257 }
258
259 // if not, add it
260 if (!entry_item) {
261 entry_item = new KeyStoreItem(KeyStoreItem::Entry, &shared);
262 entry_item->keyStoreEntry = ne;
263 entry_item->setEntry(newEntries[n].name(), newEntries[n].type(), newEntries[n].isAvailable(), n);
264 store_item->appendRow(entry_item);
265 }
266 // if so, update it
267 else {
268 entry_item->keyStoreEntry = ne;
269 entry_item->setEntry(newEntries[n].name(), newEntries[n].type(), newEntries[n].isAvailable(), n);
270 }
271 }
272
273 store_item->sortChildren(0);
274 }
275
276 void ks_unavailable()
277 {
279 KeyStoreItem *store_item = itemFromStore(ks);
280 Q_ASSERT(store_item);
281
282 store_item->removeRows(0, store_item->rowCount());
283 removeRow(store_item->row());
284 delete ks;
285 }
286};
287
288class KeySelectDlg::Private : public QObject
289{
291public:
292 KeySelectDlg *q;
293 Ui_KeySelect ui;
294 KeyStoreModel *model;
295 QCA::KeyStoreEntry cur_entry;
296 QAction *actionView;
297
298 Private(KeySelectDlg *_q)
299 : QObject(_q)
300 , q(_q)
301 {
302 ui.setupUi(q);
303
304 model = new KeyStoreModel(this);
305 connect(&model->ksm, SIGNAL(busyStarted()), SLOT(ksm_busyStarted()));
306 connect(&model->ksm, SIGNAL(busyFinished()), SLOT(ksm_busyFinished()));
307 if (model->ksm.isBusy())
308 ksm_busyStarted();
309
310 ui.lv_stores->header()->hide();
311 ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
312 ui.lv_stores->setModel(model);
313 ui.lv_stores->setContextMenuPolicy(Qt::CustomContextMenu);
314 connect(ui.lv_stores->selectionModel(),
315 SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)),
316 SLOT(stores_selectionChanged(const QItemSelection &, const QItemSelection &)));
317 connect(ui.lv_stores,
318 SIGNAL(customContextMenuRequested(const QPoint &)),
319 SLOT(stores_customContextMenuRequested(const QPoint &)));
320
321 actionView = new QAction(tr("&View"), this);
322 connect(actionView, SIGNAL(triggered()), SLOT(view()));
323 actionView->setEnabled(false);
324 }
325
326private Q_SLOTS:
327 void ksm_busyStarted()
328 {
329 ui.lb_busy->setText(tr("Looking for devices..."));
330 }
331
332 void ksm_busyFinished()
333 {
334 ui.lb_busy->setText("");
335 }
336
337 void stores_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
338 {
339 Q_UNUSED(deselected);
340
341 KeyStoreItem *i = 0;
342 if (!selected.indexes().isEmpty()) {
343 QModelIndex index = selected.indexes().first();
344 i = (KeyStoreItem *)model->itemFromIndex(index);
345 }
346
347 bool viewable = false;
348 bool choosable = false;
349 if (i && i->type() == KeyStoreItem::Entry) {
350 QCA::KeyStoreEntry entry = i->keyStoreEntry;
351 if (entry.type() == QCA::KeyStoreEntry::TypeKeyBundle) {
352 viewable = true;
353 choosable = true;
354 cur_entry = entry;
355 }
356 }
357
358 if (!choosable)
359 cur_entry = QCA::KeyStoreEntry();
360
361 actionView->setEnabled(viewable);
362
363 QPushButton *ok = ui.buttonBox->button(QDialogButtonBox::Ok);
364 if (choosable && !ok->isEnabled())
365 ok->setEnabled(true);
366 else if (!choosable && ok->isEnabled())
367 ok->setEnabled(false);
368 }
369
370 void stores_customContextMenuRequested(const QPoint &pos)
371 {
372 QItemSelection selection = ui.lv_stores->selectionModel()->selection();
373 if (selection.indexes().isEmpty())
374 return;
375
376 QModelIndex index = selection.indexes().first();
377 KeyStoreItem *i = (KeyStoreItem *)model->itemFromIndex(index);
378 if (i && i->type() == KeyStoreItem::Entry) {
379 QMenu menu(q);
380 menu.addAction(actionView);
381 menu.exec(ui.lv_stores->viewport()->mapToGlobal(pos));
382 }
383 }
384
385 void view()
386 {
387 emit q->viewCertificate(cur_entry.keyBundle().certificateChain());
388 }
389};
390
391KeySelectDlg::KeySelectDlg(QWidget *parent)
392 : QDialog(parent)
393{
394 d = new Private(this);
395}
396
397KeySelectDlg::~KeySelectDlg()
398{
399 delete d;
400}
401
402void KeySelectDlg::setIcon(IconType type, const QPixmap &icon)
403{
404 d->model->shared.iconset[type] = icon;
405}
406
407void KeySelectDlg::accept()
408{
409 QCA::KeyStoreEntry entry = d->cur_entry;
411 emit selected(entry);
412}
413
414#include "keyselectdlg.moc"
bool isEnabled() const
void setEnabled(bool enable)
CertificateChain certificateChain() const
The public certificate part of this bundle.
Single entry in a KeyStore.
Type
The type of entry in the KeyStore.
Type type() const
Determine the type of key stored in this object.
KeyBundle keyBundle() const
If a KeyBundle is stored in this object, return that bundle.
QString id() const
The ID associated with the key stored in this object.
Access keystores, and monitor keystores for changes.
QStringList keyStores() const
A list of all the key stores.
bool isBusy() const
Indicates if the manager is busy looking for key stores.
static void start()
Initialize all key store providers.
General purpose key storage object.
QString name() const
The name associated with the KeyStore.
QList< KeyStoreEntry > entryList() const
A list of the KeyStoreEntry objects in this store.
Type type() const
The KeyStore Type.
void startAsynchronousMode()
Turns on asynchronous mode for this KeyStore instance.
Type
The type of keystore.
@ PGPKeyring
for a PGP keyring
bool holdsIdentities() const
test if the KeyStore holds identities (eg KeyBundle or PGPSecretKey)
Type type(const QSqlDatabase &db)
KIOCORE_EXPORT QStringList list(const QString &fileClass)
QString name(StandardShortcut id)
bool removeRow(int row, const QModelIndex &parent)
void setEnabled(bool)
virtual void accept()
QModelIndexList indexes() const const
qsizetype count() const const
void removeAt(qsizetype i)
Q_OBJECTQ_OBJECT
Q_SLOTSQ_SLOTS
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QObject * parent() const const
QObject * sender() const const
QString tr(const char *sourceText, const char *disambiguation, int n)
void appendRow(QStandardItem *item)
QStandardItem * child(int row, int column) const const
virtual QVariant data(int role) const const
void removeRow(int row)
void removeRows(int row, int count)
int row() const const
int rowCount() const const
virtual void setData(const QVariant &value, int role)
void setFlags(Qt::ItemFlags flags)
void sortChildren(int column, Qt::SortOrder order)
void appendRow(QStandardItem *item)
QStandardItem * item(int row, int column) const const
QStandardItem * itemFromIndex(const QModelIndex &index) const const
virtual int rowCount(const QModelIndex &parent) const const override
void setSortRole(int role)
CustomContextMenu
UserRole
ItemIsEnabled
int toInt(bool *ok) const const
QString toString() const const
void customContextMenuRequested(const QPoint &pos)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:18:26 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.