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->setDynamicSortFilter(true);
37 proxyModel->setSourceModel(mModel);
38 mCustomFieldList->setModel(proxyModel);
39 mCustomFieldList->setColumnHidden(2, true); // hide the 'key' column
40}
41
42CustomFieldsListWidget::~CustomFieldsListWidget() = default;
43
44void CustomFieldsListWidget::loadContact(const KContacts::Addressee &contact)
45{
46 CustomField::List externalCustomFields;
47
48 CustomField::List globalCustomFields = CustomFieldManager::globalCustomFieldDescriptions();
49
50 const QStringList customs = contact.customs();
51 for (const QString &custom : customs) {
52 QString app;
54 QString value;
55 Akonadi::Utils::splitCustomField(custom, app, name, value);
56
57 // skip all well-known fields that have separated editor widgets
58 if (custom.startsWith(QLatin1StringView("messaging/"))) { // IM addresses
59 continue;
60 }
61
62 if (app == QLatin1StringView("KADDRESSBOOK")) {
63 static QSet<QString> blacklist;
64 if (blacklist.isEmpty()) {
65 blacklist << QStringLiteral("BlogFeed") << QStringLiteral("X-IMAddress") << QStringLiteral("X-Profession") << QStringLiteral("X-Office")
66 << QStringLiteral("X-ManagersName") << QStringLiteral("X-AssistantsName") << QStringLiteral("X-Anniversary")
67 << QStringLiteral("X-SpousesName") << QStringLiteral("MailPreferedFormatting") << QStringLiteral("MailAllowToRemoteContent")
68 << QStringLiteral("CRYPTOPROTOPREF") << QStringLiteral("OPENPGPFP") << QStringLiteral("SMIMEFP") << QStringLiteral("CRYPTOSIGNPREF")
69 << QStringLiteral("CRYPTOENCRYPTPREF");
70 }
71 QSet<QString> upperCaseBlacklist;
72 for (const QString &blacklistEntry : std::as_const(blacklist)) {
73 upperCaseBlacklist << blacklistEntry.toUpper();
74 }
75 blacklist.unite(upperCaseBlacklist);
76 if (blacklist.contains(name)) { // several KAddressBook specific fields
77 continue;
78 }
79 }
80
81 // check whether it correspond to a local custom field
82 bool isLocalCustomField = false;
83 const int localCustomFieldsCount(mLocalCustomFields.count());
84 for (int i = 0; i < localCustomFieldsCount; ++i) {
85 if (mLocalCustomFields[i].key() == name) {
86 mLocalCustomFields[i].setValue(value);
87 isLocalCustomField = true;
88 break;
89 }
90 }
91
92 // check whether it correspond to a global custom field
93 bool isGlobalCustomField = false;
94 const int globalCustomFieldsCount(globalCustomFields.count());
95 for (int i = 0; i < globalCustomFieldsCount; ++i) {
96 if (globalCustomFields[i].key() == name) {
97 globalCustomFields[i].setValue(value);
98 isGlobalCustomField = true;
99 break;
100 }
101 }
102
103 // if not local and not global it must be external
104 if (!isLocalCustomField && !isGlobalCustomField) {
105 if (app == QLatin1StringView("KADDRESSBOOK")) {
106 // however if it starts with our prefix it might be that this is an outdated
107 // global custom field, in this case treat it as local field of type text
108 CustomField customField(name, name, CustomField::TextType, CustomField::LocalScope);
109 customField.setValue(value);
110
111 mLocalCustomFields << customField;
112 } else {
113 // it is really an external custom field
114 const QString key = app + QLatin1Char('-') + name;
115 CustomField customField(key, key, CustomField::TextType, CustomField::ExternalScope);
116 customField.setValue(value);
117
118 externalCustomFields << customField;
119 }
120 }
121 }
122
123 mModel->setCustomFields(CustomField::List() << mLocalCustomFields << globalCustomFields << externalCustomFields);
124}
125
126void CustomFieldsListWidget::storeContact(KContacts::Addressee &contact) const
127{
128 const CustomField::List customFields = mModel->customFields();
129 for (const CustomField &customField : customFields) {
130 // write back values for local and global scope, leave external untouched
131 if (customField.scope() != CustomField::ExternalScope) {
132 if (!customField.value().isEmpty()) {
133 contact.insertCustom(QStringLiteral("KADDRESSBOOK"), customField.key(), customField.value());
134 } else {
135 contact.removeCustom(QStringLiteral("KADDRESSBOOK"), customField.key());
136 }
137 }
138 }
139
140 // Now remove all fields that were available in loadContact (these are stored in mLocalCustomFields)
141 // but are not part of customFields now, which means they have been removed or renamed by the user
142 // in the editor dialog.
143 for (const CustomField &oldCustomField : std::as_const(mLocalCustomFields)) {
144 if (oldCustomField.scope() != CustomField::ExternalScope) {
145 bool fieldStillExists = false;
146 for (const CustomField &newCustomField : std::as_const(customFields)) {
147 if (newCustomField.scope() != CustomField::ExternalScope) {
148 if (newCustomField.key() == oldCustomField.key()) {
149 fieldStillExists = true;
150 break;
151 }
152 }
153 }
154
155 if (!fieldStillExists) {
156 contact.removeCustom(QStringLiteral("KADDRESSBOOK"), oldCustomField.key());
157 }
158 }
159 }
160
161 // And store the global custom fields descriptions as well
162 CustomField::List globalCustomFields;
163 for (const CustomField &customField : std::as_const(customFields)) {
164 if (customField.scope() == CustomField::GlobalScope) {
165 globalCustomFields << customField;
166 }
167 }
168
169 CustomFieldManager::setGlobalCustomFieldDescriptions(globalCustomFields);
170}
171
172void CustomFieldsListWidget::setReadOnly(bool readOnly)
173{
174 mCustomFieldList->setEnabled(!readOnly);
175}
176
177void CustomFieldsListWidget::slotAddNewField(const CustomField &field)
178{
179 const int lastRow = mModel->rowCount();
180 mModel->insertRow(lastRow);
181 mModel->setData(mModel->index(lastRow, 2), field.key(), Qt::EditRole);
182 mModel->setData(mModel->index(lastRow, 0), field.title(), Qt::EditRole);
183 mModel->setData(mModel->index(lastRow, 0), field.type(), CustomFieldsModel::TypeRole);
184 mModel->setData(mModel->index(lastRow, 0), field.scope(), CustomFieldsModel::ScopeRole);
185}
186
187void CustomFieldsListWidget::setLocalCustomFieldDescriptions(const QVariantList &descriptions)
188{
189 mLocalCustomFields.clear();
190 mLocalCustomFields.reserve(descriptions.count());
191 for (const QVariant &description : descriptions) {
192 mLocalCustomFields.append(CustomField::fromVariantMap(description.toMap(), CustomField::LocalScope));
193 }
194}
195
196QVariantList CustomFieldsListWidget::localCustomFieldDescriptions() const
197{
198 const CustomField::List customFields = mModel->customFields();
199
200 QVariantList descriptions;
201 for (const CustomField &field : customFields) {
202 if (field.scope() == CustomField::LocalScope) {
203 descriptions.append(field.toVariantMap());
204 }
205 }
206
207 return descriptions;
208}
209
210#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(GameStandardAction 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 Jul 26 2024 11:57:38 by doxygen 1.11.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.