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 | |