Akonadi Contacts

customfieldslistwidget.cpp
1/*
2 This file is part of Contact Editor.
3
4 SPDX-FileCopyrightText: 2016 eyeOS S.L.U., a Telefonica company, sales@eyeos.com
5 SPDX-FileCopyrightText: 2016-2020 Laurent Montel <montel.org>
6
7 SPDX-License-Identifier: LGPL-2.0-or-later
8*/
9
10#include "customfieldslistwidget.h"
11#include "../utils/utils.h"
12
13#include "customfieldmanager_p.h"
14#include "customfieldslistdelegate.h"
15#include <KContacts/Addressee>
16#include <QSortFilterProxyModel>
17#include <QTreeView>
18#include <QVBoxLayout>
19
20using namespace Akonadi;
21
22CustomFieldsListWidget::CustomFieldsListWidget(QWidget *parent)
23 : QWidget(parent)
24 , mCustomFieldList(new QTreeView(this))
25 , mModel(new CustomFieldsModel(this))
26{
27 auto topLayout = new QVBoxLayout(this);
28 mCustomFieldList->setObjectName(QLatin1StringView("customfieldlist"));
29 mCustomFieldList->setSortingEnabled(true);
30 mCustomFieldList->setRootIsDecorated(false);
31 auto customFieldDelegate = new Akonadi::CustomFieldsListDelegate(mCustomFieldList, this);
32 mCustomFieldList->setItemDelegate(customFieldDelegate);
33 topLayout->addWidget(mCustomFieldList);
34
35 auto proxyModel = new QSortFilterProxyModel(this);
36 proxyModel->setSourceModel(mModel);
37 mCustomFieldList->setModel(proxyModel);
38 mCustomFieldList->setColumnHidden(2, true); // hide the 'key' column
39}
40
41CustomFieldsListWidget::~CustomFieldsListWidget() = default;
42
43void CustomFieldsListWidget::loadContact(const KContacts::Addressee &contact)
44{
45 CustomField::List externalCustomFields;
46
47 CustomField::List globalCustomFields = CustomFieldManager::globalCustomFieldDescriptions();
48
49 const QStringList customs = contact.customs();
50 for (const QString &custom : customs) {
51 QString app;
53 QString value;
54 Akonadi::Utils::splitCustomField(custom, app, name, value);
55
56 // skip all well-known fields that have separated editor widgets
57 if (custom.startsWith(QLatin1StringView("messaging/"))) { // IM addresses
58 continue;
59 }
60
61 if (app == QLatin1StringView("KADDRESSBOOK")) {
62 static QSet<QString> blacklist;
63 if (blacklist.isEmpty()) {
64 blacklist << QStringLiteral("BlogFeed") << QStringLiteral("X-IMAddress") << QStringLiteral("X-Profession") << QStringLiteral("X-Office")
65 << QStringLiteral("X-ManagersName") << QStringLiteral("X-AssistantsName") << QStringLiteral("X-Anniversary")
66 << QStringLiteral("X-SpousesName") << QStringLiteral("MailPreferedFormatting") << QStringLiteral("MailAllowToRemoteContent")
67 << QStringLiteral("CRYPTOPROTOPREF") << QStringLiteral("OPENPGPFP") << QStringLiteral("SMIMEFP") << QStringLiteral("CRYPTOSIGNPREF")
68 << QStringLiteral("CRYPTOENCRYPTPREF");
69 }
70 QSet<QString> upperCaseBlacklist;
71 for (const QString &blacklistEntry : std::as_const(blacklist)) {
72 upperCaseBlacklist << blacklistEntry.toUpper();
73 }
74 blacklist.unite(upperCaseBlacklist);
75 if (blacklist.contains(name)) { // several KAddressBook specific fields
76 continue;
77 }
78 }
79
80 // check whether it correspond to a local custom field
81 bool isLocalCustomField = false;
82 const int localCustomFieldsCount(mLocalCustomFields.count());
83 for (int i = 0; i < localCustomFieldsCount; ++i) {
84 if (mLocalCustomFields[i].key() == name) {
85 mLocalCustomFields[i].setValue(value);
86 isLocalCustomField = true;
87 break;
88 }
89 }
90
91 // check whether it correspond to a global custom field
92 bool isGlobalCustomField = false;
93 const int globalCustomFieldsCount(globalCustomFields.count());
94 for (int i = 0; i < globalCustomFieldsCount; ++i) {
95 if (globalCustomFields[i].key() == name) {
96 globalCustomFields[i].setValue(value);
97 isGlobalCustomField = true;
98 break;
99 }
100 }
101
102 // if not local and not global it must be external
103 if (!isLocalCustomField && !isGlobalCustomField) {
104 if (app == QLatin1StringView("KADDRESSBOOK")) {
105 // however if it starts with our prefix it might be that this is an outdated
106 // global custom field, in this case treat it as local field of type text
107 CustomField customField(name, name, CustomField::TextType, CustomField::LocalScope);
108 customField.setValue(value);
109
110 mLocalCustomFields << customField;
111 } else {
112 // it is really an external custom field
113 const QString key = app + QLatin1Char('-') + name;
114 CustomField customField(key, key, CustomField::TextType, CustomField::ExternalScope);
115 customField.setValue(value);
116
117 externalCustomFields << customField;
118 }
119 }
120 }
121
122 mModel->setCustomFields(CustomField::List() << mLocalCustomFields << globalCustomFields << externalCustomFields);
123}
124
125void CustomFieldsListWidget::storeContact(KContacts::Addressee &contact) const
126{
127 const CustomField::List customFields = mModel->customFields();
128 for (const CustomField &customField : customFields) {
129 // write back values for local and global scope, leave external untouched
130 if (customField.scope() != CustomField::ExternalScope) {
131 if (!customField.value().isEmpty()) {
132 contact.insertCustom(QStringLiteral("KADDRESSBOOK"), customField.key(), customField.value());
133 } else {
134 contact.removeCustom(QStringLiteral("KADDRESSBOOK"), customField.key());
135 }
136 }
137 }
138
139 // Now remove all fields that were available in loadContact (these are stored in mLocalCustomFields)
140 // but are not part of customFields now, which means they have been removed or renamed by the user
141 // in the editor dialog.
142 for (const CustomField &oldCustomField : std::as_const(mLocalCustomFields)) {
143 if (oldCustomField.scope() != CustomField::ExternalScope) {
144 bool fieldStillExists = false;
145 for (const CustomField &newCustomField : std::as_const(customFields)) {
146 if (newCustomField.scope() != CustomField::ExternalScope) {
147 if (newCustomField.key() == oldCustomField.key()) {
148 fieldStillExists = true;
149 break;
150 }
151 }
152 }
153
154 if (!fieldStillExists) {
155 contact.removeCustom(QStringLiteral("KADDRESSBOOK"), oldCustomField.key());
156 }
157 }
158 }
159
160 // And store the global custom fields descriptions as well
161 CustomField::List globalCustomFields;
162 for (const CustomField &customField : std::as_const(customFields)) {
163 if (customField.scope() == CustomField::GlobalScope) {
164 globalCustomFields << customField;
165 }
166 }
167
168 CustomFieldManager::setGlobalCustomFieldDescriptions(globalCustomFields);
169}
170
171void CustomFieldsListWidget::setReadOnly(bool readOnly)
172{
173 mCustomFieldList->setEnabled(!readOnly);
174}
175
176void CustomFieldsListWidget::slotAddNewField(const CustomField &field)
177{
178 const int lastRow = mModel->rowCount();
179 mModel->insertRow(lastRow);
180 mModel->setData(mModel->index(lastRow, 2), field.key(), Qt::EditRole);
181 mModel->setData(mModel->index(lastRow, 0), field.title(), Qt::EditRole);
182 mModel->setData(mModel->index(lastRow, 0), field.type(), CustomFieldsModel::TypeRole);
183 mModel->setData(mModel->index(lastRow, 0), field.scope(), CustomFieldsModel::ScopeRole);
184}
185
186void CustomFieldsListWidget::setLocalCustomFieldDescriptions(const QVariantList &descriptions)
187{
188 mLocalCustomFields.clear();
189 mLocalCustomFields.reserve(descriptions.count());
190 for (const QVariant &description : descriptions) {
191 mLocalCustomFields.append(CustomField::fromVariantMap(description.toMap(), CustomField::LocalScope));
192 }
193}
194
195QVariantList CustomFieldsListWidget::localCustomFieldDescriptions() const
196{
197 const CustomField::List customFields = mModel->customFields();
198
199 QVariantList descriptions;
200 for (const CustomField &field : customFields) {
201 if (field.scope() == CustomField::LocalScope) {
202 descriptions.append(field.toVariantMap());
203 }
204 }
205
206 return descriptions;
207}
208
209#include "moc_customfieldslistwidget.cpp"
void insertCustom(const QString &app, const QString &name, const QString &value)
QStringList customs() const
void removeCustom(const QString &app, const QString &name)
A widget for editing the display name of a contact.
QString name(StandardAction id)
bool insertRow(int row, const QModelIndex &parent)
bool contains(const QSet< T > &other) const const
bool isEmpty() const const
QSet< T > & unite(const QSet< T > &other)
EditRole
void setEnabled(bool)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Oct 11 2024 12:17:37 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.