Merge lp:~renatofilho/address-book-service/fix-edit into lp:address-book-service

Proposed by Renato Araujo Oliveira Filho
Status: Superseded
Proposed branch: lp:~renatofilho/address-book-service/fix-edit
Merge into: lp:address-book-service
Diff against target: 2842 lines (+1306/-735)
13 files modified
common/vcard-parser.cpp (+29/-8)
common/vcard-parser.h (+2/-0)
qcontacts/contacts-service.cpp (+26/-6)
qcontacts/contacts-service.h (+5/-1)
src/addressbook-adaptor.cpp (+5/-0)
src/addressbook-adaptor.h (+9/-4)
src/addressbook.cpp (+98/-74)
src/addressbook.h (+12/-4)
src/contacts-map.cpp (+11/-0)
src/contacts-map.h (+1/-0)
src/qindividual.cpp (+1050/-610)
src/qindividual.h (+56/-26)
src/view-adaptor.h (+2/-2)
To merge this branch: bzr merge lp:~renatofilho/address-book-service/fix-edit
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Approve
Ubuntu Phablet Team Pending
Review via email: mp+169953@code.launchpad.net

This proposal has been superseded by a proposal from 2013-06-20.

Commit message

Added support to edit contacts with multiple persona.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
35. By Renato Araujo Oliveira Filho

Fixed qcontacts plugins to wait for server fully start before request any data.

Approved by PS Jenkins bot, Bill Filler.

36. By Renato Araujo Oliveira Filho

Added support to edit contacts with multiple persona.

Approved by PS Jenkins bot, Bill Filler.

37. By Renato Araujo Oliveira Filho

Implemented AddressBook::availableSources.
Implemented support to change sort clause in the view.
Implemented AddressBook::sortFields.

Approved by PS Jenkins bot, Bill Filler.

38. By Renato Araujo Oliveira Filho

Update server contact cache with the new contact info if update operation finish without error. Fixes: https://bugs.launchpad.net/bugs/1193195.

Approved by Bill Filler, PS Jenkins bot.

39. By PS Jenkins bot

Releasing 0.1.0daily13.06.25-0ubuntu1 to ubuntu.

Approved by PS Jenkins bot.

40. By Renato Araujo Oliveira Filho

Changed View.count from signal to property.
Renamed callback functions to follow the code style.

Approved by Gustavo Pichorim Boiko, PS Jenkins bot.

41. By PS Jenkins bot

Releasing 0.1.0+13.10.20130627-0ubuntu1 to ubuntu.

Approved by PS Jenkins bot.

42. By Renato Araujo Oliveira Filho

Initial implementation of FetchHint.

Approved by Bill Filler, PS Jenkins bot.

43. By PS Jenkins bot

Releasing 0.1.0+13.10.20130628-0ubuntu1 to ubuntu.

Approved by PS Jenkins bot.

44. By Renato Araujo Oliveira Filho

[package]Added evolution and folks-eds into dependency list.

Approved by Sergio Schvezov, PS Jenkins bot.

45. By PS Jenkins bot

Releasing 0.1.0+13.10.20130702-0ubuntu1 to ubuntu.

Approved by PS Jenkins bot.

46. By Renato Araujo Oliveira Filho

Implemented avatars support.

Approved by Gustavo Pichorim Boiko, PS Jenkins bot.

47. By Renato Araujo Oliveira Filho

Fixed contact edit when adding a new field.

Folks return a read only list of details we need to copy it before start to modify it.

Approved by PS Jenkins bot, Gustavo Pichorim Boiko.

48. By Renato Araujo Oliveira Filho

Fixed contact update crash.

49. By Renato Araujo Oliveira Filho

Fixed contact address update.

Avoid do destroy contact address field durint the contact update.

50. By Renato Araujo Oliveira Filho

