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, [email protected]
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 
20 using namespace ContactEditor;
21 
22 CustomFieldsListWidget::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(QStringLiteral("customfieldlist"));
29  mCustomFieldList->setSortingEnabled(true);
30  mCustomFieldList->setRootIsDecorated(false);
31  auto customFieldDelegate = new ContactEditor::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 
42 CustomFieldsListWidget::~CustomFieldsListWidget() = default;
43 
44 void 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;
53  QString name;
54  QString value;
55  ContactEditor::Utils::splitCustomField(custom, app, name, value);
56 
57  // skip all well-known fields that have separated editor widgets
58  if (custom.startsWith(QLatin1String("messaging/"))) { // IM addresses
59  continue;
60  }
61 
62  if (app == QLatin1String("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 == QLatin1String("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 
126 void 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 
172 void CustomFieldsListWidget::setReadOnly(bool readOnly)
173 {
174  mCustomFieldList->setEnabled(!readOnly);
175 }
176 
177 void 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 
187 void 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 
196 QVariantList 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 }
EditRole
bool contains(const T &value) const const
void insertCustom(const QString &app, const QString &name, const QString &value)
QSet< T > & unite(const QSet< T > &other)
const char * name(StandardAction id)
void removeCustom(const QString &app, const QString &name)
QStringList customs() const
bool isEmpty() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Sat Apr 1 2023 04:09:04 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.