1
/****************************************************************************
3
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4
** Contact: http://www.qt-project.org/legal
6
** This file is part of the QtContacts module of the Qt Toolkit.
8
** $QT_BEGIN_LICENSE:LGPL$
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 Digia. For licensing terms and
14
** conditions see http://qt.digia.com/licensing. For further information
15
** use the contact form at http://qt.digia.com/contact-us.
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 as published by the Free Software
20
** Foundation and appearing in the file LICENSE.LGPL included in the
21
** packaging of this file. Please review the following information to
22
** ensure the GNU Lesser General Public License version 2.1 requirements
23
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25
** In addition, as a special exception, Digia gives you certain additional
26
** rights. These rights are described in the Digia Qt LGPL Exception
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29
** GNU General Public License Usage
30
** Alternatively, this file may be used under the terms of the GNU
31
** General Public License version 3.0 as published by the Free Software
32
** Foundation and appearing in the file LICENSE.GPL included in the
33
** packaging of this file. Please review the following information to
34
** ensure the GNU General Public License version 3.0 requirements will be
35
** met: http://www.gnu.org/copyleft/gpl.html.
40
****************************************************************************/
42
#include "qcontactmemorybackend_p.h"
44
#ifndef QT_NO_DEBUG_STREAM
45
#include <QtCore/qdebug.h>
47
#include <QtCore/qpointer.h>
48
#include <QtCore/qstringbuilder.h>
49
#include <QtCore/quuid.h>
51
#include <QtContacts/qcontactidfilter.h>
52
#include <QtContacts/qcontactrequests.h>
53
#include <QtContacts/qcontacttimestamp.h>
54
#include <QtContacts/qcontactextendeddetail.h>
55
#include <QtContacts/qcontactchangelogfilter.h>
56
#include <QtContacts/qcontactintersectionfilter.h>
57
#include <QtContacts/qcontactunionfilter.h>
58
#include <QtContacts/qcontacttimestamp.h>
60
#define ENGINE_NAME "mock"
61
#define X_DELETED_AT "X-DELETED-AT"
63
QT_BEGIN_NAMESPACE_CONTACTS
65
QContactManagerEngine* QContactMemoryEngineFactory::engine(const QMap<QString, QString> ¶meters, QContactManager::Error *error)
69
QContactMemoryEngine *ret = QContactMemoryEngine::createMemoryEngine(parameters);
74
QContactEngineId* QContactMemoryEngineFactory::createContactEngineId(const QMap<QString, QString> ¶meters, const QString &engineIdString) const
77
QContactMemoryEngineId *retn = new QContactMemoryEngineId(parameters, engineIdString);
81
QString QContactMemoryEngineFactory::managerName() const
83
return QString::fromLatin1(ENGINE_NAME);
87
\class QContactMemoryEngine
91
\brief The QContactMemoryEngine class provides an in-memory implementation
92
of a contacts backend.
96
It may be used as a reference implementation, or when persistent storage is not required.
98
During construction, it will load the in-memory data associated with the memory store
99
identified by the "id" parameter from the given parameters if it exists, or a new,
100
anonymous store if it does not.
102
Data stored in this engine is only available in the current process.
104
This engine supports sharing, so an internal reference count is increased
105
whenever a manager uses this backend, and is decreased when the manager
106
no longer requires this engine.
109
/* static data for manager class */
110
QMap<QString, QContactMemoryEngineData*> QContactMemoryEngine::engineDatas;
113
* Factory function for creating a new in-memory backend, based
114
* on the given \a parameters.
116
* The same engine will be returned for multiple calls with the
117
* same value for the "id" parameter, while one of them is in scope.
119
QContactMemoryEngine* QContactMemoryEngine::createMemoryEngine(const QMap<QString, QString> ¶meters)
121
bool anonymous = false;
122
QString idValue = parameters.value(QStringLiteral("id"));
123
if (idValue.isNull() || idValue.isEmpty()) {
124
// no store given? new, anonymous store.
125
idValue = "mock"; //QUuid::createUuid().toString();
129
QContactMemoryEngineData *data = engineDatas.value(idValue);
131
data->m_refCount.ref();
133
data = new QContactMemoryEngineData();
134
data->m_id = idValue;
135
data->m_anonymous = anonymous;
136
engineDatas.insert(idValue, data);
138
return new QContactMemoryEngine(data);
142
* Constructs a new in-memory backend which shares the given \a data with
143
* other shared memory engines.
145
QContactMemoryEngine::QContactMemoryEngine(QContactMemoryEngineData *data)
148
qRegisterMetaType<QContactAbstractRequest::State>("QContactAbstractRequest::State");
149
qRegisterMetaType<QList<QContactId> >("QList<QContactId>");
150
qRegisterMetaType<QContactId>("QContactId");
151
d->m_managerUri = managerUri();
152
d->m_sharedEngines.append(this);
155
/*! Frees any memory used by this engine */
156
QContactMemoryEngine::~QContactMemoryEngine()
158
d->m_sharedEngines.removeAll(this);
159
if (!d->m_refCount.deref()) {
160
engineDatas.remove(d->m_id);
166
QString QContactMemoryEngine::managerName() const
168
return QStringLiteral(ENGINE_NAME);
172
QMap<QString, QString> QContactMemoryEngine::managerParameters() const
174
QMap<QString, QString> params;
175
params.insert(QStringLiteral("id"), d->m_id);
180
bool QContactMemoryEngine::setSelfContactId(const QContactId &contactId, QContactManager::Error *error)
182
if (contactId.isNull() || d->m_contactIds.contains(contactId)) {
183
*error = QContactManager::NoError;
184
QContactId oldId = d->m_selfContactId;
185
d->m_selfContactId = contactId;
187
QContactChangeSet changeSet;
188
changeSet.setOldAndNewSelfContactId(QPair<QContactId, QContactId>(oldId, contactId));
189
d->emitSharedSignals(&changeSet);
193
*error = QContactManager::DoesNotExistError;
198
QContactId QContactMemoryEngine::selfContactId(QContactManager::Error *error) const
200
*error = QContactManager::DoesNotExistError;
201
if (!d->m_selfContactId.isNull())
202
*error = QContactManager::NoError;
203
return d->m_selfContactId;
207
QContact QContactMemoryEngine::contact(const QContactId &contactId, const QContactFetchHint &fetchHint, QContactManager::Error *error) const
209
Q_UNUSED(fetchHint); // no optimizations are possible in the memory backend; ignore the fetch hint.
210
int index = d->m_contactIds.indexOf(contactId);
212
// found the contact successfully.
213
*error = QContactManager::NoError;
214
return d->m_contacts.at(index);
217
*error = QContactManager::DoesNotExistError;
222
QList<QContactId> QContactMemoryEngine::contactIds(const QContactFilter &filter, const QList<QContactSortOrder> &sortOrders, QContactManager::Error *error) const
224
QList<QContact> clist = contacts(filter, sortOrders, QContactFetchHint(), error);
226
/* Extract the ids */
227
QList<QContactId> ids;
228
foreach (const QContact &c, clist)
234
bool QContactMemoryEngine::testDeletedContact(const QContactFilter &filter,
235
const QContact &contact,
236
const QDateTime &deletedAt) const
238
switch(filter.type()) {
239
case QContactFilter::ChangeLogFilter:
241
const QContactChangeLogFilter bf(filter);
242
if (bf.eventType() == QContactChangeLogFilter::EventRemoved) {
243
return (deletedAt >= bf.since());
247
case QContactFilter::IdFilter:
249
const QContactIdFilter idF(filter);
250
return (idF.ids().contains(contact.id()));
252
case QContactFilter::IntersectionFilter:
254
const QContactIntersectionFilter bf(filter);
255
const QList<QContactFilter>& terms = bf.filters();
256
if (terms.count() > 0) {
257
bool changeLogResult = false;
258
for(int j = 0; j < terms.count(); j++) {
259
if (terms.at(j).type() == QContactFilter::ChangeLogFilter) {
260
changeLogResult = testDeletedContact(terms.at(j), contact, deletedAt);
261
} else if (!QContactManagerEngine::testFilter(terms.at(j), contact)) {
265
return changeLogResult;
269
case QContactFilter::UnionFilter:
271
return QContactManagerEngine::testFilter(filter, contact);
280
QList<QContact> QContactMemoryEngine::contacts(const QContactFilter &filter, const QList<QContactSortOrder> &sortOrders, const QContactFetchHint &fetchHint, QContactManager::Error *error) const
282
Q_UNUSED(fetchHint); // no optimizations are possible in the memory backend; ignore the fetch hint.
285
QList<QContact> sorted;
287
/* First filter out contacts - check for default filter first */
288
if (filter.type() == QContactFilter::DefaultFilter) {
289
foreach(const QContact&c, d->m_contacts) {
290
if (!deleted(c).isValid())
291
QContactManagerEngine::addSorted(&sorted,c, sortOrders);
294
foreach(const QContact&c, d->m_contacts) {
295
QDateTime deletedAt = deleted(c);
296
if (deletedAt.isValid() && testDeletedContact(filter, c, deletedAt))
297
QContactManagerEngine::addSorted(&sorted,c, sortOrders);
298
else if (!deletedAt.isValid() && QContactManagerEngine::testFilter(filter, c))
299
QContactManagerEngine::addSorted(&sorted,c, sortOrders);
306
/*! Saves the given contact \a theContact, storing any error to \a error and
307
filling the \a changeSet with ids of changed contacts as required
308
Returns true if the operation was successful otherwise false.
310
bool QContactMemoryEngine::saveContact(QContact *theContact, QContactChangeSet &changeSet, QContactManager::Error *error)
312
return saveContact(theContact, changeSet, error, QList<QContactDetail::DetailType>());
316
bool QContactMemoryEngine::saveContacts(QList<QContact> *contacts, QMap<int, QContactManager::Error> *errorMap, QContactManager::Error *error)
318
return saveContacts(contacts, errorMap, error, QList<QContactDetail::DetailType>());
321
/*! Removes the contact identified by the given \a contactId, storing any error to \a error and
322
filling the \a changeSet with ids of changed contacts and relationships as required.
323
Returns true if the operation was successful otherwise false.
325
bool QContactMemoryEngine::removeContact(const QContactId &contactId, QContactChangeSet &changeSet, QContactManager::Error *error)
327
int index = d->m_contactIds.indexOf(contactId);
330
*error = QContactManager::DoesNotExistError;
334
// remove the contact from any relationships it was in.
335
QContact thisContact = d->m_contacts.at(index);
336
QList<QContactRelationship> allRelationships = relationships(QString(), thisContact, QContactRelationship::Either, error);
337
if (*error != QContactManager::NoError && *error != QContactManager::DoesNotExistError) {
338
*error = QContactManager::UnspecifiedError; // failed to clean up relationships
342
// this is meant to be a transaction, so if any of these fail, we're in BIG TROUBLE.
343
// a real backend will use DBMS transactions to ensure database integrity.
344
removeRelationships(allRelationships, 0, error);
347
// having cleaned up the relationships, remove the contact from the lists.
348
d->m_contacts.removeAt(index);
349
d->m_contactIds.removeAt(index);
351
QContact &c = d->m_contacts[index];
352
QContactExtendedDetail removedAt;
353
foreach(QContactExtendedDetail d, c.details<QContactExtendedDetail>()) {
354
if (d.name() == X_DELETED_AT) {
359
if (removedAt.isEmpty()) {
360
removedAt.setName(X_DELETED_AT);
362
removedAt.setData(currentDateTime());
363
c.saveDetail(&removedAt);
366
*error = QContactManager::NoError;
368
// and if it was the self contact, reset the self contact id
369
if (contactId == d->m_selfContactId) {
370
d->m_selfContactId = QContactId();
371
changeSet.setOldAndNewSelfContactId(QPair<QContactId, QContactId>(contactId, QContactId()));
374
changeSet.insertRemovedContact(contactId);
379
bool QContactMemoryEngine::removeContacts(const QList<QContactId> &contactIds, QMap<int, QContactManager::Error> *errorMap, QContactManager::Error *error)
381
if (contactIds.count() == 0) {
382
*error = QContactManager::BadArgumentError;
386
QContactChangeSet changeSet;
388
QContactManager::Error operationError = QContactManager::NoError;
389
for (int i = 0; i < contactIds.count(); i++) {
390
current = contactIds.at(i);
391
if (!removeContact(current, changeSet, error)) {
392
operationError = *error;
394
errorMap->insert(i, operationError);
398
*error = operationError;
399
d->emitSharedSignals(&changeSet);
400
// return false if some errors occurred
401
return (*error == QContactManager::NoError);
405
QList<QContactRelationship> QContactMemoryEngine::relationships(const QString &relationshipType, const QContact &participant, QContactRelationship::Role role, QContactManager::Error *error) const
407
QContact defaultContact;
408
QList<QContactRelationship> retn;
409
for (int i = 0; i < d->m_relationships.size(); i++) {
410
QContactRelationship curr = d->m_relationships.at(i);
412
// check that the relationship type matches
413
if (curr.relationshipType() != relationshipType && !relationshipType.isEmpty())
416
// if the participantId argument is default constructed, then the relationship matches.
417
if (participant == defaultContact) {
422
// otherwise, check that the participant exists and plays the required role in the relationship.
423
if (role == QContactRelationship::First && curr.first() == participant) {
425
} else if (role == QContactRelationship::Second && curr.second() == participant) {
427
} else if (role == QContactRelationship::Either && (curr.first() == participant || curr.second() == participant)) {
432
*error = QContactManager::NoError;
434
*error = QContactManager::DoesNotExistError;
438
/*! Saves the given relationship \a relationship, storing any error to \a error and
439
filling the \a changeSet with ids of changed contacts and relationships as required
440
Returns true if the operation was successful otherwise false.
442
bool QContactMemoryEngine::saveRelationship(QContactRelationship *relationship, QContactChangeSet &changeSet, QContactManager::Error *error)
444
// Attempt to validate the relationship.
445
// first, check that the source contact exists and is in this manager.
446
QString myUri = managerUri();
447
int firstContactIndex = d->m_contactIds.indexOf(relationship->first().id());
448
if ((!relationship->first().id().managerUri().isEmpty() && relationship->first().id().managerUri() != myUri)
449
||firstContactIndex == -1) {
450
*error = QContactManager::InvalidRelationshipError;
454
// second, check that the second contact exists (if it's local); we cannot check other managers' contacts.
455
QContact dest = relationship->second();
456
int secondContactIndex = d->m_contactIds.indexOf(dest.id());
458
if (dest.id().managerUri().isEmpty() || dest.id().managerUri() == myUri) {
459
// this entry in the destination list is supposedly stored in this manager.
460
// check that it exists, and that it isn't the source contact (circular)
461
if (secondContactIndex == -1 || dest.id() == relationship->first().id()) {
462
*error = QContactManager::InvalidRelationshipError;
467
// the relationship is valid. We need to update the manager URIs in the second contact if it is empty to our URI.
468
if (dest.id().managerUri().isEmpty()) {
469
// need to update the URI
470
relationship->setSecond(dest);
473
// check to see if the relationship already exists in the database. If so, replace.
474
// We do this because we don't want duplicates in our lists / maps of relationships.
475
*error = QContactManager::NoError;
476
QList<QContactRelationship> allRelationships = d->m_relationships;
477
for (int i = 0; i < allRelationships.size(); i++) {
478
QContactRelationship curr = allRelationships.at(i);
479
if (curr == *relationship) {
481
// TODO: set error to AlreadyExistsError and return false?
485
// no matching relationship; must be new. append it to lists in our map of relationships where required.
486
QList<QContactRelationship> firstRelationships = d->m_orderedRelationships.value(relationship->first().id());
487
QList<QContactRelationship> secondRelationships = d->m_orderedRelationships.value(relationship->second().id());
488
firstRelationships.append(*relationship);
489
secondRelationships.append(*relationship);
490
d->m_orderedRelationships.insert(relationship->first().id(), firstRelationships);
491
d->m_orderedRelationships.insert(relationship->second().id(), secondRelationships);
492
changeSet.insertAddedRelationshipsContact(relationship->first().id());
493
changeSet.insertAddedRelationshipsContact(relationship->second().id());
495
// update the contacts involved
496
QContactManagerEngine::setContactRelationships(&d->m_contacts[firstContactIndex], firstRelationships);
497
QContactManagerEngine::setContactRelationships(&d->m_contacts[secondContactIndex], secondRelationships);
499
// finally, insert into our list of all relationships, and return.
500
d->m_relationships.append(*relationship);
505
bool QContactMemoryEngine::saveRelationships(QList<QContactRelationship> *relationships, QMap<int, QContactManager::Error> *errorMap, QContactManager::Error *error)
507
*error = QContactManager::NoError;
508
QContactManager::Error functionError;
509
QContactChangeSet changeSet;
511
for (int i = 0; i < relationships->size(); i++) {
512
QContactRelationship curr = relationships->at(i);
513
saveRelationship(&curr, changeSet, &functionError);
514
if (functionError != QContactManager::NoError && errorMap)
515
errorMap->insert(i, functionError);
517
// and replace the current relationship with the updated version.
518
relationships->replace(i, curr);
520
// also, update the total error if it did not succeed.
521
if (functionError != QContactManager::NoError)
522
*error = functionError;
525
d->emitSharedSignals(&changeSet);
526
return (*error == QContactManager::NoError);
529
/*! Removes the given relationship \a relationship, storing any error to \a error and
530
filling the \a changeSet with ids of changed contacts and relationships as required
531
Returns true if the operation was successful otherwise false.
533
bool QContactMemoryEngine::removeRelationship(const QContactRelationship &relationship, QContactChangeSet &changeSet, QContactManager::Error *error)
535
// attempt to remove it from our list of relationships.
536
if (!d->m_relationships.removeOne(relationship)) {
537
*error = QContactManager::DoesNotExistError;
541
// if that worked, then we need to remove it from the two locations in our map, also.
542
QList<QContactRelationship> firstRelationships = d->m_orderedRelationships.value(relationship.first().id());
543
QList<QContactRelationship> secondRelationships = d->m_orderedRelationships.value(relationship.second().id());
544
firstRelationships.removeOne(relationship);
545
secondRelationships.removeOne(relationship);
546
d->m_orderedRelationships.insert(relationship.first().id(), firstRelationships);
547
d->m_orderedRelationships.insert(relationship.second().id(), secondRelationships);
549
// Update the contacts as well
550
int firstContactIndex = d->m_contactIds.indexOf(relationship.first().id());
551
int secondContactIndex = relationship.second().id().managerUri() == managerUri() ? d->m_contactIds.indexOf(relationship.second().id()) : -1;
552
if (firstContactIndex != -1)
553
QContactMemoryEngine::setContactRelationships(&d->m_contacts[firstContactIndex], firstRelationships);
554
if (secondContactIndex != -1)
555
QContactMemoryEngine::setContactRelationships(&d->m_contacts[secondContactIndex], secondRelationships);
557
// set our changes, and return.
558
changeSet.insertRemovedRelationshipsContact(relationship.first().id());
559
changeSet.insertRemovedRelationshipsContact(relationship.second().id());
560
*error = QContactManager::NoError;
565
bool QContactMemoryEngine::removeRelationships(const QList<QContactRelationship> &relationships, QMap<int, QContactManager::Error> *errorMap, QContactManager::Error *error)
567
QContactManager::Error functionError;
568
QContactChangeSet cs;
569
for (int i = 0; i < relationships.size(); i++) {
570
removeRelationship(relationships.at(i), cs, &functionError);
572
// update the total error if it did not succeed.
573
if (functionError != QContactManager::NoError) {
575
errorMap->insert(i, functionError);
576
*error = functionError;
580
d->emitSharedSignals(&cs);
581
return (*error == QContactManager::NoError);
585
void QContactMemoryEngine::requestDestroyed(QContactAbstractRequest *req)
591
bool QContactMemoryEngine::startRequest(QContactAbstractRequest *req)
593
updateRequestState(req, QContactAbstractRequest::ActiveState);
594
performAsynchronousOperation(req);
599
bool QContactMemoryEngine::cancelRequest(QContactAbstractRequest *req)
601
Q_UNUSED(req); // we can't cancel since we complete immediately
606
bool QContactMemoryEngine::waitForRequestFinished(QContactAbstractRequest *req, int msecs)
608
// in our implementation, we always complete any operation we start.
616
* This slot is called some time after an asynchronous request is started.
617
* It performs the required operation, sets the result and returns.
619
void QContactMemoryEngine::performAsynchronousOperation(QContactAbstractRequest *currentRequest)
621
// store up changes, and emit signals once at the end of the (possibly batch) operation.
622
QContactChangeSet changeSet;
624
// Now perform the active request and emit required signals.
625
Q_ASSERT(currentRequest->state() == QContactAbstractRequest::ActiveState);
626
switch (currentRequest->type()) {
627
case QContactAbstractRequest::ContactFetchRequest:
629
QContactFetchRequest *r = static_cast<QContactFetchRequest*>(currentRequest);
630
QContactFilter filter = r->filter();
631
QList<QContactSortOrder> sorting = r->sorting();
632
QContactFetchHint fetchHint = r->fetchHint();
634
QContactManager::Error operationError = QContactManager::NoError;
635
QList<QContact> requestedContacts = contacts(filter, sorting, fetchHint, &operationError);
637
// update the request with the results.
638
if (!requestedContacts.isEmpty() || operationError != QContactManager::NoError)
639
updateContactFetchRequest(r, requestedContacts, operationError, QContactAbstractRequest::FinishedState);
641
updateRequestState(currentRequest, QContactAbstractRequest::FinishedState);
645
case QContactAbstractRequest::ContactFetchByIdRequest:
647
QContactFetchByIdRequest *r = static_cast<QContactFetchByIdRequest*>(currentRequest);
648
QContactIdFilter idFilter;
649
idFilter.setIds(r->contactIds());
650
QList<QContactSortOrder> sorting;
651
QContactFetchHint fetchHint = r->fetchHint();
652
QContactManager::Error error = QContactManager::NoError;
653
QList<QContact> requestedContacts = contacts(idFilter, sorting, fetchHint, &error);
654
// Build an index into the results
655
QHash<QContactId, int> idMap; // value is index into unsorted
656
if (error == QContactManager::NoError) {
657
for (int i = 0; i < requestedContacts.size(); i++) {
658
idMap.insert(requestedContacts[i].id(), i);
661
// Find the order in which the results should be presented
662
// Build up the results and errors
663
QList<QContact> results;
664
QMap<int, QContactManager::Error> errorMap;
666
foreach (const QContactId &id, r->contactIds()) {
667
if (!idMap.contains(id)) {
668
errorMap.insert(index, QContactManager::DoesNotExistError);
669
error = QContactManager::DoesNotExistError;
670
results.append(QContact());
672
results.append(requestedContacts[idMap[id]]);
677
// update the request with the results.
678
if (!requestedContacts.isEmpty() || error != QContactManager::NoError)
679
QContactManagerEngine::updateContactFetchByIdRequest(r, results, error, errorMap, QContactAbstractRequest::FinishedState);
681
updateRequestState(currentRequest, QContactAbstractRequest::FinishedState);
685
case QContactAbstractRequest::ContactIdFetchRequest:
687
QContactIdFetchRequest *r = static_cast<QContactIdFetchRequest*>(currentRequest);
688
QContactFilter filter = r->filter();
689
QList<QContactSortOrder> sorting = r->sorting();
691
QContactManager::Error operationError = QContactManager::NoError;
692
QList<QContactId> requestedContactIds = contactIds(filter, sorting, &operationError);
694
if (!requestedContactIds.isEmpty() || operationError != QContactManager::NoError)
695
updateContactIdFetchRequest(r, requestedContactIds, operationError, QContactAbstractRequest::FinishedState);
697
updateRequestState(currentRequest, QContactAbstractRequest::FinishedState);
701
case QContactAbstractRequest::ContactSaveRequest:
703
QContactSaveRequest *r = static_cast<QContactSaveRequest*>(currentRequest);
704
QList<QContact> contacts = r->contacts();
706
QContactManager::Error operationError = QContactManager::NoError;
707
QMap<int, QContactManager::Error> errorMap;
708
saveContacts(&contacts, &errorMap, &operationError, r->typeMask());
710
updateContactSaveRequest(r, contacts, operationError, errorMap, QContactAbstractRequest::FinishedState);
714
case QContactAbstractRequest::ContactRemoveRequest:
716
// this implementation provides scant information to the user
717
// the operation either succeeds (all contacts matching the filter were removed)
718
// or it fails (one or more contacts matching the filter could not be removed)
719
// if a failure occurred, the request error will be set to the most recent
720
// error that occurred during the remove operation.
721
QContactRemoveRequest *r = static_cast<QContactRemoveRequest*>(currentRequest);
722
QContactManager::Error operationError = QContactManager::NoError;
723
QList<QContactId> contactsToRemove = r->contactIds();
724
QMap<int, QContactManager::Error> errorMap;
726
for (int i = 0; i < contactsToRemove.size(); i++) {
727
QContactManager::Error tempError;
728
removeContact(contactsToRemove.at(i), changeSet, &tempError);
730
if (tempError != QContactManager::NoError) {
731
errorMap.insert(i, tempError);
732
operationError = tempError;
736
if (!errorMap.isEmpty() || operationError != QContactManager::NoError)
737
updateContactRemoveRequest(r, operationError, errorMap, QContactAbstractRequest::FinishedState);
739
updateRequestState(currentRequest, QContactAbstractRequest::FinishedState);
743
case QContactAbstractRequest::RelationshipFetchRequest:
745
QContactRelationshipFetchRequest *r = static_cast<QContactRelationshipFetchRequest*>(currentRequest);
746
QContactManager::Error operationError = QContactManager::NoError;
747
QList<QContactManager::Error> operationErrors;
748
QList<QContactRelationship> allRelationships = relationships(QString(), QContact(), QContactRelationship::Either, &operationError);
749
QList<QContactRelationship> requestedRelationships;
751
// select the requested relationships.
752
for (int i = 0; i < allRelationships.size(); i++) {
753
QContactRelationship currRel = allRelationships.at(i);
754
if (r->first() != QContact() && r->first() != currRel.first())
756
if (r->second() != QContact() && r->second() != currRel.second())
758
if (!r->relationshipType().isEmpty() && r->relationshipType() != currRel.relationshipType())
760
requestedRelationships.append(currRel);
763
// update the request with the results.
764
if (!requestedRelationships.isEmpty() || operationError != QContactManager::NoError)
765
updateRelationshipFetchRequest(r, requestedRelationships, operationError, QContactAbstractRequest::FinishedState);
767
updateRequestState(currentRequest, QContactAbstractRequest::FinishedState);
771
case QContactAbstractRequest::RelationshipRemoveRequest:
773
QContactRelationshipRemoveRequest *r = static_cast<QContactRelationshipRemoveRequest*>(currentRequest);
774
QContactManager::Error operationError = QContactManager::NoError;
775
QList<QContactRelationship> relationshipsToRemove = r->relationships();
776
QMap<int, QContactManager::Error> errorMap;
778
removeRelationships(r->relationships(), &errorMap, &operationError);
780
if (!errorMap.isEmpty() || operationError != QContactManager::NoError)
781
updateRelationshipRemoveRequest(r, operationError, errorMap, QContactAbstractRequest::FinishedState);
783
updateRequestState(currentRequest, QContactAbstractRequest::FinishedState);
787
case QContactAbstractRequest::RelationshipSaveRequest:
789
QContactRelationshipSaveRequest *r = static_cast<QContactRelationshipSaveRequest*>(currentRequest);
790
QContactManager::Error operationError = QContactManager::NoError;
791
QMap<int, QContactManager::Error> errorMap;
792
QList<QContactRelationship> requestRelationships = r->relationships();
794
saveRelationships(&requestRelationships, &errorMap, &operationError);
796
// update the request with the results.
797
updateRelationshipSaveRequest(r, requestRelationships, operationError, errorMap, QContactAbstractRequest::FinishedState);
801
default: // unknown request type.
805
// now emit any signals we have to emit
806
d->emitSharedSignals(&changeSet);
809
QDateTime QContactMemoryEngine::deleted(const QContact &c) const
811
foreach(const QContactExtendedDetail &xd, c.details<QContactExtendedDetail>()) {
812
if (xd.name() == X_DELETED_AT) {
813
return xd.data().toDateTime();
819
QDateTime QContactMemoryEngine::currentDateTime() const
821
QDateTime dateTime = property("CURRENT_DATE_TIME").toDateTime();
822
if (dateTime.isValid()) {
825
return QDateTime::currentDateTime();
829
void QContactMemoryEngine::partiallySyncDetails(QContact *to, const QContact &from, const QList<QContactDetail::DetailType> &mask)
831
// these details in old contact
832
QList<QContactDetail> fromDetails;
833
// these details in new contact
834
QList<QContactDetail> toDetails;
835
// Collect details that match mask
836
foreach (QContactDetail::DetailType type, mask) {
837
fromDetails.append(from.details(type));
838
toDetails.append(to->details(type));
840
// check details to remove
841
foreach (QContactDetail detail, toDetails) {
842
if (!fromDetails.contains(detail))
843
to->removeDetail(&detail);
845
// check details to save
846
foreach (QContactDetail detail, fromDetails) {
847
if (!toDetails.contains(detail))
848
to->saveDetail(&detail);
855
bool QContactMemoryEngine::isRelationshipTypeSupported(const QString& relationshipType, QContactType::TypeValues contactType) const
857
// the memory backend supports arbitrary relationship types
858
// but some relationship types don't make sense for groups.
859
if (contactType == QContactType::TypeGroup) {
860
if (relationshipType == QContactRelationship::HasSpouse() || relationshipType == QContactRelationship::HasAssistant()) {
865
// all other relationship types for all contact types are supported.
872
QList<QVariant::Type> QContactMemoryEngine::supportedDataTypes() const
874
QList<QVariant::Type> st;
875
st.append(QVariant::String);
876
st.append(QVariant::Date);
877
st.append(QVariant::DateTime);
878
st.append(QVariant::Time);
879
st.append(QVariant::Bool);
880
st.append(QVariant::Char);
881
st.append(QVariant::Int);
882
st.append(QVariant::UInt);
883
st.append(QVariant::LongLong);
884
st.append(QVariant::ULongLong);
885
st.append(QVariant::Double);
891
* The function returns true if the backend natively supports the given filter \a filter, otherwise false.
893
bool QContactMemoryEngine::isFilterSupported(const QContactFilter &filter) const
896
// Until we add hashes for common stuff, fall back to slow code
900
bool QContactMemoryEngine::saveContacts(QList<QContact> *contacts, QMap<int, QContactManager::Error> *errorMap,
901
QContactManager::Error *error, const QList<QContactDetail::DetailType> &mask)
904
*error = QContactManager::BadArgumentError;
908
QContactChangeSet changeSet;
910
QContactManager::Error operationError = QContactManager::NoError;
911
for (int i = 0; i < contacts->count(); i++) {
912
current = contacts->at(i);
913
if (!saveContact(¤t, changeSet, error, mask)) {
914
operationError = *error;
916
errorMap->insert(i, operationError);
918
(*contacts)[i] = current;
922
*error = operationError;
923
d->emitSharedSignals(&changeSet);
924
// return false if some error occurred
925
return (*error == QContactManager::NoError);
928
bool QContactMemoryEngine::saveContact(QContact *theContact, QContactChangeSet &changeSet,
929
QContactManager::Error *error, const QList<QContactDetail::DetailType> &mask)
931
// ensure that the contact's details conform to their definitions
932
if (!validateContact(*theContact, error)) {
936
QContactId id(theContact->id());
937
if (!id.managerUri().isEmpty() && id.managerUri() != managerUri()) {
938
// the contact doesn't belong to this manager
939
*error = QContactManager::DoesNotExistError;
943
// check to see if this contact already exists
944
int index = d->m_contactIds.indexOf(id);
946
/* We also need to check that there are no modified create only details */
947
QContact oldContact = d->m_contacts.at(index);
949
if (oldContact.type() != theContact->type()) {
950
*error = QContactManager::AlreadyExistsError;
954
// check if this is partial save
955
if (!mask.isEmpty()) {
956
QContact tempContact = oldContact;
957
partiallySyncDetails(&tempContact, *theContact, mask);
958
*theContact = tempContact;
961
// Keep the value from contact
962
// ===========================
963
// QContactTimestamp ts = theContact->detail(QContactTimestamp::Type);
964
// ts.setLastModified(QDateTime::currentDateTime());
965
// QContactManagerEngine::setDetailAccessConstraints(&ts, QContactDetail::ReadOnly | QContactDetail::Irremovable);
966
// theContact->saveDetail(&ts);
968
// Looks ok, so continue
969
d->m_contacts.replace(index, *theContact);
970
changeSet.insertChangedContact(theContact->id());
972
// id does not exist; if not zero, fail.
974
if (theContact->id() != QContactId() && theContact->id() != newId) {
975
// the ID is not empty, and it doesn't identify an existing contact in our database either.
976
*error = QContactManager::DoesNotExistError;
980
// check if this is partial save
981
if (!mask.isEmpty()) {
982
QContact tempContact;
983
partiallySyncDetails(&tempContact, *theContact, mask);
984
*theContact = tempContact;
988
// Keep the value from contact
989
// ===========================
990
// QContactTimestamp ts = theContact->detail(QContactTimestamp::Type);
991
// ts.setLastModified(QDateTime::currentDateTime());
992
// ts.setCreated(ts.lastModified());
993
// setDetailAccessConstraints(&ts, QContactDetail::ReadOnly | QContactDetail::Irremovable);
994
// theContact->saveDetail(&ts);
996
// update the contact item - set its ID
997
quint32 nextContactId = d->m_nextContactId; // don't increment the persistent version until we're successful or we know it collides.
998
nextContactId += 1; // but do increment the temporary version to check for collision
999
QContactMemoryEngineId *newMemoryEngineId = new QContactMemoryEngineId;
1000
newMemoryEngineId->m_contactId = nextContactId;
1001
newMemoryEngineId->m_managerUri = d->m_managerUri;
1002
QContactId newContactId = QContactId(newMemoryEngineId);
1003
theContact->setId(newContactId);
1005
// note: do NOT delete the QContactMemoryEngineId -- the QContactId ctor takes ownership of it.
1008
// finally, add the contact to our internal lists and return
1009
d->m_contacts.append(*theContact); // add contact to list
1010
d->m_contactIds.append(theContact->id()); // track the contact id.
1012
changeSet.insertAddedContact(theContact->id());
1013
// successful, now increment the persistent version of the next item id.
1014
d->m_nextContactId += 1;
1017
*error = QContactManager::NoError; // successful.
1022
\class QContactMemoryEngineId
1023
\brief The QContactMemoryEngineId class provides an id which uniquely identifies
1024
a QContact stored within a QContactMemoryEngine.
1027
It may be used as a reference implementation, although since different platforms
1028
have different semantics for ids
1029
the precise implementation required may differ.
1031
QContactMemoryEngineId::QContactMemoryEngineId()
1032
: QContactEngineId(), m_contactId(0)
1036
QContactMemoryEngineId::QContactMemoryEngineId(quint32 contactId, const QString &managerUri)
1037
: QContactEngineId(), m_contactId(contactId), m_managerUri(managerUri)
1041
QContactMemoryEngineId::~QContactMemoryEngineId()
1045
QContactMemoryEngineId::QContactMemoryEngineId(const QContactMemoryEngineId &other)
1046
: QContactEngineId(), m_contactId(other.m_contactId), m_managerUri(other.m_managerUri)
1050
QContactMemoryEngineId::QContactMemoryEngineId(const QMap<QString, QString> ¶meters, const QString &engineIdString)
1051
: QContactEngineId()
1053
m_contactId = engineIdString.toInt();
1054
m_managerUri = QContactManager::buildUri(ENGINE_NAME, parameters);
1057
bool QContactMemoryEngineId::isEqualTo(const QContactEngineId *other) const
1059
if (m_contactId != static_cast<const QContactMemoryEngineId*>(other)->m_contactId)
1064
bool QContactMemoryEngineId::isLessThan(const QContactEngineId *other) const
1066
const QContactMemoryEngineId *otherPtr = static_cast<const QContactMemoryEngineId*>(other);
1067
if (m_managerUri < otherPtr->m_managerUri)
1069
if (m_contactId < otherPtr->m_contactId)
1074
QString QContactMemoryEngineId::managerUri() const
1076
return m_managerUri;
1079
QString QContactMemoryEngineId::toString() const
1081
return QString::number(m_contactId);
1084
QContactEngineId* QContactMemoryEngineId::clone() const
1086
return new QContactMemoryEngineId(m_contactId, m_managerUri);
1089
#ifndef QT_NO_DEBUG_STREAM
1090
QDebug& QContactMemoryEngineId::debugStreamOut(QDebug &dbg) const
1092
dbg.nospace() << "QContactMemoryEngineId(" << m_managerUri << "," << m_contactId << ")";
1093
return dbg.maybeSpace();
1097
uint QContactMemoryEngineId::hash() const
1102
#include "moc_qcontactmemorybackend_p.cpp"
1104
QT_END_NAMESPACE_CONTACTS