~chris.gagnon/+junk/qtpim-coverage

« back to all changes in this revision

Viewing changes to src/plugins/contacts/memory/qcontactmemorybackend.cpp

  • Committer: chris.gagnon
  • Date: 2013-12-10 23:09:37 UTC
  • Revision ID: chris.gagnon@canonical.com-20131210230937-2akf1ft1edcttk87
first post

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
 
4
** Contact: http://www.qt-project.org/legal
 
5
**
 
6
** This file is part of the QtContacts module of the Qt Toolkit.
 
7
**
 
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.
 
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 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.
 
24
**
 
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.
 
28
**
 
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.
 
36
**
 
37
**
 
38
** $QT_END_LICENSE$
 
39
**
 
40
****************************************************************************/
 
41
 
 
42
#include "qcontactmanager.h"
 
43
 
 
44
#include <QContactManagerEngine>
 
45
#include <QContactAbstractRequest>
 
46
#include <QContactChangeSet>
 
47
#include <QContactTimestamp>
 
48
#include <QContactIdFilter>
 
49
#include <qcontactrequests.h>
 
50
#include "qcontactmemorybackend_p.h"
 
51
 
 
52
#include <QtCore/qdebug.h>
 
53
#include <QtCore/qstringbuilder.h>
 
54
#include <QtCore/quuid.h>
 
55
 
 
56
QT_BEGIN_NAMESPACE_CONTACTS
 
57
 
 
58
QContactManagerEngine* QContactMemoryEngineFactory::engine(const QMap<QString, QString> &parameters, QContactManager::Error *error)
 
59
{
 
60
    Q_UNUSED(error);
 
61
 
 
62
    QContactMemoryEngine *ret = QContactMemoryEngine::createMemoryEngine(parameters);
 
63
    return ret;
 
64
}
 
65
 
 
66
 
 
67
QContactEngineId* QContactMemoryEngineFactory::createContactEngineId(const QMap<QString, QString> &parameters, const QString &engineIdString) const
 
68
{
 
69
    Q_UNUSED(parameters);
 
70
    QContactMemoryEngineId *retn = new QContactMemoryEngineId(parameters, engineIdString);
 
71
    return retn;
 
72
}
 
73
 
 
74
QString QContactMemoryEngineFactory::managerName() const
 
75
{
 
76
    return QString::fromLatin1("memory");
 
77
}
 
78
 
 
79
/*!
 
80
  \class QContactMemoryEngine
 
81
 
 
82
  \inmodule QtContacts
 
83
 
 
84
  \brief The QContactMemoryEngine class provides an in-memory implementation
 
85
  of a contacts backend.
 
86
 
 
87
  \internal
 
88
 
 
89
  It may be used as a reference implementation, or when persistent storage is not required.
 
90
 
 
91
  During construction, it will load the in-memory data associated with the memory store
 
92
  identified by the "id" parameter from the given parameters if it exists, or a new,
 
93
  anonymous store if it does not.
 
94
 
 
95
  Data stored in this engine is only available in the current process.
 
96
 
 
97
  This engine supports sharing, so an internal reference count is increased
 
98
  whenever a manager uses this backend, and is decreased when the manager
 
99
  no longer requires this engine.
 
100
 */
 
101
 
 
102
/* static data for manager class */
 
103
QMap<QString, QContactMemoryEngineData*> QContactMemoryEngine::engineDatas;
 
104
 
 
105
/*!
 
106
 * Factory function for creating a new in-memory backend, based
 
107
 * on the given \a parameters.
 
108
 *
 
109
 * The same engine will be returned for multiple calls with the
 
110
 * same value for the "id" parameter, while one of them is in scope.
 
111
 */
 
112
QContactMemoryEngine* QContactMemoryEngine::createMemoryEngine(const QMap<QString, QString> &parameters)
 
113
{
 
114
    bool anonymous = false;
 
115
    QString idValue = parameters.value(QStringLiteral("id"));
 
116
    if (idValue.isNull() || idValue.isEmpty()) {
 
117
        // no store given?  new, anonymous store.
 
118
        idValue = QUuid::createUuid().toString();
 
119
        anonymous = true;
 
120
    }
 
121
 
 
122
    QContactMemoryEngineData *data = engineDatas.value(idValue);
 
123
    if (data) {
 
124
        data->m_refCount.ref();
 
125
    } else {
 
126
        data = new QContactMemoryEngineData();
 
127
        data->m_id = idValue;
 
128
        data->m_anonymous = anonymous;
 
129
        engineDatas.insert(idValue, data);
 
130
    }
 
131
    return new QContactMemoryEngine(data);
 
132
}
 
