• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.14.10 API Reference
  • KDE Home
  • Contact Us
 

akonadi

  • akonadi
  • contact
  • editor
customfieldseditwidget.cpp
1/*
2 This file is part of Akonadi Contact.
3
4 Copyright (c) 2010 Tobias Koenig <tokoe@kde.org>
5
6 This library is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Library General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or (at your
9 option) any later version.
10
11 This library is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
14 License for more details.
15
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301, USA.
20*/
21
22#include "customfieldseditwidget.h"
23
24#include "customfieldeditordialog.h"
25#include "customfieldmanager_p.h"
26#include "customfieldsdelegate.h"
27#include "customfieldsmodel.h"
28
29#include <kabc/addressee.h>
30#include <klocalizedstring.h>
31#include <kmessagebox.h>
32
33#include <QtCore/QPointer>
34#include <QtCore/QUuid>
35#include <QGridLayout>
36#include <QPushButton>
37#include <QTreeView>
38#include <QSortFilterProxyModel>
39
40void splitCustomField(const QString &str, QString &app, QString &name, QString &value)
41{
42 const int colon = str.indexOf(QLatin1Char(':'));
43 if (colon != -1) {
44 const QString tmp = str.left(colon);
45 value = str.mid(colon + 1);
46
47 const int dash = tmp.indexOf(QLatin1Char('-'));
48 if (dash != -1) {
49 app = tmp.left(dash);
50 name = tmp.mid(dash + 1);
51 }
52 }
53}
54
55CustomFieldsEditWidget::CustomFieldsEditWidget(QWidget *parent)
56 : QWidget(parent)
57 , mReadOnly(false)
58{
59 QGridLayout *layout = new QGridLayout(this);
60 layout->setMargin(0);
61
62 mView = new QTreeView;
63 mView->setSortingEnabled(true);
64 mView->setRootIsDecorated(false);
65 mView->setItemDelegate(new CustomFieldsDelegate(this));
66
67 mAddButton = new QPushButton(i18n("Add..."));
68 mEditButton = new QPushButton(i18n("Edit..."));
69 mRemoveButton = new QPushButton(i18n("Remove"));
70
71 layout->addWidget(mView, 0, 0, 4, 1);
72 layout->addWidget(mAddButton, 0, 1);
73 layout->addWidget(mEditButton, 1, 1);
74 layout->addWidget(mRemoveButton, 2, 1);
75
76 mModel = new CustomFieldsModel(this);
77 QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel;
78 proxyModel->setDynamicSortFilter(true);
79 proxyModel->setSourceModel(mModel);
80 mView->setModel(proxyModel);
81 mView->setColumnHidden(2, true); // hide the 'key' column
82
83 connect(mView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
84 this, SLOT(slotUpdateButtons()));
85 connect(mAddButton, SIGNAL(clicked()), this, SLOT(slotAdd()));
86 connect(mEditButton, SIGNAL(clicked()), this, SLOT(slotEdit()));
87 connect(mRemoveButton, SIGNAL(clicked()), this, SLOT(slotRemove()));
88 slotUpdateButtons();
89}
90
91CustomFieldsEditWidget::~CustomFieldsEditWidget()
92{
93}
94
95void CustomFieldsEditWidget::loadContact(const KABC::Addressee &contact)
96{
97 CustomField::List externalCustomFields;
98
99 CustomField::List globalCustomFields = CustomFieldManager::globalCustomFieldDescriptions();
100
101 const QStringList customs = contact.customs();
102 foreach (const QString &custom, customs) {
103
104 QString app, name, value;
105 splitCustomField(custom, app, name, value);
106
107 // skip all well-known fields that have separated editor widgets
108 if (custom.startsWith(QLatin1String("messaging/"))) { // IM addresses
109 continue;
110 }
111
112 if (app == QLatin1String("KADDRESSBOOK")) {
113 static QSet<QString> blacklist;
114 if (blacklist.isEmpty()) {
115 blacklist << QLatin1String("BlogFeed")
116 << QLatin1String("X-IMAddress")
117 << QLatin1String("X-Profession")
118 << QLatin1String("X-Office")
119 << QLatin1String("X-ManagersName")
120 << QLatin1String("X-AssistantsName")
121 << QLatin1String("X-Anniversary")
122 << QLatin1String("X-ANNIVERSARY")
123 << QLatin1String("X-SpousesName")
124 << QLatin1String("X-Profession")
125 << QLatin1String("MailPreferedFormatting")
126 << QLatin1String("MailAllowToRemoteContent")
127 << QLatin1String("CRYPTOPROTOPREF")
128 << QLatin1String("OPENPGPFP")
129 << QLatin1String("SMIMEFP")
130 << QLatin1String("CRYPTOSIGNPREF")
131 << QLatin1String("CRYPTOENCRYPTPREF");
132 }
133
134 if (blacklist.contains(name)) { // several KAddressBook specific fields
135 continue;
136 }
137 }
138
139 // check whether it correspond to a local custom field
140 bool isLocalCustomField = false;
141 for (int i = 0; i < mLocalCustomFields.count(); ++i) {
142 if (mLocalCustomFields[i].key() == name) {
143 mLocalCustomFields[i].setValue(value);
144 isLocalCustomField = true;
145 break;
146 }
147 }
148
149 // check whether it correspond to a global custom field
150 bool isGlobalCustomField = false;
151 for (int i = 0; i < globalCustomFields.count(); ++i) {
152 if (globalCustomFields[i].key() == name) {
153 globalCustomFields[i].setValue(value);
154 isGlobalCustomField = true;
155 break;
156 }
157 }
158
159 // if not local and not global it must be external
160 if (!isLocalCustomField && !isGlobalCustomField) {
161 if (app == QLatin1String("KADDRESSBOOK")) {
162 // however if it starts with our prefix it might be that this is an outdated
163 // global custom field, in this case treat it as local field of type text
164 CustomField customField(name, name, CustomField::TextType, CustomField::LocalScope);
165 customField.setValue(value);
166
167 mLocalCustomFields << customField;
168 } else {
169 // it is really an external custom field
170 const QString key = app + QLatin1Char('-') + name;
171 CustomField customField(key, key, CustomField::TextType, CustomField::ExternalScope);
172 customField.setValue(value);
173
174 externalCustomFields << customField;
175 }
176 }
177 }
178
179 mModel->setCustomFields(CustomField::List() << mLocalCustomFields << globalCustomFields << externalCustomFields);
180}
181
182void CustomFieldsEditWidget::storeContact(KABC::Addressee &contact) const
183{
184 const CustomField::List customFields = mModel->customFields();
185 foreach (const CustomField &customField, customFields) {
186 // write back values for local and global scope, leave external untouched
187 if (customField.scope() != CustomField::ExternalScope) {
188 if (!customField.value().isEmpty()) {
189 contact.insertCustom(QLatin1String("KADDRESSBOOK"), customField.key(), customField.value());
190 } else {
191 contact.removeCustom(QLatin1String("KADDRESSBOOK"), customField.key());
192 }
193 }
194 }
195
196 // Now remove all fields that were available in loadContact (these are stored in mLocalCustomFields)
197 // but are not part of customFields now, which means they have been removed or renamed by the user
198 // in the editor dialog.
199 foreach (const CustomField &oldCustomField, mLocalCustomFields) {
200 if (oldCustomField.scope() != CustomField::ExternalScope) {
201
202 bool fieldStillExists = false;
203 foreach (const CustomField &newCustomField, customFields) {
204 if (newCustomField.scope() != CustomField::ExternalScope) {
205 if (newCustomField.key() == oldCustomField.key()) {
206 fieldStillExists = true;
207 break;
208 }
209 }
210 }
211
212 if (!fieldStillExists) {
213 contact.removeCustom(QLatin1String("KADDRESSBOOK"), oldCustomField.key());
214 }
215 }
216 }
217
218 // And store the global custom fields descriptions as well
219 CustomField::List globalCustomFields;
220 foreach (const CustomField &customField, customFields) {
221 if (customField.scope() == CustomField::GlobalScope) {
222 globalCustomFields << customField;
223 }
224 }
225
226 CustomFieldManager::setGlobalCustomFieldDescriptions(globalCustomFields);
227}
228
229void CustomFieldsEditWidget::setReadOnly(bool readOnly)
230{
231 mReadOnly = readOnly;
232
233 mView->setEnabled(!mReadOnly);
234
235 slotUpdateButtons();
236}
237
238void CustomFieldsEditWidget::setLocalCustomFieldDescriptions(const QVariantList &descriptions)
239{
240 mLocalCustomFields.clear();
241
242 foreach (const QVariant &description, descriptions) {
243 mLocalCustomFields.append(CustomField::fromVariantMap(description.toMap(), CustomField::LocalScope));
244 }
245}
246
247QVariantList CustomFieldsEditWidget::localCustomFieldDescriptions() const
248{
249 const CustomField::List customFields = mModel->customFields();
250
251 QVariantList descriptions;
252 foreach (const CustomField &field, customFields) {
253 if (field.scope() == CustomField::LocalScope) {
254 descriptions.append(field.toVariantMap());
255 }
256 }
257
258 return descriptions;
259}
260
261void CustomFieldsEditWidget::slotAdd()
262{
263 CustomField field;
264
265 // We use a Uuid as default key, so we won't have any duplicated keys,
266 // the user can still change it to something else in the editor dialog.
267 // Since the key only allows [A-Za-z0-9\-]*, we have to remove the curly
268 // braces as well.
269 QString key = QUuid::createUuid().toString();
270 key.remove(QLatin1Char('{'));
271 key.remove(QLatin1Char('}'));
272
273 field.setKey(key);
274
275 QPointer<CustomFieldEditorDialog> dlg = new CustomFieldEditorDialog(this);
276 dlg->setCustomField(field);
277
278 if (dlg->exec() == QDialog::Accepted) {
279 const int lastRow = mModel->rowCount();
280 mModel->insertRow(lastRow);
281
282 field = dlg->customField();
283 mModel->setData(mModel->index(lastRow, 2), field.key(), Qt::EditRole);
284 mModel->setData(mModel->index(lastRow, 0), field.title(), Qt::EditRole);
285 mModel->setData(mModel->index(lastRow, 0), field.type(), CustomFieldsModel::TypeRole);
286 mModel->setData(mModel->index(lastRow, 0), field.scope(), CustomFieldsModel::ScopeRole);
287 }
288
289 delete dlg;
290}
291
292void CustomFieldsEditWidget::slotEdit()
293{
294 const QModelIndex currentIndex = mView->currentIndex();
295 if (!currentIndex.isValid()) {
296 return;
297 }
298
299 CustomField field;
300 field.setKey(mModel->index(currentIndex.row(), 2).data(Qt::DisplayRole).toString());
301 field.setTitle(mModel->index(currentIndex.row(), 0).data(Qt::DisplayRole).toString());
302 field.setType(static_cast<CustomField::Type>(currentIndex.data(CustomFieldsModel::TypeRole).toInt()));
303 field.setScope(static_cast<CustomField::Scope>(currentIndex.data(CustomFieldsModel::ScopeRole).toInt()));
304
305 QPointer<CustomFieldEditorDialog> dlg = new CustomFieldEditorDialog(this);
306 dlg->setCustomField(field);
307
308 if (dlg->exec() == QDialog::Accepted) {
309 field = dlg->customField();
310 mModel->setData(mModel->index(currentIndex.row(), 2), field.key(), Qt::EditRole);
311 mModel->setData(mModel->index(currentIndex.row(), 0), field.title(), Qt::EditRole);
312 mModel->setData(currentIndex, field.type(), CustomFieldsModel::TypeRole);
313 mModel->setData(currentIndex, field.scope(), CustomFieldsModel::ScopeRole);
314 }
315
316 delete dlg;
317}
318
319void CustomFieldsEditWidget::slotRemove()
320{
321 const QModelIndex currentIndex = mView->currentIndex();
322 if (!currentIndex.isValid()) {
323 return;
324 }
325
326 if (KMessageBox::warningContinueCancel(this,
327 i18nc("Custom Fields", "Do you really want to delete the selected custom field?"),
328 i18n("Confirm Delete"), KStandardGuiItem::del()) != KMessageBox::Continue) {
329 return;
330 }
331
332 mModel->removeRow(currentIndex.row());
333}
334
335void CustomFieldsEditWidget::slotUpdateButtons()
336{
337 const bool hasCurrent = mView->currentIndex().isValid();
338 const bool isExternal = (hasCurrent &&
339 (static_cast<CustomField::Scope>(mView->currentIndex().data(CustomFieldsModel::ScopeRole).toInt()) == CustomField::ExternalScope));
340
341 mAddButton->setEnabled(!mReadOnly);
342 mEditButton->setEnabled(!mReadOnly && hasCurrent && !isExternal);
343 mRemoveButton->setEnabled(!mReadOnly && hasCurrent && !isExternal);
344}
CustomField
A class that represents non-standard contact fields.
Definition: customfields_p.h:48
CustomField::Scope
Scope
Definition: customfields_p.h:62
CustomField::LocalScope
@ LocalScope
Field has been defined by user for one contact.
Definition: customfields_p.h:63
CustomField::ExternalScope
@ ExternalScope
Field has been defined by the external data source (e.g. vCard)
Definition: customfields_p.h:65
CustomField::GlobalScope
@ GlobalScope
Field has been defined by user for all contacts.
Definition: customfields_p.h:64
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Thu Jul 21 2022 00:00:00 by doxygen 1.9.5 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

akonadi

Skip menu "akonadi"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • Modules
  • Related Pages

kdepimlibs-4.14.10 API Reference

Skip menu "kdepimlibs-4.14.10 API Reference"
  • akonadi
  •   contact
  •   kmime
  •   socialutils
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal