~ubuntu-branches/ubuntu/wily/sflphone/wily

« back to all changes in this revision

Viewing changes to kde/src/klib/akonadibackend.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2015-01-07 14:51:16 UTC
  • mfrom: (4.3.5 sid)
  • Revision ID: package-import@ubuntu.com-20150107145116-yxnafinf4lrdvrmx
Tags: 1.4.1-0.1ubuntu1
* Merge with Debian, remaining changes:
 - Drop soprano, nepomuk build-dep
* Drop ubuntu patches, now upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
26
26
 
27
27
//KDE
28
28
#include <KDebug>
 
29
#include <KJob>
29
30
#include <kdialog.h>
30
31
#include <akonadi/control.h>
31
32
#include <akonadi/collectionfilterproxymodel.h>
32
33
#include <akonadi/kmime/messagemodel.h>
33
34
#include <akonadi/recursiveitemfetchjob.h>
 
35
#include <akonadi/itemfetchjob.h>
34
36
#include <akonadi/itemfetchscope.h>
35
37
#include <akonadi/collectionfetchjob.h>
36
38
#include <akonadi/collectionfetchscope.h>
38
40
#include <akonadi/contact/contacteditordialog.h>
39
41
#include <akonadi/session.h>
40
42
#include <akonadi/monitor.h>
 
43
#include <akonadi/itemdeletejob.h>
 
44
#include <akonadi/entitydisplayattribute.h>
41
45
#include <kabc/addressee.h>
42
46
#include <kabc/addresseelist.h>
43
47
#include <kabc/contactgroup.h>
52
56
#include "../lib/phonedirectorymodel.h"
53
57
#include "../lib/numbercategorymodel.h"
54
58
#include "../lib/numbercategory.h"
 
59
#include "../lib/contactmodel.h"
55
60
#include "kcfg_settings.h"
56
61
 
57
 
///Init static attributes
58
 
AkonadiBackend*  AkonadiBackend::m_pInstance = nullptr;
 
62
Akonadi::Session* AkonadiBackend::m_pSession = nullptr;
 
63
QHash<Akonadi::Collection::Id, AkonadiBackend*> AkonadiBackend::m_hParentLookup;
59
64
 
60
65
///Constructor
61
 
AkonadiBackend::AkonadiBackend(QObject* parent) : AbstractContactBackend(parent)
62
 
{
63
 
   m_pSession = new Akonadi::Session( "SFLPhone::instance" );
 
66
AkonadiBackend::AkonadiBackend(const Akonadi::Collection& parentCol, QObject* parent) :
 
67
   AbstractContactBackend(m_hParentLookup[parentCol.parent()],parent),m_pJob(nullptr),
 
68
   m_pMonitor(nullptr),m_isEnabled(false),m_wasEnabled(false)
 
69
{
 
70
   if (!m_pSession)
 
71
      m_pSession = new Akonadi::Session( "SFLPhone::instance" );
 
72
   setObjectName(parentCol.name());
 
73
   m_Coll = parentCol;
 
74
   m_hParentLookup[m_Coll.id()] = this;
 
75
} //AkonadiBackend
 
76
 
 
77
///Destructor
 
78
AkonadiBackend::~AkonadiBackend()
 
79
{
 
80
   if (m_pJob)
 
81
      delete m_pJob;
 
82
   if (m_pMonitor)
 
83
      delete m_pMonitor;
 
84
   m_lBackendContacts.clear();
 
85
   m_ItemHash.clear();
 
86
   m_AddrHash.clear();
 
87
}
 
88
 
 
89
QString AkonadiBackend::name () const
 
90
{
 
91
   QString name;
 
92
   Akonadi::EntityDisplayAttribute* attr = m_Coll.attribute<Akonadi::EntityDisplayAttribute>();
 
93
   if (attr)
 
94
      name = attr->displayName().trimmed();
 
95
   return name.isEmpty()?m_Coll.name():name;
 
96
}
 
97
 
 
98
QVariant AkonadiBackend::icon() const
 
99
{
 
100
   Akonadi::EntityDisplayAttribute* attr = m_Coll.attribute<Akonadi::EntityDisplayAttribute>();
 
101
   if (attr)
 
102
      return QVariant(attr->icon());
 
103
   return QVariant();
 
104
}
 
105
 
 
106
bool AkonadiBackend::isEnabled() const
 
107
{
 
108
   return m_isEnabled;
 
109
}
 
110
 
 
111
bool AkonadiBackend::load()
 
112
{
 
113
   Akonadi::ItemFetchScope scope;
 
114
   scope.fetchFullPayload(true);
64
115
 
65
116
   // fetching all collections recursively, starting at the root collection
66
 
   m_pJob = new Akonadi::CollectionFetchJob( Akonadi::Collection::root(), Akonadi::CollectionFetchJob::Recursive, this );
67
 
   m_pJob->fetchScope().setContentMimeTypes( QStringList() << "text/directory" );
68
 
   connect( m_pJob, SIGNAL(collectionsReceived(Akonadi::Collection::List)), this, SLOT(collectionsReceived(Akonadi::Collection::List)) );
 
117
   m_pJob = new Akonadi::ItemFetchJob( m_Coll, this );
 
118
   m_pJob->setFetchScope(scope);
 
119
//    m_pJob->fetchScope().setContentMimeTypes( QStringList() << "text/x-vcard" );
 
120
   connect( m_pJob, SIGNAL(itemsReceived(Akonadi::Item::List)), this, SLOT(itemsReceived(Akonadi::Item::List)) );
69
121
 
70
122
   //Configure change monitor
71
123
   m_pMonitor = new Akonadi::Monitor(this);
72
124
   m_pMonitor->fetchCollectionStatistics(false);
73
 
   Akonadi::ItemFetchScope scope;
74
 
   scope.fetchFullPayload(true);
75
125
   m_pMonitor->setItemFetchScope(scope);
76
 
   connect(m_pMonitor,SIGNAL(itemAdded(Akonadi::Item,Akonadi::Collection)),
77
 
      this,SLOT(slotItemAdded(Akonadi::Item,Akonadi::Collection)));
78
 
   connect(m_pMonitor,SIGNAL(itemChanged(const Akonadi::Item,const QSet<QByteArray>)),
79
 
      this,SLOT(slotItemChanged(const Akonadi::Item,const QSet<QByteArray>)));
80
 
   connect(m_pMonitor,SIGNAL(itemRemoved(const Akonadi::Item)),
81
 
      this,SLOT(slotItemRemoved(const Akonadi::Item)));
82
 
} //AkonadiBackend
83
 
 
84
 
///Destructor
85
 
AkonadiBackend::~AkonadiBackend()
86
 
{
87
 
   delete m_pSession;
88
 
   if (Call::contactBackend() == this)
89
 
      Call::setContactBackend(nullptr);
90
 
   delete m_pJob;
91
 
   delete m_pMonitor;
92
 
}
93
 
 
94
 
 
95
 
/*****************************************************************************
96
 
 *                                                                           *
97
 
 *                                  Getters                                  *
98
 
 *                                                                           *
99
 
 ****************************************************************************/
100
 
 
101
 
///Singleton
102
 
AbstractContactBackend* AkonadiBackend::instance()
103
 
{
104
 
   if (m_pInstance == nullptr) {
105
 
      m_pInstance = new AkonadiBackend(0);
106
 
   }
107
 
   return m_pInstance;
108
 
}
109
 
 
110
 
///Find contact by UID
111
 
Contact* AkonadiBackend::getContactByUid(const QString& uid)
112
 
{
113
 
   return m_ContactByUid[uid];
114
 
}
115
 
 
116
 
///Return contact list
117
 
const ContactList& AkonadiBackend::getContactList() const
118
 
{
119
 
   return m_pContacts;
120
 
}
121
 
 
 
126
   connect(m_pMonitor,SIGNAL(itemAdded(Akonadi::Item,Akonadi::Collection)),this,SLOT(slotItemAdded(Akonadi::Item,Akonadi::Collection)));
 
127
   connect(m_pMonitor,SIGNAL(itemChanged(Akonadi::Item,QSet<QByteArray>)),this,SLOT(slotItemChanged(Akonadi::Item,QSet<QByteArray>)));
 
128
   connect(m_pMonitor,SIGNAL(itemRemoved(Akonadi::Item)),this,SLOT(slotItemRemoved(Akonadi::Item)));
 
129
 
 
130
 
 
131
   m_pMonitor->setCollectionMonitored(m_Coll,true);
 
132
   m_isEnabled = true; //FIXME does it make sense to merge loaded and enabled?
 
133
   return true;
 
134
}
 
135
 
 
136
bool AkonadiBackend::enable (bool enable)
 
137
{
 
138
   if (enable && (!m_wasEnabled)) {
 
139
      return load();
 
140
   }
 
141
   else if (m_wasEnabled && enable) {
 
142
      foreach(Contact* contact, m_lBackendContacts) {
 
143
         contact->setActive(true);
 
144
      }
 
145
      m_wasEnabled = false;
 
146
      m_isEnabled = true;
 
147
   }
 
148
   else if (isEnabled()) {
 
149
      foreach(Contact* contact, m_lBackendContacts) {
 
150
         contact->setActive(false);
 
151
      }
 
152
      m_isEnabled = false;
 
153
      m_wasEnabled = true;
 
154
   }
 
155
   return false;
 
156
}
 
