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

akonadi/contact

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

KDE's Doxygen guidelines are available online.

akonadi/contact

Skip menu "akonadi/contact"
  • Main Page
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • Related Pages

kdepimlibs-4.11.3 API Reference

Skip menu "kdepimlibs-4.11.3 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