1/****************************************************************************
2**
3** Copyright (C) 2015 The Qt Company Ltd.
4** Contact: http://www.qt.io/licensing/
5**
6** This file is part of the QtContacts module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL21$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see http://www.qt.io/terms-conditions. For further
15** information use the contact form at http://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 or version 3 as published by the Free
20** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22** following information to ensure the GNU Lesser General Public License
23** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25**
26** As a special exception, The Qt Company gives you certain additional
27** rights. These rights are described in The Qt Company LGPL Exception
28** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29**
30** $QT_END_LICENSE$
31**
32****************************************************************************/
33
34#include "qcontactmemorybackend_p.h"
35
36#ifndef QT_NO_DEBUG_STREAM
37#include <QtCore/qdebug.h>
38#endif
39#include <QtCore/qpointer.h>
40#include <QtCore/qstringbuilder.h>
41#include <QtCore/quuid.h>
42
43#include <QtContacts/qcontactidfilter.h>
44#include <QtContacts/qcontactrequests.h>
45#include <QtContacts/qcontacttimestamp.h>
46
47QT_BEGIN_NAMESPACE_CONTACTS
48
49QContactManagerEngine* QContactMemoryEngineFactory::engine(const QMap<QString, QString> &parameters, QContactManager::Error *error)
50{
51 Q_UNUSED(error);
52
53 QContactMemoryEngine *ret = QContactMemoryEngine::createMemoryEngine(parameters);
54 return ret;
55}
56
57QString QContactMemoryEngineFactory::managerName() const
58{
59 return QString::fromLatin1(str: "memory");
60}
61
62/*!
63 \class QContactMemoryEngine
64
65 \inmodule QtContacts
66
67 \brief The QContactMemoryEngine class provides an in-memory implementation
68 of a contacts backend.
69
70 \internal
71
72 It may be used as a reference implementation, or when persistent storage is not required.
73
74 During construction, it will load the in-memory data associated with the memory store
75 identified by the "id" parameter from the given parameters if it exists, or a new,
76 anonymous store if it does not.
77
78 Data stored in this engine is only available in the current process.
79
80 This engine supports sharing, so an internal reference count is increased
81 whenever a manager uses this backend, and is decreased when the manager
82 no longer requires this engine.
83 */
84
85/* static data for manager class */
86QMap<QString, QContactMemoryEngineData*> QContactMemoryEngine::engineDatas;
87
88/*!
89 * Factory function for creating a new in-memory backend, based
90 * on the given \a parameters.
91 *
92 * The same engine will be returned for multiple calls with the
93 * same value for the "id" parameter, while one of them is in scope.
94 */
95QContactMemoryEngine* QContactMemoryEngine::createMemoryEngine(const QMap<QString, QString> &parameters)
96{
97 bool anonymous = false;
98 QString idValue = parameters.value(QStringLiteral("id"));
99 if (idValue.isNull() || idValue.isEmpty()) {
100 // no store given? new, anonymous store.
101 idValue = QUuid::createUuid().toString();
102 anonymous = true;
103 }
104
105 QContactMemoryEngineData *data = engineDatas.value(akey: idValue);
106 if (data) {
107 data->m_refCount.ref();
108 } else {
109 data = new QContactMemoryEngineData();
110 data->m_id = idValue;
111 data->m_anonymous = anonymous;
112 engineDatas.insert(akey: idValue, avalue: data);
113 }
114 return new QContactMemoryEngine(data);
115}
116
117/*!
118 * Constructs a new in-memory backend which shares the given \a data with
119 * other shared memory engines.
120 */
121QContactMemoryEngine::QContactMemoryEngine(QContactMemoryEngineData *data)
122 : d(data)
123{
124 qRegisterMetaType<QContactAbstractRequest::State>(typeName: "QContactAbstractRequest::State");
125 qRegisterMetaType<QList<QContactId> >(typeName: "QList<QContactId>");
126 qRegisterMetaType<QContactId>(typeName: "QContactId");
127 d->m_managerUri = managerUri();
128 d->m_sharedEngines.append(t: this);
129
130 // the default collection always exists.
131 if (d->m_idToCollectionHash.isEmpty()) {
132 d->m_managerUri = managerUri();
133 const QContactCollectionId defaultId = defaultCollectionId();
134 QContactCollection defaultCollection;
135 defaultCollection.setId(defaultId);
136 defaultCollection.setMetaData(key: QContactCollection::KeyName, value: QString(QStringLiteral("Default Collection")));
137 d->m_idToCollectionHash.insert(akey: defaultId, avalue: defaultCollection);
138 }
139}
140
141/*! Frees any memory used by this engine */
142QContactMemoryEngine::~QContactMemoryEngine()
143{
144 d->m_sharedEngines.removeAll(t: this);
145 if (!d->m_refCount.deref()) {
146 engineDatas.remove(akey: d->m_id);
147 delete d;
148 }
149}
150
151/*! \reimp */
152QString QContactMemoryEngine::managerName() const
153{
154 return QStringLiteral("memory");
155}
156
157/*! \reimp */
158QMap<QString, QString> QContactMemoryEngine::managerParameters() const
159{
160 QMap<QString, QString> params;
161 params.insert(QStringLiteral("id"), avalue: d->m_id);
162 return params;
163}
164
165/*! \reimp
166*/
167QMap<QString, QString> QContactMemoryEngine::idInterpretationParameters() const
168{
169 return managerParameters();
170}
171
172/*! \reimp */
173bool QContactMemoryEngine::setSelfContactId(const QContactId &contactId, QContactManager::Error *error)
174{
175 if (contactId.isNull() || d->m_contactIds.contains(t: contactId)) {
176 *error = QContactManager::NoError;
177 QContactId oldId = d->m_selfContactId;
178 d->m_selfContactId = contactId;
179
180 QContactChangeSet changeSet;
181 changeSet.setOldAndNewSelfContactId(QPair<QContactId, QContactId>(oldId, contactId));
182 d->emitSharedSignals(cs: &changeSet);
183 return true;
184 }
185
186 *error = QContactManager::DoesNotExistError;
187 return false;
188}
189
190/*! \reimp */
191QContactId QContactMemoryEngine::selfContactId(QContactManager::Error *error) const
192{
193 *error = QContactManager::DoesNotExistError;
194 if (!d->m_selfContactId.isNull())
195 *error = QContactManager::NoError;
196 return d->m_selfContactId;
197}
198
199/*! \reimp */
200QContact QContactMemoryEngine::contact(const QContactId &contactId, const QContactFetchHint &fetchHint, QContactManager::Error *error) const
201{
202 Q_UNUSED(fetchHint); // no optimizations are possible in the memory backend; ignore the fetch hint.
203 int index = d->m_contactIds.indexOf(t: contactId);
204 if (index != -1) {
205 // found the contact successfully.
206 *error = QContactManager::NoError;
207 return d->m_contacts.at(i: index);
208 }
209
210 *error = QContactManager::DoesNotExistError;
211 return QContact();
212}
213
214/*! \reimp */
215QList<QContactId> QContactMemoryEngine::contactIds(const QContactFilter &filter, const QList<QContactSortOrder> &sortOrders, QContactManager::Error *error) const
216{
217 /* Special case the fast case */
218 if (filter.type() == QContactFilter::DefaultFilter && sortOrders.count() == 0) {
219 return d->m_contactIds;
220 } else {
221 QList<QContact> clist = contacts(filter, sortOrders, fetchHint: QContactFetchHint(), error);
222
223 /* Extract the ids */
224 QList<QContactId> ids;
225 foreach (const QContact &c, clist)
226 ids.append(t: c.id());
227
228 return ids;
229 }
230}
231
232/*! \reimp */
233QList<QContact> QContactMemoryEngine::contacts(const QContactFilter &filter, const QList<QContactSortOrder> &sortOrders, const QContactFetchHint &fetchHint, QContactManager::Error *error) const
234{
235 Q_UNUSED(fetchHint); // no optimizations are possible in the memory backend; ignore the fetch hint.
236 Q_UNUSED(error);
237
238 QList<QContact> sorted;
239
240 /* First filter out contacts - check for default filter first */
241 if (filter.type() == QContactFilter::DefaultFilter) {
242 foreach(const QContact&c, d->m_contacts) {
243 QContactManagerEngine::addSorted(sorted: &sorted,toAdd: c, sortOrders);
244 }
245 } else {
246 foreach(const QContact&c, d->m_contacts) {
247 if (QContactManagerEngine::testFilter(filter, contact: c))
248 QContactManagerEngine::addSorted(sorted: &sorted,toAdd: c, sortOrders);
249 }
250 }
251
252 return sorted;
253}
254
255/*! Saves the given contact \a theContact, storing any error to \a error and
256 filling the \a changeSet with ids of changed contacts as required
257 Returns true if the operation was successful otherwise false.
258*/
259bool QContactMemoryEngine::saveContact(QContact *theContact, QContactChangeSet &changeSet, QContactManager::Error *error)
260{
261 return saveContact(theContact, changeSet, error, mask: QList<QContactDetail::DetailType>());
262}
263
264/*! \reimp */
265bool QContactMemoryEngine::saveContacts(QList<QContact> *contacts, QMap<int, QContactManager::Error> *errorMap, QContactManager::Error *error)
266{
267 return saveContacts(contacts, errorMap, error, mask: QList<QContactDetail::DetailType>());
268}
269
270/*! Removes the contact identified by the given \a contactId, storing any error to \a error and
271 filling the \a changeSet with ids of changed contacts and relationships as required.
272 Returns true if the operation was successful otherwise false.
273*/
274bool QContactMemoryEngine::removeContact(const QContactId &contactId, QContactChangeSet &changeSet, QContactManager::Error *error)
275{
276 int index = d->m_contactIds.indexOf(t: contactId);
277
278 if (index == -1) {
279 *error = QContactManager::DoesNotExistError;
280 return false;
281 }
282
283 // remove the contact from any relationships it was in.
284 QContact thisContact = d->m_contacts.at(i: index);
285 QList<QContactRelationship> allRelationships = relationships(relationshipType: QString(), participantId: thisContact.id(), role: QContactRelationship::Either, error);
286 if (*error != QContactManager::NoError && *error != QContactManager::DoesNotExistError) {
287 *error = QContactManager::UnspecifiedError; // failed to clean up relationships
288 return false;
289 }
290
291 // this is meant to be a transaction, so if any of these fail, we're in BIG TROUBLE.
292 // a real backend will use DBMS transactions to ensure database integrity.
293 removeRelationships(relationships: allRelationships, errorMap: 0, error);
294
295 // having cleaned up the relationships, remove the contact from the lists.
296 d->m_contacts.removeAt(i: index);
297 d->m_contactIds.removeAt(i: index);
298 *error = QContactManager::NoError;
299
300 // and if it was the self contact, reset the self contact id
301 if (contactId == d->m_selfContactId) {
302 d->m_selfContactId = QContactId();
303 changeSet.setOldAndNewSelfContactId(QPair<QContactId, QContactId>(contactId, QContactId()));
304 }
305
306 changeSet.insertRemovedContact(addedContactId: contactId);
307 return true;
308}
309
310/*! \reimp */
311bool QContactMemoryEngine::removeContacts(const QList<QContactId> &contactIds, QMap<int, QContactManager::Error> *errorMap, QContactManager::Error *error)
312{
313 if (contactIds.count() == 0) {
314 *error = QContactManager::BadArgumentError;
315 return false;
316 }
317
318 QContactChangeSet changeSet;
319 QContactId current;
320 QContactManager::Error operationError = QContactManager::NoError;
321 for (int i = 0; i < contactIds.count(); i++) {
322 current = contactIds.at(i);
323 if (!removeContact(contactId: current, changeSet, error)) {
324 operationError = *error;
325 if (errorMap)
326 errorMap->insert(akey: i, avalue: operationError);
327 }
328 }
329
330 *error = operationError;
331 d->emitSharedSignals(cs: &changeSet);
332 // return false if some errors occurred
333 return (*error == QContactManager::NoError);
334}
335
336/*! \reimp */
337QList<QContactRelationship> QContactMemoryEngine::relationships(const QString &relationshipType, const QContactId &participantId, QContactRelationship::Role role, QContactManager::Error *error) const
338{
339 const QContactId defaultId;
340 QList<QContactRelationship> retn;
341 for (int i = 0; i < d->m_relationships.size(); i++) {
342 QContactRelationship curr = d->m_relationships.at(i);
343
344 // check that the relationship type matches
345 if (curr.relationshipType() != relationshipType && !relationshipType.isEmpty())
346 continue;
347
348 // if the participantId argument is default constructed, then the relationship matches.
349 if (participantId == defaultId) {
350 retn.append(t: curr);
351 continue;
352 }
353
354 // otherwise, check that the participant exists and plays the required role in the relationship.
355 if (role == QContactRelationship::First && curr.first() == participantId) {
356 retn.append(t: curr);
357 } else if (role == QContactRelationship::Second && curr.second() == participantId) {
358 retn.append(t: curr);
359 } else if (role == QContactRelationship::Either && (curr.first() == participantId || curr.second() == participantId)) {
360 retn.append(t: curr);
361 }
362 }
363
364 *error = QContactManager::NoError;
365 if (retn.isEmpty())
366 *error = QContactManager::DoesNotExistError;
367 return retn;
368}
369
370/*! Saves the given relationship \a relationship, storing any error to \a error and
371 filling the \a changeSet with ids of changed contacts and relationships as required
372 Returns true if the operation was successful otherwise false.
373*/
374bool QContactMemoryEngine::saveRelationship(QContactRelationship *relationship, QContactChangeSet &changeSet, QContactManager::Error *error)
375{
376 // Attempt to validate the relationship.
377 // first, check that the source contact exists and is in this manager.
378 QString myUri = managerUri();
379 int firstContactIndex = d->m_contactIds.indexOf(t: relationship->first());
380 if ((!relationship->first().managerUri().isEmpty() && relationship->first().managerUri() != myUri)
381 ||firstContactIndex == -1) {
382 *error = QContactManager::InvalidRelationshipError;
383 return false;
384 }
385
386 // second, check that the second contact exists (if it's local); we cannot check other managers' contacts.
387 QContactId dest = relationship->second();
388 int secondContactIndex = d->m_contactIds.indexOf(t: dest);
389
390 if (dest.managerUri().isEmpty() || dest.managerUri() == myUri) {
391 // this entry in the destination list is supposedly stored in this manager.
392 // check that it exists, and that it isn't the source contact (circular)
393 if (secondContactIndex == -1 || dest == relationship->first()) {
394 *error = QContactManager::InvalidRelationshipError;
395 return false;
396 }
397 }
398
399 // the relationship is valid. We need to update the manager URIs in the second contact if it is empty to our URI.
400 if (dest.managerUri().isEmpty()) {
401 // need to update the URI
402 relationship->setSecond(dest);
403 }
404
405 // check to see if the relationship already exists in the database. If so, replace.
406 // We do this because we don't want duplicates in our lists / maps of relationships.
407 *error = QContactManager::NoError;
408 QList<QContactRelationship> allRelationships = d->m_relationships;
409 for (int i = 0; i < allRelationships.size(); i++) {
410 QContactRelationship curr = allRelationships.at(i);
411 if (curr == *relationship) {
412 return true;
413 // TODO: set error to AlreadyExistsError and return false?
414 }
415 }
416
417 // no matching relationship; must be new. append it to lists in our map of relationships where required.
418 QList<QContactRelationship> firstRelationships = d->m_orderedRelationships.value(akey: relationship->first());
419 QList<QContactRelationship> secondRelationships = d->m_orderedRelationships.value(akey: relationship->second());
420 firstRelationships.append(t: *relationship);
421 secondRelationships.append(t: *relationship);
422 d->m_orderedRelationships.insert(akey: relationship->first(), avalue: firstRelationships);
423 d->m_orderedRelationships.insert(akey: relationship->second(), avalue: secondRelationships);
424 changeSet.insertAddedRelationshipsContact(affectedContactId: relationship->first());
425 changeSet.insertAddedRelationshipsContact(affectedContactId: relationship->second());
426
427 // update the contacts involved
428 QContactManagerEngine::setContactRelationships(contact: &d->m_contacts[firstContactIndex], relationships: firstRelationships);
429 QContactManagerEngine::setContactRelationships(contact: &d->m_contacts[secondContactIndex], relationships: secondRelationships);
430
431 // finally, insert into our list of all relationships, and return.
432 d->m_relationships.append(t: *relationship);
433 return true;
434}
435
436/*! \reimp */
437bool QContactMemoryEngine::saveRelationships(QList<QContactRelationship> *relationships, QMap<int, QContactManager::Error> *errorMap, QContactManager::Error *error)
438{
439 *error = QContactManager::NoError;
440 QContactManager::Error functionError;
441 QContactChangeSet changeSet;
442
443 for (int i = 0; i < relationships->size(); i++) {
444 QContactRelationship curr = relationships->at(i);
445 saveRelationship(relationship: &curr, changeSet, error: &functionError);
446 if (functionError != QContactManager::NoError && errorMap)
447 errorMap->insert(akey: i, avalue: functionError);
448
449 // and replace the current relationship with the updated version.
450 relationships->replace(i, t: curr);
451
452 // also, update the total error if it did not succeed.
453 if (functionError != QContactManager::NoError)
454 *error = functionError;
455 }
456
457 d->emitSharedSignals(cs: &changeSet);
458 return (*error == QContactManager::NoError);
459}
460
461/*! Removes the given relationship \a relationship, storing any error to \a error and
462 filling the \a changeSet with ids of changed contacts and relationships as required
463 Returns true if the operation was successful otherwise false.
464*/
465bool QContactMemoryEngine::removeRelationship(const QContactRelationship &relationship, QContactChangeSet &changeSet, QContactManager::Error *error)
466{
467 // attempt to remove it from our list of relationships.
468 if (!d->m_relationships.removeOne(t: relationship)) {
469 *error = QContactManager::DoesNotExistError;
470 return false;
471 }
472
473 // if that worked, then we need to remove it from the two locations in our map, also.
474 QList<QContactRelationship> firstRelationships = d->m_orderedRelationships.value(akey: relationship.first());
475 QList<QContactRelationship> secondRelationships = d->m_orderedRelationships.value(akey: relationship.second());
476 firstRelationships.removeOne(t: relationship);
477 secondRelationships.removeOne(t: relationship);
478 d->m_orderedRelationships.insert(akey: relationship.first(), avalue: firstRelationships);
479 d->m_orderedRelationships.insert(akey: relationship.second(), avalue: secondRelationships);
480
481 // Update the contacts as well
482 int firstContactIndex = d->m_contactIds.indexOf(t: relationship.first());
483 int secondContactIndex = relationship.second().managerUri() == managerUri() ? d->m_contactIds.indexOf(t: relationship.second()) : -1;
484 if (firstContactIndex != -1)
485 QContactMemoryEngine::setContactRelationships(contact: &d->m_contacts[firstContactIndex], relationships: firstRelationships);
486 if (secondContactIndex != -1)
487 QContactMemoryEngine::setContactRelationships(contact: &d->m_contacts[secondContactIndex], relationships: secondRelationships);
488
489 // set our changes, and return.
490 changeSet.insertRemovedRelationshipsContact(affectedContactId: relationship.first());
491 changeSet.insertRemovedRelationshipsContact(affectedContactId: relationship.second());
492 *error = QContactManager::NoError;
493 return true;
494}
495
496/*! \reimp */
497bool QContactMemoryEngine::removeRelationships(const QList<QContactRelationship> &relationships, QMap<int, QContactManager::Error> *errorMap, QContactManager::Error *error)
498{
499 QContactManager::Error functionError;
500 QContactChangeSet cs;
501 for (int i = 0; i < relationships.size(); i++) {
502 removeRelationship(relationship: relationships.at(i), changeSet&: cs, error: &functionError);
503
504 // update the total error if it did not succeed.
505 if (functionError != QContactManager::NoError) {
506 if (errorMap)
507 errorMap->insert(akey: i, avalue: functionError);
508 *error = functionError;
509 }
510 }
511
512 d->emitSharedSignals(cs: &cs);
513 return (*error == QContactManager::NoError);
514}
515
516QContactCollectionId QContactMemoryEngine::defaultCollectionId() const
517{
518 static const QByteArray id("Personal");
519 return collectionId(localId: id);
520}
521
522QContactCollection QContactMemoryEngine::collection(const QContactCollectionId &collectionId, QContactManager::Error *error)
523{
524 if (d->m_idToCollectionHash.contains(akey: collectionId)) {
525 *error = QContactManager::NoError;
526 return d->m_idToCollectionHash.value(akey: collectionId);
527 }
528
529 *error = QContactManager::DoesNotExistError;
530 return QContactCollection();
531}
532
533QList<QContactCollection> QContactMemoryEngine::collections(QContactManager::Error *error)
534{
535 Q_ASSERT(!d->m_idToCollectionHash.isEmpty());
536 *error = QContactManager::NoError;
537 return d->m_idToCollectionHash.values();
538}
539
540bool QContactMemoryEngine::saveCollection(QContactCollection *collection, QContactManager::Error *error)
541{
542 QContactCollectionId collectionId = collection->id();
543
544 QContactCollectionChangeSet cs;
545 if (d->m_idToCollectionHash.contains(akey: collectionId)) {
546 // this collection already exists. update our internal list
547 // if the collection has been modified.
548 if (d->m_idToCollectionHash.value(akey: collectionId) == *collection) {
549 *error = QContactManager::NoError;
550 return true;
551 }
552
553 cs.insertChangedCollection(collectionId);
554 } else {
555 // this must be a new collection. check that the id is null.
556 if (!collectionId.isNull() && collectionId.managerUri() != d->m_managerUri) {
557 // nope, this collection belongs in another manager, or has been deleted.
558 *error = QContactManager::DoesNotExistError;
559 return false;
560 }
561
562 // this is a new collection with a null id; create a new id, add it to our list.
563 QUuid id = QUuid::createUuid();
564 collectionId = this->collectionId(localId: id.toByteArray());
565 collection->setId(collectionId);
566 cs.insertAddedCollection(collectionId);
567 }
568
569 d->m_idToCollectionHash.insert(akey: collectionId, avalue: *collection);
570 d->emitSharedSignals(cs: &cs);
571 *error = QContactManager::NoError;
572 return true;
573}
574
575bool QContactMemoryEngine::removeCollection(const QContactCollectionId &collectionId, QContactManager::Error *error)
576{
577 if (collectionId == defaultCollectionId()) {
578 // attempting to remove the default collection. this is not allowed in the memory engine.
579 *error = QContactManager::PermissionsError;
580 return false;
581 }
582
583 // try to find the collection to remove it (and the items it contains)
584 if (d->m_idToCollectionHash.contains(akey: collectionId)) {
585 // found the collection to remove. remove the items in the collection.
586 const QList<QContactId> contactsToRemove = d->m_contactsInCollections.values(akey: collectionId);
587 if (!contactsToRemove.isEmpty()) {
588 QMap<int, QContactManager::Error> errorMap;
589 if (!removeContacts(contactIds: contactsToRemove, errorMap: &errorMap, error)) {
590 // without transaction support, we can't back out. but the operation should fail.
591 return false;
592 }
593 }
594
595 // now remove the collection from our lists.
596 d->m_idToCollectionHash.remove(akey: collectionId);
597 d->m_contactsInCollections.remove(akey: collectionId);
598 QContactCollectionChangeSet cs;
599 cs.insertRemovedCollection(collectionId);
600 d->emitSharedSignals(cs: &cs);
601 *error = QContactManager::NoError;
602 return true;
603 }
604
605 // the collection doesn't exist...
606 *error = QContactManager::DoesNotExistError;
607 return false;
608}
609
610/*! \reimp */
611void QContactMemoryEngine::requestDestroyed(QContactAbstractRequest *req)
612{
613 Q_UNUSED(req);
614}
615
616/*! \reimp */
617bool QContactMemoryEngine::startRequest(QContactAbstractRequest *req)
618{
619 updateRequestState(req, state: QContactAbstractRequest::ActiveState);
620 performAsynchronousOperation(request: req);
621
622 return true;
623}
624
625bool QContactMemoryEngine::cancelRequest(QContactAbstractRequest *req)
626{
627 Q_UNUSED(req); // we can't cancel since we complete immediately
628 return false;
629}
630
631/*! \reimp */
632bool QContactMemoryEngine::waitForRequestFinished(QContactAbstractRequest *req, int msecs)
633{
634 // in our implementation, we always complete any operation we start.
635 Q_UNUSED(msecs);
636 Q_UNUSED(req);
637
638 return true;
639}
640
641/*!
642 * This slot is called some time after an asynchronous request is started.
643 * It performs the required operation, sets the result and returns.
644 */
645void QContactMemoryEngine::performAsynchronousOperation(QContactAbstractRequest *currentRequest)
646{
647 // store up changes, and emit signals once at the end of the (possibly batch) operation.
648 QContactChangeSet changeSet;
649
650 // Now perform the active request and emit required signals.
651 Q_ASSERT(currentRequest->state() == QContactAbstractRequest::ActiveState);
652 switch (currentRequest->type()) {
653 case QContactAbstractRequest::ContactFetchRequest:
654 {
655 QContactFetchRequest *r = static_cast<QContactFetchRequest*>(currentRequest);
656 QContactFilter filter = r->filter();
657 QList<QContactSortOrder> sorting = r->sorting();
658 QContactFetchHint fetchHint = r->fetchHint();
659
660 QContactManager::Error operationError = QContactManager::NoError;
661 QList<QContact> requestedContacts = contacts(filter, sortOrders: sorting, fetchHint, error: &operationError);
662
663 // update the request with the results.
664 if (!requestedContacts.isEmpty() || operationError != QContactManager::NoError)
665 updateContactFetchRequest(req: r, result: requestedContacts, error: operationError, QContactAbstractRequest::FinishedState);
666 else
667 updateRequestState(req: currentRequest, state: QContactAbstractRequest::FinishedState);
668 }
669 break;
670
671 case QContactAbstractRequest::ContactFetchByIdRequest:
672 {
673 QContactFetchByIdRequest *r = static_cast<QContactFetchByIdRequest*>(currentRequest);
674 QContactIdFilter idFilter;
675 idFilter.setIds(r->contactIds());
676 QList<QContactSortOrder> sorting;
677 QContactFetchHint fetchHint = r->fetchHint();
678 QContactManager::Error error = QContactManager::NoError;
679 QList<QContact> requestedContacts = contacts(filter: idFilter, sortOrders: sorting, fetchHint, error: &error);
680 // Build an index into the results
681 QHash<QContactId, int> idMap; // value is index into unsorted
682 if (error == QContactManager::NoError) {
683 for (int i = 0; i < requestedContacts.size(); i++) {
684 idMap.insert(akey: requestedContacts[i].id(), avalue: i);
685 }
686 }
687 // Find the order in which the results should be presented
688 // Build up the results and errors
689 QList<QContact> results;
690 QMap<int, QContactManager::Error> errorMap;
691 int index = 0;
692 foreach (const QContactId &id, r->contactIds()) {
693 if (!idMap.contains(akey: id)) {
694 errorMap.insert(akey: index, avalue: QContactManager::DoesNotExistError);
695 error = QContactManager::DoesNotExistError;
696 results.append(t: QContact());
697 } else {
698 results.append(t: requestedContacts[idMap[id]]);
699 }
700 index++;
701 }
702
703 // update the request with the results.
704 if (!requestedContacts.isEmpty() || error != QContactManager::NoError)
705 QContactManagerEngine::updateContactFetchByIdRequest(req: r, result: results, error, errorMap, QContactAbstractRequest::FinishedState);
706 else
707 updateRequestState(req: currentRequest, state: QContactAbstractRequest::FinishedState);
708 }
709 break;
710
711 case QContactAbstractRequest::ContactIdFetchRequest:
712 {
713 QContactIdFetchRequest *r = static_cast<QContactIdFetchRequest*>(currentRequest);
714 QContactFilter filter = r->filter();
715 QList<QContactSortOrder> sorting = r->sorting();
716
717 QContactManager::Error operationError = QContactManager::NoError;
718 QList<QContactId> requestedContactIds = contactIds(filter, sortOrders: sorting, error: &operationError);
719
720 if (!requestedContactIds.isEmpty() || operationError != QContactManager::NoError)
721 updateContactIdFetchRequest(req: r, result: requestedContactIds, error: operationError, QContactAbstractRequest::FinishedState);
722 else
723 updateRequestState(req: currentRequest, state: QContactAbstractRequest::FinishedState);
724 }
725 break;
726
727 case QContactAbstractRequest::ContactSaveRequest:
728 {
729 QContactSaveRequest *r = static_cast<QContactSaveRequest*>(currentRequest);
730 QList<QContact> contacts = r->contacts();
731
732 QContactManager::Error operationError = QContactManager::NoError;
733 QMap<int, QContactManager::Error> errorMap;
734 saveContacts(contacts: &contacts, errorMap: &errorMap, error: &operationError, mask: r->typeMask());
735
736 updateContactSaveRequest(req: r, result: contacts, error: operationError, errorMap, QContactAbstractRequest::FinishedState);
737 }
738 break;
739
740 case QContactAbstractRequest::ContactRemoveRequest:
741 {
742 // this implementation provides scant information to the user
743 // the operation either succeeds (all contacts matching the filter were removed)
744 // or it fails (one or more contacts matching the filter could not be removed)
745 // if a failure occurred, the request error will be set to the most recent
746 // error that occurred during the remove operation.
747 QContactRemoveRequest *r = static_cast<QContactRemoveRequest*>(currentRequest);
748 QContactManager::Error operationError = QContactManager::NoError;
749 QList<QContactId> contactsToRemove = r->contactIds();
750 QMap<int, QContactManager::Error> errorMap;
751
752 for (int i = 0; i < contactsToRemove.size(); i++) {
753 QContactManager::Error tempError;
754 removeContact(contactId: contactsToRemove.at(i), changeSet, error: &tempError);
755
756 if (tempError != QContactManager::NoError) {
757 errorMap.insert(akey: i, avalue: tempError);
758 operationError = tempError;
759 }
760 }
761
762 if (!errorMap.isEmpty() || operationError != QContactManager::NoError)
763 updateContactRemoveRequest(req: r, error: operationError, errorMap, QContactAbstractRequest::FinishedState);
764 else
765 updateRequestState(req: currentRequest, state: QContactAbstractRequest::FinishedState);
766 }
767 break;
768
769 case QContactAbstractRequest::RelationshipFetchRequest:
770 {
771 QContactRelationshipFetchRequest *r = static_cast<QContactRelationshipFetchRequest*>(currentRequest);
772 QContactManager::Error operationError = QContactManager::NoError;
773 QList<QContactManager::Error> operationErrors;
774 QList<QContactRelationship> allRelationships = relationships(relationshipType: QString(), participantId: QContactId(), role: QContactRelationship::Either, error: &operationError);
775 QList<QContactRelationship> requestedRelationships;
776
777 // select the requested relationships.
778 for (int i = 0; i < allRelationships.size(); i++) {
779 QContactRelationship currRel = allRelationships.at(i);
780 if (r->first() != QContactId() && r->first() != currRel.first())
781 continue;
782 if (r->second() != QContactId() && r->second() != currRel.second())
783 continue;
784 if (!r->relationshipType().isEmpty() && r->relationshipType() != currRel.relationshipType())
785 continue;
786 requestedRelationships.append(t: currRel);
787 }
788
789 // update the request with the results.
790 if (!requestedRelationships.isEmpty() || operationError != QContactManager::NoError)
791 updateRelationshipFetchRequest(req: r, result: requestedRelationships, error: operationError, QContactAbstractRequest::FinishedState);
792 else
793 updateRequestState(req: currentRequest, state: QContactAbstractRequest::FinishedState);
794 }
795 break;
796
797 case QContactAbstractRequest::RelationshipRemoveRequest:
798 {
799 QContactRelationshipRemoveRequest *r = static_cast<QContactRelationshipRemoveRequest*>(currentRequest);
800 QContactManager::Error operationError = QContactManager::NoError;
801 QList<QContactRelationship> relationshipsToRemove = r->relationships();
802 QMap<int, QContactManager::Error> errorMap;
803
804 removeRelationships(relationships: r->relationships(), errorMap: &errorMap, error: &operationError);
805
806 if (!errorMap.isEmpty() || operationError != QContactManager::NoError)
807 updateRelationshipRemoveRequest(req: r, error: operationError, errorMap, QContactAbstractRequest::FinishedState);
808 else
809 updateRequestState(req: currentRequest, state: QContactAbstractRequest::FinishedState);
810 }
811 break;
812
813 case QContactAbstractRequest::RelationshipSaveRequest:
814 {
815 QContactRelationshipSaveRequest *r = static_cast<QContactRelationshipSaveRequest*>(currentRequest);
816 QContactManager::Error operationError = QContactManager::NoError;
817 QMap<int, QContactManager::Error> errorMap;
818 QList<QContactRelationship> requestRelationships = r->relationships();
819
820 saveRelationships(relationships: &requestRelationships, errorMap: &errorMap, error: &operationError);
821
822 // update the request with the results.
823 updateRelationshipSaveRequest(req: r, result: requestRelationships, error: operationError, errorMap, QContactAbstractRequest::FinishedState);
824 }
825 break;
826
827 case QContactAbstractRequest::CollectionFetchRequest:
828 {
829 QContactCollectionFetchRequest* r = static_cast<QContactCollectionFetchRequest*>(currentRequest);
830 QContactManager::Error operationError = QContactManager::NoError;
831 QList<QContactCollection> requestedContactCollections = collections(error: &operationError);
832
833 // update the request with the results.
834 updateCollectionFetchRequest(request: r, result: requestedContactCollections, error: operationError, newState: QContactAbstractRequest::FinishedState);
835 }
836 break;
837
838 case QContactAbstractRequest::CollectionSaveRequest:
839 {
840 QContactCollectionSaveRequest* r = static_cast<QContactCollectionSaveRequest*>(currentRequest);
841 QList<QContactCollection> collections = r->collections();
842 QList<QContactCollection> retn;
843
844 QContactManager::Error operationError = QContactManager::NoError;
845 QMap<int, QContactManager::Error> errorMap;
846 for (int i = 0; i < collections.size(); ++i) {
847 QContactManager::Error tempError = QContactManager::NoError;
848 QContactCollection curr = collections.at(i);
849 if (!saveCollection(collection: &curr, error: &tempError)) {
850 errorMap.insert(akey: i, avalue: tempError);
851 operationError = tempError;
852 }
853 retn.append(t: curr);
854 }
855
856 updateCollectionSaveRequest(request: r, result: retn, error: operationError, errorMap, newState: QContactAbstractRequest::FinishedState);
857 }
858 break;
859
860 case QContactAbstractRequest::CollectionRemoveRequest:
861 {
862 // removes the collections identified in the list of ids.
863 QContactCollectionRemoveRequest* r = static_cast<QContactCollectionRemoveRequest*>(currentRequest);
864 QContactManager::Error operationError = QContactManager::NoError;
865 QList<QContactCollectionId> collectionsToRemove = r->collectionIds();
866 QMap<int, QContactManager::Error> errorMap;
867
868 for (int i = 0; i < collectionsToRemove.size(); i++) {
869 QContactManager::Error tempError = QContactManager::NoError;
870 removeCollection(collectionId: collectionsToRemove.at(i), error: &tempError);
871
872 if (tempError != QContactManager::NoError) {
873 errorMap.insert(akey: i, avalue: tempError);
874 operationError = tempError;
875 }
876 }
877
878 if (!errorMap.isEmpty() || operationError != QContactManager::NoError)
879 updateCollectionRemoveRequest(request: r, error: operationError, errorMap, newState: QContactAbstractRequest::FinishedState);
880 else
881 updateRequestState(req: currentRequest, state: QContactAbstractRequest::FinishedState);
882 }
883 break;
884
885
886 default: // unknown request type.
887 break;
888 }
889
890 // now emit any signals we have to emit
891 d->emitSharedSignals(cs: &changeSet);
892}
893
894void QContactMemoryEngine::partiallySyncDetails(QContact *to, const QContact &from, const QList<QContactDetail::DetailType> &mask)
895{
896 // these details in old contact
897 QList<QContactDetail> fromDetails;
898 // these details in new contact
899 QList<QContactDetail> toDetails;
900 // Collect details that match mask
901 foreach (QContactDetail::DetailType type, mask) {
902 fromDetails.append(t: from.details(type));
903 toDetails.append(t: to->details(type));
904 }
905 // check details to remove
906 foreach (QContactDetail detail, toDetails) {
907 if (!fromDetails.contains(t: detail))
908 to->removeDetail(detail: &detail);
909 }
910 // check details to save
911 foreach (QContactDetail detail, fromDetails) {
912 if (!toDetails.contains(t: detail))
913 to->saveDetail(detail: &detail);
914 }
915}
916
917/*!
918 * \reimp
919 */
920bool QContactMemoryEngine::isRelationshipTypeSupported(const QString& relationshipType, QContactType::TypeValues contactType) const
921{
922 // the memory backend supports arbitrary relationship types
923 // but some relationship types don't make sense for groups or facets.
924 if (contactType == QContactType::TypeGroup || contactType == QContactType::TypeFacet) {
925 if (relationshipType == QContactRelationship::HasSpouse() || relationshipType == QContactRelationship::HasAssistant()) {
926 return false;
927 }
928
929 if (contactType == QContactType::TypeGroup) {
930 if (relationshipType == QContactRelationship::Aggregates())
931 return false;
932 } else {
933 if (relationshipType == QContactRelationship::HasMember())
934 return false;
935 }
936 }
937
938 // all other relationship types for all contact types are supported.
939 return true;
940}
941
942/*!
943 * \reimp
944 */
945QList<QVariant::Type> QContactMemoryEngine::supportedDataTypes() const
946{
947 QList<QVariant::Type> st;
948 st.append(t: QVariant::String);
949 st.append(t: QVariant::Date);
950 st.append(t: QVariant::DateTime);
951 st.append(t: QVariant::Time);
952 st.append(t: QVariant::Bool);
953 st.append(t: QVariant::Char);
954 st.append(t: QVariant::Int);
955 st.append(t: QVariant::UInt);
956 st.append(t: QVariant::LongLong);
957 st.append(t: QVariant::ULongLong);
958 st.append(t: QVariant::Double);
959
960 return st;
961}
962
963/*!
964 * The function returns true if the backend natively supports the given filter \a filter, otherwise false.
965 */
966bool QContactMemoryEngine::isFilterSupported(const QContactFilter &filter) const
967{
968 Q_UNUSED(filter);
969 // Until we add hashes for common stuff, fall back to slow code
970 return false;
971}
972
973bool QContactMemoryEngine::saveContacts(QList<QContact> *contacts, QMap<int, QContactManager::Error> *errorMap,
974 QContactManager::Error *error, const QList<QContactDetail::DetailType> &mask)
975{
976 if (!contacts) {
977 *error = QContactManager::BadArgumentError;
978 return false;
979 }
980
981 QContactChangeSet changeSet;
982 QContact current;
983 QContactManager::Error operationError = QContactManager::NoError;
984 for (int i = 0; i < contacts->count(); i++) {
985 current = contacts->at(i);
986 if (!saveContact(theContact: &current, changeSet, error, mask)) {
987 operationError = *error;
988 if (errorMap)
989 errorMap->insert(akey: i, avalue: operationError);
990 } else {
991 (*contacts)[i] = current;
992 }
993 }
994
995 *error = operationError;
996 d->emitSharedSignals(cs: &changeSet);
997 // return false if some error occurred
998 return (*error == QContactManager::NoError);
999}
1000
1001bool QContactMemoryEngine::saveContact(QContact *theContact, QContactChangeSet &changeSet,
1002 QContactManager::Error *error, const QList<QContactDetail::DetailType> &mask)
1003{
1004 // ensure that the contact's details conform to their definitions
1005 if (!validateContact(contact: *theContact, error)) {
1006 return false;
1007 }
1008
1009 QContactId id(theContact->id());
1010 if (!id.managerUri().isEmpty() && id.managerUri() != managerUri()) {
1011 // the contact doesn't belong to this manager
1012 *error = QContactManager::DoesNotExistError;
1013 return false;
1014 }
1015
1016 // check to see if this contact already exists
1017 int index = d->m_contactIds.indexOf(t: id);
1018 if (index != -1) {
1019 /* We also need to check that there are no modified create only details */
1020 QContact oldContact = d->m_contacts.at(i: index);
1021
1022 if (oldContact.type() != theContact->type()) {
1023 *error = QContactManager::AlreadyExistsError;
1024 return false;
1025 }
1026
1027 // check if this is partial save
1028 if (!mask.isEmpty()) {
1029 QContact tempContact = oldContact;
1030 partiallySyncDetails(to: &tempContact, from: *theContact, mask);
1031 *theContact = tempContact;
1032 }
1033
1034 QContactTimestamp ts = theContact->detail(type: QContactTimestamp::Type);
1035 ts.setLastModified(QDateTime::currentDateTime());
1036 QContactManagerEngine::setDetailAccessConstraints(detail: &ts, constraints: QContactDetail::ReadOnly | QContactDetail::Irremovable);
1037 theContact->saveDetail(detail: &ts);
1038
1039 // Looks ok, so continue
1040 d->m_contacts.replace(i: index, t: *theContact);
1041 changeSet.insertChangedContact(addedContactId: theContact->id(), typesChanged: mask);
1042 } else {
1043 // id does not exist; if not zero, fail.
1044 QContactId newId;
1045 if (theContact->id() != QContactId() && theContact->id() != newId) {
1046 // the ID is not empty, and it doesn't identify an existing contact in our database either.
1047 *error = QContactManager::DoesNotExistError;
1048 return false;
1049 }
1050
1051 // check the contact collection
1052 QContactCollectionId collectionId = theContact->collectionId();
1053 // if is null use default collection
1054 if (collectionId.isNull()) {
1055 collectionId = this->defaultCollectionId();
1056 theContact->setCollectionId(collectionId);
1057 } else {
1058 // check if the collection exists
1059 QContactCollection collection = this->collection(collectionId, error);
1060 if (collection.id().isNull()) {
1061 return false;
1062 }
1063 }
1064
1065 // check if this is partial save
1066 if (!mask.isEmpty()) {
1067 QContact tempContact;
1068 partiallySyncDetails(to: &tempContact, from: *theContact, mask);
1069 *theContact = tempContact;
1070 }
1071
1072 /* New contact */
1073 QContactTimestamp ts = theContact->detail(type: QContactTimestamp::Type);
1074 ts.setLastModified(QDateTime::currentDateTime());
1075 ts.setCreated(ts.lastModified());
1076 setDetailAccessConstraints(detail: &ts, constraints: QContactDetail::ReadOnly | QContactDetail::Irremovable);
1077 theContact->saveDetail(detail: &ts);
1078
1079 // update the contact item - set its ID
1080 QContactId newContactId = contactId(localId: QByteArray(reinterpret_cast<const char *>(&d->m_nextContactId), sizeof(quint32)));
1081 ++(d->m_nextContactId);
1082 theContact->setId(newContactId);
1083
1084 // finally, add the contact to our internal lists and return
1085 d->m_contacts.append(t: *theContact); // add contact to list
1086 d->m_contactIds.append(t: theContact->id()); // track the contact id.
1087 d->m_contactsInCollections.insert(akey: collectionId, avalue: newContactId); // link contact to collection
1088
1089 changeSet.insertAddedContact(addedContactId: theContact->id());
1090 }
1091
1092 *error = QContactManager::NoError; // successful.
1093 return true;
1094}
1095
1096#include "moc_qcontactmemorybackend_p.cpp"
1097
1098QT_END_NAMESPACE_CONTACTS
1099

source code of qtpim/src/plugins/contacts/memory/qcontactmemorybackend.cpp