Emit the signal ¨contactUpdated¨ after a contact has been changed.

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'common/vcard-parser.cpp'
2--- common/vcard-parser.cpp 2013-05-18 01:11:38 +0000
3+++ common/vcard-parser.cpp 2013-06-20 13:17:29 +0000
4@@ -55,7 +55,7 @@
5
6 if (detail.type() == QContactDetail::TypeExtendedDetail) {
7 const QContactExtendedDetail *extendedDetail = static_cast<const QContactExtendedDetail *>(&detail);
8- if (extendedDetail->name() == "CLIENTPIDMAP") {
9+ if (extendedDetail->name() == galera::VCardParser::PidMapFieldName) {
10 QVersitProperty prop;
11 prop.setName(extendedDetail->name());
12 QStringList value;
13@@ -70,11 +70,12 @@
14 }
15
16 if (!detail.detailUri().isEmpty()) {
17- QVersitProperty prop = toBeAdded->takeLast();
18- QMultiHash<QString, QString> params = prop.parameters();
19- params.insert("PID", detail.detailUri());
20- prop.setParameters(params);
21- *toBeAdded << prop;
22+ if (toBeAdded->size() > 0) {
23+ QVersitProperty &prop = toBeAdded->last();
24+ QMultiHash<QString, QString> params = prop.parameters();
25+ params.insert(galera::VCardParser::PidFieldName, detail.detailUri());
26+ prop.setParameters(params);
27+ }
28 }
29 }
30
31@@ -102,16 +103,33 @@
32 Q_UNUSED(document);
33 Q_UNUSED(contact);
34
35- if (!*alreadyProcessed && (property.name() == "CLIENTPIDMAP")) {
36+ if (!*alreadyProcessed && (property.name() == galera::VCardParser::PidMapFieldName)) {
37 QContactExtendedDetail detail;
38 detail.setName(property.name());
39- QStringList value = property.value<QStringList>();
40+ QStringList value = property.value<QString>().split(";");
41 detail.setValue(QContactExtendedDetail::FieldData, value[0]);
42 detail.setValue(QContactExtendedDetail::FieldData + 1, value[1]);
43 *updatedDetails << detail;
44 *alreadyProcessed = true;
45 }
46
47+ QString pid = property.parameters().value(galera::VCardParser::PidFieldName);
48+ if (!pid.isEmpty()) {
49+ QContactDetail &det = updatedDetails->last();
50+ det.setDetailUri(pid);
51+ }
52+
53+ // Remove empty phone subtypes
54+ // Remove this after this fix get merged: https://codereview.qt-project.org/#change,59156
55+ if (updatedDetails->size() > 0) {
56+ QContactDetail &det = updatedDetails->last();
57+ if (det.type() == QContactPhoneNumber::Type) {
58+ QContactPhoneNumber phone = static_cast<QContactPhoneNumber>(det);
59+ if (phone.subTypes().size() == 0) {
60+ det.setValue(QContactPhoneNumber::FieldSubTypes, QVariant());
61+ }
62+ }
63+ }
64 }
65
66 virtual void documentProcessed(const QVersitDocument& document, QContact* contact)
67@@ -125,6 +143,9 @@
68 namespace galera
69 {
70
71+const QString VCardParser::PidMapFieldName = QString("CLIENTPIDMAP");
72+const QString VCardParser::PidFieldName = QString("PID");
73+
74 QStringList VCardParser::contactToVcard(QList<QtContacts::QContact> contacts)
75 {
76 QStringList result;
77
78=== modified file 'common/vcard-parser.h'
79--- common/vcard-parser.h 2013-05-18 01:11:38 +0000
80+++ common/vcard-parser.h 2013-06-20 13:17:29 +0000
81@@ -29,6 +29,8 @@
82 class VCardParser
83 {
84 public:
85+ static const QString PidMapFieldName;
86+ static const QString PidFieldName;
87
88 static QStringList contactToVcard(QList<QtContacts::QContact> contacts);
89 static QtContacts::QContact vcardToContact(const QString &vcard);
90
91=== modified file 'qcontacts/contacts-service.cpp'
92--- qcontacts/contacts-service.cpp 2013-06-13 14:35:08 +0000
93+++ qcontacts/contacts-service.cpp 2013-06-20 13:17:29 +0000
94@@ -54,6 +54,7 @@
95 GaleraContactsService::GaleraContactsService(const QString &managerUri)
96 : m_selfContactId(),
97 m_managerUri(managerUri),
98+ m_serviceIsReady(false),
99 m_iface(0)
100 {
101 RequestData::registerMetaType();
102@@ -78,7 +79,12 @@
103
104 GaleraContactsService::~GaleraContactsService()
105 {
106- Q_ASSERT(m_pendingRequests.size() == 0);
107+ while(!m_pendingRequests.isEmpty()) {
108+ QContactManagerEngine::updateRequestState(m_pendingRequests.takeFirst(),
109+ QContactAbstractRequest::CanceledState);
110+ }
111+
112+ Q_ASSERT(m_runningRequests.size() == 0);
113 delete m_serviceWatcher;
114 }
115
116@@ -96,6 +102,14 @@
117 }
118 }
119
120+void GaleraContactsService::onServiceReady()
121+{
122+ m_serviceIsReady = true;
123+ while(!m_pendingRequests.isEmpty()) {
124+ addRequest(m_pendingRequests.takeFirst());
125+ }
126+}
127+
128 void GaleraContactsService::initialize()
129 {
130 if (m_iface.isNull()) {
131@@ -103,6 +117,8 @@
132 CPIM_ADDRESSBOOK_OBJECT_PATH,
133 CPIM_ADDRESSBOOK_IFACE_NAME));
134 if (!m_iface->lastError().isValid()) {
135+ m_serviceIsReady = m_iface.data()->property("isReady").toBool();
136+ connect(m_iface.data(), SIGNAL(ready()), this, SLOT(onServiceReady()));
137 connect(m_iface.data(), SIGNAL(contactsAdded(QStringList)), this, SLOT(onContactsAdded(QStringList)));
138 connect(m_iface.data(), SIGNAL(contactsRemoved(QStringList)), this, SLOT(onContactsRemoved(QStringList)));
139 } else {
140@@ -159,7 +175,7 @@
141 CPIM_ADDRESSBOOK_VIEW_IFACE_NAME);
142
143 RequestData *requestData = new RequestData(request, view);
144- m_pendingRequests << requestData;
145+ m_runningRequests << requestData;
146 QMetaObject::invokeMethod(this, "fetchContactsPage", Qt::QueuedConnection, Q_ARG(galera::RequestData*, requestData));
147 }
148
149@@ -295,7 +311,7 @@
150 QDBusPendingCall pcall = m_iface->asyncCall("createContact", contact, "");
151 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pcall, 0);
152 RequestData *requestData = new RequestData(request, 0, watcher);
153- m_pendingRequests << requestData;
154+ m_runningRequests << requestData;
155 QObject::connect(watcher, &QDBusPendingCallWatcher::finished,
156 [=](QDBusPendingCallWatcher *call) {
157 this->createContactsDone(requestData, call);
158@@ -367,7 +383,7 @@
159 } else {
160 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pcall, 0);
161 RequestData *requestData = new RequestData(request, 0, watcher);
162- m_pendingRequests << requestData;
163+ m_runningRequests << requestData;
164 QObject::connect(watcher, &QDBusPendingCallWatcher::finished,
165 [=](QDBusPendingCallWatcher *call) {
166 this->removeContactDone(requestData, call);
167@@ -423,7 +439,7 @@
168 } else {
169 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pcall, 0);
170 RequestData *requestData = new RequestData(request, 0, watcher);
171- m_pendingRequests << requestData;
172+ m_runningRequests << requestData;
173 QObject::connect(watcher, &QDBusPendingCallWatcher::finished,
174 [=](QDBusPendingCallWatcher *call) {
175 this->updateContactDone(requestData, call);
176@@ -471,6 +487,10 @@
177 void GaleraContactsService::addRequest(QtContacts::QContactAbstractRequest *request)
178 {
179 qDebug() << Q_FUNC_INFO << request->state();
180+ if (!m_serviceIsReady) {
181+ m_pendingRequests << request;
182+ return;
183+ }
184 if (!isOnline()) {
185 QContactManagerEngine::updateRequestState(request, QContactAbstractRequest::FinishedState);
186 return;
187@@ -511,7 +531,7 @@
188 void GaleraContactsService::destroyRequest(RequestData *request)
189 {
190 qDebug() << Q_FUNC_INFO;
191- m_pendingRequests.remove(request);
192+ m_runningRequests.remove(request);
193 delete request;
194 }
195
196
197=== modified file 'qcontacts/contacts-service.h'
198--- qcontacts/contacts-service.h 2013-06-12 22:41:11 +0000
199+++ qcontacts/contacts-service.h 2013-06-20 13:17:29 +0000
200@@ -24,6 +24,7 @@
201 #include <QtCore/QStringList>
202 #include <QtCore/QSet>
203 #include <QtCore/QMutex>
204+#include <QtCore/QQueue>
205
206 #include <QtContacts/QContact>
207 #include <QtContacts/QContactManagerEngine>
208@@ -68,6 +69,7 @@
209 void onContactsAdded(QStringList ids);
210 void onContactsRemoved(QStringList ids);
211 void serviceOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner);
212+ void onServiceReady();
213
214 private:
215 QString m_id;
216@@ -78,9 +80,11 @@
217 QMap<QtContacts::QContactId, QList<QtContacts::QContactRelationship> > m_orderedRelationships; // map of ordered lists of contact relationships
218 QString m_managerUri; // for faster lookup.
219 QDBusServiceWatcher *m_serviceWatcher;
220+ bool m_serviceIsReady;
221
222 QSharedPointer<QDBusInterface> m_iface;
223- QSet<RequestData*> m_pendingRequests;
224+ QSet<RequestData*> m_runningRequests;
225+ QQueue<QtContacts::QContactAbstractRequest*> m_pendingRequests;
226
227 Q_INVOKABLE void initialize();
228 Q_INVOKABLE void deinitialize();
229
230=== modified file 'src/addressbook-adaptor.cpp'
231--- src/addressbook-adaptor.cpp 2013-06-13 14:00:42 +0000
232+++ src/addressbook-adaptor.cpp 2013-06-20 13:17:29 +0000
233@@ -94,4 +94,9 @@
234 return QStringList();
235 }
236
237+bool AddressBookAdaptor::isReady()
238+{
239+ return m_addressBook->isReady();
240+}
241+
242 } //namespace
243
244=== modified file 'src/addressbook-adaptor.h'
245--- src/addressbook-adaptor.h 2013-06-07 18:54:26 +0000
246+++ src/addressbook-adaptor.h 2013-06-20 13:17:29 +0000
247@@ -37,6 +37,7 @@
248 Q_CLASSINFO("D-Bus Interface", CPIM_ADDRESSBOOK_IFACE_NAME)
249 Q_CLASSINFO("D-Bus Introspection", ""
250 " <interface name=\"com.canonical.pim.AddressBook\">\n"
251+" <property name=\"isReady\" type=\"b\" access=\"read\"/>\n"
252 " <signal name=\"contactsUpdated\">\n"
253 " <arg direction=\"out\" type=\"as\" name=\"ids\"/>\n"
254 " </signal>\n"
255@@ -49,6 +50,7 @@
256 " <signal name=\"asyncOperationResult\">\n"
257 " <arg direction=\"out\" type=\"a(ss)\" name=\"errorMap\"/>\n"
258 " </signal>\n"
259+" <signal name=\"ready\"/>\n"
260 " <method name=\"availableSources\">\n"
261 " <arg direction=\"out\" type=\"a(sb)\"/>\n"
262 " <annotation value=\"SourceList\" name=\"com.trolltech.QtDBus.QtTypeName.Out0\"/>\n"
263@@ -90,25 +92,28 @@
264 " </method>\n"
265 " </interface>\n"
266 "")
267+ Q_PROPERTY(bool isReady READ isReady NOTIFY ready)
268 public:
269 AddressBookAdaptor(const QDBusConnection &connection, AddressBook *parent);
270 virtual ~AddressBookAdaptor();
271
272 public Q_SLOTS:
273 SourceList availableSources();
274+ QStringList sortFields();
275+ QDBusObjectPath query(const QString &clause, const QString &sort, const QStringList &sources);
276+ int removeContacts(const QStringList &contactIds, const QDBusMessage &message);
277 QString createContact(const QString &contact, const QString &source, const QDBusMessage &message);
278+ QStringList updateContacts(const QStringList &contacts, const QDBusMessage &message);
279 QString linkContacts(const QStringList &contacts);
280- QDBusObjectPath query(const QString &clause, const QString &sort, const QStringList &sources);
281- int removeContacts(const QStringList &contactIds, const QDBusMessage &message);
282- QStringList sortFields();
283 bool unlinkContacts(const QString &parentId, const QStringList &contactsIds);
284- QStringList updateContacts(const QStringList &contacts, const QDBusMessage &message);
285+ bool isReady();
286
287 Q_SIGNALS:
288 void contactsAdded(const QStringList &ids);
289 void contactsRemoved(const QStringList &ids);
290 void contactsUpdated(const QStringList &ids);
291 void asyncOperationResult(QMap<QString, QString> errors);
292+ void ready();
293
294 private:
295 AddressBook *m_addressBook;
296
297=== modified file 'src/addressbook.cpp'
298--- src/addressbook.cpp 2013-06-13 14:35:08 +0000
299+++ src/addressbook.cpp 2013-06-20 13:17:29 +0000
300@@ -26,7 +26,6 @@
301
302 #include <QtCore/QPair>
303 #include <QtCore/QUuid>
304-#include <QtContacts/QContact>
305
306 using namespace QtContacts;
307
308@@ -60,7 +59,7 @@
309 AddressBook::AddressBook(QObject *parent)
310 : QObject(parent),
311 m_contacts(new ContactsMap),
312- m_initializing(true),
313+ m_ready(false),
314 m_adaptor(0)
315 {
316 prepareFolks();
317@@ -97,10 +96,20 @@
318 {
319 //TODO: filter EDS (FolksBackendStore)
320 m_individualAggregator = folks_individual_aggregator_new();
321+ g_object_get(G_OBJECT(m_individualAggregator), "is-quiescent", &m_ready, NULL);
322+ if (m_ready) {
323+ AddressBook::isQuiescentChanged(G_OBJECT(m_individualAggregator), NULL, this);
324+ }
325+ g_signal_connect(m_individualAggregator,
326+ "notify::is-quiescent",
327+ (GCallback)AddressBook::isQuiescentChanged,
328+ this);
329+
330 g_signal_connect(m_individualAggregator,
331 "individuals-changed-detailed",
332 (GCallback) AddressBook::individualsChangedCb,
333 this);
334+
335 folks_individual_aggregator_prepare(m_individualAggregator,
336 (GAsyncReadyCallback) AddressBook::aggregatorPrepareCb,
337 this);
338@@ -223,78 +232,81 @@
339 return false;
340 }
341
342+bool AddressBook::isReady() const
343+{
344+ return m_ready;
345+}
346+
347 QStringList AddressBook::updateContacts(const QStringList &contacts, const QDBusMessage &message)
348 {
349- UpdateContactsData *data = 0;
350-
351- if (!contacts.isEmpty()) {
352- data = new UpdateContactsData;
353- data->m_contacts = VCardParser::vcardToContact(contacts);
354- data->m_request = contacts;
355- data->m_currentIndex = -1;
356- data->m_addressbook = this;
357- data->m_message = message;
358-
359- }
360- updateContacts("", data);
361+ //TODO: support multiple update contacts calls
362+ Q_ASSERT(m_updateCommandPendingContacts.isEmpty());
363+
364+ m_updateCommandReplyMessage = message;
365+ m_updateCommandResult = contacts;
366+ m_updateCommandPendingContacts << VCardParser::vcardToContact(contacts);
367+
368+ updateContactsDone(0, QString());
369
370 return QStringList();
371 }
372
373-void AddressBook::updateContacts(const QString &error, void *userData)
374+void AddressBook::updateContactsDone(galera::QIndividual *individual, const QString &error)
375 {
376- qDebug() << Q_FUNC_INFO << userData;
377- UpdateContactsData *data = static_cast<UpdateContactsData*>(userData);
378- QDBusMessage reply;
379-
380- if (data) {
381- if (!error.isEmpty()) {
382- data->m_result << error;
383- } else if (data->m_currentIndex > -1) {
384- data->m_result << data->m_request[data->m_currentIndex];
385- }
386-
387- if (!data->m_contacts.isEmpty()) {
388- QContact newContact = data->m_contacts.takeFirst();
389- data->m_currentIndex++;
390-
391- ContactEntry *entry = data->m_addressbook->m_contacts->value(newContact.detail<QContactGuid>().guid());
392- if (entry) {
393- entry->individual()->update(newContact, updateContacts, userData);
394- } else {
395- updateContacts("Contact not found!", userData);
396- }
397- return;
398- }
399- folks_persona_store_flush(folks_individual_aggregator_get_primary_store(data->m_addressbook->m_individualAggregator), 0, 0);
400- reply = data->m_message.createReply(data->m_result);
401+ Q_UNUSED(individual);
402+ qDebug() << Q_FUNC_INFO;
403+
404+ if (!error.isEmpty()) {
405+ // update the result with the error
406+ m_updateCommandResult[m_updateCommandResult.size() - m_updateCommandPendingContacts.size()] = error;
407+ }
408+
409+ if (!m_updateCommandPendingContacts.isEmpty()) {
410+ QContact newContact = m_updateCommandPendingContacts.takeFirst();
411+ ContactEntry *entry = m_contacts->value(newContact.detail<QContactGuid>().guid());
412+ if (entry) {
413+ entry->individual()->update(newContact, this, "updateContactsDone(galera::QIndividual*, const QString&)"); //));
414+ } else {
415+ updateContactsDone(0, "Contact not found!");
416+ }
417 } else {
418- reply = data->m_message.createReply(QStringList());
419+ folks_persona_store_flush(folks_individual_aggregator_get_primary_store(m_individualAggregator), 0, 0);
420+ QDBusMessage reply = m_updateCommandReplyMessage.createReply(m_updateCommandResult);
421+ QDBusConnection::sessionBus().send(reply);
422+
423+ // clear command data
424+ m_updateCommandResult.clear();
425+ m_updateCommandReplyMessage = QDBusMessage();
426 }
427-
428- QDBusConnection::sessionBus().send(reply);
429- delete data;
430 }
431
432
433 QString AddressBook::removeContact(FolksIndividual *individual)
434 {
435- Q_ASSERT(m_contacts->contains(individual));
436- ContactEntry *ci = m_contacts->take(individual);
437- if (ci) {
438- QString id = QString::fromUtf8(folks_individual_get_id(individual));
439- delete ci;
440- return id;
441+ if (m_contacts->contains(individual)) {
442+ ContactEntry *ci = m_contacts->take(individual);
443+ if (ci) {
444+ QString id = QString::fromUtf8(folks_individual_get_id(individual));
445+ qDebug() << "Remove contact" << id;
446+ delete ci;
447+ return id;
448+ }
449 }
450 return QString();
451 }
452
453 QString AddressBook::addContact(FolksIndividual *individual)
454 {
455- Q_ASSERT(!m_contacts->contains(individual));
456- m_contacts->insert(new ContactEntry(new QIndividual(individual, m_individualAggregator)));
457- //TODO: Notify view
458- return QString::fromUtf8(folks_individual_get_id(individual));
459+ QString id = QString::fromUtf8(folks_individual_get_id(individual));
460+ ContactEntry *entry = m_contacts->value(id);
461+ if (entry) {
462+ entry->individual()->setIndividual(individual);
463+ } else {
464+ m_contacts->insert(new ContactEntry(new QIndividual(individual, m_individualAggregator)));
465+ qDebug() << "Add contact" << folks_individual_get_id(individual);
466+ //TODO: Notify view
467+ }
468+ return id;
469 }
470
471 void AddressBook::individualsChangedCb(FolksIndividualAggregator *individualAggregator,
472@@ -307,28 +319,28 @@
473
474 GeeIterator *iter;
475 GeeSet *removed = gee_multi_map_get_keys(changes);
476- iter = gee_iterable_iterator(GEE_ITERABLE(removed));
477-
478- while(gee_iterator_next(iter)) {
479- FolksIndividual *individual = FOLKS_INDIVIDUAL(gee_iterator_get(iter));
480- if (individual) {
481- QString id = self->removeContact(individual);
482- if(!id.isEmpty()) {
483- removedIds << id;
484- }
485- g_object_unref(individual);
486- }
487- }
488- g_object_unref (iter);
489-
490 GeeCollection *added = gee_multi_map_get_values(changes);
491+
492 iter = gee_iterable_iterator(GEE_ITERABLE(added));
493 while(gee_iterator_next(iter)) {
494 FolksIndividual *individual = FOLKS_INDIVIDUAL(gee_iterator_get(iter));
495 if (individual) {
496- QString id = self->addContact(individual);
497- if(!id.isEmpty()) {
498- addedIds << id;
499+ // add contact to the map
500+ addedIds << self->addContact(individual);
501+ g_object_unref(individual);
502+ }
503+ }
504+ g_object_unref (iter);
505+
506+
507+ iter = gee_iterable_iterator(GEE_ITERABLE(removed));
508+ while(gee_iterator_next(iter)) {
509+ FolksIndividual *individual = FOLKS_INDIVIDUAL(gee_iterator_get(iter));
510+ if (individual) {
511+ QString id = QString::fromUtf8(folks_individual_get_id(individual));
512+ if (!addedIds.contains(id)) {
513+ // delete from contact map
514+ removedIds << self->removeContact(individual);
515 }
516 g_object_unref(individual);
517 }
518@@ -336,14 +348,14 @@
519 g_object_unref (iter);
520
521 //TODO: check for linked and unliked contacts
522- if (!removedIds.isEmpty()) {
523+ if (!removedIds.isEmpty() && self->m_ready) {
524 Q_EMIT self->m_adaptor->contactsRemoved(removedIds);
525 }
526
527- if (!addedIds.isEmpty()) {
528+ if (!addedIds.isEmpty() && self->m_ready) {
529 Q_EMIT self->m_adaptor->contactsAdded(addedIds);
530 }
531- self->m_initializing = false;
532+ qDebug() << "Added" << addedIds;
533 }
534
535 void AddressBook::aggregatorPrepareCb(GObject *source,
536@@ -379,4 +391,16 @@
537 delete msg;
538 }
539
540+void AddressBook::isQuiescentChanged(GObject *source, GParamSpec *param, AddressBook *self)
541+{
542+ Q_UNUSED(source);
543+ Q_UNUSED(param);
544+
545+ g_object_get(source, "is-quiescent", &self->m_ready, NULL);
546+ if (self->m_ready) {
547+ Q_EMIT self->m_adaptor->ready();
548+ }
549+}
550+
551+
552 } //namespace
553
554=== modified file 'src/addressbook.h'
555--- src/addressbook.h 2013-06-13 14:35:08 +0000
556+++ src/addressbook.h 2013-06-20 13:17:29 +0000
557@@ -28,6 +28,8 @@
558
559 #include <QtDBus/QtDBus>
560
561+#include <QtContacts/QContact>
562+
563 #include <folks/folks.h>
564 #include <glib.h>
565 #include <glib-object.h>
566@@ -37,6 +39,7 @@
567 class View;
568 class ContactsMap;
569 class AddressBookAdaptor;
570+class QIndividual;
571
572 class AddressBook: public QObject
573 {
574@@ -54,11 +57,13 @@
575 View *query(const QString &clause, const QString &sort, const QStringList &sources);
576 QStringList sortFields();
577 bool unlinkContacts(const QString &parent, const QStringList &contacts);
578+ bool isReady() const;
579
580 public Q_SLOTS:
581 QString createContact(const QString &contact, const QString &source, const QDBusMessage &message);
582 int removeContacts(const QStringList &contactIds, const QDBusMessage &message);
583 QStringList updateContacts(const QStringList &contacts, const QDBusMessage &message);
584+ void updateContactsDone(galera::QIndividual *individual, const QString &error);
585
586 private Q_SLOTS:
587 void viewClosed();
588@@ -67,16 +72,18 @@
589 FolksIndividualAggregator *m_individualAggregator;
590 ContactsMap *m_contacts;
591 QSet<View*> m_views;
592- bool m_initializing;
593+ bool m_ready;
594 AddressBookAdaptor *m_adaptor;
595
596+ // Update command
597+ QDBusMessage m_updateCommandReplyMessage;
598+ QStringList m_updateCommandResult;
599+ QList<QtContacts::QContact> m_updateCommandPendingContacts;
600+
601 void prepareFolks();
602 QString removeContact(FolksIndividual *individual);
603 QString addContact(FolksIndividual *individual);
604
605-
606- static void updateContacts(const QString &error, void *userData);
607-
608 static void individualsChangedCb(FolksIndividualAggregator *individualAggregator,
609 GeeMultiMap *changes,
610 AddressBook *self);
611@@ -89,6 +96,7 @@
612 static void removeContactContinue(FolksIndividualAggregator *individualAggregator,
613 GAsyncResult *result,
614 void *data);
615+ static void isQuiescentChanged(GObject *source, GParamSpec *param, AddressBook *self);
616 };
617
618 } //namespace
619
620=== modified file 'src/contacts-map.cpp'
621--- src/contacts-map.cpp 2013-06-11 13:00:01 +0000
622+++ src/contacts-map.cpp 2013-06-20 13:17:29 +0000
623@@ -28,6 +28,7 @@
624 ContactEntry::ContactEntry(QIndividual *individual)
625 : m_individual(individual)
626 {
627+ Q_ASSERT(individual);
628 }
629
630 ContactEntry::~ContactEntry()
631@@ -75,6 +76,16 @@
632 return 0;
633 }
634
635+void ContactsMap::remove(const QString &id)
636+{
637+ ContactEntry *entry = m_idToEntry[id];
638+ if (entry) {
639+ m_individualsToEntry.remove(entry->individual()->individual());
640+ m_idToEntry.remove(id);
641+ delete entry;
642+ }
643+}
644+
645 bool ContactsMap::contains(FolksIndividual *individual) const
646 {
647 return m_individualsToEntry.contains(individual);
648
649=== modified file 'src/contacts-map.h'
650--- src/contacts-map.h 2013-06-11 13:00:01 +0000
651+++ src/contacts-map.h 2013-06-20 13:17:29 +0000
652@@ -60,6 +60,7 @@
653 ContactEntry *value(FolksIndividual *individual) const;
654 ContactEntry *value(const QString &id) const;
655 ContactEntry *take(FolksIndividual *individual);
656+ void remove(const QString &id);
657 void insert(ContactEntry *entry);
658 int size() const;
659
660
661=== modified file 'src/qindividual.cpp'
662--- src/qindividual.cpp 2013-06-11 21:49:45 +0000
663+++ src/qindividual.cpp 2013-06-20 13:17:29 +0000
664@@ -53,14 +53,14 @@
665 class UpdateContactData
666 {
667 public:
668- QContactDetail::DetailType m_currentDetailType;
669 QContact m_newContact;
670 galera::QIndividual *m_self;
671- FolksPersona *m_persona;
672-
673- QList<QContactDetail> m_detailsChanged;
674- galera::UpdateDoneCB m_doneCB;
675- void *m_doneData;
676+
677+ QList<QContactDetail> m_details;
678+ QContactDetail m_currentDetail;
679+
680+ QObject *m_object;
681+ QMetaMethod m_slot;
682 };
683
684 #ifdef FOLKS_0_9_0
685@@ -82,9 +82,6 @@
686 namespace galera
687 {
688
689-// TODO: find a better way to link abstract field with details
690-#define FOLKS_DATA_FIELD 10000
691-
692 #ifdef FOLKS_0_9_0
693 #define SET_AFD_NEW() \
694 GEE_SET(gee_hash_set_new(FOLKS_TYPE_ABSTRACT_FIELD_DETAILS, \
695@@ -96,6 +93,16 @@
696 NULL, \
697 NULL))
698
699+ #define SET_PERSONA_NEW() \
700+ GEE_SET(gee_hash_set_new(FOLKS_TYPE_PERSONA, \
701+ (GBoxedCopyFunc) g_object_ref, g_object_unref, \
702+ NULL, \
703+ NULL, \
704+ NULL, \
705+ NULL, \
706+ NULL, \
707+ NULL))
708+
709 #define GEE_MULTI_MAP_AFD_NEW(FOLKS_TYPE) \
710 GEE_MULTI_MAP(gee_hash_multi_map_new(G_TYPE_STRING,\
711 (GBoxedCopyFunc) g_strdup, g_free, \
712@@ -120,6 +127,13 @@
713 (GHashFunc) folks_abstract_field_details_hash, \
714 (GEqualFunc) folks_abstract_field_details_equal))
715
716+ #define SET_PERSONA_NEW() \
717+ GEE_SET(gee_hash_set_new(FOLKS_TYPE_PERSONA, \
718+ (GBoxedCopyFunc) g_object_ref, g_object_unref, \
719+ NULL, \
720+ NULL))
721+
722+
723 #define GEE_MULTI_MAP_AFD_NEW(FOLKS_TYPE) \
724 GEE_MULTI_MAP(gee_hash_multi_map_new(G_TYPE_STRING, \
725 (GBoxedCopyFunc) g_strdup, \
726@@ -131,16 +145,17 @@
727 (GHashFunc) folks_abstract_field_details_hash, \
728 (GEqualFunc) folks_abstract_field_details_equal));
729
730+
731+
732 #endif
733
734
735 #define PERSONA_DETAILS_INSERT_STRING_FIELD_DETAILS(\
736- details, key, value, q_type, g_type, member) \
737+ details, cDetails, key, value, q_type, g_type, member) \
738 { \
739- QList<q_type> contactDetails = contact.details<q_type>(); \
740- if(contactDetails.size() > 0) { \
741+ if(cDetails.size() > 0) { \
742 value = QIndividualUtils::gValueSliceNew(G_TYPE_OBJECT); \
743- Q_FOREACH(const q_type& detail, contact.details<q_type>()) { \
744+ Q_FOREACH(const q_type& detail, cDetails) { \
745 if(!detail.isEmpty()) { \
746 QIndividualUtils::gValueGeeSetAddStringFieldDetails(value, (g_type), \
747 detail.member().toUtf8().data(), \
748@@ -242,10 +257,53 @@
749 return retval;
750 }
751
752+ static FolksAbstractFieldDetails *getDetails(GeeSet *set, const QString &uri)
753+ {
754+ Q_ASSERT(set);
755+
756+ int pos = 0;
757+ int size = 0;
758+ QStringList index = uri.split(".");
759+ gpointer* values = gee_collection_to_array(GEE_COLLECTION(set), &size);
760+
761+ if (size == 0) {
762+ return 0;
763+ } else if (index.count() == 2) {
764+ pos = index[1].toInt() - 1;
765+ Q_ASSERT(pos >= 0);
766+ Q_ASSERT(pos < size);
767+ }
768+ return FOLKS_ABSTRACT_FIELD_DETAILS(values[pos]);
769+ }
770+
771+ static FolksPersona *personaFromUri(const QString &uri, FolksIndividual *individual, FolksPersona *defaultPersona)
772+ {
773+ Q_ASSERT(individual);
774+
775+ if (uri.isEmpty()) {
776+ //TODO
777+ qWarning() << "NO PERSONA";
778+ return defaultPersona;
779+ } else {
780+
781+ GeeSet *personas = folks_individual_get_personas(individual);
782+ QStringList index = uri.split(".");
783+ Q_ASSERT(index.count() >= 1);
784+ int pos = index[0].toInt() - 1;
785+ int size = 0;
786+ gpointer* values = gee_collection_to_array(GEE_COLLECTION(personas), &size);
787+ Q_ASSERT(pos >= 0);
788+ Q_ASSERT(pos < size);
789+
790+ return FOLKS_PERSONA(values[pos]);
791+ }
792+ }
793+
794 }; // class
795
796 QIndividual::QIndividual(FolksIndividual *individual, FolksIndividualAggregator *aggregator)
797 : m_individual(individual),
798+ m_primaryPersona(0),
799 m_aggregator(aggregator)
800 {
801 g_object_ref(m_individual);
802@@ -267,7 +325,6 @@
803 QList<QtContacts::QContactDetail> QIndividual::getClientPidMap() const
804 {
805 QList<QtContacts::QContactDetail> details;
806- /*
807 int index = 1;
808 GeeSet *personas = folks_individual_get_personas(m_individual);
809 GeeIterator *iter = gee_iterable_iterator(GEE_ITERABLE(personas));
810@@ -282,16 +339,75 @@
811 }
812
813 g_object_unref(iter);
814- */
815- return details;
816-}
817-
818-
819-QtContacts::QContactDetail QIndividual::getName() const
820-{
821+ return details;
822+}
823+
824+void QIndividual::appendDetailsForPersona(QList<QtContacts::QContactDetail> *list, QtContacts::QContactDetail detail, const QString &personaIndex, bool readOnly) const
825+{
826+ if (!detail.isEmpty()) {
827+ detail.setDetailUri(personaIndex);
828+ if (readOnly) {
829+ QContactManagerEngine::setDetailAccessConstraints(&detail, QContactDetail::ReadOnly);
830+ }
831+ list->append(detail);
832+ }
833+}
834+
835+void QIndividual::appendDetailsForPersona(QList<QtContacts::QContactDetail> *list, QList<QtContacts::QContactDetail> details, const QString &personaIndex, bool readOnly) const
836+{
837+ int subIndex = 1;
838+ Q_FOREACH(QContactDetail detail, details) {
839+ appendDetailsForPersona(list, detail, QString("%1.%2").arg(personaIndex).arg(subIndex), readOnly);
840+ subIndex++;
841+ }
842+}
843+
844+
845+QList<QContactDetail> QIndividual::getDetails() const
846+{
847+ int personaIndex = 1;
848+ QList<QContactDetail> details;
849+ GeeSet *personas = folks_individual_get_personas(m_individual);
850+ GeeIterator *iter = gee_iterable_iterator(GEE_ITERABLE(personas));
851+
852+ while(gee_iterator_next(iter)) {
853+ FolksPersona *persona = FOLKS_PERSONA(gee_iterator_get(iter));
854+
855+ int wsize = 0;
856+ gchar **wproperties = folks_persona_get_writeable_properties(persona, &wsize);
857+ //"gender", "local-ids", "avatar", "postal-addresses", "urls", "phone-numbers", "structured-name",
858+ //"anti-links", "im-addresses", "is-favourite", "birthday", "notes", "roles", "email-addresses",
859+ //"web-service-addresses", "groups", "full-name"
860+ QStringList wPropList;
861+ for(int i=0; i < wsize; i++) {
862+ wPropList << wproperties[i];
863+ }
864+
865+ QString index = QString::number(personaIndex);
866+
867+ appendDetailsForPersona(&details, getPersonaName(persona), index, !wPropList.contains("structured-name"));
868+ appendDetailsForPersona(&details, getPersonaFullName(persona), index, !wPropList.contains("full-name"));
869+ appendDetailsForPersona(&details, getPersonaNickName(persona), index, !wPropList.contains("nickname"));
870+ appendDetailsForPersona(&details, getPersonaBirthday(persona), index, !wPropList.contains("birthday"));
871+ appendDetailsForPersona(&details, getPersonaRoles(persona), index, !wPropList.contains("roles"));
872+ appendDetailsForPersona(&details, getPersonaEmails(persona), index, !wPropList.contains("email-addresses"));
873+ appendDetailsForPersona(&details, getPersonaPhones(persona), index, !wPropList.contains("phone-numbers"));
874+ appendDetailsForPersona(&details, getPersonaAddresses(persona), index, !wPropList.contains("postal-addresses"));
875+ appendDetailsForPersona(&details, getPersonaIms(persona), index, !wPropList.contains("im-addresses"));
876+ appendDetailsForPersona(&details, getPersonaUrls(persona), index, !wPropList.contains("urls"));
877+ personaIndex++;
878+ }
879+ return details;
880+}
881+
882+QContactDetail QIndividual::getPersonaName(FolksPersona *persona) const
883+{
884+ if (!FOLKS_IS_NAME_DETAILS(persona)) {
885+ return QContactDetail();
886+ }
887+
888 QContactName detail;
889- FolksStructuredName *sn = folks_name_details_get_structured_name(FOLKS_NAME_DETAILS(m_individual));
890-
891+ FolksStructuredName *sn = folks_name_details_get_structured_name(FOLKS_NAME_DETAILS(persona));
892 if (sn) {
893 const char *name = folks_structured_name_get_given_name(sn);
894 if (name && strlen(name)) {
895@@ -317,30 +433,42 @@
896 return detail;
897 }
898
899-QtContacts::QContactDetail QIndividual::getFullName() const
900+QtContacts::QContactDetail QIndividual::getPersonaFullName(FolksPersona *persona) const
901 {
902+ if (!FOLKS_IS_NAME_DETAILS(persona)) {
903+ return QContactDetail();
904+ }
905+
906 QContactDisplayLabel detail;
907- const gchar *fullName = folks_name_details_get_full_name(FOLKS_NAME_DETAILS(m_individual));
908+ const gchar *fullName = folks_name_details_get_full_name(FOLKS_NAME_DETAILS(persona));
909 if (fullName && strlen(fullName)) {
910 detail.setLabel(QString::fromUtf8(fullName));
911 }
912 return detail;
913 }
914
915-QtContacts::QContactDetail QIndividual::getNickname() const
916+QtContacts::QContactDetail QIndividual::getPersonaNickName(FolksPersona *persona) const
917 {
918+ if (!FOLKS_IS_NAME_DETAILS(persona)) {
919+ return QContactDetail();
920+ }
921+
922 QContactNickname detail;
923- const gchar* nickname = folks_name_details_get_nickname(FOLKS_NAME_DETAILS(m_individual));
924+ const gchar* nickname = folks_name_details_get_nickname(FOLKS_NAME_DETAILS(persona));
925 if (nickname && strlen(nickname)) {
926 detail.setNickname(QString::fromUtf8(nickname));
927 }
928 return detail;
929 }
930
931-QtContacts::QContactDetail QIndividual::getBirthday() const
932+QtContacts::QContactDetail QIndividual::getPersonaBirthday(FolksPersona *persona) const
933 {
934+ if (!FOLKS_IS_BIRTHDAY_DETAILS(persona)) {
935+ return QContactDetail();
936+ }
937+
938 QContactBirthday detail;
939- GDateTime* datetime = folks_birthday_details_get_birthday(FOLKS_BIRTHDAY_DETAILS(m_individual));
940+ GDateTime* datetime = folks_birthday_details_get_birthday(FOLKS_BIRTHDAY_DETAILS(persona));
941 if (datetime) {
942 QDate date(g_date_time_get_year(datetime), g_date_time_get_month(datetime), g_date_time_get_day_of_month(datetime));
943 QTime time(g_date_time_get_hour(datetime), g_date_time_get_minute(datetime), g_date_time_get_second(datetime));
944@@ -349,16 +477,20 @@
945 return detail;
946 }
947
948-QtContacts::QContactDetail QIndividual::getPhoto() const
949+QtContacts::QContactDetail QIndividual::getPersonaPhoto(FolksPersona *persona) const
950 {
951 // TODO
952 return QContactAvatar();
953 }
954
955-QList<QtContacts::QContactDetail> QIndividual::getRoles() const
956+QList<QtContacts::QContactDetail> QIndividual::getPersonaRoles(FolksPersona *persona) const
957 {
958+ if (!FOLKS_IS_ROLE_DETAILS(persona)) {
959+ return QList<QtContacts::QContactDetail>();
960+ }
961+
962 QList<QtContacts::QContactDetail> details;
963- GeeSet *roles = folks_role_details_get_roles(FOLKS_ROLE_DETAILS(m_individual));
964+ GeeSet *roles = folks_role_details_get_roles(FOLKS_ROLE_DETAILS(persona));
965 GeeIterator *iter = gee_iterable_iterator(GEE_ITERABLE(roles));
966
967 while(gee_iterator_next(iter)) {
968@@ -379,10 +511,14 @@
969 return details;
970 }
971
972-QList<QtContacts::QContactDetail> QIndividual::getEmails() const
973+QList<QtContacts::QContactDetail> QIndividual::getPersonaEmails(FolksPersona *persona) const
974 {
975+ if (!FOLKS_IS_EMAIL_DETAILS(persona)) {
976+ return QList<QtContacts::QContactDetail>();
977+ }
978+
979 QList<QtContacts::QContactDetail> details;
980- GeeSet *emails = folks_email_details_get_email_addresses(FOLKS_EMAIL_DETAILS(m_individual));
981+ GeeSet *emails = folks_email_details_get_email_addresses(FOLKS_EMAIL_DETAILS(persona));
982 GeeIterator *iter = gee_iterable_iterator(GEE_ITERABLE(emails));
983
984 while(gee_iterator_next(iter)) {
985@@ -402,10 +538,14 @@
986 return details;
987 }
988
989-QList<QtContacts::QContactDetail> QIndividual::getPhones() const
990+QList<QtContacts::QContactDetail> QIndividual::getPersonaPhones(FolksPersona *persona) const
991 {
992+ if (!FOLKS_IS_PHONE_DETAILS(persona)) {
993+ return QList<QtContacts::QContactDetail>();
994+ }
995+
996 QList<QtContacts::QContactDetail> details;
997- GeeSet *phones = folks_phone_details_get_phone_numbers(FOLKS_PHONE_DETAILS(m_individual));
998+ GeeSet *phones = folks_phone_details_get_phone_numbers(FOLKS_PHONE_DETAILS(persona));
999 GeeIterator *iter = gee_iterable_iterator(GEE_ITERABLE(phones));
1000
1001 while(gee_iterator_next(iter)) {
1002@@ -425,10 +565,14 @@
1003 return details;
1004 }
1005
1006-QList<QtContacts::QContactDetail> QIndividual::getAddresses() const
1007+QList<QtContacts::QContactDetail> QIndividual::getPersonaAddresses(FolksPersona *persona) const
1008 {
1009+ if (!FOLKS_IS_POSTAL_ADDRESS_DETAILS(persona)) {
1010+ return QList<QtContacts::QContactDetail>();
1011+ }
1012+
1013 QList<QtContacts::QContactDetail> details;
1014- GeeSet *addresses = folks_postal_address_details_get_postal_addresses(FOLKS_POSTAL_ADDRESS_DETAILS(m_individual));
1015+ GeeSet *addresses = folks_postal_address_details_get_postal_addresses(FOLKS_POSTAL_ADDRESS_DETAILS(persona));
1016 GeeIterator *iter = gee_iterable_iterator(GEE_ITERABLE(addresses));
1017
1018 while(gee_iterator_next(iter)) {
1019@@ -476,10 +620,14 @@
1020 return details;
1021 }
1022
1023-QList<QtContacts::QContactDetail> QIndividual::getIms() const
1024+QList<QtContacts::QContactDetail> QIndividual::getPersonaIms(FolksPersona *persona) const
1025 {
1026+ if (!FOLKS_IS_IM_DETAILS(persona)) {
1027+ return QList<QtContacts::QContactDetail>();
1028+ }
1029+
1030 QList<QtContacts::QContactDetail> details;
1031- GeeMultiMap *ims = folks_im_details_get_im_addresses(FOLKS_IM_DETAILS(m_individual));
1032+ GeeMultiMap *ims = folks_im_details_get_im_addresses(FOLKS_IM_DETAILS(persona));
1033 GeeSet *keys = gee_multi_map_get_keys(ims);
1034 GeeIterator *iter = gee_iterable_iterator(GEE_ITERABLE(keys));
1035
1036@@ -508,16 +656,14 @@
1037 return details;
1038 }
1039
1040-QtContacts::QContactDetail QIndividual::getTimeZone() const
1041+QList<QtContacts::QContactDetail> QIndividual::getPersonaUrls(FolksPersona *persona) const
1042 {
1043- //TODO
1044- return QContactDetail();
1045-}
1046+ if (!FOLKS_IS_URL_DETAILS(persona)) {
1047+ return QList<QtContacts::QContactDetail>();
1048+ }
1049
1050-QList<QtContacts::QContactDetail> QIndividual::getUrls() const
1051-{
1052 QList<QtContacts::QContactDetail> details;
1053- GeeSet *urls = folks_url_details_get_urls(FOLKS_URL_DETAILS(m_individual));
1054+ GeeSet *urls = folks_url_details_get_urls(FOLKS_URL_DETAILS(persona));
1055 GeeIterator *iter = gee_iterable_iterator(GEE_ITERABLE(urls));
1056
1057 while(gee_iterator_next(iter)) {
1058@@ -635,519 +781,662 @@
1059 {
1060 m_contact = QContact();
1061 m_contact.appendDetail(getUid());
1062- m_contact.appendDetail(getName());
1063- m_contact.appendDetail(getFullName());
1064- m_contact.appendDetail(getNickname());
1065- m_contact.appendDetail(getBirthday());
1066- m_contact.appendDetail(getPhoto());
1067- m_contact.appendDetail(getTimeZone());
1068 Q_FOREACH(QContactDetail detail, getClientPidMap()) {
1069 m_contact.appendDetail(detail);
1070 }
1071- Q_FOREACH(QContactDetail detail, getRoles()) {
1072- m_contact.appendDetail(detail);
1073- }
1074- Q_FOREACH(QContactDetail detail, getEmails()) {
1075- m_contact.appendDetail(detail);
1076- }
1077- Q_FOREACH(QContactDetail detail, getPhones()) {
1078- m_contact.appendDetail(detail);
1079- }
1080- Q_FOREACH(QContactDetail detail, getAddresses()) {
1081- m_contact.appendDetail(detail);
1082- }
1083- Q_FOREACH(QContactDetail detail, getIms()) {
1084- m_contact.appendDetail(detail);
1085- }
1086- Q_FOREACH(QContactDetail detail, getUrls()) {
1087- m_contact.appendDetail(detail);
1088- }
1089+
1090+ Q_FOREACH(QContactDetail detail, getDetails()) {
1091+ m_contact.appendDetail(detail);
1092+ }
1093+}
1094+
1095+void QIndividual::createPersonaForDetail(QList<QtContacts::QContactDetail> cDetails, ParseDetailsFunc parseFunc, void *data) const
1096+{
1097+ GHashTable *details = g_hash_table_new_full(g_str_hash,
1098+ g_str_equal,
1099+ NULL,
1100+ (GDestroyNotify) QIndividualUtils::gValueSliceFree);
1101+
1102+ parseFunc(details, cDetails);
1103+
1104+ folks_individual_aggregator_add_persona_from_details(m_aggregator,
1105+ NULL, // we should pass the m_individual here but due a bug on folks lest do a work around
1106+ folks_individual_aggregator_get_primary_store(m_aggregator),
1107+ details,
1108+ (GAsyncReadyCallback) createPersonaDone,
1109+ (void*) data);
1110+
1111+ g_hash_table_destroy(details);
1112 }
1113
1114 void QIndividual::updateFullName(const QtContacts::QContactDetail &detail, void* data)
1115 {
1116- UpdateContactData *udata = static_cast<UpdateContactData*>(data);
1117- QContactDetail originalLabel = m_contact.detail(QContactDetail::TypeDisplayLabel);
1118- if (FOLKS_IS_NAME_DETAILS(udata->m_persona) && (originalLabel != detail)) {
1119+ FolksPersona *persona = QIndividualUtils::personaFromUri(detail.detailUri(), m_individual, primaryPersona());
1120+ QContactDetail originalLabel = detailFromUri(QContactDetail::TypeDisplayLabel, detail.detailUri());
1121+
1122+ if (persona == 0) {
1123+ createPersonaForDetail(QList<QContactDetail>() << detail, QIndividual::parseFullNameDetails, data);
1124+ } else if (FOLKS_IS_NAME_DETAILS(persona) && (originalLabel != detail)) {
1125 const QContactDisplayLabel *label = static_cast<const QContactDisplayLabel*>(&detail);
1126
1127- folks_name_details_change_full_name(FOLKS_NAME_DETAILS(udata->m_persona),
1128+ folks_name_details_change_full_name(FOLKS_NAME_DETAILS(persona),
1129 label->label().toUtf8().data(),
1130 (GAsyncReadyCallback) updateDetailsDone,
1131 data);
1132 } else {
1133- updateDetailsDone(G_OBJECT(udata->m_persona), NULL, data);
1134+ updateDetailsDone(G_OBJECT(persona), NULL, data);
1135 }
1136 }
1137
1138 void QIndividual::updateName(const QtContacts::QContactDetail &detail, void* data)
1139 {
1140- UpdateContactData *udata = static_cast<UpdateContactData*>(data);
1141- QContactDetail originalName = m_contact.detail(QContactDetail::TypeName);
1142- if (FOLKS_IS_NAME_DETAILS(udata->m_persona) && (originalName != detail)) {
1143+ FolksPersona *persona = QIndividualUtils::personaFromUri(detail.detailUri(), m_individual, primaryPersona());
1144+ QContactDetail originalName = detailFromUri(QContactDetail::TypeName, detail.detailUri());
1145+
1146+ if (persona == 0) {
1147+ createPersonaForDetail(QList<QContactDetail>() << detail, QIndividual::parseNameDetails, data);
1148+ } else if (FOLKS_IS_NAME_DETAILS(persona) && (originalName != detail)) {
1149 const QContactName *name = static_cast<const QContactName*>(&detail);
1150- FolksStructuredName *sn = folks_name_details_get_structured_name(FOLKS_NAME_DETAILS(m_individual));
1151- if (!sn) {
1152- sn = folks_structured_name_new(name->lastName().toUtf8().data(),
1153- name->firstName().toUtf8().data(),
1154- name->middleName().toUtf8().data(),
1155- name->prefix().toUtf8().data(),
1156- name->suffix().toUtf8().data());
1157- } else {
1158- folks_structured_name_set_family_name(sn, name->lastName().toUtf8().data());
1159- folks_structured_name_set_given_name(sn, name->firstName().toUtf8().data());
1160- folks_structured_name_set_additional_names(sn, name->middleName().toUtf8().data());
1161- folks_structured_name_set_prefixes(sn, name->prefix().toUtf8().data());
1162- folks_structured_name_set_suffixes(sn, name->suffix().toUtf8().data());
1163- }
1164+ FolksStructuredName *sn;
1165+ sn = folks_structured_name_new(name->lastName().toUtf8().data(),
1166+ name->firstName().toUtf8().data(),
1167+ name->middleName().toUtf8().data(),
1168+ name->prefix().toUtf8().data(),
1169+ name->suffix().toUtf8().data());
1170
1171- folks_name_details_change_structured_name(FOLKS_NAME_DETAILS(udata->m_persona),
1172+ folks_name_details_change_structured_name(FOLKS_NAME_DETAILS(persona),
1173 sn,
1174 (GAsyncReadyCallback) updateDetailsDone,
1175 data);
1176+
1177 g_object_unref(sn);
1178 } else {
1179- updateDetailsDone(G_OBJECT(udata->m_persona), NULL, data);
1180+ updateDetailsDone(G_OBJECT(persona), NULL, data);
1181 }
1182 }
1183
1184 void QIndividual::updateNickname(const QtContacts::QContactDetail &detail, void* data)
1185 {
1186- UpdateContactData *udata = static_cast<UpdateContactData*>(data);
1187- QContactDetail originalNickname = m_contact.detail(QContactDetail::TypeNickname);
1188- if (FOLKS_IS_NAME_DETAILS(udata->m_persona) && (originalNickname != detail)) {
1189+ FolksPersona *persona = QIndividualUtils::personaFromUri(detail.detailUri(), m_individual, primaryPersona());
1190+ QContactDetail originalNickname = detailFromUri(QContactDetail::TypeNickname, detail.detailUri());
1191+
1192+ if (persona == 0) {
1193+ createPersonaForDetail(QList<QContactDetail>() << detail, QIndividual::parseNicknameDetails, data);
1194+ } else if (FOLKS_IS_NAME_DETAILS(persona) && (originalNickname != detail)) {
1195 const QContactNickname *nickname = static_cast<const QContactNickname*>(&detail);
1196- folks_name_details_change_nickname(FOLKS_NAME_DETAILS(udata->m_persona),
1197+ folks_name_details_change_nickname(FOLKS_NAME_DETAILS(persona),
1198 nickname->nickname().toUtf8().data(),
1199 (GAsyncReadyCallback) updateDetailsDone,
1200 data);
1201 } else {
1202- updateDetailsDone(G_OBJECT(udata->m_persona), NULL, data);
1203+ updateDetailsDone(G_OBJECT(persona), NULL, data);
1204 }
1205 }
1206
1207 void QIndividual::updateBirthday(const QtContacts::QContactDetail &detail, void* data)
1208 {
1209- UpdateContactData *udata = static_cast<UpdateContactData*>(data);
1210- QContactDetail originalBirthday = m_contact.detail(QContactDetail::TypeBirthday);
1211- if (FOLKS_IS_BIRTHDAY_DETAILS(udata->m_persona) && (originalBirthday != detail)) {
1212+ FolksPersona *persona = QIndividualUtils::personaFromUri(detail.detailUri(), m_individual, primaryPersona());
1213+ QContactDetail originalBirthday = detailFromUri(QContactDetail::TypeBirthday, detail.detailUri());
1214+
1215+ if (persona == 0) {
1216+ createPersonaForDetail(QList<QContactDetail>() << detail, QIndividual::parseBirthdayDetails, data);
1217+ } else if (FOLKS_IS_BIRTHDAY_DETAILS(persona) && (originalBirthday != detail)) {
1218 const QContactBirthday *birthday = static_cast<const QContactBirthday*>(&detail);
1219+
1220 GDateTime *dateTime = NULL;
1221 if (!birthday->isEmpty()) {
1222 dateTime = g_date_time_new_from_unix_utc(birthday->dateTime().toMSecsSinceEpoch() / 1000);
1223 }
1224- folks_birthday_details_change_birthday(FOLKS_BIRTHDAY_DETAILS(udata->m_persona),
1225+ folks_birthday_details_change_birthday(FOLKS_BIRTHDAY_DETAILS(persona),
1226 dateTime,
1227 (GAsyncReadyCallback) updateDetailsDone,
1228 data);
1229 g_date_time_unref(dateTime);
1230 } else {
1231- updateDetailsDone(G_OBJECT(udata->m_persona), NULL, data);
1232+ updateDetailsDone(G_OBJECT(persona), NULL, data);
1233 }
1234 }
1235
1236 void QIndividual::updatePhoto(const QtContacts::QContactDetail &detail, void* data)
1237 {
1238- UpdateContactData *udata = static_cast<UpdateContactData*>(data);
1239- QContactDetail originalAvatar = m_contact.detail(QContactDetail::TypeAvatar);
1240- if (FOLKS_IS_AVATAR_DETAILS(udata->m_persona) && (detail != originalAvatar)) {
1241+ FolksPersona *persona = QIndividualUtils::personaFromUri(detail.detailUri(), m_individual, primaryPersona());
1242+ QContactDetail originalAvatar = detailFromUri(QContactDetail::TypeAvatar, detail.detailUri());
1243+
1244+ if (persona == 0) {
1245+ createPersonaForDetail(QList<QContactDetail>() << detail, QIndividual::parsePhotoDetails, data);
1246+ } else if (FOLKS_IS_AVATAR_DETAILS(persona) && (detail != originalAvatar)) {
1247 //TODO:
1248 //const QContactAvatar *avatar = static_cast<const QContactAvatar*>(&detail);
1249- folks_avatar_details_change_avatar(FOLKS_AVATAR_DETAILS(udata->m_persona),
1250+ folks_avatar_details_change_avatar(FOLKS_AVATAR_DETAILS(persona),
1251 0,
1252 (GAsyncReadyCallback) updateDetailsDone,
1253 data);
1254 } else {
1255- updateDetailsDone(G_OBJECT(udata->m_persona), NULL, data);
1256+ updateDetailsDone(G_OBJECT(persona), NULL, data);
1257 }
1258 }
1259
1260-void QIndividual::updateTimezone(const QtContacts::QContactDetail &detail, void* data)
1261-{
1262- //TODO
1263- UpdateContactData *udata = static_cast<UpdateContactData*>(data);
1264- updateDetailsDone(G_OBJECT(udata->m_persona), NULL, data);
1265-}
1266-
1267-void QIndividual::updateRoles(QList<QtContacts::QContactDetail> details, void* data)
1268-{
1269- UpdateContactData *udata = static_cast<UpdateContactData*>(data);
1270- QList<QContactDetail> originalOrganizations = m_contact.details(QContactDetail::TypeOrganization);
1271-
1272- if (FOLKS_IS_ROLE_DETAILS(udata->m_persona) && !detailListIsEqual(originalOrganizations, details)) {
1273- GeeSet *roleSet = SET_AFD_NEW();
1274- Q_FOREACH(const QContactDetail& detail, details) {
1275- const QContactOrganization *org = static_cast<const QContactOrganization*>(&detail);
1276-
1277- // The role values can not be NULL
1278- const gchar* title = org->title().toUtf8().data();
1279- const gchar* name = org->name().toUtf8().data();
1280- const gchar* roleName = org->role().toUtf8().data();
1281-
1282- FolksRole *role = folks_role_new(title ? title : "", name ? name : "", "");
1283- folks_role_set_role(role, roleName ? roleName : "");
1284-
1285- FolksRoleFieldDetails *fieldDetails = folks_role_field_details_new(role, NULL);
1286- parseContext(FOLKS_ABSTRACT_FIELD_DETAILS(fieldDetails), detail);
1287- gee_collection_add(GEE_COLLECTION(roleSet), fieldDetails);
1288-
1289- g_object_unref(role);
1290- g_object_unref(fieldDetails);
1291- }
1292-
1293- folks_role_details_change_roles(FOLKS_ROLE_DETAILS(udata->m_persona),
1294+void QIndividual::updateRole(QtContacts::QContactDetail detail, void* data)
1295+{
1296+ FolksPersona *persona = QIndividualUtils::personaFromUri(detail.detailUri(), m_individual, primaryPersona());
1297+ QContactDetail originalRole = detailFromUri(QContactDetail::TypeOrganization, detail.detailUri());
1298+
1299+ if (!persona) {
1300+ createPersonaForDetail(QList<QContactDetail>() << detail, QIndividual::parseOrganizationDetails, data);
1301+ } else if (FOLKS_IS_ROLE_DETAILS(persona) && (originalRole != detail)) {
1302+ FolksRoleFieldDetails *roleDetails = 0;
1303+ const QContactOrganization *cRole = static_cast<const QContactOrganization*>(&detail);
1304+ GeeSet *roleSet = folks_role_details_get_roles(FOLKS_ROLE_DETAILS(persona));
1305+
1306+ if (!roleSet || (gee_collection_get_size(GEE_COLLECTION(roleSet)) == 0)) {
1307+ roleSet = SET_AFD_NEW();
1308+ } else {
1309+ roleDetails = FOLKS_ROLE_FIELD_DETAILS(QIndividualUtils::getDetails(roleSet, detail.detailUri()));
1310+ // this will be unref at the end of the function
1311+ g_object_ref(roleSet);
1312+ g_object_ref(roleDetails);
1313+ }
1314+
1315+ const gchar* title = cRole->title().isEmpty() ? "" : cRole->title().toUtf8().data();
1316+ const gchar* name = cRole->name().isEmpty() ? "" : cRole->name().toUtf8().data();
1317+ const gchar* roleName = cRole->role().isEmpty() ? "" : cRole->role().toUtf8().data();
1318+
1319+ FolksRole *roleValue;
1320+ if (!roleDetails) {
1321+ roleValue = folks_role_new(title, name, "");
1322+ folks_role_set_role(roleValue, roleName);
1323+
1324+ roleDetails = folks_role_field_details_new(roleValue, NULL);
1325+ gee_collection_add(GEE_COLLECTION(roleSet), roleDetails);
1326+ } else {
1327+ roleValue = FOLKS_ROLE(folks_abstract_field_details_get_value(FOLKS_ABSTRACT_FIELD_DETAILS(roleDetails)));
1328+ folks_role_set_organisation_name(roleValue, name);
1329+ folks_role_set_title(roleValue, title);
1330+ folks_role_set_role(roleValue, roleName);
1331+ }
1332+
1333+ parseContext(FOLKS_ABSTRACT_FIELD_DETAILS(roleDetails), detail);
1334+ folks_role_details_change_roles(FOLKS_ROLE_DETAILS(persona),
1335 roleSet,
1336 (GAsyncReadyCallback) updateDetailsDone,
1337 data);
1338+
1339+ g_object_unref(roleDetails);
1340 g_object_unref(roleSet);
1341+ g_object_unref(roleValue);
1342 } else {
1343- updateDetailsDone(G_OBJECT(udata->m_persona), NULL, data);
1344+ updateDetailsDone(G_OBJECT(persona), NULL, data);
1345 }
1346 }
1347
1348-void QIndividual::updateEmails(QList<QtContacts::QContactDetail> details, void* data)
1349+void QIndividual::updateEmail(QtContacts::QContactDetail detail, void* data)
1350 {
1351- UpdateContactData *udata = static_cast<UpdateContactData*>(data);
1352- QList<QContactDetail> originalEmails = m_contact.details(QContactDetail::TypeEmailAddress);
1353-
1354- if (FOLKS_IS_EMAIL_DETAILS(udata->m_persona) && !detailListIsEqual(originalEmails, details)) {
1355- GeeSet *emailSet = SET_AFD_NEW();
1356- Q_FOREACH(const QContactDetail& detail, details) {
1357- const QContactEmailAddress *email = static_cast<const QContactEmailAddress*>(&detail);
1358-
1359- if(!email->isEmpty()) {
1360- FolksEmailFieldDetails *emailDetails = folks_email_field_details_new(email->emailAddress().toUtf8().data(), NULL);
1361- parseContext(FOLKS_ABSTRACT_FIELD_DETAILS(emailDetails), detail);
1362- gee_collection_add(GEE_COLLECTION(emailSet), emailDetails);
1363- g_object_unref(emailDetails);
1364- }
1365- }
1366- folks_email_details_change_email_addresses(FOLKS_EMAIL_DETAILS(udata->m_persona),
1367+ FolksPersona *persona = QIndividualUtils::personaFromUri(detail.detailUri(), m_individual, primaryPersona());
1368+ QContactDetail originalEmail = detailFromUri(QContactDetail::TypeEmailAddress, detail.detailUri());
1369+
1370+ if (!persona) {
1371+ createPersonaForDetail(QList<QContactDetail>() << detail, QIndividual::parseEmailDetails, data);
1372+ } else if (FOLKS_IS_EMAIL_DETAILS(persona) && (originalEmail != detail)) {
1373+ FolksEmailFieldDetails *emailDetails = 0;
1374+ const QContactEmailAddress *email = static_cast<const QContactEmailAddress*>(&detail);
1375+ GeeSet *emailSet = folks_email_details_get_email_addresses(FOLKS_EMAIL_DETAILS(persona));
1376+ if (!emailSet || (gee_collection_get_size(GEE_COLLECTION(emailSet)) == 0)) {
1377+ emailSet = SET_AFD_NEW();
1378+ } else {
1379+ emailDetails = FOLKS_EMAIL_FIELD_DETAILS(QIndividualUtils::getDetails(emailSet, detail.detailUri()));
1380+ // this will be unref at the end of the function
1381+ g_object_ref(emailSet);
1382+ g_object_ref(emailDetails);
1383+ }
1384+
1385+ if (!emailDetails) {
1386+ emailDetails = folks_email_field_details_new(email->emailAddress().toUtf8().data(), NULL);
1387+ gee_collection_add(GEE_COLLECTION(emailSet), emailDetails);
1388+ } else {
1389+ folks_abstract_field_details_set_value(FOLKS_ABSTRACT_FIELD_DETAILS(emailDetails),
1390+ email->emailAddress().toUtf8().data());
1391+ }
1392+
1393+ folks_email_details_change_email_addresses(FOLKS_EMAIL_DETAILS(persona),
1394 emailSet,
1395 (GAsyncReadyCallback) updateDetailsDone,
1396 data);
1397+
1398 g_object_unref(emailSet);
1399+ g_object_unref(emailDetails);
1400 } else {
1401- updateDetailsDone(G_OBJECT(udata->m_persona), NULL, data);
1402+ updateDetailsDone(G_OBJECT(persona), NULL, data);
1403 }
1404 }
1405
1406-void QIndividual::updatePhones(QList<QtContacts::QContactDetail> details, void* data)
1407+void QIndividual::updatePhone(QtContacts::QContactDetail detail, void* data)
1408 {
1409- UpdateContactData *udata = static_cast<UpdateContactData*>(data);
1410- QList<QContactDetail> originalPhones = m_contact.details(QContactDetail::TypePhoneNumber);
1411-
1412- if (FOLKS_IS_PHONE_DETAILS(udata->m_persona) && !detailListIsEqual(originalPhones, details)) {
1413- GeeSet *phoneSet = SET_AFD_NEW();
1414- Q_FOREACH(const QContactDetail& detail, details) {
1415- const QContactPhoneNumber *phone = static_cast<const QContactPhoneNumber*>(&detail);
1416-
1417- if(!phone->isEmpty()) {
1418- FolksPhoneFieldDetails *phoneDetails = folks_phone_field_details_new(phone->number().toUtf8().data(), NULL);
1419- parseContext(FOLKS_ABSTRACT_FIELD_DETAILS(phoneDetails), detail);
1420- gee_collection_add(GEE_COLLECTION(phoneSet), phoneDetails);
1421- g_object_unref(phoneDetails);
1422- }
1423- }
1424- folks_phone_details_change_phone_numbers(FOLKS_PHONE_DETAILS(udata->m_persona),
1425+ FolksPersona *persona = QIndividualUtils::personaFromUri(detail.detailUri(), m_individual, primaryPersona());
1426+ QContactDetail originalPhone = detailFromUri(QContactDetail::TypePhoneNumber, detail.detailUri());
1427+ // if we do not have a persona for this detail we need to create one
1428+ if (!persona) {
1429+ createPersonaForDetail(QList<QContactDetail>() << detail, QIndividual::parsePhoneNumbersDetails, data);
1430+ } else if (FOLKS_IS_PHONE_DETAILS(persona) && (originalPhone != detail)) {
1431+ /// Only update the details on the current persona
1432+ FolksPhoneFieldDetails *phoneDetails = 0;
1433+ const QContactPhoneNumber *phone = static_cast<const QContactPhoneNumber*>(&detail);
1434+ GeeSet *phoneSet = folks_phone_details_get_phone_numbers(FOLKS_PHONE_DETAILS(persona));
1435+
1436+ if (!phoneSet || (gee_collection_get_size(GEE_COLLECTION(phoneSet)) == 0)) {
1437+ phoneSet = SET_AFD_NEW();
1438+ } else {
1439+ phoneDetails = FOLKS_PHONE_FIELD_DETAILS(QIndividualUtils::getDetails(phoneSet, detail.detailUri()));
1440+ // this will be unref at the end of the function
1441+ g_object_ref(phoneSet);
1442+ g_object_ref(phoneDetails);
1443+ }
1444+
1445+ if (!phoneDetails) {
1446+ phoneDetails = folks_phone_field_details_new(phone->number().toUtf8().data(), NULL);
1447+ gee_collection_add(GEE_COLLECTION(phoneSet), phoneDetails);
1448+ } else {
1449+ folks_abstract_field_details_set_value(FOLKS_ABSTRACT_FIELD_DETAILS(phoneDetails),
1450+ phone->number().toUtf8().data());
1451+ }
1452+
1453+ parseContext(FOLKS_ABSTRACT_FIELD_DETAILS(phoneDetails), detail);
1454+ folks_phone_details_change_phone_numbers(FOLKS_PHONE_DETAILS(persona),
1455 phoneSet,
1456 (GAsyncReadyCallback) updateDetailsDone,
1457 data);
1458+ g_object_unref(phoneDetails);
1459 g_object_unref(phoneSet);
1460 } else {
1461- updateDetailsDone(G_OBJECT(udata->m_persona), NULL, data);
1462- }
1463-}
1464-
1465-bool QIndividual::detailListIsEqual(QList<QtContacts::QContactDetail> original, QList<QtContacts::QContactDetail> details)
1466-{
1467- if (original.size() != details.size()) {
1468- return false;
1469- }
1470-
1471- Q_FOREACH(const QContactDetail& detail, details) {
1472- if (!original.contains(detail)) {
1473- return false;
1474- }
1475- }
1476-
1477- return true;
1478-}
1479-
1480-void QIndividual::updateAddresses(QList<QtContacts::QContactDetail> details, void* data)
1481-{
1482- UpdateContactData *udata = static_cast<UpdateContactData*>(data);
1483- QList<QContactDetail> originalAddress = m_contact.details(QContactDetail::TypeAddress);
1484-
1485- if (FOLKS_IS_POSTAL_ADDRESS_DETAILS(udata->m_persona) && !detailListIsEqual(originalAddress, details)) {
1486- GeeSet *addressSet = SET_AFD_NEW();
1487- Q_FOREACH(const QContactDetail& detail, details) {
1488- const QContactAddress *address = static_cast<const QContactAddress*>(&detail);
1489- if (!address->isEmpty()) {
1490- FolksPostalAddress *postalAddress = folks_postal_address_new(address->postOfficeBox().toUtf8().data(),
1491- NULL,
1492- address->street().toUtf8().data(),
1493- address->locality().toUtf8().data(),
1494- address->region().toUtf8().data(),
1495- address->postcode().toUtf8().data(),
1496- address->country().toUtf8().data(),
1497- NULL,
1498- NULL);
1499- FolksPostalAddressFieldDetails *pafd = folks_postal_address_field_details_new(postalAddress, NULL);
1500-
1501- parseContext(FOLKS_ABSTRACT_FIELD_DETAILS(pafd), detail);
1502- gee_collection_add(GEE_COLLECTION(addressSet), pafd);
1503-
1504- g_object_unref(postalAddress);
1505- g_object_unref(pafd);
1506- }
1507- }
1508-
1509- folks_postal_address_details_change_postal_addresses(FOLKS_POSTAL_ADDRESS_DETAILS(udata->m_persona),
1510- addressSet,
1511+ updateDetailsDone(G_OBJECT(persona), NULL, data);
1512+ }
1513+}
1514+
1515+void QIndividual::updateAddress(QtContacts::QContactDetail detail, void* data)
1516+{
1517+ FolksPersona *persona = QIndividualUtils::personaFromUri(detail.detailUri(), m_individual, primaryPersona());
1518+ QContactDetail originalAddress = detailFromUri(QContactDetail::TypeAddress, detail.detailUri());
1519+
1520+ if (!persona) {
1521+ createPersonaForDetail(QList<QContactDetail>() << detail, QIndividual::parseAddressDetails, data);
1522+ } else if (FOLKS_IS_POSTAL_ADDRESS_DETAILS(persona) && (originalAddress != detail)) {
1523+ FolksPostalAddressFieldDetails *addrDetails = 0;
1524+ const QContactAddress *addr = static_cast<const QContactAddress*>(&detail);
1525+ GeeSet *addrSet = folks_postal_address_details_get_postal_addresses(FOLKS_POSTAL_ADDRESS_DETAILS(persona));
1526+
1527+ if (!addrSet || (gee_collection_get_size(GEE_COLLECTION(addrSet)) == 0)) {
1528+ addrSet = SET_AFD_NEW();
1529+ } else {
1530+ addrDetails = FOLKS_POSTAL_ADDRESS_FIELD_DETAILS(QIndividualUtils::getDetails(addrSet, detail.detailUri()));
1531+ // this will be unref at the end of the function
1532+ g_object_ref(addrSet);
1533+ g_object_ref(addrDetails);
1534+ }
1535+
1536+ FolksPostalAddress *addrValue;
1537+ if (!addrDetails) {
1538+ addrValue = folks_postal_address_new(addr->postOfficeBox().toUtf8().data(),
1539+ NULL,
1540+ addr->street().toUtf8().data(),
1541+ addr->locality().toUtf8().data(),
1542+ addr->region().toUtf8().data(),
1543+ addr->postcode().toUtf8().data(),
1544+ addr->country().toUtf8().data(),
1545+ NULL,
1546+ NULL);
1547+ addrDetails = folks_postal_address_field_details_new(addrValue, NULL);
1548+ gee_collection_add(GEE_COLLECTION(addrSet), addrDetails);
1549+ } else {
1550+ addrValue = FOLKS_POSTAL_ADDRESS(folks_abstract_field_details_get_value(FOLKS_ABSTRACT_FIELD_DETAILS(addrDetails)));
1551+ Q_ASSERT(addrValue);
1552+ folks_postal_address_set_po_box(addrValue, addr->postOfficeBox().toUtf8().data());
1553+ folks_postal_address_set_street(addrValue, addr->street().toUtf8().data());
1554+ folks_postal_address_set_locality(addrValue, addr->locality().toUtf8().data());
1555+ folks_postal_address_set_region(addrValue, addr->region().toUtf8().data());
1556+ folks_postal_address_set_postal_code(addrValue, addr->postcode().toUtf8().data());
1557+ folks_postal_address_set_country(addrValue, addr->country().toUtf8().data());
1558+ }
1559+
1560+ parseContext(FOLKS_ABSTRACT_FIELD_DETAILS(addrDetails), detail);
1561+ folks_postal_address_details_change_postal_addresses(FOLKS_POSTAL_ADDRESS_DETAILS(persona),
1562+ addrSet,
1563 (GAsyncReadyCallback) updateDetailsDone,
1564 data);
1565- g_object_unref(addressSet);
1566+ g_object_unref(addrDetails);
1567+ g_object_unref(addrSet);
1568+ g_object_unref(addrValue);
1569 } else {
1570- updateDetailsDone(G_OBJECT(udata->m_persona), NULL, data);
1571+ updateDetailsDone(G_OBJECT(persona), NULL, data);
1572 }
1573 }
1574
1575-void QIndividual::updateIms(QList<QtContacts::QContactDetail> details, void* data)
1576+void QIndividual::updateIm(QtContacts::QContactDetail detail, void* data)
1577 {
1578- UpdateContactData *udata = static_cast<UpdateContactData*>(data);
1579- QList<QContactDetail> originalIms = m_contact.details(QContactDetail::TypeOnlineAccount);
1580-
1581- if (FOLKS_IS_IM_DETAILS(udata->m_persona) && !detailListIsEqual(originalIms, details)) {
1582- GeeMultiMap *imAddressHash = GEE_MULTI_MAP_AFD_NEW(FOLKS_TYPE_IM_FIELD_DETAILS);
1583- Q_FOREACH(const QContactDetail& detail, details) {
1584- const QContactOnlineAccount *im = static_cast<const QContactOnlineAccount*>(&detail);
1585- if (!im->accountUri().isEmpty()) {
1586- FolksImFieldDetails *imfd = folks_im_field_details_new(im->accountUri().toUtf8().data(), NULL);
1587- parseContext(FOLKS_ABSTRACT_FIELD_DETAILS(imfd), detail);
1588- gee_multi_map_set(imAddressHash,
1589- onlineAccountProtocolFromEnum(im->protocol()).toUtf8().data(), imfd);
1590- g_object_unref(imfd);
1591+ FolksPersona *persona = QIndividualUtils::personaFromUri(detail.detailUri(), m_individual, primaryPersona());
1592+ QContactDetail originalIm = detailFromUri(QContactDetail::TypeOnlineAccount, detail.detailUri());
1593+
1594+ if (!persona) {
1595+ createPersonaForDetail(QList<QContactDetail>() << detail, QIndividual::parseImDetails, data);
1596+ } else if (FOLKS_IS_IM_DETAILS(persona) && (originalIm != detail)) {
1597+ const QContactOnlineAccount *im = static_cast<const QContactOnlineAccount*>(&detail);
1598+ GeeMultiMap *imSet = folks_im_details_get_im_addresses(FOLKS_IM_DETAILS(persona));
1599+
1600+ if (!imSet || (gee_multi_map_get_size(GEE_MULTI_MAP(imSet)) == 0)) {
1601+ imSet = GEE_MULTI_MAP_AFD_NEW(FOLKS_TYPE_IM_FIELD_DETAILS);
1602+ } else {
1603+ // We can not relay on the index inside of detailUri because online account are stored in a hash
1604+ QContactOnlineAccount oldIm = static_cast<QContactOnlineAccount>(originalIm);
1605+ QString oldProtocolName = onlineAccountProtocolFromEnum(oldIm.protocol());
1606+ GeeCollection *value = gee_multi_map_get(imSet, oldProtocolName.toUtf8().data());
1607+
1608+ // Remove the old one
1609+ if (value) {
1610+ // if there is more than one address only remove the correct one
1611+ if (gee_collection_get_size(value) > 1) {
1612+ gee_collection_remove(value, oldIm.accountUri().toUtf8().data());
1613+ } else {
1614+ // otherwise remove the key
1615+ gee_multi_map_remove_all(imSet, oldProtocolName.toUtf8().data());
1616+ }
1617 }
1618+
1619+ g_object_ref(imSet);
1620 }
1621
1622- folks_im_details_change_im_addresses(FOLKS_IM_DETAILS(udata->m_persona),
1623- imAddressHash,
1624+ // Append the new one
1625+ FolksImFieldDetails *imDetails = folks_im_field_details_new(im->accountUri().toUtf8().data(), NULL);
1626+ parseContext(FOLKS_ABSTRACT_FIELD_DETAILS(imDetails), detail);
1627+
1628+ gee_multi_map_set(imSet,
1629+ onlineAccountProtocolFromEnum(im->protocol()).toUtf8().data(),
1630+ imDetails);
1631+
1632+ folks_im_details_change_im_addresses(FOLKS_IM_DETAILS(persona),
1633+ imSet,
1634 (GAsyncReadyCallback) updateDetailsDone,
1635 data);
1636- g_object_unref(imAddressHash);
1637+ g_object_unref(imSet);
1638+ g_object_unref(imDetails);
1639 } else {
1640- updateDetailsDone(G_OBJECT(udata->m_persona), NULL, data);
1641+ updateDetailsDone(G_OBJECT(persona), NULL, data);
1642 }
1643 }
1644
1645-void QIndividual::updateUrls(QList<QtContacts::QContactDetail> details, void* data)
1646+void QIndividual::updateUrl(QtContacts::QContactDetail detail, void* data)
1647 {
1648- UpdateContactData *udata = static_cast<UpdateContactData*>(data);
1649- QList<QContactDetail> originalUrls = m_contact.details(QContactDetail::TypeUrl);
1650-
1651- if (FOLKS_IS_URL_DETAILS(udata->m_persona) && !detailListIsEqual(originalUrls, details)) {
1652- GeeSet *urlSet = SET_AFD_NEW();
1653- Q_FOREACH(const QContactDetail& detail, details) {
1654- const QContactUrl *url = static_cast<const QContactUrl*>(&detail);
1655-
1656- if(!url->isEmpty()) {
1657- FolksUrlFieldDetails *urlDetails = folks_url_field_details_new(url->url().toUtf8().data(), NULL);
1658- parseContext(FOLKS_ABSTRACT_FIELD_DETAILS(urlDetails), detail);
1659- gee_collection_add(GEE_COLLECTION(urlSet), urlDetails);
1660- g_object_unref(urlDetails);
1661- }
1662- }
1663- folks_url_details_change_urls(FOLKS_URL_DETAILS(udata->m_persona),
1664+ FolksPersona *persona = QIndividualUtils::personaFromUri(detail.detailUri(), m_individual, primaryPersona());
1665+ QContactDetail originalUrl = detailFromUri(QContactDetail::TypeUrl, detail.detailUri());
1666+
1667+ if (!persona) {
1668+ createPersonaForDetail(QList<QContactDetail>() << detail, QIndividual::parseUrlDetails, data);
1669+ } else if (FOLKS_IS_URL_DETAILS(persona) && (originalUrl != detail)) {
1670+ FolksUrlFieldDetails *urlDetails = 0;
1671+ const QContactUrl *url = static_cast<const QContactUrl*>(&detail);
1672+ GeeSet *urlSet = folks_url_details_get_urls(FOLKS_URL_DETAILS(persona));
1673+
1674+ if (!urlSet || (gee_collection_get_size(GEE_COLLECTION(urlSet)) == 0)) {
1675+ urlSet = SET_AFD_NEW();
1676+ } else {
1677+ urlDetails = FOLKS_URL_FIELD_DETAILS(QIndividualUtils::getDetails(urlSet, detail.detailUri()));
1678+
1679+ // this will be unref at the end of the function
1680+ g_object_ref(urlSet);
1681+ g_object_ref(urlDetails);
1682+ }
1683+
1684+ if (!urlDetails) {
1685+ urlDetails = folks_url_field_details_new(url->url().toUtf8().data(), NULL);
1686+ gee_collection_add(GEE_COLLECTION(urlSet), urlDetails);
1687+ } else {
1688+ folks_abstract_field_details_set_value(FOLKS_ABSTRACT_FIELD_DETAILS(urlDetails),
1689+ url->url().toUtf8().data());
1690+ }
1691+
1692+ parseContext(FOLKS_ABSTRACT_FIELD_DETAILS(urlDetails), detail);
1693+ folks_url_details_change_urls(FOLKS_URL_DETAILS(persona),
1694 urlSet,
1695 (GAsyncReadyCallback) updateDetailsDone,
1696 data);
1697+ g_object_unref(urlDetails);
1698 g_object_unref(urlSet);
1699 } else {
1700- updateDetailsDone(G_OBJECT(m_individual), NULL, data);
1701+ updateDetailsDone(G_OBJECT(persona), NULL, data);
1702 }
1703 }
1704
1705-void QIndividual::updateNotes(QList<QtContacts::QContactDetail> details, void* data)
1706+void QIndividual::updateNote(QtContacts::QContactDetail detail, void* data)
1707 {
1708- UpdateContactData *udata = static_cast<UpdateContactData*>(data);
1709- QList<QContactDetail> originalNotes = m_contact.details(QContactDetail::TypeNote);
1710-
1711- if (FOLKS_IS_NOTE_DETAILS(udata->m_persona) && !detailListIsEqual(originalNotes, details)) {
1712- GeeSet *noteSet = SET_AFD_NEW();
1713- Q_FOREACH(const QContactDetail& detail, details) {
1714- const QContactNote *note = static_cast<const QContactNote*>(&detail);
1715-
1716- if(!note->isEmpty()) {
1717- FolksNoteFieldDetails *noteDetails = folks_note_field_details_new(note->note().toUtf8().data(), NULL, 0);
1718-
1719- //TODO: set context
1720- gee_collection_add(GEE_COLLECTION(noteSet), noteDetails);
1721- g_object_unref(noteDetails);
1722- }
1723- }
1724- folks_note_details_change_notes(FOLKS_NOTE_DETAILS(udata->m_persona),
1725+ FolksPersona *persona = QIndividualUtils::personaFromUri(detail.detailUri(), m_individual, primaryPersona());
1726+ QContactDetail originalNote = detailFromUri(QContactDetail::TypeNote, detail.detailUri());
1727+
1728+ if (!persona) {
1729+ createPersonaForDetail(QList<QContactDetail>() << detail, QIndividual::parseNoteDetails, data);
1730+ } else if (FOLKS_IS_URL_DETAILS(persona) && (originalNote != detail)) {
1731+ FolksNoteFieldDetails *noteDetails = 0;
1732+ const QContactNote *note = static_cast<const QContactNote*>(&detail);
1733+ GeeSet *noteSet = folks_note_details_get_notes(FOLKS_NOTE_DETAILS(persona));
1734+
1735+ if (!noteSet || (gee_collection_get_size(GEE_COLLECTION(noteSet)) == 0)) {
1736+ noteSet = SET_AFD_NEW();
1737+ } else {
1738+ noteDetails = FOLKS_NOTE_FIELD_DETAILS(QIndividualUtils::getDetails(noteSet, detail.detailUri()));
1739+
1740+ // this will be unref at the end of the function
1741+ g_object_ref(noteSet);
1742+ g_object_ref(noteDetails);
1743+ }
1744+
1745+ if (!noteDetails) {
1746+ noteDetails = folks_note_field_details_new(note->note().toUtf8().data(), NULL, 0);
1747+ gee_collection_add(GEE_COLLECTION(noteSet), noteDetails);
1748+ } else {
1749+ folks_abstract_field_details_set_value(FOLKS_ABSTRACT_FIELD_DETAILS(noteDetails),
1750+ note->note().toUtf8().data());
1751+ }
1752+
1753+ parseContext(FOLKS_ABSTRACT_FIELD_DETAILS(noteDetails), detail);
1754+ folks_note_details_change_notes(FOLKS_NOTE_DETAILS(persona),
1755 noteSet,
1756 (GAsyncReadyCallback) updateDetailsDone,
1757- data);
1758+ data);;
1759+ g_object_unref(noteDetails);
1760 g_object_unref(noteSet);
1761 } else {
1762- updateDetailsDone(G_OBJECT(m_individual), NULL, data);
1763- }
1764-}
1765-
1766+ updateDetailsDone(G_OBJECT(persona), NULL, data);
1767+ }
1768+}
1769+
1770+QString QIndividual::callDetailChangeFinish(QtContacts::QContactDetail::DetailType detailType,
1771+ FolksPersona *persona,
1772+ GAsyncResult *result)
1773+{
1774+ Q_ASSERT(persona);
1775+ Q_ASSERT(result);
1776+
1777+ GError *error = 0;
1778+ switch(detailType) {
1779+ case QContactDetail::TypeAddress:
1780+ folks_postal_address_details_change_postal_addresses_finish(FOLKS_POSTAL_ADDRESS_DETAILS(persona), result, &error);
1781+ break;
1782+ case QContactDetail::TypeAvatar:
1783+ folks_avatar_details_change_avatar_finish(FOLKS_AVATAR_DETAILS(persona), result, &error);
1784+ break;
1785+ case QContactDetail::TypeBirthday:
1786+ folks_birthday_details_change_birthday_finish(FOLKS_BIRTHDAY_DETAILS(persona), result, &error);
1787+ break;
1788+ case QContactDetail::TypeDisplayLabel:
1789+ folks_name_details_change_full_name_finish(FOLKS_NAME_DETAILS(persona), result, &error);
1790+ break;
1791+ case QContactDetail::TypeEmailAddress:
1792+ folks_email_details_change_email_addresses_finish(FOLKS_EMAIL_DETAILS(persona), result, &error);
1793+ break;
1794+ case QContactDetail::TypeName:
1795+ folks_name_details_change_structured_name_finish(FOLKS_NAME_DETAILS(persona), result, &error);
1796+ break;
1797+ case QContactDetail::TypeNickname:
1798+ folks_name_details_change_nickname_finish(FOLKS_NAME_DETAILS(persona), result, &error);
1799+ break;
1800+ case QContactDetail::TypeNote:
1801+ folks_note_details_change_notes_finish(FOLKS_NOTE_DETAILS(persona), result, &error);
1802+ break;
1803+ case QContactDetail::TypeOnlineAccount:
1804+ folks_im_details_change_im_addresses_finish(FOLKS_IM_DETAILS(persona), result, &error);
1805+ break;
1806+ case QContactDetail::TypeOrganization:
1807+ folks_role_details_change_roles_finish(FOLKS_ROLE_DETAILS(persona), result, &error);
1808+ break;
1809+ case QContactDetail::TypePhoneNumber:
1810+ folks_phone_details_change_phone_numbers_finish(FOLKS_PHONE_DETAILS(persona), result, &error);
1811+ break;
1812+ case QContactDetail::TypeUrl:
1813+ folks_url_details_change_urls_finish(FOLKS_URL_DETAILS(persona), result, &error);
1814+ default:
1815+ break;
1816+ }
1817+
1818+ QString errorMessage;
1819+ if (error) {
1820+ errorMessage = QString::fromUtf8(error->message);
1821+ g_error_free(error);
1822+ }
1823+ return errorMessage;
1824+}
1825+
1826+void QIndividual::updateDetailsSendReply(gpointer userdata, const QString &errorMessage)
1827+{
1828+ UpdateContactData *data = static_cast<UpdateContactData*>(userdata);
1829+ data->m_slot.invoke(data->m_object,
1830+ Q_ARG(QIndividual*, data->m_self), Q_ARG(QString, errorMessage));
1831+ delete data;
1832+}
1833+
1834+void QIndividual::updateDetailsSendReply(gpointer userdata, GError *error)
1835+{
1836+ QString errorMessage;
1837+ if (error) {
1838+ errorMessage = QString::fromUtf8(error->message);
1839+ qWarning() << error->message;
1840+ g_error_free(error);
1841+ }
1842+ updateDetailsSendReply(userdata, errorMessage);
1843+}
1844+
1845+
1846+void QIndividual::createPersonaDone(GObject *aggregator, GAsyncResult *result, gpointer userdata)
1847+{
1848+ qDebug() << Q_FUNC_INFO;
1849+ UpdateContactData *data = static_cast<UpdateContactData*>(userdata);
1850+
1851+ // A new persona was create to store the new data
1852+ GError *error = 0;
1853+ FolksPersona *newPersona = folks_individual_aggregator_add_persona_from_details_finish(FOLKS_INDIVIDUAL_AGGREGATOR(aggregator),
1854+ result,
1855+ &error);
1856+ if (error) {
1857+ updateDetailsSendReply(data, error);
1858+ } else {
1859+ // Link the new personas
1860+ GeeSet *personas = folks_individual_get_personas(data->m_self->m_individual);
1861+ GeeSet *newPersonas = SET_PERSONA_NEW();
1862+ gee_collection_add_all(GEE_COLLECTION(newPersonas), GEE_COLLECTION(personas));
1863+ gee_collection_add(GEE_COLLECTION(newPersonas), newPersona);
1864+ data->m_self->m_primaryPersona = newPersona;
1865+ folks_individual_aggregator_link_personas(data->m_self->m_aggregator, newPersonas, updateDetailsDone, userdata);
1866+ }
1867+}
1868
1869 void QIndividual::updateDetailsDone(GObject *detail, GAsyncResult *result, gpointer userdata)
1870 {
1871- GError *error = 0;
1872+ QString errorMessage;
1873 UpdateContactData *data = static_cast<UpdateContactData*>(userdata);
1874-
1875- switch(data->m_currentDetailType) {
1876+ if (result && !data->m_currentDetail.isEmpty()) {
1877+ if (FOLKS_IS_PERSONA(detail)) {
1878+ // This is a normal field update
1879+ errorMessage = QIndividual::callDetailChangeFinish(data->m_currentDetail.type(),
1880+ FOLKS_PERSONA(detail),
1881+ result);
1882+ } else if (FOLKS_IS_INDIVIDUAL_AGGREGATOR(detail)) {
1883+ GError *error = 0;
1884+ folks_individual_aggregator_link_personas_finish(FOLKS_INDIVIDUAL_AGGREGATOR(detail), result, &error);
1885+ if (error) {
1886+ errorMessage = QString::fromUtf8(error->message);
1887+ }
1888+ }
1889+
1890+ if (!errorMessage.isEmpty()) {
1891+ updateDetailsSendReply(data, errorMessage);
1892+ return;
1893+ }
1894+ }
1895+
1896+ if (data->m_details.isEmpty()) {
1897+ updateDetailsSendReply(data, 0);
1898+ return;
1899+ }
1900+
1901+
1902+ data->m_currentDetail = data->m_details.takeFirst();
1903+ switch(data->m_currentDetail.type()) {
1904 case QContactDetail::TypeAddress:
1905- if (result) {
1906- folks_postal_address_details_change_postal_addresses_finish(FOLKS_POSTAL_ADDRESS_DETAILS(data->m_persona), result, &error);
1907- }
1908- if (!error) {
1909- data->m_currentDetailType = QContactDetail::TypeAvatar;
1910- data->m_self->updatePhoto(data->m_newContact.detail(QContactDetail::TypeAvatar), data);
1911- return;
1912- }
1913+ data->m_self->updateAddress(data->m_currentDetail, data);
1914 break;
1915 case QContactDetail::TypeAvatar:
1916- if (result) {
1917- folks_avatar_details_change_avatar_finish(FOLKS_AVATAR_DETAILS(data->m_persona), result, &error);
1918- }
1919- if (!error) {
1920- data->m_currentDetailType = QContactDetail::TypeBirthday;
1921- data->m_self->updateBirthday(data->m_newContact.detail(QContactDetail::TypeBirthday), data);
1922- return;
1923- }
1924+ data->m_self->updatePhoto(data->m_currentDetail, data);
1925 break;
1926 case QContactDetail::TypeBirthday:
1927- if (result) {
1928- folks_birthday_details_change_birthday_finish(FOLKS_BIRTHDAY_DETAILS(data->m_persona), result, &error);
1929- }
1930- if (!error) {
1931- data->m_currentDetailType = QContactDetail::TypeDisplayLabel;
1932- data->m_self->updateFullName(data->m_newContact.detail(QContactDetail::TypeDisplayLabel), data);
1933- return;
1934- }
1935+ data->m_self->updateBirthday(data->m_currentDetail, data);
1936 break;
1937 case QContactDetail::TypeDisplayLabel:
1938- if (result) {
1939- folks_name_details_change_full_name_finish(FOLKS_NAME_DETAILS(data->m_persona), result, &error);
1940- }
1941- if (!error) {
1942- data->m_currentDetailType = QContactDetail::TypeEmailAddress;
1943- data->m_self->updateEmails(data->m_newContact.details(QContactDetail::TypeEmailAddress), data);
1944- return;
1945- }
1946+ data->m_self->updateFullName(data->m_currentDetail, data);
1947 break;
1948-
1949 case QContactDetail::TypeEmailAddress:
1950- if (result) {
1951- folks_email_details_change_email_addresses_finish(FOLKS_EMAIL_DETAILS(data->m_persona), result, &error);
1952- }
1953- if (!error) {
1954- data->m_currentDetailType = QContactDetail::TypeName;
1955- data->m_self->updateName(data->m_newContact.detail(QContactDetail::TypeName), data);
1956- return;
1957- }
1958+ data->m_self->updateEmail(data->m_currentDetail, data);
1959 break;
1960 case QContactDetail::TypeName:
1961- if (result) {
1962- folks_name_details_change_structured_name_finish(FOLKS_NAME_DETAILS(data->m_persona), result, &error);
1963- }
1964- if (!error) {
1965- data->m_currentDetailType = QContactDetail::TypeNickname;
1966- data->m_self->updateNickname(data->m_newContact.detail(QContactDetail::TypeNickname), data);
1967- return;
1968- }
1969+ data->m_self->updateName(data->m_currentDetail, data);
1970 break;
1971 case QContactDetail::TypeNickname:
1972- if (result) {
1973- folks_name_details_change_nickname_finish(FOLKS_NAME_DETAILS(data->m_persona), result, &error);
1974- }
1975- if (!error) {
1976- data->m_currentDetailType = QContactDetail::TypeNote;
1977- data->m_self->updateNotes(data->m_newContact.details(QContactDetail::TypeNote), data);
1978- return;
1979- }
1980+ data->m_self->updateNickname(data->m_currentDetail, data);
1981 break;
1982 case QContactDetail::TypeNote:
1983- if (result) {
1984- folks_note_details_change_notes_finish(FOLKS_NOTE_DETAILS(data->m_persona), result, &error);
1985- }
1986- if (!error) {
1987- data->m_currentDetailType = QContactDetail::TypeOnlineAccount;
1988- data->m_self->updateIms(data->m_newContact.details(QContactDetail::TypeOnlineAccount), data);
1989- return;
1990- }
1991+ data->m_self->updateNote(data->m_currentDetail, data);
1992 break;
1993 case QContactDetail::TypeOnlineAccount:
1994- if (result) {
1995- folks_im_details_change_im_addresses_finish(FOLKS_IM_DETAILS(data->m_persona), result, &error);
1996- }
1997- if (!error) {
1998- data->m_currentDetailType = QContactDetail::TypeOrganization;
1999- data->m_self->updateRoles(data->m_newContact.details(QContactDetail::TypeOrganization), data);
2000- return;
2001- }
2002+ data->m_self->updateIm(data->m_currentDetail, data);
2003 break;
2004 case QContactDetail::TypeOrganization:
2005- if (result) {
2006- folks_role_details_change_roles_finish(FOLKS_ROLE_DETAILS(data->m_persona), result, &error);
2007- }
2008- if (!error) {
2009- data->m_currentDetailType = QContactDetail::TypePhoneNumber;
2010- data->m_self->updatePhones(data->m_newContact.details(QContactDetail::TypePhoneNumber), data);
2011- return;
2012- }
2013+ data->m_self->updateRole(data->m_currentDetail, data);
2014 break;
2015 case QContactDetail::TypePhoneNumber:
2016- if (result) {
2017- folks_phone_details_change_phone_numbers_finish(FOLKS_PHONE_DETAILS(data->m_persona), result, &error);
2018- }
2019- if (!error) {
2020- data->m_currentDetailType = QContactDetail::TypeUrl;
2021- data->m_self->updateUrls(data->m_newContact.details(QContactDetail::TypeUrl), data);
2022- return;
2023- }
2024+ data->m_self->updatePhone(data->m_currentDetail, data);
2025 break;
2026 case QContactDetail::TypeUrl:
2027- if (result) {
2028- folks_url_details_change_urls_finish(FOLKS_URL_DETAILS(data->m_persona), result, &error);
2029- }
2030+ data->m_self->updateUrl(data->m_currentDetail, data);
2031+ break;
2032 default:
2033+ qWarning() << "Update not implemented for" << data->m_currentDetail.type();
2034+ updateDetailsDone(0, 0, data);
2035 break;
2036 }
2037-
2038- QString errorMessage;
2039- if (error) {
2040- errorMessage = QString::fromUtf8(error->message);
2041- g_error_free(error);
2042- }
2043-
2044- qDebug() << "Update done" << errorMessage;
2045- data->m_doneCB(errorMessage, data->m_doneData);
2046- delete data;
2047 }
2048
2049-
2050-bool QIndividual::update(const QtContacts::QContact &newContact, UpdateDoneCB cb, void* userData)
2051+bool QIndividual::update(const QtContacts::QContact &newContact, QObject *object, const QString &slot)
2052 {
2053+ int slotIndex = object->metaObject()->indexOfSlot(QMetaObject::normalizedSignature(slot.toUtf8().data()));
2054+ if (slotIndex == -1) {
2055+ qWarning() << "Invalid slot:" << slot << "for object" << object;
2056+ return false;
2057+ }
2058+
2059 QContact &originalContact = contact();
2060 if (newContact != originalContact) {
2061
2062 UpdateContactData *data = new UpdateContactData;
2063- data->m_currentDetailType = QContactDetail::TypeAddress;
2064+ data->m_details = newContact.details();
2065 data->m_newContact = newContact;
2066 data->m_self = this;
2067- data->m_doneCB = cb;
2068- data->m_doneData = userData;
2069- data->m_persona = primaryPersona();
2070-
2071- updateAddresses(newContact.details(QContactDetail::TypeAddress), data);
2072+ data->m_object = object;
2073+ data->m_slot = object->metaObject()->method(slotIndex);
2074+ updateDetailsDone(0, 0, data);
2075 return true;
2076 } else {
2077 qDebug() << "Contact is equal";
2078@@ -1160,10 +1449,26 @@
2079 return m_individual;
2080 }
2081
2082-bool QIndividual::update(const QString &vcard, UpdateDoneCB cb, void* data)
2083+void QIndividual::setIndividual(FolksIndividual *individual)
2084+{
2085+ if (m_individual != individual) {
2086+ if (m_individual) {
2087+ g_object_unref(m_individual);
2088+ }
2089+ m_individual = individual;
2090+ if (m_individual) {
2091+ g_object_ref(m_individual);
2092+ }
2093+ // initialize qcontact
2094+ m_contact = QContact();
2095+ updateContact();
2096+ }
2097+}
2098+
2099+bool QIndividual::update(const QString &vcard, QObject *object, const QString &slot)
2100 {
2101 QContact contact = VCardParser::vcardToContact(vcard);
2102- return update(contact, cb, data);
2103+ return update(contact, object, slot);
2104 }
2105
2106 QStringList QIndividual::listParameters(FolksAbstractFieldDetails *details)
2107@@ -1532,31 +1837,26 @@
2108 return map[QContactOnlineAccount::ProtocolUnknown];
2109 }
2110
2111-GHashTable *QIndividual::parseDetails(const QtContacts::QContact &contact)
2112+GHashTable *QIndividual::parseAddressDetails(GHashTable *details, const QList<QtContacts::QContactDetail> &cDetails)
2113 {
2114- GHashTable *details = g_hash_table_new_full(g_str_hash,
2115- g_str_equal,
2116- NULL,
2117- (GDestroyNotify) QIndividualUtils::gValueSliceFree);
2118- GValue *value;
2119-
2120- /*
2121- * Addresses
2122- */
2123- QList<QContactAddress> addresses = contact.details<QContactAddress>();
2124- if(addresses.size() > 0) {
2125- value = QIndividualUtils::gValueSliceNew(G_TYPE_OBJECT);
2126- Q_FOREACH(const QContactAddress& address, addresses) {
2127- if(!address.isEmpty()) {
2128+ if(cDetails.size() == 0) {
2129+ return details;
2130+ }
2131+
2132+ GValue *value = QIndividualUtils::gValueSliceNew(G_TYPE_OBJECT);
2133+
2134+ Q_FOREACH(const QContactDetail& detail, cDetails) {
2135+ if(!detail.isEmpty()) {
2136+ QContactAddress address = static_cast<QContactAddress>(detail);
2137 FolksPostalAddress *postalAddress = folks_postal_address_new(address.postOfficeBox().toUtf8().data(),
2138- NULL, // extension
2139- address.street().toUtf8().data(),
2140- address.locality().toUtf8().data(),
2141- address.region().toUtf8().data(),
2142- address.postcode().toUtf8().data(),
2143- address.country().toUtf8().data(),
2144- NULL, // address format
2145- NULL); //UID
2146+ NULL, // extension
2147+ address.street().toUtf8().data(),
2148+ address.locality().toUtf8().data(),
2149+ address.region().toUtf8().data(),
2150+ address.postcode().toUtf8().data(),
2151+ address.country().toUtf8().data(),
2152+ NULL, // address format
2153+ NULL); //UID
2154
2155 GeeCollection *collection = (GeeCollection*) g_value_get_object(value);
2156 if(collection == NULL) {
2157@@ -1570,188 +1870,318 @@
2158
2159 g_object_unref(pafd);
2160 g_object_unref(postalAddress);
2161- }
2162 }
2163 QIndividualUtils::personaDetailsInsert(details, FOLKS_PERSONA_DETAIL_POSTAL_ADDRESSES, value);
2164 }
2165
2166-
2167- /*
2168- * Avatar
2169- */
2170- QContactAvatar avatar = contact.detail<QContactAvatar>();
2171- if(!avatar.isEmpty()) {
2172- value = QIndividualUtils::gValueSliceNew(G_TYPE_FILE_ICON);
2173- QUrl avatarUri = avatar.imageUrl();
2174- if(!avatarUri.isEmpty()) {
2175- QString formattedUri = avatarUri.toString(QUrl::RemoveUserInfo);
2176- if(!formattedUri.isEmpty()) {
2177- GFile *avatarFile = g_file_new_for_uri(formattedUri.toUtf8().data());
2178- GFileIcon *avatarFileIcon = G_FILE_ICON(g_file_icon_new(avatarFile));
2179- g_value_take_object(value, avatarFileIcon);
2180-
2181- QIndividualUtils::personaDetailsInsert(details, FOLKS_PERSONA_DETAIL_AVATAR, value);
2182- g_clear_object((GObject**) &avatarFile);
2183- }
2184- }
2185- }
2186-
2187- /*
2188- * Birthday
2189- */
2190- QContactBirthday birthday = contact.detail<QContactBirthday>();
2191- if(!birthday.isEmpty()) {
2192- value = QIndividualUtils::gValueSliceNew(G_TYPE_DATE_TIME);
2193- GDateTime *dateTime = g_date_time_new_from_unix_utc(birthday.dateTime().toMSecsSinceEpoch() / 1000);
2194- g_value_set_boxed(value, dateTime);
2195-
2196- QIndividualUtils::personaDetailsInsert(details, FOLKS_PERSONA_DETAIL_BIRTHDAY, value);
2197- g_date_time_unref(dateTime);
2198- }
2199-
2200- /*
2201- * Email addresses
2202- */
2203- PERSONA_DETAILS_INSERT_STRING_FIELD_DETAILS(details,
2204+ return details;
2205+}
2206+
2207+GHashTable *QIndividual::parsePhotoDetails(GHashTable *details, const QList<QtContacts::QContactDetail> &cDetails)
2208+{
2209+ if(cDetails.size() == 0) {
2210+ return details;
2211+ }
2212+
2213+ Q_FOREACH(const QContactDetail& detail, cDetails) {
2214+ QContactAvatar avatar = static_cast<QContactAvatar>(detail);
2215+ if(!avatar.isEmpty()) {
2216+ GValue *value = QIndividualUtils::gValueSliceNew(G_TYPE_FILE_ICON);
2217+ QUrl avatarUri = avatar.imageUrl();
2218+ if(!avatarUri.isEmpty()) {
2219+ QString formattedUri = avatarUri.toString(QUrl::RemoveUserInfo);
2220+ if(!formattedUri.isEmpty()) {
2221+ GFile *avatarFile = g_file_new_for_uri(formattedUri.toUtf8().data());
2222+ GFileIcon *avatarFileIcon = G_FILE_ICON(g_file_icon_new(avatarFile));
2223+ g_value_take_object(value, avatarFileIcon);
2224+
2225+ QIndividualUtils::personaDetailsInsert(details, FOLKS_PERSONA_DETAIL_AVATAR, value);
2226+ g_clear_object((GObject**) &avatarFile);
2227+ }
2228+ } else {
2229+ g_object_unref(value);
2230+ }
2231+ }
2232+ }
2233+
2234+ return details;
2235+}
2236+
2237+GHashTable *QIndividual::parseBirthdayDetails(GHashTable *details, const QList<QtContacts::QContactDetail> &cDetails)
2238+{
2239+ if(cDetails.size() == 0) {
2240+ return details;
2241+ }
2242+
2243+ Q_FOREACH(const QContactDetail& detail, cDetails) {
2244+ QContactBirthday birthday = static_cast<QContactBirthday>(detail);
2245+ if(!birthday.isEmpty()) {
2246+ GValue *value = QIndividualUtils::gValueSliceNew(G_TYPE_DATE_TIME);
2247+ GDateTime *dateTime = g_date_time_new_from_unix_utc(birthday.dateTime().toMSecsSinceEpoch() / 1000);
2248+ g_value_set_boxed(value, dateTime);
2249+
2250+ QIndividualUtils::personaDetailsInsert(details, FOLKS_PERSONA_DETAIL_BIRTHDAY, value);
2251+ g_date_time_unref(dateTime);
2252+ }
2253+ }
2254+
2255+ return details;
2256+}
2257+
2258+GHashTable *QIndividual::parseEmailDetails(GHashTable *details, const QList<QtContacts::QContactDetail> &cDetails)
2259+{
2260+ if(cDetails.size() == 0) {
2261+ return details;
2262+ }
2263+
2264+ GValue *value;
2265+ PERSONA_DETAILS_INSERT_STRING_FIELD_DETAILS(details, cDetails,
2266 FOLKS_PERSONA_DETAIL_EMAIL_ADDRESSES, value, QContactEmailAddress,
2267 FOLKS_TYPE_EMAIL_FIELD_DETAILS, emailAddress);
2268-
2269- /*
2270- * Favorite
2271- */
2272- QContactFavorite favorite = contact.detail<QContactFavorite>();
2273- if(!favorite.isEmpty()) {
2274- value = QIndividualUtils::gValueSliceNew(G_TYPE_BOOLEAN);
2275- g_value_set_boolean(value, favorite.isFavorite());
2276-
2277- QIndividualUtils::personaDetailsInsert(details, FOLKS_PERSONA_DETAIL_IS_FAVOURITE, value);
2278- }
2279-
2280- /*
2281- * Gender
2282- */
2283- QContactGender gender = contact.detail<QContactGender>();
2284- if(!gender.isEmpty()) {
2285- value = QIndividualUtils::gValueSliceNew(FOLKS_TYPE_GENDER);
2286- FolksGender genderEnum = FOLKS_GENDER_UNSPECIFIED;
2287- if(gender.gender() == QContactGender::GenderMale) {
2288- genderEnum = FOLKS_GENDER_MALE;
2289- } else if(gender.gender() == QContactGender::GenderFemale) {
2290- genderEnum = FOLKS_GENDER_FEMALE;
2291- }
2292- g_value_set_enum(value, genderEnum);
2293-
2294- QIndividualUtils::personaDetailsInsert(details, FOLKS_PERSONA_DETAIL_GENDER, value);
2295- }
2296-
2297- /*
2298- * Names
2299- */
2300- QContactName name = contact.detail<QContactName>();
2301- if(!name.isEmpty()) {
2302- value = QIndividualUtils::gValueSliceNew(FOLKS_TYPE_STRUCTURED_NAME);
2303- FolksStructuredName *sn = folks_structured_name_new(name.lastName().toUtf8().data(),
2304- name.firstName().toUtf8().data(),
2305- name.middleName().toUtf8().data(),
2306- name.prefix().toUtf8().data(),
2307- name.suffix().toUtf8().data());
2308- g_value_take_object(value, sn);
2309- QIndividualUtils::personaDetailsInsert(details, FOLKS_PERSONA_DETAIL_STRUCTURED_NAME, value);
2310- }
2311-
2312- QContactDisplayLabel displayLabel = contact.detail<QContactDisplayLabel>();
2313- if(!displayLabel.label().isEmpty()) {
2314- value = QIndividualUtils::gValueSliceNew(G_TYPE_STRING);
2315- g_value_set_string(value, displayLabel.label().toUtf8().data());
2316- QIndividualUtils::personaDetailsInsert(details, FOLKS_PERSONA_DETAIL_FULL_NAME, value);
2317-
2318- // FIXME: check if those values should all be set to the same thing
2319- value = QIndividualUtils::gValueSliceNew(G_TYPE_STRING);
2320- g_value_set_string(value, displayLabel.label().toUtf8().data());
2321- QIndividualUtils::personaDetailsInsert(details, FOLKS_PERSONA_DETAIL_ALIAS, value);
2322- }
2323-
2324- /*
2325- * Notes
2326- */
2327- PERSONA_DETAILS_INSERT_STRING_FIELD_DETAILS(details,
2328+ return details;
2329+}
2330+
2331+GHashTable *QIndividual::parseFavoriteDetails(GHashTable *details, const QList<QtContacts::QContactDetail> &cDetails)
2332+{
2333+ if(cDetails.size() == 0) {
2334+ return details;
2335+ }
2336+
2337+ Q_FOREACH(const QContactDetail& detail, cDetails) {
2338+ QContactFavorite favorite = static_cast<QContactFavorite>(detail);
2339+ if(!favorite.isEmpty()) {
2340+ GValue *value = QIndividualUtils::gValueSliceNew(G_TYPE_BOOLEAN);
2341+ g_value_set_boolean(value, favorite.isFavorite());
2342+
2343+ QIndividualUtils::personaDetailsInsert(details, FOLKS_PERSONA_DETAIL_IS_FAVOURITE, value);
2344+ }
2345+ }
2346+
2347+ return details;
2348+}
2349+
2350+GHashTable *QIndividual::parseGenderDetails(GHashTable *details, const QList<QtContacts::QContactDetail> &cDetails)
2351+{
2352+ if(cDetails.size() == 0) {
2353+ return details;
2354+ }
2355+
2356+ Q_FOREACH(const QContactDetail& detail, cDetails) {
2357+ QContactGender gender = static_cast<QContactDetail>(detail);
2358+ if(!gender.isEmpty()) {
2359+ GValue *value = QIndividualUtils::gValueSliceNew(FOLKS_TYPE_GENDER);
2360+ FolksGender genderEnum = FOLKS_GENDER_UNSPECIFIED;
2361+ if(gender.gender() == QContactGender::GenderMale) {
2362+ genderEnum = FOLKS_GENDER_MALE;
2363+ } else if(gender.gender() == QContactGender::GenderFemale) {
2364+ genderEnum = FOLKS_GENDER_FEMALE;
2365+ }
2366+ g_value_set_enum(value, genderEnum);
2367+
2368+ QIndividualUtils::personaDetailsInsert(details, FOLKS_PERSONA_DETAIL_GENDER, value);
2369+ }
2370+ }
2371+
2372+ return details;
2373+}
2374+
2375+GHashTable *QIndividual::parseNameDetails(GHashTable *details, const QList<QtContacts::QContactDetail> &cDetails)
2376+{
2377+ if(cDetails.size() == 0) {
2378+ return details;
2379+ }
2380+
2381+ Q_FOREACH(const QContactDetail& detail, cDetails) {
2382+ QContactName name = static_cast<QContactName>(detail);
2383+ if(!name.isEmpty()) {
2384+ GValue *value = QIndividualUtils::gValueSliceNew(FOLKS_TYPE_STRUCTURED_NAME);
2385+ FolksStructuredName *sn = folks_structured_name_new(name.lastName().toUtf8().data(),
2386+ name.firstName().toUtf8().data(),
2387+ name.middleName().toUtf8().data(),
2388+ name.prefix().toUtf8().data(),
2389+ name.suffix().toUtf8().data());
2390+ g_value_take_object(value, sn);
2391+ QIndividualUtils::personaDetailsInsert(details, FOLKS_PERSONA_DETAIL_STRUCTURED_NAME, value);
2392+ }
2393+ }
2394+
2395+ return details;
2396+}
2397+
2398+GHashTable *QIndividual::parseFullNameDetails(GHashTable *details, const QList<QtContacts::QContactDetail> &cDetails)
2399+{
2400+ if(cDetails.size() == 0) {
2401+ return details;
2402+ }
2403+
2404+ Q_FOREACH(const QContactDetail& detail, cDetails) {
2405+ QContactDisplayLabel displayLabel = static_cast<QContactDisplayLabel>(detail);
2406+ if(!displayLabel.label().isEmpty()) {
2407+ GValue *value = QIndividualUtils::gValueSliceNew(G_TYPE_STRING);
2408+ g_value_set_string(value, displayLabel.label().toUtf8().data());
2409+ QIndividualUtils::personaDetailsInsert(details, FOLKS_PERSONA_DETAIL_FULL_NAME, value);
2410+
2411+ // FIXME: check if those values should all be set to the same thing
2412+ value = QIndividualUtils::gValueSliceNew(G_TYPE_STRING);
2413+ g_value_set_string(value, displayLabel.label().toUtf8().data());
2414+ QIndividualUtils::personaDetailsInsert(details, FOLKS_PERSONA_DETAIL_ALIAS, value);
2415+ }
2416+ }
2417+
2418+ return details;
2419+}
2420+
2421+GHashTable *QIndividual::parseNicknameDetails(GHashTable *details, const QList<QtContacts::QContactDetail> &cDetails)
2422+{
2423+ if(cDetails.size() == 0) {
2424+ return details;
2425+ }
2426+
2427+ Q_FOREACH(const QContactDetail& detail, cDetails) {
2428+ QContactNickname nickname = static_cast<QContactNickname>(detail);
2429+ if(!nickname.nickname().isEmpty()) {
2430+ GValue *value = QIndividualUtils::gValueSliceNew(G_TYPE_STRING);
2431+ g_value_set_string(value, nickname.nickname().toUtf8().data());
2432+ QIndividualUtils::personaDetailsInsert(details, FOLKS_PERSONA_DETAIL_NICKNAME, value);
2433+
2434+ // FIXME: check if those values should all be set to the same thing
2435+ value = QIndividualUtils::gValueSliceNew(G_TYPE_STRING);
2436+ g_value_set_string(value, nickname.nickname().toUtf8().data());
2437+ QIndividualUtils::personaDetailsInsert(details, FOLKS_PERSONA_DETAIL_ALIAS, value);
2438+ }
2439+ }
2440+
2441+ return details;
2442+}
2443+
2444+GHashTable *QIndividual::parseNoteDetails(GHashTable *details, const QList<QtContacts::QContactDetail> &cDetails)
2445+{
2446+ if(cDetails.size() == 0) {
2447+ return details;
2448+ }
2449+
2450+ GValue *value;
2451+ PERSONA_DETAILS_INSERT_STRING_FIELD_DETAILS(details, cDetails,
2452 FOLKS_PERSONA_DETAIL_NOTES, value, QContactNote,
2453 FOLKS_TYPE_NOTE_FIELD_DETAILS, note);
2454
2455-
2456-
2457- /*
2458- * OnlineAccounts
2459- */
2460- QList<QContactOnlineAccount> accounts = contact.details<QContactOnlineAccount>();
2461- if(!accounts.isEmpty()) {
2462- QMultiMap<QString, QString> providerUidMap;
2463-
2464- Q_FOREACH(const QContactOnlineAccount &account, accounts) {
2465- if (!account.isEmpty()) {
2466- providerUidMap.insert(onlineAccountProtocolFromEnum(account.protocol()), account.accountUri());
2467- }
2468- }
2469-
2470- if(!providerUidMap.isEmpty()) {
2471- //TODO: add account type and subtype
2472- value = QIndividualUtils::asvSetStrNew(providerUidMap);
2473- QIndividualUtils::personaDetailsInsert(details, FOLKS_PERSONA_DETAIL_IM_ADDRESSES, value);
2474- }
2475- }
2476-
2477- /*
2478- * Organization
2479- */
2480- QList<QContactOrganization> orgs = contact.details<QContactOrganization>();
2481- if(orgs.size() > 0) {
2482- value = QIndividualUtils::gValueSliceNew(G_TYPE_OBJECT);
2483- Q_FOREACH(const QContactOrganization& org, orgs) {
2484- if(!org.isEmpty()) {
2485- FolksRole *role = folks_role_new(org.title().toUtf8().data(),
2486- org.name().toUtf8().data(),
2487- NULL);
2488- folks_role_set_role(role, org.role().toUtf8().data());
2489-
2490- GeeCollection *collection = (GeeCollection*) g_value_get_object(value);
2491- if(collection == NULL) {
2492- collection = GEE_COLLECTION(SET_AFD_NEW());
2493- g_value_take_object(value, collection);
2494- }
2495- FolksRoleFieldDetails *rfd = folks_role_field_details_new(role, NULL);
2496- parseContext(FOLKS_ABSTRACT_FIELD_DETAILS(rfd), org);
2497- gee_collection_add(collection, rfd);
2498-
2499- g_object_unref(rfd);
2500- g_object_unref(role);
2501- }
2502- }
2503- QIndividualUtils::personaDetailsInsert(details, FOLKS_PERSONA_DETAIL_ROLES, value);
2504- }
2505-
2506- /*
2507- * Phone Numbers
2508- */
2509- QList<QContactPhoneNumber> phones = contact.details<QContactPhoneNumber>();
2510- if (phones.size() > 0) {
2511- value = QIndividualUtils::gValueSliceNew(G_TYPE_OBJECT);
2512- Q_FOREACH(const QContactPhoneNumber &phone, phones) {
2513- if(!phone.isEmpty()) {
2514- QIndividualUtils::gValueGeeSetAddStringFieldDetails(value,
2515- FOLKS_TYPE_PHONE_FIELD_DETAILS,
2516- phone.number().toUtf8().data(),
2517- phone);
2518- }
2519- }
2520- QIndividualUtils::personaDetailsInsert(details, FOLKS_PERSONA_DETAIL_PHONE_NUMBERS, value);
2521- }
2522-
2523- /*
2524- * URLs
2525- */
2526- PERSONA_DETAILS_INSERT_STRING_FIELD_DETAILS(details,
2527+ return details;
2528+}
2529+
2530+GHashTable *QIndividual::parseImDetails(GHashTable *details, const QList<QtContacts::QContactDetail> &cDetails)
2531+{
2532+ if(cDetails.size() == 0) {
2533+ return details;
2534+ }
2535+
2536+ QMultiMap<QString, QString> providerUidMap;
2537+ Q_FOREACH(const QContactDetail &detail, cDetails) {
2538+ QContactOnlineAccount account = static_cast<QContactOnlineAccount>(detail);
2539+ if (!account.isEmpty()) {
2540+ providerUidMap.insert(onlineAccountProtocolFromEnum(account.protocol()), account.accountUri());
2541+ }
2542+ }
2543+
2544+ if(!providerUidMap.isEmpty()) {
2545+ //TODO: add account type and subtype
2546+ GValue *value = QIndividualUtils::asvSetStrNew(providerUidMap);
2547+ QIndividualUtils::personaDetailsInsert(details, FOLKS_PERSONA_DETAIL_IM_ADDRESSES, value);
2548+ }
2549+
2550+ return details;
2551+}
2552+
2553+GHashTable *QIndividual::parseOrganizationDetails(GHashTable *details, const QList<QtContacts::QContactDetail> &cDetails)
2554+{
2555+ if(cDetails.size() == 0) {
2556+ return details;
2557+ }
2558+
2559+ GValue *value = QIndividualUtils::gValueSliceNew(G_TYPE_OBJECT);
2560+ Q_FOREACH(const QContactDetail& detail, cDetails) {
2561+ QContactOrganization org = static_cast<QContactOrganization>(detail);
2562+ if(!org.isEmpty()) {
2563+ FolksRole *role = folks_role_new(org.title().toUtf8().data(),
2564+ org.name().toUtf8().data(),
2565+ NULL);
2566+ folks_role_set_role(role, org.role().toUtf8().data());
2567+
2568+ GeeCollection *collection = (GeeCollection*) g_value_get_object(value);
2569+ if(collection == NULL) {
2570+ collection = GEE_COLLECTION(SET_AFD_NEW());
2571+ g_value_take_object(value, collection);
2572+ }
2573+ FolksRoleFieldDetails *rfd = folks_role_field_details_new(role, NULL);
2574+ parseContext(FOLKS_ABSTRACT_FIELD_DETAILS(rfd), org);
2575+ gee_collection_add(collection, rfd);
2576+
2577+ g_object_unref(rfd);
2578+ g_object_unref(role);
2579+ }
2580+ }
2581+ QIndividualUtils::personaDetailsInsert(details, FOLKS_PERSONA_DETAIL_ROLES, value);
2582+
2583+ return details;
2584+}
2585+
2586+GHashTable *QIndividual::parsePhoneNumbersDetails(GHashTable *details, const QList<QtContacts::QContactDetail> &cDetails)
2587+{
2588+ if(cDetails.size() == 0) {
2589+ return details;
2590+ }
2591+
2592+ GValue *value = QIndividualUtils::gValueSliceNew(G_TYPE_OBJECT);
2593+ Q_FOREACH(const QContactDetail &detail, cDetails) {
2594+ QContactPhoneNumber phone = static_cast<QContactPhoneNumber>(detail);
2595+ if(!phone.isEmpty()) {
2596+ QIndividualUtils::gValueGeeSetAddStringFieldDetails(value,
2597+ FOLKS_TYPE_PHONE_FIELD_DETAILS,
2598+ phone.number().toUtf8().data(),
2599+ phone);
2600+ }
2601+ }
2602+ QIndividualUtils::personaDetailsInsert(details, FOLKS_PERSONA_DETAIL_PHONE_NUMBERS, value);
2603+
2604+ return details;
2605+}
2606+
2607+GHashTable *QIndividual::parseUrlDetails(GHashTable *details, const QList<QtContacts::QContactDetail> &cDetails)
2608+{
2609+ if(cDetails.size() == 0) {
2610+ return details;
2611+ }
2612+
2613+ GValue *value;
2614+ PERSONA_DETAILS_INSERT_STRING_FIELD_DETAILS(details, cDetails,
2615 FOLKS_PERSONA_DETAIL_URLS, value, QContactUrl,
2616 FOLKS_TYPE_URL_FIELD_DETAILS, url);
2617+
2618+ return details;
2619+}
2620+
2621+
2622+GHashTable *QIndividual::parseDetails(const QtContacts::QContact &contact)
2623+{
2624+ GHashTable *details = g_hash_table_new_full(g_str_hash,
2625+ g_str_equal,
2626+ NULL,
2627+ (GDestroyNotify) QIndividualUtils::gValueSliceFree);
2628+
2629+ parseAddressDetails(details, contact.details(QContactAddress::Type));
2630+ parsePhotoDetails(details, contact.details(QContactAvatar::Type));
2631+ parseBirthdayDetails(details, contact.details(QContactBirthday::Type));
2632+ parseEmailDetails(details, contact.details(QContactEmailAddress::Type));
2633+ parseFavoriteDetails(details, contact.details(QContactFavorite::Type));
2634+ parseGenderDetails(details, contact.details(QContactGender::Type));
2635+ parseNameDetails(details, contact.details(QContactName::Type));
2636+ parseFullNameDetails(details, contact.details(QContactDisplayLabel::Type));
2637+ parseNicknameDetails(details, contact.details(QContactNickname::Type));
2638+ parseNoteDetails(details, contact.details(QContactNote::Type));
2639+ parseImDetails(details, contact.details(QContactOnlineAccount::Type));
2640+ parseOrganizationDetails(details, contact.details(QContactOrganization::Type));
2641+ parsePhoneNumbersDetails(details, contact.details(QContactPhoneNumber::Type));
2642+ parseUrlDetails(details, contact.details(QContactUrl::Type));
2643+
2644 return details;
2645 }
2646
2647@@ -1761,29 +2191,39 @@
2648 {
2649 }
2650
2651-FolksPersona* QIndividual::primaryPersona() const
2652+FolksPersona* QIndividual::primaryPersona()
2653 {
2654- if(m_individual == 0) {
2655- return 0;
2656+ Q_ASSERT(m_individual);
2657+
2658+ if (m_primaryPersona) {
2659+ return m_primaryPersona;
2660 }
2661
2662- FolksPersona *retval = NULL;
2663 GeeSet *personas = folks_individual_get_personas(m_individual);
2664 GeeIterator *iter = gee_iterable_iterator(GEE_ITERABLE(personas));
2665+ FolksPersonaStore *primaryStore = folks_individual_aggregator_get_primary_store(m_aggregator);
2666
2667- while(retval == NULL && gee_iterator_next(iter)) {
2668+ while(m_primaryPersona == NULL && gee_iterator_next(iter)) {
2669 FolksPersona *persona = FOLKS_PERSONA(gee_iterator_get(iter));
2670- FolksPersonaStore *primaryStore = folks_individual_aggregator_get_primary_store(m_aggregator);
2671 if(folks_persona_get_store(persona) == primaryStore) {
2672- retval = persona;
2673- g_object_ref(retval);
2674+ m_primaryPersona = persona;
2675+ g_object_ref (persona);
2676 }
2677-
2678 g_object_unref(persona);
2679 }
2680 g_object_unref (iter);
2681
2682- return retval;
2683+ return m_primaryPersona;
2684+}
2685+
2686+QtContacts::QContactDetail QIndividual::detailFromUri(QtContacts::QContactDetail::DetailType type, const QString &uri) const
2687+{
2688+ Q_FOREACH(QContactDetail detail, m_contact.details(type)) {
2689+ if (detail.detailUri() == uri) {
2690+ return detail;
2691+ }
2692+ }
2693+ return m_contact.detail(type);
2694 }
2695
2696 } //namespace
2697
2698=== modified file 'src/qindividual.h'
2699--- src/qindividual.h 2013-06-11 13:00:01 +0000
2700+++ src/qindividual.h 2013-06-20 13:17:29 +0000
2701@@ -31,7 +31,7 @@
2702
2703 namespace galera
2704 {
2705-typedef void (*UpdateDoneCB)(const QString&, void*);
2706+typedef GHashTable* (ParseDetailsFunc)(GHashTable*, const QList<QtContacts::QContactDetail> &);
2707
2708 typedef QList<QtVersit::QVersitProperty> PropertyList;
2709 class QIndividual
2710@@ -59,40 +59,47 @@
2711
2712 QtContacts::QContact &contact();
2713 QtContacts::QContact copy(Fields fields = QIndividual::All);
2714- bool update(const QString &vcard, UpdateDoneCB cb, void* data);
2715- bool update(const QtContacts::QContact &contact, UpdateDoneCB cb, void* data);
2716+ bool update(const QString &vcard, QObject *object, const QString &slot);
2717+ bool update(const QtContacts::QContact &contact, QObject *object, const QString &slot);
2718 FolksIndividual *individual() const;
2719+ void setIndividual(FolksIndividual *individual);
2720
2721 static GHashTable *parseDetails(const QtContacts::QContact &contact);
2722-
2723 private:
2724 FolksIndividual *m_individual;
2725+ FolksPersona *m_primaryPersona;
2726 FolksIndividualAggregator *m_aggregator;
2727 QtContacts::QContact m_contact;
2728 QMap<QString, QPair<QtContacts::QContactDetail, FolksAbstractFieldDetails*> > m_fieldsMap;
2729- unsigned int m_fieldMapNextKey;
2730+
2731
2732 bool fieldsContains(Fields fields, Field value) const;
2733 QList<QtVersit::QVersitProperty> parseFieldList(const QString &fieldName, GeeSet *values) const;
2734 QMultiHash<QString, QString> parseDetails(FolksAbstractFieldDetails *details) const;
2735 void updateContact();
2736- FolksPersona *primaryPersona() const;
2737+
2738+ FolksPersona *primaryPersona();
2739+ QtContacts::QContactDetail detailFromUri(QtContacts::QContactDetail::DetailType type, const QString &uri) const;
2740
2741 // QContact
2742+ QList<QtContacts::QContactDetail> getDetails() const;
2743+ void appendDetailsForPersona(QList<QtContacts::QContactDetail> *list, QtContacts::QContactDetail detail, const QString &personaIndex, bool readOnly) const;
2744+ void appendDetailsForPersona(QList<QtContacts::QContactDetail> *list, QList<QtContacts::QContactDetail> details, const QString &personaIndex, bool readOnly) const;
2745+
2746 QtContacts::QContactDetail getUid() const;
2747 QList<QtContacts::QContactDetail> getClientPidMap() const;
2748- QtContacts::QContactDetail getName() const;
2749- QtContacts::QContactDetail getFullName() const;
2750- QtContacts::QContactDetail getNickname() const;
2751- QtContacts::QContactDetail getBirthday() const;
2752- QtContacts::QContactDetail getPhoto() const;
2753- QList<QtContacts::QContactDetail> getRoles() const;
2754- QList<QtContacts::QContactDetail> getEmails() const;
2755- QList<QtContacts::QContactDetail> getPhones() const;
2756- QList<QtContacts::QContactDetail> getAddresses() const;
2757- QList<QtContacts::QContactDetail> getIms() const;
2758- QtContacts::QContactDetail getTimeZone() const;
2759- QList<QtContacts::QContactDetail> getUrls() const;
2760+ QtContacts::QContactDetail getPersonaName(FolksPersona *persona) const;
2761+ QtContacts::QContactDetail getPersonaFullName(FolksPersona *persona) const;
2762+ QtContacts::QContactDetail getPersonaNickName(FolksPersona *persona) const;
2763+ QtContacts::QContactDetail getPersonaBirthday(FolksPersona *persona) const;
2764+ QtContacts::QContactDetail getPersonaPhoto(FolksPersona *persona) const;
2765+ //TODO: organization
2766+ QList<QtContacts::QContactDetail> getPersonaRoles(FolksPersona *persona) const;
2767+ QList<QtContacts::QContactDetail> getPersonaEmails(FolksPersona *persona) const;
2768+ QList<QtContacts::QContactDetail> getPersonaPhones(FolksPersona *persona) const;
2769+ QList<QtContacts::QContactDetail> getPersonaAddresses(FolksPersona *persona) const;
2770+ QList<QtContacts::QContactDetail> getPersonaIms(FolksPersona *persona) const;
2771+ QList<QtContacts::QContactDetail> getPersonaUrls(FolksPersona *persona) const;
2772
2773
2774 // update
2775@@ -102,15 +109,38 @@
2776 void updateBirthday(const QtContacts::QContactDetail &detail, void* data);
2777 void updatePhoto(const QtContacts::QContactDetail &detail, void* data);
2778 void updateTimezone(const QtContacts::QContactDetail &detail, void* data);
2779- void updateRoles(QList<QtContacts::QContactDetail> details, void* data);
2780- void updatePhones(QList<QtContacts::QContactDetail> details, void* data);
2781- void updateEmails(QList<QtContacts::QContactDetail> details, void* data);
2782- void updateIms(QList<QtContacts::QContactDetail> details, void* data);
2783- void updateUrls(QList<QtContacts::QContactDetail> details, void* data);
2784- void updateNotes(QList<QtContacts::QContactDetail> details, void* data);
2785- void updateAddresses(QList<QtContacts::QContactDetail> details, void* data);
2786+ void updateRole(QtContacts::QContactDetail detail, void* data);
2787+ void updatePhone(QtContacts::QContactDetail detail, void* data);
2788+ void updateEmail(QtContacts::QContactDetail detail, void* data);
2789+ void updateIm(QtContacts::QContactDetail detail, void* data);
2790+ void updateUrl(QtContacts::QContactDetail details, void* data);
2791+ void updateNote(QtContacts::QContactDetail detail, void* data);
2792+ void updateAddress(QtContacts::QContactDetail detail, void* data);
2793+ void createPersonaForDetail(QList<QtContacts::QContactDetail> detail, ParseDetailsFunc parseFunc, void *data) const;
2794+
2795+ static void createPersonaDone(GObject *detail, GAsyncResult *result, gpointer userdata);
2796 static void updateDetailsDone(GObject *detail, GAsyncResult *result, gpointer userdata);
2797- static bool detailListIsEqual(QList<QtContacts::QContactDetail> original, QList<QtContacts::QContactDetail> details);
2798+ static void updateDetailsSendReply(gpointer userdata, GError *error);
2799+ static void updateDetailsSendReply(gpointer userdata, const QString &errorMessage);
2800+ static QString callDetailChangeFinish(QtContacts::QContactDetail::DetailType type, FolksPersona *persona, GAsyncResult *result);
2801+ //static bool detailListIsEqual(QList<QtContacts::QContactDetail> original, QList<QtContacts::QContactDetail> details);
2802+
2803+ // translate details
2804+ static GHashTable *parseAddressDetails(GHashTable *details, const QList<QtContacts::QContactDetail> &cDetails);
2805+ static GHashTable *parsePhotoDetails(GHashTable *details, const QList<QtContacts::QContactDetail> &cDetails);
2806+ static GHashTable *parsePhoneNumbersDetails(GHashTable *details, const QList<QtContacts::QContactDetail> &cDetails);
2807+ static GHashTable *parseOrganizationDetails(GHashTable *details, const QList<QtContacts::QContactDetail> &cDetails);
2808+ static GHashTable *parseImDetails(GHashTable *details, const QList<QtContacts::QContactDetail> &cDetails);
2809+ static GHashTable *parseNoteDetails(GHashTable *details, const QList<QtContacts::QContactDetail> &cDetails);
2810+ static GHashTable *parseFullNameDetails(GHashTable *details, const QList<QtContacts::QContactDetail> &cDetails);
2811+ static GHashTable *parseNicknameDetails(GHashTable *details, const QList<QtContacts::QContactDetail> &cDetails);
2812+ static GHashTable *parseNameDetails(GHashTable *details, const QList<QtContacts::QContactDetail> &cDetails);
2813+ static GHashTable *parseGenderDetails(GHashTable *details, const QList<QtContacts::QContactDetail> &cDetails);
2814+ static GHashTable *parseFavoriteDetails(GHashTable *details, const QList<QtContacts::QContactDetail> &cDetails);
2815+ static GHashTable *parseEmailDetails(GHashTable *details, const QList<QtContacts::QContactDetail> &cDetails);
2816+ static GHashTable *parseBirthdayDetails(GHashTable *details, const QList<QtContacts::QContactDetail> &cDetails);
2817+ static GHashTable *parseUrlDetails(GHashTable *details, const QList<QtContacts::QContactDetail> &cDetails);
2818+
2819
2820 // parse context and parameters
2821 static void parseParameters(QtContacts::QContactDetail &detail, FolksAbstractFieldDetails *fd);
2822
2823=== modified file 'src/view-adaptor.h'
2824--- src/view-adaptor.h 2013-06-13 14:00:42 +0000
2825+++ src/view-adaptor.h 2013-06-20 13:17:29 +0000
2826@@ -45,7 +45,7 @@
2827 " <arg direction=\"out\" type=\"i\" name=\"pos\"/>\n"
2828 " <arg direction=\"out\" type=\"i\" name=\"lenght\"/>\n"
2829 " </signal>\n"
2830-" <signal name=\"contactsCreated\">\n"
2831+" <signal name=\"contactsAdded\">\n"
2832 " <arg direction=\"out\" type=\"i\" name=\"pos\"/>\n"
2833 " <arg direction=\"out\" type=\"i\" name=\"lenght\"/>\n"
2834 " </signal>\n"
2835@@ -81,7 +81,7 @@
2836 void close();
2837
2838 Q_SIGNALS:
2839- void contactsCreated(int pos, int lenght);
2840+ void contactsAdded(int pos, int lenght);
2841 void contactsRemoved(int pos, int lenght);
2842 void contactsUpdated(int pos, int lenght);
2843

Subscribers

People subscribed via source and target branches