useridlistmodel.cpp 8.8 KB
Newer Older
1
2
3
4
/* -*- mode: c++; c-basic-offset:4 -*-
    models/useridlistmodel.cpp

    This file is part of Kleopatra, the KDE keymanager
5
6
    SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB
    SPDX-FileCopyrightText: 2016 Andre Heinecke <aheinecke@gnupg.org>
7

8
    SPDX-License-Identifier: GPL-2.0-or-later
9
10
11
12
*/

#include "useridlistmodel.h"

Ingo Klöcker's avatar
Ingo Klöcker committed
13
14
#include "keycache.h"
#include "utils/formatting.h"
15
16
17
18

#include <KLocalizedString>

#include <QVariant>
19
#include <QIcon>
20

Ingo Klöcker's avatar
Ingo Klöcker committed
21
#include <gpgme++/key.h>
22
23
24
25
26

#include <gpgme++/gpgmepp_version.h>
#if GPGMEPP_VERSION >= 0x10E00 // 1.14.0
# define GPGME_HAS_REMARKS
#endif
27
28
29
#if GPGMEPP_VERSION >= 0x10E01 // 1.14.1
# define GPGME_USERID_SIGNATURES_ARE_SORTABLE
#endif
30

31
32
33
34
35
36
37
38
39
40
using namespace GpgME;
using namespace Kleo;

class UIDModelItem
{
    // A uid model item can either be a UserID::Signature or a UserID.
    // you can find out which it is if the uid or the signature return
    // null values. (Not null but isNull)
    //
public:
41
    explicit UIDModelItem(const UserID::Signature &sig, UIDModelItem *parentItem, bool showRemarks)
Ingo Klöcker's avatar
Ingo Klöcker committed
42
43
        : mParentItem{parentItem}
        , mSig{sig}
44
45
46
47
48
49
    {
        mItemData  << QString::fromUtf8(sig.signerKeyID())
                   << Formatting::prettyName(sig)
                   << Formatting::prettyEMail(sig)
                   << Formatting::creationDateString(sig)
                   << Formatting::expirationDateString(sig)
50
51
52
53
54
55
56
57
58
59
60
61
                   << Formatting::validityShort(sig)
                   << (sig.isExportable() ? QStringLiteral("✓") : QString());

        if (showRemarks && parentItem) {
            QString lastNotation;
            for (const auto &notation: sig.notations()) {
                if (notation.name() && !strcmp(notation.name(), "rem@gnupg.org")) {
                    lastNotation = QString::fromUtf8(notation.value());
                }
            }
            mItemData << lastNotation;
        }
62
63
64
    }

    explicit UIDModelItem(const UserID &uid, UIDModelItem *parentItem)
Ingo Klöcker's avatar
Ingo Klöcker committed
65
66
        : mParentItem{parentItem}
        , mUid{uid}
67
68
69
70
71
    {
        mItemData << Formatting::prettyUserID(uid);
    }

    // The root item
Ingo Klöcker's avatar
Ingo Klöcker committed
72
    explicit UIDModelItem(bool showRemarks)
73
74
75
    {
        mItemData << i18n("ID")
                  << i18n("Name")
Andre Heinecke's avatar
Andre Heinecke committed
76
                  << i18n("E-Mail")
77
78
                  << i18n("Valid From")
                  << i18n("Valid Until")
79
80
81
82
83
84
                  << i18n("Status")
                  << i18n("Exportable");

        if (showRemarks) {
            mItemData << i18n("Tags");
        }
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
    }

    ~UIDModelItem()
    {
        qDeleteAll(mChildItems);
    }

    void appendChild(UIDModelItem *child)
    {
        mChildItems << child;
    }

    UIDModelItem *child(int row) const
    {
        return mChildItems.value(row);
    }

    const UIDModelItem *constChild(int row) const
    {
        return mChildItems.value(row);
    }

    int childCount() const
    {
        return mChildItems.count();
    }

    int columnCount() const
    {
        if (childCount()) {
            // We take the value from the first child
            // as we are likely a UID and our children
            // are UID Signatures.
            return constChild(0)->columnCount();
        }
        return mItemData.count();
    }

    QVariant data(int column) const
    {
        return mItemData.value(column);
    }

128
129
    QVariant toolTip(int column) const
    {
Ingo Klöcker's avatar
Ingo Klöcker committed
130
131
132
133
        if (!mSig.isNull()) {
            if (column == static_cast<int>(UserIDListModel::Column::Status)) {
                return i18n("class %1", mSig.certClass());
            }
134
135
136
137
138
139
        }
        return mItemData.value(column);
    }

    QVariant icon(int column) const
    {
Ingo Klöcker's avatar
Ingo Klöcker committed
140
        if (!mSig.isNull() && column == static_cast<int>(UserIDListModel::Column::Status)) {
141
142
            return Formatting::validityIcon(mSig);
        }
Ingo Klöcker's avatar
Ingo Klöcker committed
143
        return {};
144
145
    }

146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
    int row() const
    {
        if (mParentItem) {
            return mParentItem->mChildItems.indexOf(const_cast<UIDModelItem*>(this));
        }
        return 0;
    }

    UIDModelItem *parentItem() const
    {
        return mParentItem;
    }

    UserID::Signature signature() const
    {
        return mSig;
    }

    UserID uid() const
    {
        return mUid;
    }

private:
    QList<UIDModelItem*> mChildItems;
    QList<QVariant> mItemData;
Laurent Montel's avatar
Laurent Montel committed
172
    UIDModelItem *mParentItem = nullptr;
173
174
175
176
177
    UserID::Signature mSig;
    UserID mUid;
};