133
 
 
134
/*!
 
135
 * Constructs a new in-memory backend which shares the given \a data with
 
136
 * other shared memory engines.
 
137
 */
 
138
QContactMemoryEngine::QContactMemoryEngine(QContactMemoryEngineData *data)
 
139
    : d(data)
 
140
{
 
141
    qRegisterMetaType<QContactAbstractRequest::State>("QContactAbstractRequest::State");
 
142
    qRegisterMetaType<QList<QContactId> >("QList<QContactId>");
 
143
    qRegisterMetaType<QContactId>("QContactId");
 
144
    d->m_managerUri = managerUri();
 
145
    d->m_sharedEngines.append(this);
 
146
}
 
147
 
 
148
/*! Frees any memory used by this engine */
 
149
QContactMemoryEngine::~QContactMemoryEngine()
 
150
{
 
151
    d->m_sharedEngines.removeAll(this);
 
152
    if (!d->m_refCount.deref()) {
 
153
        engineDatas.remove(d->m_id);
 
154
        delete d;
 
155
    }
 
156
}
 
157
 
 
158
/*! \reimp */
 
159
QString QContactMemoryEngine::managerName() const
 
160
{
 
161
    return QStringLiteral("memory");
 
162
}
 
163
 
 
164
/*! \reimp */
 
165
QMap<QString, QString> QContactMemoryEngine::managerParameters() const
 
166
{
 
167
    QMap<QString, QString> params;
 
168
    params.insert(QStringLiteral("id"), d->m_id);
 
169
    return params;
 
170
}
 
171
 
 
172
/*! \reimp */
 
173
bool QContactMemoryEngine::setSelfContactId(const QContactId &contactId, QContactManager::Error *error)
 
174
{
 
175
    if (contactId.isNull() || d->m_contactIds.contains(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(&changeSet);
 
183
        return true;
 
184
    }
 
185
 
 
186
    *error = QContactManager::DoesNotExistError;
 
187
    return false;
 
188
}
 
189
 
 
190
/*! \reimp */
 
191
QContactId 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 */
 
200
QContact 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(contactId);
 
204
    if (index != -1) {
 
205
        // found the contact successfully.
 
206
        *error = QContactManager::NoError;
 
207
        return d->m_contacts.at(index);
 
208
    }
 
209
 
 
210
    *error = QContactManager::DoesNotExistError;
 
211
    return QContact();
 
212
}
 
213
 
 
214
/*! \reimp */
 
215
QList<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, QContactFetchHint(), error);
 
222
 
 
223
        /* Extract the ids */
 
224
        QList<QContactId> ids;
 
225
        foreach (const QContact &c, clist)
 
226
            ids.append(c.id());
 
227
 
 
228
        return ids;
 
229
    }
 
230
}
 
231
 
 
232
/*! \reimp */
 
233
QList<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,c, sortOrders);
 
244
        }
 
