| 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 |  | 
| 47 | QT_BEGIN_NAMESPACE_CONTACTS | 
| 48 |  | 
| 49 | QContactManagerEngine* QContactMemoryEngineFactory::engine(const QMap<QString, QString> ¶meters, QContactManager::Error *error) | 
| 50 | { | 
| 51 |     Q_UNUSED(error); | 
| 52 |  | 
| 53 |     QContactMemoryEngine *ret = QContactMemoryEngine::createMemoryEngine(parameters); | 
| 54 |     return ret; | 
| 55 | } | 
| 56 |  | 
| 57 | QString 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 */ | 
| 86 | QMap<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 |  */ | 
| 95 | QContactMemoryEngine* QContactMemoryEngine::createMemoryEngine(const QMap<QString, QString> ¶meters) | 
| 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 |  */ | 
| 121 | QContactMemoryEngine::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 */ | 
| 142 | QContactMemoryEngine::~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 */ | 
| 152 | QString QContactMemoryEngine::managerName() const | 
| 153 | { | 
| 154 |     return QStringLiteral("memory" ); | 
| 155 | } | 
| 156 |  | 
| 157 | /*! \reimp */ | 
| 158 | QMap<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 | */ | 
| 167 | QMap<QString, QString> QContactMemoryEngine::idInterpretationParameters() const | 
| 168 | { | 
| 169 |     return managerParameters(); | 
| 170 | } | 
| 171 |  | 
| 172 | /*! \reimp */ | 
| 173 | bool 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 */ | 
| 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(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 */ | 
| 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, 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 */ | 
| 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: &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 | */ | 
| 259 | bool QContactMemoryEngine::saveContact(QContact *theContact, QContactChangeSet &changeSet, QContactManager::Error *error) | 
| 260 | { | 
| 261 |     return saveContact(theContact, changeSet, error, mask: 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, 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 | */ | 
| 274 | bool 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 */ | 
| 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(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 */ | 
| 337 | QList<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 | */ | 
| 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(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 */ | 
| 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(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 | */ | 
| 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(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 */ | 
| 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(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 |  | 
| 516 | QContactCollectionId QContactMemoryEngine::defaultCollectionId() const | 
| 517 | { | 
| 518 |     static const QByteArray id("Personal" ); | 
| 519 |     return collectionId(localId: id); | 
| 520 | } | 
| 521 |  | 
| 522 | QContactCollection 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 |  | 
| 533 | QList<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 |  | 
| 540 | bool 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 |  | 
| 575 | bool 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 */ | 
| 611 | void QContactMemoryEngine::requestDestroyed(QContactAbstractRequest *req) | 
| 612 | { | 
| 613 |     Q_UNUSED(req); | 
| 614 | } | 
| 615 |  | 
| 616 | /*! \reimp */ | 
| 617 | bool QContactMemoryEngine::startRequest(QContactAbstractRequest *req) | 
| 618 | { | 
| 619 |     updateRequestState(req, state: QContactAbstractRequest::ActiveState); | 
| 620 |     performAsynchronousOperation(request: req); | 
| 621 |  | 
| 622 |     return true; | 
| 623 | } | 
| 624 |  | 
| 625 | bool QContactMemoryEngine::cancelRequest(QContactAbstractRequest *req) | 
| 626 | { | 
| 627 |     Q_UNUSED(req); // we can't cancel since we complete immediately | 
| 628 |     return false; | 
| 629 | } | 
| 630 |  | 
| 631 | /*! \reimp */ | 
| 632 | bool 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 |  */ | 
| 645 | void 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 |  | 
| 894 | void 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 |  */ | 
| 920 | bool 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 |  */ | 
| 945 | QList<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 |  */ | 
| 966 | bool 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 |  | 
| 973 | bool 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: ¤t, 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 |  | 
| 1001 | bool 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 |  | 
| 1098 | QT_END_NAMESPACE_CONTACTS | 
| 1099 |  |