File indexing completed on 2024-03-24 05:53:29
0001 /* 0002 SPDX-FileCopyrightText: 2008, 2009, 2010, 2011, 2012, 2013, 2016, 2017 Rolf Eike Beer <kde@opensource.sf-tec.de> 0003 0004 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0005 */ 0006 #include "kgpgitemmodel.h" 0007 0008 #include "gpgproc.h" 0009 #include "kgpgsettings.h" 0010 #include "core/convert.h" 0011 #include "core/images.h" 0012 #include "model/kgpgitemnode.h" 0013 0014 #include <KLocalizedString> 0015 0016 #include <QLocale> 0017 #include <QMetaObject> 0018 0019 KGpgItemModel::KGpgItemModel(QObject *parent) 0020 : QAbstractItemModel(parent), 0021 m_root(new KGpgRootNode(this)), 0022 m_default(KGpgSettings::defaultKey()) 0023 { 0024 QMetaObject::invokeMethod(this, "refreshGroups", Qt::QueuedConnection); 0025 } 0026 0027 KGpgItemModel::~KGpgItemModel() 0028 { 0029 delete m_root; 0030 } 0031 0032 QModelIndex 0033 KGpgItemModel::index(int row, int column, const QModelIndex &parent) const 0034 { 0035 if (hasIndex(row, column, parent)) { 0036 KGpgNode *parentNode = nodeForIndex(parent); 0037 KGpgNode *childNode = parentNode->getChild(row); 0038 return createIndex(row, column, childNode); 0039 } 0040 return QModelIndex(); 0041 } 0042 0043 QModelIndex 0044 KGpgItemModel::parent(const QModelIndex &child) const 0045 { 0046 if (!child.isValid()) 0047 return QModelIndex(); 0048 KGpgNode *childNode = nodeForIndex(child); 0049 KGpgNode *parentNode = childNode->m_parent; 0050 0051 if (parentNode == m_root) 0052 return QModelIndex(); 0053 0054 Q_ASSERT(parentNode != nullptr); 0055 int row = rowForNode(parentNode); 0056 int column = 0; 0057 0058 return createIndex(row, column, parentNode); 0059 } 0060 0061 int 0062 KGpgItemModel::rowCount(const QModelIndex &parent) const 0063 { 0064 if (parent.column() > 0) 0065 return 0; 0066 0067 KGpgNode *parentNode = nodeForIndex(parent); 0068 0069 return parentNode->getChildCount(); 0070 } 0071 0072 bool 0073 KGpgItemModel::hasChildren(const QModelIndex &parent) const 0074 { 0075 if (parent.column() > 0) 0076 return false; 0077 0078 KGpgNode *parentNode = nodeForIndex(parent); 0079 0080 return parentNode->hasChildren(); 0081 } 0082 0083 QVariant 0084 KGpgItemModel::data(const QModelIndex &index, int role) const 0085 { 0086 if (!index.isValid()) 0087 return QVariant(); 0088 0089 KGpgNode *node = nodeForIndex(index); 0090 0091 if (role == Qt::FontRole) { 0092 QFont f; 0093 f.setBold(isDefaultKey(node)); 0094 return f; 0095 } 0096 0097 switch (index.column()) { 0098 case KEYCOLUMN_NAME: 0099 switch (role) { 0100 case Qt::DisplayRole: 0101 case Qt::EditRole: 0102 return node->getName(); 0103 case Qt::DecorationRole: 0104 switch (node->getType()) { 0105 case ITYPE_GROUP: 0106 return Images::group(); 0107 case ITYPE_GSECRET: 0108 case ITYPE_SECRET: 0109 return Images::orphan(); 0110 case ITYPE_GPUBLIC: 0111 case ITYPE_SUB: 0112 case ITYPE_PUBLIC: 0113 return Images::single(); 0114 case ITYPE_GPAIR: 0115 case ITYPE_PAIR: 0116 return Images::pair(); 0117 case ITYPE_UID: 0118 return Images::userId(); 0119 case ITYPE_UAT: 0120 return node->toUatNode()->getPixmap(); 0121 case ITYPE_REVSIGN: 0122 return Images::revoke(); 0123 case ITYPE_SIGN: 0124 return Images::signature(); 0125 default: 0126 Q_ASSERT(0); 0127 return QVariant(); 0128 } 0129 case Qt::ToolTipRole: 0130 return node->getComment(); 0131 } 0132 break; 0133 case KEYCOLUMN_EMAIL: 0134 if (role == Qt::DisplayRole) 0135 return node->getEmail(); 0136 break; 0137 case KEYCOLUMN_TRUST: 0138 { 0139 KgpgKeyTrust t = node->getTrust(); 0140 switch(node->getType()) { 0141 case ITYPE_PAIR: 0142 case ITYPE_PUBLIC: 0143 if(!node->toKeyNode()->getKey()->valid()) 0144 t = TRUST_DISABLED; 0145 break; 0146 default: 0147 break; 0148 } 0149 0150 switch (role) { 0151 case Qt::BackgroundRole: 0152 switch (t) { 0153 case TRUST_INVALID: 0154 case TRUST_DISABLED: 0155 return KGpgSettings::colorBad(); 0156 case TRUST_EXPIRED: 0157 return KGpgSettings::colorExpired(); 0158 case TRUST_MARGINAL: 0159 return KGpgSettings::colorMarginal(); 0160 case TRUST_REVOKED: 0161 return KGpgSettings::colorRev(); 0162 case TRUST_UNDEFINED: 0163 case TRUST_NONE: 0164 return KGpgSettings::colorUnknown(); 0165 case TRUST_FULL: 0166 return KGpgSettings::colorGood(); 0167 case TRUST_ULTIMATE: 0168 return KGpgSettings::colorUltimate(); 0169 case TRUST_UNKNOWN: 0170 default: 0171 return KGpgSettings::colorUnknown(); 0172 } 0173 case Qt::AccessibleTextRole: 0174 return Convert::toString(t); 0175 case Qt::ToolTipRole: 0176 switch(node->getType()) { 0177 case ITYPE_PAIR: 0178 case ITYPE_PUBLIC: 0179 return i18n("Trust: %1<br>Owner Trust: %2", 0180 Convert::toString(node->getTrust()), 0181 Convert::toString(node->toKeyNode()->getKey()->ownerTrust())); 0182 default: 0183 return i18n("Trust: %1", Convert::toString(node->getTrust())); 0184 } 0185 } 0186 break; 0187 } 0188 case KEYCOLUMN_EXPIR: 0189 if (role == Qt::DisplayRole) 0190 return QLocale().toString(node->getExpiration().date(), QLocale::ShortFormat); 0191 break; 0192 case KEYCOLUMN_SIZE: 0193 switch (role) { 0194 case Qt::DisplayRole: 0195 return node->getSize(); 0196 case Qt::ToolTipRole: 0197 switch (node->getType()) { 0198 case ITYPE_PAIR: 0199 case ITYPE_PUBLIC: 0200 return node->toKeyNode()->getSignCount(); 0201 case ITYPE_UAT: 0202 return node->toUatNode()->getSignCount(); 0203 case ITYPE_UID: 0204 return node->toUidNode()->getSignCount(); 0205 case ITYPE_SUB: 0206 return node->toSubkeyNode()->getSignCount(); 0207 } 0208 } 0209 break; 0210 case KEYCOLUMN_CREAT: 0211 if (role == Qt::DisplayRole) 0212 return QLocale().toString(node->getCreation().date(), QLocale::ShortFormat); 0213 break; 0214 case KEYCOLUMN_ID: 0215 switch (role) { 0216 case Qt::DisplayRole: 0217 return node->getId(); 0218 case Qt::ToolTipRole: 0219 switch (node->getType()) { 0220 case ITYPE_PAIR: 0221 case ITYPE_PUBLIC: 0222 return node->toKeyNode()->getFingerprint(); 0223 case ITYPE_SECRET: 0224 return node->toOrphanNode()->getFingerprint(); 0225 case ITYPE_SUB: 0226 return node->toSubkeyNode()->getFingerprint(); 0227 default: 0228 return QVariant(); 0229 } 0230 default: 0231 return QVariant(); 0232 } 0233 break; 0234 } 0235 0236 return QVariant(); 0237 } 0238 0239 KGpgNode * 0240 KGpgItemModel::nodeForIndex(const QModelIndex &index) const 0241 { 0242 if (index.isValid()) 0243 return static_cast<KGpgNode*>(index.internalPointer()); 0244 return m_root; 0245 } 0246 0247 KGpgKeyNode * 0248 KGpgItemModel::findKeyNode(const QString& id) const 0249 { 0250 return m_root->findKey(id); 0251 } 0252 0253 int 0254 KGpgItemModel::rowForNode(KGpgNode *node) const 0255 { 0256 return node->m_parent->getChildIndex(node); 0257 } 0258 0259 KGpgRootNode * 0260 KGpgItemModel::getRootNode() const 0261 { 0262 return m_root; 0263 } 0264 0265 QString 0266 KGpgItemModel::statusCountMessage() const 0267 { 0268 const int groups = m_root->groupChildren(); 0269 const int keys = m_root->getChildCount() - groups; 0270 0271 return statusCountMessageString(keys, groups); 0272 } 0273 0274 QString 0275 KGpgItemModel::statusCountMessageString(const unsigned int keys, const unsigned int groups) 0276 { 0277 // Most people will not have groups. Handle this case 0278 // special so the string isn't displayed in this case at all 0279 if (groups == 0) { 0280 return i18np("1 Key", "%1 Keys", keys); 0281 } 0282 0283 const QString keyString = i18np("1 Key", "%1 Keys", keys); 0284 const QString groupString = i18np("1 Group", "%1 Groups", groups); 0285 0286 return i18nc("%1 = something like 7 keys, %2 = something like 2 groups", "%1, %2", keyString, groupString); 0287 0288 } 0289 0290 KGpgGroupNode * 0291 KGpgItemModel::addGroup(const QString &name, const KGpgKeyNode::List &keys) 0292 { 0293 KGpgGroupNode *nd; 0294 const int cIndex = m_root->getChildCount(); // row of the new node 0295 0296 beginInsertRows(QModelIndex(), cIndex, cIndex); 0297 nd = new KGpgGroupNode(m_root, name, keys); 0298 endInsertRows(); 0299 0300 nd->saveMembers(); 0301 0302 Q_ASSERT(m_root->getChildIndex(nd) == cIndex); 0303 0304 return nd; 0305 } 0306 0307 void 0308 KGpgItemModel::delNode(KGpgNode *node) 0309 { 0310 beginResetModel(); 0311 delete node; 0312 endResetModel(); 0313 } 0314 0315 void 0316 KGpgItemModel::changeGroup(KGpgGroupNode *node, const KGpgNode::List &keys) 0317 { 0318 const QModelIndex gIndex = nodeIndex(node); 0319 for (int i = node->getChildCount() - 1; i >= 0; i--) { 0320 bool found = false; 0321 0322 for (const KGpgNode *nd : keys) { 0323 found = (node->getChild(i)->getId() == nd->getId()); 0324 if (found) 0325 break; 0326 } 0327 if (found) 0328 continue; 0329 0330 beginRemoveRows(gIndex, i, i); 0331 delete node->getChild(i); 0332 endRemoveRows(); 0333 } 0334 0335 int cnt = node->getChildCount(); 0336 0337 for (int i = 0; i < keys.count(); i++) { 0338 bool found = false; 0339 0340 for (const KGpgNode *nd : node->getChildren()) { 0341 found = (nd->getId() == keys.at(i)->getId()); 0342 if (found) 0343 break; 0344 } 0345 if (found) 0346 continue; 0347 0348 beginInsertRows(gIndex, cnt, cnt); 0349 new KGpgGroupMemberNode(node, keys.at(i)->toKeyNode()); 0350 endInsertRows(); 0351 cnt++; 0352 } 0353 0354 node->saveMembers(); 0355 } 0356 0357 void 0358 KGpgItemModel::deleteFromGroup(KGpgGroupNode *group, KGpgGroupMemberNode *member) 0359 { 0360 Q_ASSERT(group == member->getParentKeyNode()); 0361 0362 const int childRow = group->getChildIndex(member); 0363 const QModelIndex pIndex = nodeIndex(group); 0364 0365 beginRemoveRows(pIndex, childRow, childRow); 0366 delete member; 0367 endRemoveRows(); 0368 0369 group->saveMembers(); 0370 } 0371 0372 QVariant 0373 KGpgItemModel::headerData(int section, Qt::Orientation orientation, int role) const 0374 { 0375 if (role != Qt::DisplayRole) 0376 return QVariant(); 0377 0378 if (orientation != Qt::Horizontal) 0379 return QVariant(); 0380 0381 switch (section) { 0382 case KEYCOLUMN_NAME: return QString(i18n("Name")); 0383 case KEYCOLUMN_EMAIL: return QString(i18nc("@title:column Title of a column of emails", "Email")); 0384 case KEYCOLUMN_TRUST: return QString(i18n("Trust")); 0385 case KEYCOLUMN_SIZE: return QString(i18n("Size")); 0386 case KEYCOLUMN_EXPIR: return QString(i18n("Expiration")); 0387 case KEYCOLUMN_CREAT: return QString(i18n("Creation")); 0388 case KEYCOLUMN_ID: return QString(i18n("ID")); 0389 default: return QVariant(); 0390 } 0391 } 0392 0393 void 0394 KGpgItemModel::setDefaultKey(KGpgKeyNode *def) 0395 { 0396 int defrow = m_root->findKeyRow(def); 0397 int odefrow = m_root->findKeyRow(m_default); 0398 if (defrow == odefrow) 0399 return; 0400 0401 int lastcol = columnCount(QModelIndex()) - 1; 0402 if (odefrow >= 0) { 0403 KGpgNode *nd = m_root->getChild(odefrow); 0404 Q_EMIT dataChanged(createIndex(odefrow, 0, nd), createIndex(odefrow, lastcol, nd)); 0405 } 0406 0407 if (def) { 0408 m_default = def->getId(); 0409 Q_EMIT dataChanged(createIndex(defrow, 0, def), createIndex(defrow, lastcol, def)); 0410 } else { 0411 m_default.clear(); 0412 } 0413 } 0414 0415 QModelIndex 0416 KGpgItemModel::nodeIndex(KGpgNode *node, const int column) 0417 { 0418 KGpgNode *p = node->getParentKeyNode(); 0419 0420 for (int i = 0; i < p->getChildCount(); i++) 0421 if (p->getChild(i) == node) 0422 return createIndex(i, column, node); 0423 0424 Q_ASSERT(0); 0425 return QModelIndex(); 0426 } 0427 0428 static QStringList 0429 readGroups() 0430 { 0431 return GPGProc::getGgpParsedConfig(KGpgSettings::gpgBinaryPath(), "group"); 0432 } 0433 0434 void 0435 KGpgItemModel::refreshKeys(const QStringList &ids) 0436 { 0437 if (ids.isEmpty()) { 0438 refreshAllKeys(); 0439 } else { 0440 beginResetModel(); 0441 0442 QStringList::ConstIterator it = ids.constBegin(); 0443 const QStringList::ConstIterator itEnd = ids.constEnd(); 0444 0445 KGpgKeyNode::List refreshNodes; 0446 QStringList addIds; 0447 0448 for (; it != itEnd; ++it) { 0449 KGpgKeyNode *nd = m_root->findKey(*it); 0450 if (nd) 0451 refreshNodes << nd; 0452 else 0453 addIds << *it; 0454 } 0455 0456 if (!refreshNodes.isEmpty()) 0457 m_root->refreshKeys(refreshNodes); 0458 if (!addIds.isEmpty()) 0459 m_root->addKeys(addIds); 0460 0461 endResetModel(); 0462 } 0463 } 0464 0465 void 0466 KGpgItemModel::refreshKeys(KGpgKeyNode::List keys) 0467 { 0468 beginResetModel(); 0469 m_root->refreshKeys(keys); 0470 endResetModel(); 0471 } 0472 0473 void 0474 KGpgItemModel::refreshAllKeys() 0475 { 0476 beginResetModel(); 0477 0478 for (int i = m_root->getChildCount() - 1; i >= 0; i--) 0479 delete m_root->getChild(i); 0480 m_root->addKeys(); 0481 0482 m_root->addGroups(readGroups()); 0483 0484 endResetModel(); 0485 } 0486 0487 void 0488 KGpgItemModel::refreshGroups() 0489 { 0490 for (int i = m_root->getChildCount() - 1; i >= 0; i--) { 0491 KGpgNode *nd = m_root->getChild(i); 0492 if (nd->getType() != ITYPE_GROUP) 0493 continue; 0494 0495 beginRemoveRows(QModelIndex(), i, i); 0496 delete nd; 0497 endRemoveRows(); 0498 } 0499 0500 const QStringList groups = readGroups(); 0501 0502 if (groups.isEmpty()) 0503 return; 0504 0505 const int oldCount = m_root->getChildCount(); 0506 beginInsertRows(QModelIndex(), oldCount, oldCount + groups.count()); 0507 m_root->addGroups(groups); 0508 endInsertRows(); 0509 } 0510 0511 bool 0512 KGpgItemModel::isDefaultKey(const KGpgNode *node) const 0513 { 0514 return !m_default.isEmpty() && (QStringView(node->getId()).right(m_default.length()).compare(m_default) == 0); 0515 } 0516 0517 void 0518 KGpgItemModel::invalidateIndexes(KGpgNode *nd) 0519 { 0520 const auto indexList = persistentIndexList(); 0521 for (const QModelIndex &idx : indexList) { 0522 KGpgNode *n = nodeForIndex(idx); 0523 0524 if (n != nd) 0525 continue; 0526 0527 changePersistentIndex(idx, QModelIndex()); 0528 } 0529 } 0530 0531 void 0532 KGpgItemModel::refreshTrust(const KgpgCore::KgpgKeyTrust trust, const QColor& color) 0533 { 0534 updateNodeTrustColor(m_root, trust, color); 0535 } 0536 0537 void 0538 KGpgItemModel::updateNodeTrustColor(KGpgExpandableNode *node, const KgpgCore::KgpgKeyTrust trust, const QColor &color) 0539 { 0540 for (int i = 0; i < node->getChildCount(); i++) { 0541 KGpgNode *child = node->getChild(i); 0542 0543 if (child->getTrust() == trust) 0544 Q_EMIT dataChanged(createIndex(i, KEYCOLUMN_TRUST, child), createIndex(i, KEYCOLUMN_TRUST, child)); 0545 0546 if (!child->hasChildren()) 0547 continue; 0548 0549 KGpgExpandableNode *echild = child->toExpandableNode(); 0550 if (echild->wasExpanded()) 0551 updateNodeTrustColor(echild, trust, color); 0552 } 0553 }