245
    } else {
 
246
        foreach(const QContact&c, d->m_contacts) {
 
247
            if (QContactManagerEngine::testFilter(filter, c))
 
248
                QContactManagerEngine::addSorted(&sorted,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
*/
 
259
bool QContactMemoryEngine::saveContact(QContact *theContact, QContactChangeSet &changeSet, QContactManager::Error *error)
 
260
{
 
261
    return saveContact(theContact, changeSet, error, QList<QContactDetail::DetailType>());
 
262
}
 
263
 
 
264
/*! \reimp */
 
265
bool QContactMemoryEngine::saveContacts(QList<QContact> *contacts, QMap<int, QContactManager::Error> *errorMap, QContactManager::Error *error)
 
266
{
 
267
    return saveContacts(contacts, errorMap, error, 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
*/
 
274
bool QContactMemoryEngine::removeContact(const QContactId &contactId, QContactChangeSet &changeSet, QContactManager::Error *error)
 
275
{
 
276
    int index = d->m_contactIds.indexOf(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(index);
 
285
    QList<QContactRelationship> allRelationships = relationships(QString(), thisContact, 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(allRelationships, 0, error);
 
294
 
 
295
    // having cleaned up the relationships, remove the contact from the lists.
 
296
    d->m_contacts.removeAt(index);
 
297
    d->m_contactIds.removeAt(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(contactId);
 
307
    return true;
 
308
}
 
309
 
 
310
/*! \reimp */
 
311
bool 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(current, changeSet, error)) {
 
324
            operationError = *error;
 
325
            if (errorMap)
 
326
                errorMap->insert(i, operationError);
 
327
        }
 
328
    }
 
329
 
 
330
    *error = operationError;
 
331
    d->emitSharedSignals(&changeSet);
 
332
    // return false if some errors occurred
 
333
    return (*error == QContactManager::NoError);
 
334
}
 
335
 
 
336
/*! \reimp */
 
337
QList<QContactRelationship> QContactMemoryEngine::relationships(const QString &relationshipType, const QContact &participant, QContactRelationship::Role role, QContactManager::Error *error) const
 
338
{
 
339
    QContact defaultContact;
 
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 (participant == defaultContact) {
 
350
            retn.append(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() == participant) {
 
356
            retn.append(curr);
 
357
        } else if (role == QContactRelationship::Second && curr.second() == participant) {
 
358
            retn.append(curr);
 
359
        } else if (role == QContactRelationship::Either && (curr.first() == participant || curr.second() == participant)) {
 
360
            retn.append(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
*/
 
374
bool 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(relationship->first().id());
 
380
    if ((!relationship->first().id().managerUri().isEmpty() && relationship->first().id().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
    QContact dest = relationship->second();
 
388
    int secondContactIndex = d->m_contactIds.indexOf(dest.id());
 
389
 
 
390
    if (dest.id().managerUri().isEmpty() || dest.id().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.id() == relationship->first().id()) {
 
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.id().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(relationship->first().id());
 
419
    QList<QContactRelationship> secondRelationships = d->m_orderedRelationships.value(relationship->second().id());
 
420
    firstRelationships.append(*relationship);
 
421
    secondRelationships.append(*relationship);
 
422
    d->m_orderedRelationships.insert(relationship->first().id(), firstRelationships);
 
423
    d->m_orderedRelationships.insert(relationship->second().id(), secondRelationships);
 
424
    changeSet.insertAddedRelationshipsContact(relationship->first().id());
 
425
    changeSet.insertAddedRelationshipsContact(relationship->second().id());
 
426
 
 
427
    // update the contacts involved
 
428
    QContactManagerEngine::setContactRelationships(&d->m_contacts[firstContactIndex], firstRelationships);
 
429
    QContactManagerEngine::setContactRelationships(&d->m_contacts[secondContactIndex], secondRelationships);
 
430
 
 
431
    // finally, insert into our list of all relationships, and return.
 
432
    d->m_relationships.append(*relationship);
 
433
    return true;
 
434
}
 
435
 
 
436
/*! \reimp */
 
437
bool 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(&curr, changeSet, &functionError);
 
446
        if (functionError != QContactManager::NoError && errorMap)
 
447
            errorMap->insert(i, functionError);
 
448
 
 
449
        // and replace the current relationship with the updated version.
 
450
        relationships->replace(i, 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(&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
*/
 
465
bool 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(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(relationship.first().id());
 
475
    QList<QContactRelationship> secondRelationships = d->m_orderedRelationships.value(relationship.second().id());
 
476
    firstRelationships.removeOne(relationship);
 
477
    secondRelationships.removeOne(relationship);
 
478
    d->m_orderedRelationships.insert(relationship.first().id(), firstRelationships);
 
479
    d->m_orderedRelationships.insert(relationship.second().id(), secondRelationships);
 
480
 
 
481
    // Update the contacts as well
 
482
    int firstContactIndex = d->m_contactIds.indexOf(relationship.first().id());
 
483
    int secondContactIndex = relationship.second().id().managerUri() == managerUri() ? d->m_contactIds.indexOf(relationship.second().id()) : -1;
 
484
    if (firstContactIndex != -1)
 
485
        QContactMemoryEngine::setContactRelationships(&d->m_contacts[firstContactIndex], firstRelationships);
 
486
    if (secondContactIndex != -1)
 
487
        QContactMemoryEngine::setContactRelationships(&d->m_contacts[secondContactIndex], secondRelationships);
 
488
 
 
489
    // set our changes, and return.
 
490
    changeSet.insertRemovedRelationshipsContact(relationship.first().id());
 
491
    changeSet.insertRemovedRelationshipsContact(relationship.second().id());
 
492
    *error = QContactManager::NoError;
 
493
    return true;
 
494
}
 
495
 
 
496
/*! \reimp */
 
497
bool 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(relationships.at(i), cs, &functionError);
 
503
 
 
504
        // update the total error if it did not succeed.
 
505
        if (functionError != QContactManager::NoError) {
 
506
            if (errorMap)
 
507
                errorMap->insert(i, functionError);
 
508
            *error = functionError;
 
509
        }
 
510
    }
 
511
 
 
512
    d->emitSharedSignals(&cs);
 
513
    return (*error == QContactManager::NoError);
 
514
}
 
515
 
 
516
/*! \reimp */
 
517
void QContactMemoryEngine::requestDestroyed(QContactAbstractRequest *req)
 
518
{
 
519
    Q_UNUSED(req);
 
520
}
 
521
 
 
522
/*! \reimp */
 
523
bool QContactMemoryEngine::startRequest(QContactAbstractRequest *req)
 
524
{
 
525
    if (!req)
 
526
        return false;
 
527
 
 
528
    QPointer<QContactAbstractRequest> checkDeletion(req);
 
529
    updateRequestState(req, QContactAbstractRequest::ActiveState);
 
530
    if (!checkDeletion.isNull())
 
531
        performAsynchronousOperation(req);
 
532
 
 
533
    return true;
 
534
}
 
535
 
 
536
bool QContactMemoryEngine::cancelRequest(QContactAbstractRequest *req)
 
537
{
 
538
    Q_UNUSED(req); // we can't cancel since we complete immediately
 
539
    return false;
 
540
}
 
541
 
 
542
/*! \reimp */
 
543
bool QContactMemoryEngine::waitForRequestFinished(QContactAbstractRequest *req, int msecs)
 
544
{
 
545
    // in our implementation, we always complete any operation we start.
 
546
    Q_UNUSED(msecs);
 
547
    Q_UNUSED(req);
 
548
 
 
549
    return true;
 
550
}
 
551
 
 
552
/*!
 
553
 * This slot is called some time after an asynchronous request is started.
 
554
 * It performs the required operation, sets the result and returns.
 
555
 */
 
556
void QContactMemoryEngine::performAsynchronousOperation(QContactAbstractRequest *currentRequest)
 
557
{
 
558
    // store up changes, and emit signals once at the end of the (possibly batch) operation.
 
559
    QContactChangeSet changeSet;
 
560
 
 
561
    // Now perform the active request and emit required signals.
 
562
    Q_ASSERT(currentRequest->state() == QContactAbstractRequest::ActiveState);
 
563
    switch (currentRequest->type()) {
 
564
        case QContactAbstractRequest::ContactFetchRequest:
 
565
        {
 
566
            QContactFetchRequest *r = static_cast<QContactFetchRequest*>(currentRequest);
 
567
            QContactFilter filter = r->filter();
 
568
            QList<QContactSortOrder> sorting = r->sorting();
 
569
            QContactFetchHint fetchHint = r->fetchHint();
 
570
 
 
571
            QContactManager::Error operationError = QContactManager::NoError;
 
572
            QList<QContact> requestedContacts = contacts(filter, sorting, fetchHint, &operationError);
 
573
 
 
574
            // update the request with the results.
 
575
            if (!requestedContacts.isEmpty() || operationError != QContactManager::NoError)
 
576
                updateContactFetchRequest(r, requestedContacts, operationError, QContactAbstractRequest::FinishedState);
 
577
            else
 
578
                updateRequestState(currentRequest, QContactAbstractRequest::FinishedState);
 
579
        }
 
580
        break;
 
581
 
 
582
        case QContactAbstractRequest::ContactFetchByIdRequest:
 
583
        {
 
584
            QContactFetchByIdRequest *r = static_cast<QContactFetchByIdRequest*>(currentRequest);
 
585
            QContactIdFilter idFilter;
 
586
            idFilter.setIds(r->contactIds());
 
587
            QList<QContactSortOrder> sorting;
 
588
            QContactFetchHint fetchHint = r->fetchHint();
 
589
            QContactManager::Error error = QContactManager::NoError;
 
590
            QList<QContact> requestedContacts = contacts(idFilter, sorting, fetchHint, &error);
 
591
            // Build an index into the results
 
592
            QHash<QContactId, int> idMap; // value is index into unsorted
 
593
            if (error == QContactManager::NoError) {
 
594
                for (int i = 0; i < requestedContacts.size(); i++) {
 
595
                    idMap.insert(requestedContacts[i].id(), i);
 
596
                }
 
597
            }
 
598
            // Find the order in which the results should be presented
 
599
            // Build up the results and errors
 
600
            QList<QContact> results;
 
601
            QMap<int, QContactManager::Error> errorMap;
 
602
            int index = 0;
 
603
            foreach (const QContactId &id, r->contactIds()) {
 
604
                if (!idMap.contains(id)) {
 
605
                    errorMap.insert(index, QContactManager::DoesNotExistError);
 
606
                    error = QContactManager::DoesNotExistError;
 
607
                    results.append(QContact());
 
608
                } else {
 
609
                    results.append(requestedContacts[idMap[id]]);
 
610
                }
 
611
                index++;
 
612
            }
 
613
 
 
614
            // update the request with the results.
 
615
            if (!requestedContacts.isEmpty() || error != QContactManager::NoError)
 
616
                QContactManagerEngine::updateContactFetchByIdRequest(r, results, error, errorMap, QContactAbstractRequest::FinishedState);
 
617
            else
 
618
                updateRequestState(currentRequest, QContactAbstractRequest::FinishedState);
 
619
        }
 
620
        break;
 
621
 
 
622
        case QContactAbstractRequest::ContactIdFetchRequest:
 
623
        {
 
624
            QContactIdFetchRequest *r = static_cast<QContactIdFetchRequest*>(currentRequest);
 
625
            QContactFilter filter = r->filter();
 
626
            QList<QContactSortOrder> sorting = r->sorting();
 
627
 
 
628
            QContactManager::Error operationError = QContactManager::NoError;
 
629
            QList<QContactId> requestedContactIds = contactIds(filter, sorting, &operationError);
 
630
 
 
631
            if (!requestedContactIds.isEmpty() || operationError != QContactManager::NoError)
 
632
                updateContactIdFetchRequest(r, requestedContactIds, operationError, QContactAbstractRequest::FinishedState);
 
633
            else
 
634
                updateRequestState(currentRequest, QContactAbstractRequest::FinishedState);
 
635
        }
 
636
        break;
 
637
 
 
638
        case QContactAbstractRequest::ContactSaveRequest:
 
639
        {
 
640
            QContactSaveRequest *r = static_cast<QContactSaveRequest*>(currentRequest);
 
641
            QList<QContact> contacts = r->contacts();
 
642
 
 
643
            QContactManager::Error operationError = QContactManager::NoError;
 
644
            QMap<int, QContactManager::Error> errorMap;
 
645
            saveContacts(&contacts, &errorMap, &operationError, r->typeMask());
 
646
 
 
647
            updateContactSaveRequest(r, contacts, operationError, errorMap, QContactAbstractRequest::FinishedState);
 
648
        }
 
649
        break;
 
650
 
 
651
        case QContactAbstractRequest::ContactRemoveRequest:
 
652
        {
 
653
            // this implementation provides scant information to the user
 
654
            // the operation either succeeds (all contacts matching the filter were removed)
 
655
            // or it fails (one or more contacts matching the filter could not be removed)
 
656
            // if a failure occurred, the request error will be set to the most recent
 
657
            // error that occurred during the remove operation.
 
658
            QContactRemoveRequest *r = static_cast<QContactRemoveRequest*>(currentRequest);
 
659
            QContactManager::Error operationError = QContactManager::NoError;
 
660
            QList<QContactId> contactsToRemove = r->contactIds();
 
661
            QMap<int, QContactManager::Error> errorMap;
 
662
 
 
663
            for (int i = 0; i < contactsToRemove.size(); i++) {
 
664
                QContactManager::Error tempError;
 
665
                removeContact(contactsToRemove.at(i), changeSet, &tempError);
 
666
 
 
667
                if (tempError != QContactManager::NoError) {
 
668
                    errorMap.insert(i, tempError);
 
669
                    operationError = tempError;
 
670
                }
 
671
            }
 
672
 
 
673
            if (!errorMap.isEmpty() || operationError != QContactManager::NoError)
 
674
                updateContactRemoveRequest(r, operationError, errorMap, QContactAbstractRequest::FinishedState);
 
675
            else
 
676
                updateRequestState(currentRequest, QContactAbstractRequest::FinishedState);
 
677
        }
 
678
        break;
 
679
 
 
680
        case QContactAbstractRequest::RelationshipFetchRequest:
 
681
        {
 
682
            QContactRelationshipFetchRequest *r = static_cast<QContactRelationshipFetchRequest*>(currentRequest);
 
683
            QContactManager::Error operationError = QContactManager::NoError;
 
684
            QList<QContactManager::Error> operationErrors;
 
685
            QList<QContactRelationship> allRelationships = relationships(QString(), QContact(), QContactRelationship::Either, &operationError);
 
686
            QList<QContactRelationship> requestedRelationships;
 
687
 
 
688
            // select the requested relationships.
 
689
            for (int i = 0; i < allRelationships.size(); i++) {
 
690
                QContactRelationship currRel = allRelationships.at(i);
 
691
                if (r->first() != QContact() && r->first() != currRel.first())
 
692
                    continue;
 
693
                if (r->second() != QContact() && r->second() != currRel.second())
 
694
                    continue;
 
695
                if (!r->relationshipType().isEmpty() && r->relationshipType() != currRel.relationshipType())
 
696
                    continue;
 
697
                requestedRelationships.append(currRel);
 
698
            }
 
699
 
 
700
            // update the request with the results.
 
701
            if (!requestedRelationships.isEmpty() || operationError != QContactManager::NoError)
 
702
                updateRelationshipFetchRequest(r, requestedRelationships, operationError, QContactAbstractRequest::FinishedState);
 
703
            else
 
704
                updateRequestState(currentRequest, QContactAbstractRequest::FinishedState);
 
705
        }
 
706
        break;
 
707
 
 
708
        case QContactAbstractRequest::RelationshipRemoveRequest:
 
709
        {
 
710
            QContactRelationshipRemoveRequest *r = static_cast<QContactRelationshipRemoveRequest*>(currentRequest);
 
711
            QContactManager::Error operationError = QContactManager::NoError;
 
712
            QList<QContactRelationship> relationshipsToRemove = r->relationships();
 
713
            QMap<int, QContactManager::Error> errorMap;
 
714
 
 
715
            removeRelationships(r->relationships(), &errorMap, &operationError);
 
716
 
 
717
            if (!errorMap.isEmpty() || operationError != QContactManager::NoError)
 
718
                updateRelationshipRemoveRequest(r, operationError, errorMap, QContactAbstractRequest::FinishedState);
 
719
            else
 
720
                updateRequestState(currentRequest, QContactAbstractRequest::FinishedState);
 
721
        }
 
722
        break;
 
723
 
 
724
        case QContactAbstractRequest::RelationshipSaveRequest:
 
725
        {
 
726
            QContactRelationshipSaveRequest *r = static_cast<QContactRelationshipSaveRequest*>(currentRequest);
 
727
            QContactManager::Error operationError = QContactManager::NoError;
 
728
            QMap<int, QContactManager::Error> errorMap;
 
729
            QList<QContactRelationship> requestRelationships = r->relationships();
 
730
 
 
731
            saveRelationships(&requestRelationships, &errorMap, &operationError);
 
732
 
 
733
            // update the request with the results.
 
734
            updateRelationshipSaveRequest(r, requestRelationships, operationError, errorMap, QContactAbstractRequest::FinishedState);
 
735
        }
 
736
        break;
 
737
 
 
738
        default: // unknown request type.
 
739
        break;
 
740
    }
 
741
 
 
742
    // now emit any signals we have to emit
 
743
    d->emitSharedSignals(&changeSet);
 
744
}
 
745
 
 
746
void QContactMemoryEngine::partiallySyncDetails(QContact *to, const QContact &from, const QList<QContactDetail::DetailType> &mask)
 
747
{
 
748
    // these details in old contact
 
749
    QList<QContactDetail> fromDetails;
 
750
    // these details in new contact
 
751
    QList<QContactDetail> toDetails;
 
752
    // Collect details that match mask
 
753
    foreach (QContactDetail::DetailType type, mask) {
 
754
        fromDetails.append(from.details(type));
 
755
        toDetails.append(to->details(type));
 
756
    }
 
757
    // check details to remove
 
758
    foreach (QContactDetail detail, toDetails) {
 
759
        if (!fromDetails.contains(detail))
 
760
            to->removeDetail(&detail);
 
761
    }
 
762
    // check details to save
 
763
    foreach (QContactDetail detail, fromDetails) {
 
764
        if (!toDetails.contains(detail))
 
765
            to->saveDetail(&detail);
 
766
    }
 
767
}
 
768
 
 
769
/*!
 
770
 * \reimp
 
771
 */
 
772
bool QContactMemoryEngine::isRelationshipTypeSupported(const QString& relationshipType, QContactType::TypeValues contactType) const
 
773
{
 
774
    // the memory backend supports arbitrary relationship types
 
775
    // but some relationship types don't make sense for groups.
 
776
    if (contactType == QContactType::TypeGroup) {
 
777
        if (relationshipType == QContactRelationship::HasSpouse() || relationshipType == QContactRelationship::HasAssistant()) {
 
778
            return false;
 
779
        }
 
780
    }
 
781
 
 
782
    // all other relationship types for all contact types are supported.
 
783
    return true;
 
784
}
 
785
 
 
786
/*!
 
787
 * \reimp
 
788
 */
 
789
QList<QVariant::Type> QContactMemoryEngine::supportedDataTypes() const
 
790
{
 
791
    QList<QVariant::Type> st;
 
792
    st.append(QVariant::String);
 
793
    st.append(QVariant::Date);
 
794
    st.append(QVariant::DateTime);
 
795
    st.append(QVariant::Time);
 
796
    st.append(QVariant::Bool);
 
797
    st.append(QVariant::Char);
 
798
    st.append(QVariant::Int);
 
799
    st.append(QVariant::UInt);
 
800
    st.append(QVariant::LongLong);
 
801
    st.append(QVariant::ULongLong);
 
802
    st.append(QVariant::Double);
 
803
 
 
804
    return st;
 
805
}
 
806
 
 
807
/*!
 
808
 * The function returns true if the backend natively supports the given filter \a filter, otherwise false.
 
809
 */
 
810
bool QContactMemoryEngine::isFilterSupported(const QContactFilter &filter) const
 
811
{
 
812
    Q_UNUSED(filter);
 
813
    // Until we add hashes for common stuff, fall back to slow code
 
814
    return false;
 
815
}
 
816
 
 
817
bool QContactMemoryEngine::saveContacts(QList<QContact> *contacts, QMap<int, QContactManager::Error> *errorMap,
 
818
                                        QContactManager::Error *error, const QList<QContactDetail::DetailType> &mask)
 
819
{
 
820
    if (!contacts) {
 
821
        *error = QContactManager::BadArgumentError;
 
822
        return false;
 
823
    }
 
824
 
 
825
    QContactChangeSet changeSet;
 
826
    QContact current;
 
827
    QContactManager::Error operationError = QContactManager::NoError;
 
828
    for (int i = 0; i < contacts->count(); i++) {
 
829
        current = contacts->at(i);
 
830
        if (!saveContact(&current, changeSet, error, mask)) {
 
831
            operationError = *error;
 
832
            if (errorMap)
 
833
                errorMap->insert(i, operationError);
 
834
        } else {
 
835
            (*contacts)[i] = current;
 
836
        }
 
837
    }
 
838
 
 
839
    *error = operationError;
 
840
    d->emitSharedSignals(&changeSet);
 
841
    // return false if some error occurred
 
842
    return (*error == QContactManager::NoError);
 
843
}
 
844
 
 
845
bool QContactMemoryEngine::saveContact(QContact *theContact, QContactChangeSet &changeSet,
 
846
                                       QContactManager::Error *error, const QList<QContactDetail::DetailType> &mask)
 
847
{
 
848
    // ensure that the contact's details conform to their definitions
 
849
    if (!validateContact(*theContact, error)) {
 
850
        return false;
 
851
    }
 
852
 
 
853
    QContactId id(theContact->id());
 
854
    if (!id.managerUri().isEmpty() && id.managerUri() != managerUri()) {
 
855
        // the contact doesn't belong to this manager
 
856
        *error = QContactManager::DoesNotExistError;
 
857
        return false;
 
858
    }
 
859
 
 
860
    // check to see if this contact already exists
 
861
    int index = d->m_contactIds.indexOf(id);
 
862
    if (index != -1) {
 
863
        /* We also need to check that there are no modified create only details */
 
864
        QContact oldContact = d->m_contacts.at(index);
 
865
 
 
866
        if (oldContact.type() != theContact->type()) {
 
867
            *error = QContactManager::AlreadyExistsError;
 
868
            return false;
 
869
        }
 
870
 
 
871
        // check if this is partial save
 
872
        if (!mask.isEmpty()) {
 
873
            QContact tempContact = oldContact;
 
874
            partiallySyncDetails(&tempContact, *theContact, mask);
 
875
            *theContact = tempContact;
 
876
        }
 
877
 
 
878
        QContactTimestamp ts = theContact->detail(QContactTimestamp::Type);
 
879
        ts.setLastModified(QDateTime::currentDateTime());
 
880
        QContactManagerEngine::setDetailAccessConstraints(&ts, QContactDetail::ReadOnly | QContactDetail::Irremovable);
 
881
        theContact->saveDetail(&ts);
 
882
 
 
883
        // Looks ok, so continue
 
884
        d->m_contacts.replace(index, *theContact);
 
885
        changeSet.insertChangedContact(theContact->id());
 
886
    } else {
 
887
        // id does not exist; if not zero, fail.
 
888
        QContactId newId;
 
889
        if (theContact->id() != QContactId() && theContact->id() != newId) {
 
890
            // the ID is not empty, and it doesn't identify an existing contact in our database either.
 
891
            *error = QContactManager::DoesNotExistError;
 
892
            return false;
 
893
        }
 
894
 
 
895
        // check if this is partial save
 
896
        if (!mask.isEmpty()) {
 
897
            QContact tempContact;
 
898
            partiallySyncDetails(&tempContact, *theContact, mask);
 
899
            *theContact = tempContact;
 
900
        }
 
901
 
 
902
        /* New contact */
 
903
        QContactTimestamp ts = theContact->detail(QContactTimestamp::Type);
 
904
        ts.setLastModified(QDateTime::currentDateTime());
 
905
        ts.setCreated(ts.lastModified());
 
906
        setDetailAccessConstraints(&ts, QContactDetail::ReadOnly | QContactDetail::Irremovable);
 
907
        theContact->saveDetail(&ts);
 
908
 
 
909
        // update the contact item - set its ID
 
910
        quint32 nextContactId = d->m_nextContactId; // don't increment the persistent version until we're successful or we know it collides.
 
911
        nextContactId += 1; // but do increment the temporary version to check for collision
 
912
        QContactMemoryEngineId *newMemoryEngineId = new QContactMemoryEngineId;
 
913
        newMemoryEngineId->m_contactId = nextContactId;
 
914
        newMemoryEngineId->m_managerUri = d->m_managerUri;
 
915
        QContactId newContactId = QContactId(newMemoryEngineId);
 
916
        theContact->setId(newContactId);
 
917
 
 
918
        // note: do NOT delete the QContactMemoryEngineId -- the QContactId ctor takes ownership of it.
 
919
 
 
920
 
 
921
        // finally, add the contact to our internal lists and return
 
922
        d->m_contacts.append(*theContact);                   // add contact to list
 
923
        d->m_contactIds.append(theContact->id());  // track the contact id.
 
924
 
 
925
        changeSet.insertAddedContact(theContact->id());
 
926
        // successful, now increment the persistent version of the next item id.
 
927
        d->m_nextContactId += 1;
 
928
    }
 
929
 
 
930
    *error = QContactManager::NoError;     // successful.
 
931
    return true;
 
932
}
 
933
 
 
934
/*!
 
935
  \class QContactMemoryEngineId
 
936
  \brief The QContactMemoryEngineId class provides an id which uniquely identifies
 
937
  a QContact stored within a QContactMemoryEngine.
 
938
 
 
939
  \internal
 
940
  It may be used as a reference implementation, although since different platforms
 
941
  have different semantics for ids
 
942
  the precise implementation required may differ.
 
943
 */
 
944
QContactMemoryEngineId::QContactMemoryEngineId()
 
945
    : QContactEngineId(), m_contactId(0)
 
946
{
 
947
}
 
948
 
 
949
QContactMemoryEngineId::QContactMemoryEngineId(quint32 contactId, const QString &managerUri)
 
950
    : QContactEngineId(), m_contactId(contactId), m_managerUri(managerUri)
 
951
{
 
952
}
 
953
 
 
954
QContactMemoryEngineId::~QContactMemoryEngineId()
 
955
{
 
956
}
 
957
 
 
958
QContactMemoryEngineId::QContactMemoryEngineId(const QContactMemoryEngineId &other)
 
959
    : QContactEngineId(), m_contactId(other.m_contactId), m_managerUri(other.m_managerUri)
 
960
{
 
961
}
 
962
 
 
963
QContactMemoryEngineId::QContactMemoryEngineId(const QMap<QString, QString> &parameters, const QString &engineIdString)
 
964
    : QContactEngineId()
 
965
{
 
966
    m_contactId = engineIdString.toInt();
 
967
    m_managerUri = QContactManager::buildUri("memory", parameters);
 
968
}
 
969
 
 
970
bool QContactMemoryEngineId::isEqualTo(const QContactEngineId *other) const
 
971
{
 
972
    if (m_contactId != static_cast<const QContactMemoryEngineId*>(other)->m_contactId)
 
973
        return false;
 
974
    return true;
 
975
}
 
976
 
 
977
bool QContactMemoryEngineId::isLessThan(const QContactEngineId *other) const
 
978
{
 
979
    const QContactMemoryEngineId *otherPtr = static_cast<const QContactMemoryEngineId*>(other);
 
980
    if (m_managerUri < otherPtr->m_managerUri)
 
981
        return true;
 
982
    if (m_contactId < otherPtr->m_contactId)
 
983
        return true;
 
984
    return false;
 
985
}
 
986
 
 
987
QString QContactMemoryEngineId::managerUri() const
 
988
{
 
989
    return m_managerUri;
 
990
}
 
991
 
 
992
QString QContactMemoryEngineId::toString() const
 
993
{
 
994
    return QString::number(m_contactId);
 
995
}
 
996
 
 
997
QContactEngineId* QContactMemoryEngineId::clone() const
 
998
{
 
999
    return new QContactMemoryEngineId(m_contactId, m_managerUri);
 
1000
}
 
1001
 
 
1002
#ifndef QT_NO_DEBUG_STREAM
 
1003
QDebug& QContactMemoryEngineId::debugStreamOut(QDebug &dbg) const
 
1004
{
 
1005
    dbg.nospace() << "QContactMemoryEngineId(" << m_managerUri << "," << m_contactId << ")";
 
1006
    return dbg.maybeSpace();
 
1007
}
 
1008
#endif
 
1009
 
 
1010
uint QContactMemoryEngineId::hash() const
 
1011
{
 
1012
    return m_contactId;
 
1013
}
 
1014
 
 
1015
 
 
1016
#include "moc_qcontactmemorybackend_p.cpp"
 
1017
 
 
1018
QT_END_NAMESPACE_CONTACTS
 
1019