157
 
 
158
bool AkonadiBackend::reload()
 
159
{
 
160
   //TODO
 
161
   return false;
 
162
}
 
163
 
 
164
QByteArray AkonadiBackend::id() const
 
165
{
 
166
   return QString::number(m_Coll.id()).toAscii();
 
167
}
 
168
 
 
169
AbstractContactBackend::SupportedFeatures AkonadiBackend::supportedFeatures() const
 
170
{
 
171
   return (AbstractContactBackend::SupportedFeatures) (
 
172
      AbstractContactBackend::SupportedFeatures::NONE        |
 
173
      AbstractContactBackend::SupportedFeatures::LOAD        |
 
174
      AbstractContactBackend::SupportedFeatures::SAVE        |
 
175
      AbstractContactBackend::SupportedFeatures::EDIT        |
 
176
      AbstractContactBackend::SupportedFeatures::REMOVE      |
 
177
      AbstractContactBackend::SupportedFeatures::ADD         |
 
178
      AbstractContactBackend::SupportedFeatures::MANAGEABLE  |
 
179
      AbstractContactBackend::SupportedFeatures::DISABLEABLE |
 
180
      AbstractContactBackend::SupportedFeatures::ENABLEABLE
 
181
   );
 
182
}
122
183
 
123
184
/*****************************************************************************
124
185
 *                                                                           *
155
216
   c->setOrganization   (addr.organization()   );
156
217
   c->setPreferredEmail (addr.preferredEmail() );
157
218
   c->setDepartment     (addr.department()     );
158
 
   c->setUid            (addr.uid()            );
 
219
   c->setUid            (addr.uid().toUtf8()   );
159
220
 
160
221
   const KABC::PhoneNumber::List numbers = addr.phoneNumbers();
161
222
   Contact::PhoneNumbers newNumbers(c);
178
239
      KABC::Addressee tmp = item.payload<KABC::Addressee>();
179
240
      const KABC::PhoneNumber::List numbers = tmp.phoneNumbers();
180
241
      const QString uid = tmp.uid();
181
 
 
182
242
      if (numbers.size() || !ignoreEmpty) {
183
243
         aContact   = new Contact(this);
184
244
 
185
245
         //This need to be done first because of the phone numbers indexes
186
246
         fillContact(aContact,tmp);
187
247
 
188
 
         m_ContactByUid[uid] = aContact;
189
 
 
190
248
         if (!tmp.photo().data().isNull())
191
249
            aContact->setPhoto(new QPixmap(QPixmap::fromImage( tmp.photo().data()).scaled(QSize(48,48))));
192
250
         else
193
 
            aContact->setPhoto(0);
 
251
            aContact->setPhoto(nullptr);
194
252
 
195
253
         m_AddrHash[ uid ] = tmp ;
196
254
         m_ItemHash[ uid ] = item;
 
255
         m_lBackendContacts << aContact;
197
256
      }
198
257
   }
199
258
   return aContact;
212
271
      kDebug() << "An Akonadi job failed";
213
272
      return;
214
273
   }
215
 
 
216
274
   Akonadi::RecursiveItemFetchJob* akojob = qobject_cast<Akonadi::RecursiveItemFetchJob*>(job);
217
275
   if (akojob) {
218
276
      const bool onlyWithNumber =  ConfigurationSkeleton::hideContactWithoutPhone();
219
277
      const Akonadi::Item::List items = akojob->items();
220
278
      foreach ( const Akonadi::Item &item, items ) {
221
 
         addItem(item,onlyWithNumber);
 
279
         Contact* c = addItem(item,onlyWithNumber);
 
280
         ContactModel::instance()->addContact(c);
222
281
      }
223
 
      beginResetModel();
224
 
      const int oldSize = m_pContacts.size();
225
 
      m_pContacts = m_ContactByUid.values();
226
 
      endResetModel();
227
 
      emit layoutChanged();
228
 
      if (oldSize != m_pContacts.size())
229
 
         emit collectionChanged();
230
282
   }
231
283
}
232
284
 
240
292
 
241
293
   Akonadi::RecursiveItemFetchJob *job = new Akonadi::RecursiveItemFetchJob( collection, QStringList() << KABC::Addressee::mimeType() << KABC::ContactGroup::mimeType());
242
294
   job->fetchScope().fetchFullPayload();
243
 
 
244
295
   connect(job, SIGNAL( result( KJob* ) ), this, SLOT( slotJobCompleted( KJob* ) ) );
245
296
   job->start();
246
 
   return;
 
297
//    return m_ContactByUid.values();
247
298
} //update
248
299
 
 
300
bool AkonadiBackend::remove(Contact* c)
 
301
{
 
302
   if (!c)
 
303
      return false;
 
304
   Akonadi::Item item = m_ItemHash[c->uid()];
 
305
   Akonadi::ItemDeleteJob *job = new Akonadi::ItemDeleteJob( item );
 
306
   job->exec();
 
307
   c->setActive(false);
 
308
   return true;
 
309
}
 
310
 
249
311
///Edit backend value using an updated frontend contact
250
 
void AkonadiBackend::editContact(Contact* contact,QWidget* parent)
 
312
bool AkonadiBackend::edit(Contact* contact,QWidget* parent)
251
313
{
252
314
   Akonadi::Item item = m_ItemHash[contact->uid()];
253
315
   if (!(item.hasPayload<KABC::Addressee>() && item.payload<KABC::Addressee>().uid() == contact->uid())) {
254
316
      kDebug() << "Contact not found";
255
 
      return;
 
317
      return false ;
256
318
   }
257
319
 
258
320
   if ( item.isValid() ) {
264
326
         if ( !editor->saveContact() ) {
265
327
            delete dlg;
266
328
            kDebug() << "Unable to save new contact to storage";
267
 
            return;
 
329
            return false;
268
330
         }
269
331
      }
270
332
      delete editor;
271
333
      delete dlg   ;
 
334
      return true;
272
335
   }
 
336
   return false;
273
337
} //editContact
274
338
 
 
339
///Save a contact
 
340
bool AkonadiBackend::save(const Contact* contact)
 
341
{
 
342
   Akonadi::Item item = m_ItemHash[contact->uid()];
 
343
   if (!(item.hasPayload<KABC::Addressee>() && item.payload<KABC::Addressee>().uid() == contact->uid())) {
 
344
      kDebug() << "Contact not found";
 
345
      return false;
 
346
   }
 
347
   KABC::Addressee payload = item.payload<KABC::Addressee>();
 
348
   payload.setNickName       ( contact->nickName()        );
 
349
   payload.setFormattedName  ( contact->formattedName()   );
 
350
   payload.setGivenName      ( contact->firstName()       );
 
351
   payload.setFamilyName     ( contact->secondName()      );
 
352
   payload.setOrganization   ( contact->organization()    );
 
353
   payload.setDepartment     ( contact->department()      );
 
354
 
 
355
   foreach (PhoneNumber* nb, contact->phoneNumbers()) {
 
356
      KABC::PhoneNumber pn;
 
357
      pn.setType(nameToType(nb->category()->name()));
 
358
 
 
359
      pn.setNumber(nb->uri());
 
360
      payload.insertPhoneNumber(pn);
 
361
   }
 
362
   //TODO save the contact
 
363
   return false;
 
364
}
 
365
 
 
366
 
 
367
bool AkonadiBackend::append(const Contact* item)
 
368
{
 
369
   Q_UNUSED(item)
 
370
   return false;
 
371
}
 
372
 
275
373
///Add a new contact
276
 
void AkonadiBackend::addNewContact(Contact* contact,QWidget* parent)
 
374
bool AkonadiBackend::addNewContact(Contact* contact,QWidget* parent)
277
375
{
278
376
   KABC::Addressee newContact;
279
377
   newContact.setNickName       ( contact->nickName()        );
304
402
      if ( !editor->saveContact() ) {
305
403
         delete dlg;
306
404
         kDebug() << "Unable to save new contact to storage";
307
 
         return;
 
405
         return false;
308
406
      }
309
407
   }
310
408
   delete dlg;
 
409
   return true;
311
410
} //addNewContact
312
411
 
313
412
///Implement virtual pure method
314
 
void AkonadiBackend::editContact(Contact* contact)
 
413
bool AkonadiBackend::edit(Contact* contact)
315
414
{
316
 
   editContact(contact,nullptr);
 
415
   return edit(contact,nullptr);
317
416
}
318
417
 
319
418
///Implement virtual pure method
320
 
void AkonadiBackend::addNewContact(Contact* contact)
 
419
bool AkonadiBackend::addNew(Contact* contact)
321
420
{
322
 
   addNewContact(contact,nullptr);
 
421
   return addNewContact(contact,nullptr);
323
422
}
324
423
 
325
424
///Add a new phone number to an existing contact
326
 
void AkonadiBackend::addPhoneNumber(Contact* contact, QString number, QString type)
 
425
bool AkonadiBackend::addPhoneNumber(Contact* contact, PhoneNumber* number)
327
426
{
328
427
   Akonadi::Item item = m_ItemHash[contact->uid()];
329
428
   if (!(item.hasPayload<KABC::Addressee>() && item.payload<KABC::Addressee>().uid() == contact->uid())) {
330
429
      kDebug() << "Contact not found";
331
 
      return;
 
430
      return false;
332
431
   }
333
432
   if ( item.isValid() ) {
334
433
      KABC::Addressee payload = item.payload<KABC::Addressee>();
335
 
      payload.insertPhoneNumber(KABC::PhoneNumber(number,nameToType(type)));
 
434
      payload.insertPhoneNumber(KABC::PhoneNumber(number->uri(),nameToType(number->category()->name())));
336
435
      item.setPayload<KABC::Addressee>(payload);
337
436
      QPointer<Akonadi::ContactEditor> editor = new Akonadi::ContactEditor( Akonadi::ContactEditor::EditMode, (QWidget*)nullptr );
338
437
      editor->loadContact(item);
343
442
         if ( !editor->saveContact() ) {
344
443
            delete dlg;
345
444
            kDebug() << "Unable to save new contact to storage";
346
 
            return;
 
445
            return false;
347
446
         }
348
447
      }
349
448
      delete dlg   ;
350
449
      delete editor;
 
450
      return true;
351
451
   }
352
452
   else {
353
453
      kDebug() << "Invalid item";
 
454
      return false;
354
455
   }
355
456
}
356
457
 
362
463
 ****************************************************************************/