UserIDListModel::UserIDListModel(QObject *p)
178
    : QAbstractItemModel{p}
179
180
181
{
}

182
UserIDListModel::~UserIDListModel() = default;
183
184
185
186
187
188
189
190
191
192
193

Key UserIDListModel::key() const
{
    return mKey;
}

void UserIDListModel::setKey(const Key &key)
{
    beginResetModel();
    mKey = key;

194
    mRootItem.reset(new UIDModelItem(mRemarksEnabled));
195
196
    for (int i = 0, ids = key.numUserIDs(); i < ids; ++i) {
        UserID uid = key.userID(i);
197
        auto uidItem = new UIDModelItem(uid, mRootItem.get());
198
        mRootItem->appendChild(uidItem);
199
200
201
202
203
        std::vector<UserID::Signature> sigs = uid.signatures();
#ifdef GPGME_USERID_SIGNATURES_ARE_SORTABLE
        std::sort(sigs.begin(), sigs.end());
#endif
        for (const auto &sig : sigs) {
204
            auto sigItem = new UIDModelItem(sig, uidItem, mRemarksEnabled);
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
            uidItem->appendChild(sigItem);
        }
    }

    endResetModel();
}

int UserIDListModel::columnCount(const QModelIndex &parent) const
{
    if (parent.isValid()) {
        return static_cast<UIDModelItem*>(parent.internalPointer())->columnCount();
    }

    if (!mRootItem) {
        return 0;
    }

    return mRootItem->columnCount();
}

int UserIDListModel::rowCount(const QModelIndex &parent) const
{
    if (parent.column() > 0 || !mRootItem) {
        return 0;
    }

231
    const UIDModelItem *const parentItem = !parent.isValid() ? mRootItem.get() : static_cast<UIDModelItem*>(parent.internalPointer());
232
233
234
235
236
237
    return parentItem->childCount();
}

QModelIndex UserIDListModel::index(int row, int column, const QModelIndex &parent) const
{
    if (!hasIndex(row, column, parent)) {
Laurent Montel's avatar
Laurent Montel committed
238
        return {};
239
240
    }

241
242
    const UIDModelItem *const parentItem = !parent.isValid() ? mRootItem.get() : static_cast<UIDModelItem*>(parent.internalPointer());
    UIDModelItem *const childItem = parentItem->child(row);
243
244
245
246
247
248
249
250
251
252
    if (childItem) {
        return createIndex(row, column, childItem);
    } else {
        return QModelIndex();
    }
}

QModelIndex UserIDListModel::parent(const QModelIndex &index) const
{
    if (!index.isValid()) {
Laurent Montel's avatar
Laurent Montel committed
253
        return {};
254
    }
255
    auto childItem = static_cast<UIDModelItem*>(index.internalPointer());
256
257
    UIDModelItem *parentItem = childItem->parentItem();

258
    if (parentItem == mRootItem.get()) {
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
        return QModelIndex();
    }

    return createIndex(parentItem->row(), 0, parentItem);
}

QVariant UserIDListModel::headerData(int section, Qt::Orientation o, int role) const
{
    if (o == Qt::Horizontal && mRootItem) {
        if (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::ToolTipRole) {
            return mRootItem->data(section);
        }
    }
    return QVariant();
}

QVariant UserIDListModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid()) {
        return QVariant();
    }

281
282
    if (role != Qt::DisplayRole && role != Qt::EditRole && role != Qt::ToolTipRole &&
        role != Qt::DecorationRole) {
283
284
285
        return QVariant();
    }

286
    auto item = static_cast<UIDModelItem*>(index.internalPointer());
287

288
289
290
291
292
293
294
295
    if (role == Qt::ToolTipRole) {
        return item->toolTip(index.column());
    }

    if (role == Qt::DecorationRole) {
        return item->icon(index.column());
    }

296
297
298
    return item->data(index.column());
}

299
300
301
302
303
304
305
306
307
308
309
UserID UserIDListModel::userID(const QModelIndex& index) const
{
    if (!index.isValid()) {
        return UserID();
    }
    UIDModelItem *item = static_cast<UIDModelItem*>(index.internalPointer());
    return item->uid();
}

QVector<UserID> UserIDListModel::userIDs(const QModelIndexList &indexs) const
{
310
    QVector<GpgME::UserID> ret;
311
    for (const QModelIndex &idx : indexs) {
312
313
314
        if (!idx.isValid()) {
            continue;
        }
315
        auto item = static_cast<UIDModelItem*>(idx.internalPointer());
316
317
318
319
320
321
322
        if (!item->uid().isNull()) {
            ret << item->uid();
        }
    }
    return ret;
}

323
324
325
326
327
328
329
330
331
332
333
UserID::Signature UserIDListModel::signature(const QModelIndex& index) const
{
    if (!index.isValid()) {
        return UserID::Signature();
    }
    UIDModelItem *item = static_cast<UIDModelItem*>(index.internalPointer());
    return item->signature();
}

QVector<UserID::Signature> UserIDListModel::signatures(const QModelIndexList &indexs) const
{
334
    QVector<GpgME::UserID::Signature> ret;
335
    for (const QModelIndex &idx : indexs) {
336
337
338
        if (!idx.isValid()) {
            continue;
        }
339
        auto item = static_cast<UIDModelItem*>(idx.internalPointer());
340
341
342
343
344
345
        if (!item->signature().isNull()) {
            ret << item->signature();
        }
    }
    return ret;
}
346
347
348
349
350

void UserIDListModel::enableRemarks(bool value)
{
    mRemarksEnabled = value;
}