363
464
 
364
465
///Called when a new collection is added
365
 
void AkonadiBackend::collectionsReceived( const Akonadi::Collection::List&  list)
 
466
void AkonadiBackend::itemsReceived( const Akonadi::Item::List& list)
366
467
{
367
 
   foreach (const Akonadi::Collection& coll, list) {
368
 
      update(coll);
369
 
      m_pMonitor->setCollectionMonitored(coll,true);
370
 
      emit collectionChanged();
 
468
//    QList<int> disabledColl = ConfigurationSkeleton::disabledCollectionList();
 
469
   foreach (const Akonadi::Item& item, list) {
 
470
//       if (disabledColl.indexOf(coll.id()) == -1) {
 
471
//          update(coll);
 
472
//          emit reloaded();
 
473
//       }
 
474
      slotItemAdded(item,m_Coll);
371
475
   }
372
476
}
373
477
 
374
478
///Callback when a new item is added
375
 
void AkonadiBackend::slotItemAdded(Akonadi::Item item,Akonadi::Collection coll)
 
479
void AkonadiBackend::slotItemAdded(const Akonadi::Item& item,const Akonadi::Collection& coll)
376
480
{
377
481
   Q_UNUSED(coll)
378
482
   Contact* c = addItem(item,ConfigurationSkeleton::hideContactWithoutPhone());
379
483
   if (c) { //Not all items will have an addressee payload
380
 
      beginInsertRows(QModelIndex(),m_pContacts.size()-1,m_pContacts.size());
381
 
      m_pContacts << c;
382
 
      endInsertRows();
383
484
      emit newContactAdded(c);
384
 
      emit layoutChanged();
385
485
   }
386
486
}
387
487
 
391
491
   Q_UNUSED(part)
392
492
   if (item.hasPayload<KABC::Addressee>()) {
393
493
      KABC::Addressee tmp = item.payload<KABC::Addressee>();
394
 
      Contact* c = getContactByUid(tmp.uid());
 
494
      Contact* c = ContactModel::instance()->getContactByUid(tmp.uid().toUtf8());
395
495
      if (c)
396
496
         fillContact(c,tmp);
397
497
   }
400
500
///Callback when a contact is removed
401
501
void AkonadiBackend::slotItemRemoved(const Akonadi::Item &item)
402
502
{
403
 
   Contact* c = getContactByUid(item.remoteId());
404
 
   if (c)
405
 
      c->setActive(false);
406
 
}
407
 
 
408
 
///Update the contact list even without a new collection
409
 
ContactList AkonadiBackend::update_slot()
410
 
{
411
 
   return m_pContacts;//update(m_Collection);
 
503
   Contact* c = ContactModel::instance()->getContactByUid(item.remoteId().toUtf8());
 
504
   ContactModel::instance()->disableContact(c);
 
505
}
 
506
 
 
507
Akonadi::Collection AkonadiBackend::collection() const
 
508
{
 
509
   return m_Coll;
 
510
}
 
511
 
 
512
QList<Contact*> AkonadiBackend::items() const
 
513
{
 
514
   return m_lBackendContacts;
412
515
}