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 "qcontactmanagerengine.h"
35
36#include <QtCore/qmutex.h>
37#include <QtCore/qpointer.h>
38#include <QtCore/qset.h>
39
40#include "qcontact_p.h"
41#include "qcontactdetail_p.h"
42#include "qcontactdetails.h"
43#include "qcontactfilters.h"
44#include "qcontactabstractrequest_p.h"
45#include "qcontactaction.h"
46#include "qcontactactiondescriptor.h"
47#include "qcontactactionmanager_p.h"
48#include "qcontactrequests_p.h"
49#include "qcontactsortorder.h"
50
51QT_BEGIN_NAMESPACE_CONTACTS
52
53static bool validateActionFilter(const QContactFilter& filter);
54
55/*!
56 \class QContactManagerEngine
57 \brief The QContactManagerEngine class provides the interface for
58 implementations of the contact manager backend functionality.
59 \inmodule QtContacts
60
61 \ingroup contacts-backends
62
63 Instances of this class are usually provided by a
64 \l QContactManagerEngineFactory, which is loaded from a plugin.
65
66 The default implementation of this interface provides a basic
67 level of functionality for some functions so that specific engines
68 can simply implement the functionality that is supported by
69 the specific contacts engine that is being adapted.
70
71 More information on writing a contacts engine plugin is available in
72 the \l{Qt Contacts Manager Engines} documentation.
73
74 \sa QContactManager, QContactManagerEngineFactory
75 */
76
77/*!
78 \fn QContactManagerEngine::QContactManagerEngine()
79
80 A default, empty constructor.
81 */
82
83/*!
84 \fn QContactManagerEngine::dataChanged()
85
86 This signal is emitted some time after changes occur to the data managed by this
87 engine, and the engine is unable to determine which changes occurred, or if the
88 engine considers the changes to be radical enough to require clients to reload all data.
89
90 If this signal is emitted, no other signals may be emitted for the associated changes.
91
92 As it is possible that other processes (or other devices) may have caused the
93 changes, the timing can not be determined.
94
95 \sa contactsAdded(), contactsChanged(), contactsRemoved()
96 */
97
98/*!
99 \fn QContactManagerEngine::contactsAdded(const QList<QContactId>& contactIds);
100
101 This signal is emitted some time after a set of contacts has been added to
102 this engine where the \l dataChanged() signal was not emitted for those changes.
103 As it is possible that other processes (or other devices) may
104 have added the contacts, the timing cannot be determined.
105
106 The list of ids of contacts added is given by \a contactIds. There may be one or more
107 ids in the list.
108
109 \sa dataChanged()
110 */
111
112/*!
113 \fn QContactManagerEngine::contactsChanged(const QList<QContactId>& contactIds, const QList<QContactDetail::DetailType> &typesChanged);
114
115 This signal is emitted some time after a set of contacts has been modified in
116 this engine where the \l dataChanged() signal was not emitted for those changes.
117 As it is possible that other processes (or other devices) may
118 have modified the contacts, the timing cannot be determined.
119
120 The list of ids of changed contacts is given by \a contactIds. There may be one or more
121 ids in the list.
122
123 The set of contact detail types modified in the reported changes is a subset of those
124 listed in \a typesChanged, unless \a typesChanged is empty, in which case no limitation
125 on the reported changes may be assumed.
126
127 \sa dataChanged()
128 */
129
130/*!
131 \fn QContactManagerEngine::contactsRemoved(const QList<QContactId>& contactIds);
132
133 This signal is emitted some time after a set of contacts has been removed from
134 this engine where the \l dataChanged() signal was not emitted for those changes.
135 As it is possible that other processes (or other devices) may
136 have removed the contacts, the timing cannot be determined.
137
138 The list of ids of removed contacts is given by \a contactIds. There may be one or more
139 ids in the list.
140
141 \sa dataChanged()
142 */
143
144/*!
145 \fn QContactManagerEngine::relationshipsAdded(const QList<QContactId>& affectedContactIds);
146
147 This signal is emitted some time after a set of contacts has been added to
148 this engine where the \l dataChanged() signal was not emitted for those changes.
149 As it is possible that other processes (or other devices) may
150 have added the contacts, the timing cannot be determined.
151
152 The list of ids of affected contacts is given by \a affectedContactIds. There may be one or more
153 ids in the list.
154
155 \sa dataChanged()
156 */
157
158/*!
159 \fn QContactManagerEngine::relationshipsRemoved(const QList<QContactId>& affectedContactIds);
160
161 This signal is emitted some time after a set of relationships has been removed from
162 this engine where the \l dataChanged() signal was not emitted for those changes.
163 As it is possible that other processes (or other devices) may
164 have removed the relationships, the timing cannot be determined.
165
166 The list of ids of affected contacts is given by \a affectedContactIds. There may be one or more
167 ids in the list.
168
169 \sa dataChanged()
170 */
171
172/*!
173 \fn QContactManagerEngine::selfContactIdChanged(const QContactId& oldId, const QContactId& newId)
174
175 This signal is emitted at some point after the id of the self-contact is changed from \a oldId to \a newId in the manager.
176 If the \a newId is the invalid, null id, then the self contact was deleted or no self contact exists.
177 This signal must not be emitted if the dataChanged() signal was previously emitted for this change.
178 As it is possible that other processes (or other devices) may
179 have removed or changed the self contact, the timing cannot be determined.
180
181 \sa dataChanged()
182 */
183
184/*! Returns the manager name for this QContactManagerEngine
185*/
186QString QContactManagerEngine::managerName() const
187{
188 return QString(QStringLiteral("base"));
189}
190
191/*!
192 Returns the parameters with which this engine was constructed. Note that
193 the engine may have discarded unused or invalid parameters at the time of
194 construction, and these will not be returned.
195 */
196QMap<QString, QString> QContactManagerEngine::managerParameters() const
197{
198 return QMap<QString, QString>(); // default implementation requires no parameters.
199}
200
201/*!
202 Returns the subset of the manager parameters that are relevant when interpreting
203 contact ID values. Since contact ID comparison involves equivalence of
204 managerUri values, parameters that do not differentiate contact IDs should not
205 be returned by this function.
206
207 For example, a manager engine may support 'user' and 'cachesize' parameters,
208 where the former distinguishes between separate user domains, and the latter
209 is for performance tuning. The 'user' parameter will be relevant to the interpretation
210 of contact IDs and thus should be returned by this function, whereas 'cachesize'
211 is not relevant and should be omitted.
212
213 \sa managerUri(), managerParamaters()
214 */
215QMap<QString, QString> QContactManagerEngine::idInterpretationParameters() const
216{
217 return QMap<QString, QString>(); // default implementation returns no parameters.
218}
219
220/*!
221 \fn QString QContactManagerEngine::managerUri() const
222
223 Returns the unique URI of this manager, which is built from the manager name and the
224 ID interpretation parameters used to construct it.
225
226 \sa idInterpretationParameters()
227 */
228
229/*!
230 \fn QContactId QContactManagerEngine::contactId(const QString &localId) const
231
232 Returns the contact ID for this managerUri() and the given
233 engine specific ID part \a localId.
234*/
235
236/*!
237 Returns a list of contact ids that match the given \a filter, sorted according to the given list of \a sortOrders.
238 Depending on the backend, this filtering operation may involve retrieving all the contacts.
239 Any error which occurs will be saved in \a error.
240 */
241QList<QContactId> QContactManagerEngine::contactIds(const QContactFilter& filter, const QList<QContactSortOrder>& sortOrders, QContactManager::Error* error) const
242{
243 Q_UNUSED(filter);
244 Q_UNUSED(sortOrders);
245
246 *error = QContactManager::NotSupportedError;
247 return QList<QContactId>();
248}
249
250/*!
251 Returns the list of contacts which match the given \a filter stored in the manager sorted according to the given list of \a sortOrders.
252
253 Any operation error which occurs will be saved in \a error.
254
255 The \a fetchHint parameter describes the optimization hints that a manager may take.
256 If the \a fetchHint is the default constructed hint, all existing details, relationships and
257 action preferences in the matching contacts will be returned.
258
259 If a non-default fetch hint is supplied, and the client wishes to make changes to the contacts,
260 they should ensure that only a detail type hint is supplied and that when saving it back, a
261 type mask should be used which corresponds to the detail type hint. This is to ensure
262 that no data is lost by overwriting an existing contact with a restricted version of it.
263
264 \sa QContactFetchHint
265 */
266QList<QContact> QContactManagerEngine::contacts(const QContactFilter& filter, const QList<QContactSortOrder>& sortOrders, const QContactFetchHint& fetchHint, QContactManager::Error* error) const
267{
268 Q_UNUSED(filter);
269 Q_UNUSED(sortOrders);
270 Q_UNUSED(fetchHint);
271 *error = QContactManager::NotSupportedError;
272 return QList<QContact>();
273}
274
275/*!
276 Returns the contact in the database identified by \a contactId.
277
278 If the contact does not exist, an empty, default constructed QContact will be returned,
279 and the \a error will be set to \c QContactManager::DoesNotExistError.
280
281 Any operation error which occurs will be saved in \a error.
282
283 The \a fetchHint parameter describes the optimization hints that a manager may take.
284 If the \a fetchHint is the default constructed hint, all existing details, relationships and
285 action preferences in the matching contact will be returned. If a client makes changes to an
286 contact which has been retrieved with a fetch hint, they should save it back using a partial save,
287 masked by the same set of detail names in order to avoid information loss.
288
289 \sa QContactFetchHint
290 */
291QContact QContactManagerEngine::contact(const QContactId& contactId, const QContactFetchHint& fetchHint, QContactManager::Error* error) const
292{
293 Q_UNUSED(contactId);
294 Q_UNUSED(fetchHint);
295 *error = QContactManager::NotSupportedError;
296 return QContact();
297}
298
299/*!
300 Sets the id of the "self" contact to the given \a contactId.
301 Returns true if the "self" contact id was set successfully.
302 If the given \a contactId does not identify a contact
303 stored in this manager, the \a error will be set to
304 \c QContactManager::DoesNotExistError and the function will
305 return false; if the backend does not support the
306 concept of a "self" contact, the \a error will be set to
307 \c QContactManager::NotSupportedError and the function will
308 return false.
309 */
310bool QContactManagerEngine::setSelfContactId(const QContactId& contactId, QContactManager::Error* error)
311{
312 Q_UNUSED(contactId);
313
314 *error = QContactManager::NotSupportedError;
315 return false;
316}
317
318/*!
319 Returns the id of the "self" contact which has previously been set.
320 If no "self" contact has been set, or if the self contact was removed
321 from the manager after being set, or if the backend does not support
322 the concept of a "self" contact, the null id will be returned
323 and the \a error will be set to \c QContactManager::DoesNotExistError.
324 */
325QContactId QContactManagerEngine::selfContactId(QContactManager::Error* error) const
326{
327 *error = QContactManager::DoesNotExistError;
328 return QContactId();
329}
330
331/*!
332 Returns a list of relationships of the given \a relationshipType in which the contact identified by \a participantId participates in the given \a role.
333 If \a participantId is default-constructed, \a role is ignored and all relationships of the given \a relationshipType are returned.
334 If \a relationshipType is empty, relationships of any type are returned.
335 If no relationships of the given \a relationshipType in which the contact identified by \a participantId is involved in the given \a role exists,
336 \a error is set to QContactManager::DoesNotExistError.
337 */
338QList<QContactRelationship> QContactManagerEngine::relationships(const QString& relationshipType, const QContactId& participantId, QContactRelationship::Role role, QContactManager::Error* error) const
339{
340 Q_UNUSED(relationshipType);
341 Q_UNUSED(participantId);
342 Q_UNUSED(role);
343
344 *error = QContactManager::NotSupportedError;
345 return QList<QContactRelationship>();
346}
347
348/*!
349 Saves the given \a relationships in the database and returns true if the operation was successful.
350 For any relationship which was unable to be saved, an entry into the \a errorMap will be created,
351 with the key being the index into the input relationships list, and the value being the error which
352 occurred for that index.
353
354 The supplied \a errorMap parameter may be null, if the client does not desire detailed error information.
355 If supplied, it will be empty upon entry to this function.
356
357 The overall operation error will be saved in \a error.
358 */
359bool QContactManagerEngine::saveRelationships(QList<QContactRelationship>* relationships, QMap<int, QContactManager::Error>* errorMap, QContactManager::Error* error)
360{
361 Q_UNUSED(relationships);
362 Q_UNUSED(errorMap);
363
364 *error = QContactManager::NotSupportedError;
365 return false;
366}
367
368/*!
369 Saves the given \a relationship in the database. If the relationship already exists in the database, this function will
370 return \c false and the \a error will be set to \c QContactManager::AlreadyExistsError.
371 If the relationship is saved successfully, this function will return \c true and \a error will be set
372 to \c QContactManager::NoError. Note that relationships cannot be updated directly using this function; in order
373 to update a relationship, you must remove the old relationship, make the required modifications, and then save it.
374
375 The given relationship is invalid if it is circular (the first contact is the second contact), or
376 if it references a non-existent local contact (either the first or second contact). If the given \a relationship is invalid,
377 the function will return \c false and the \a error will be set to \c QContactManager::InvalidRelationshipError.
378
379 The default implementation of this function converts the argument into a call to saveRelationships.
380 */
381bool QContactManagerEngine::saveRelationship(QContactRelationship *relationship, QContactManager::Error *error)
382{
383 // Convert to a list op
384 if (relationship) {
385 QList<QContactRelationship> list;
386 list.append(t: *relationship);
387
388 QMap<int, QContactManager::Error> errors;
389 bool ret = saveRelationships(relationships: &list, errorMap: &errors, error);
390
391 if (errors.count() > 0)
392 *error = errors.begin().value();
393
394 *relationship = list.value(i: 0);
395 return ret;
396 } else {
397 *error = QContactManager::BadArgumentError;
398 return false;
399 }
400}
401
402/*!
403 Removes the given \a relationship from the manager. If the relationship exists in the manager, the relationship
404 will be removed, the \a error will be set to \c QContactManager::NoError and this function will return true. If no such
405 relationship exists in the manager, the \a error will be set to \c QContactManager::DoesNotExistError and this function
406 will return false.
407
408 The default implementation of this function converts the argument into a call to removeRelationships
409 */
410bool QContactManagerEngine::removeRelationship(const QContactRelationship& relationship, QContactManager::Error* error)
411{
412 // Convert to a list op
413 QList<QContactRelationship> list;
414 list.append(t: relationship);
415
416 QMap<int, QContactManager::Error> errors;
417 bool ret = removeRelationships(relationships: list, errorMap: &errors, error);
418
419 if (errors.count() > 0)
420 *error = errors.begin().value();
421
422 return ret;
423}
424
425
426/*!
427 Removes the given \a relationships from the database and returns true if the operation was successful.
428 For any relationship which was unable to be removed, an entry into the \a errorMap will be created,
429 with the key being the index into the input relationships list, and the value being the error which
430 occurred for that index.
431
432 The supplied \a errorMap parameter may be null, if the client does not desire detailed error information.
433 If supplied, it will be empty upon entry to this function.
434
435 The overall operation error will be saved in \a error.
436 */
437bool QContactManagerEngine::removeRelationships(const QList<QContactRelationship>& relationships, QMap<int, QContactManager::Error>* errorMap, QContactManager::Error* error)
438{
439 Q_UNUSED(relationships);
440 Q_UNUSED(errorMap);
441
442 *error = QContactManager::NotSupportedError;
443 return false;
444}
445
446/*!
447 This function should be reimplemented to support synchronous calls to fetch the default collection id.
448*/
449QContactCollectionId QContactManagerEngine::defaultCollectionId() const
450{
451 return QContactCollectionId();
452}
453
454/*!
455 This function should be reimplemented to support synchronous calls to fetch a collection based
456 on its ID. Any errors encountered during this operation should be stored to \a error. If the
457 given \a collectionId does not specify a valid collection, \a error will be set to
458 \c QContactManager::DoesNotExistError.
459
460*/
461QContactCollection QContactManagerEngine::collection(const QContactCollectionId& collectionId, QContactManager::Error* error)
462{
463 Q_UNUSED(collectionId);
464 *error = QContactManager::NotSupportedError;
465 return QContactCollection();
466}
467
468/*!
469 This function should be reimplemented to support synchronous calls to fetch all the collections
470 managed by this backend. Any errors encountered during this operation should be stored to \a error.
471 */
472QList<QContactCollection> QContactManagerEngine::collections(QContactManager::Error* error)
473{
474 *error = QContactManager::NotSupportedError;
475 return QList<QContactCollection>();
476}
477
478/*!
479 This function should be reimplemented to support synchronous calls to save a collection.
480
481 This function is supposed to save the given \a collection to the backend, and returns true on
482 success or false otherwise. Any errors encountered during this operation should be stored to
483 \a error.
484
485 A new collection will be created in the backend store if the collection ID of it is null.
486 Otherwise, an existing collection with the same ID will be updated. If the given collection ID
487 does not exist in the backend, it will result a QContactManager::DoesNotExistError error.
488
489 Note that upon successful saving, the backend may update the collection, e.g. collection ID for
490 newly saved collections.
491*/
492bool QContactManagerEngine::saveCollection(QContactCollection* collection, QContactManager::Error* error)
493{
494 Q_UNUSED(collection);
495
496 *error = QContactManager::NotSupportedError;
497 return false;
498}
499
500/*!
501 This function should be reimplemented to support synchronous calls to remove a collection.
502
503 This function is supposed to remove the collection identified by the given \a collectionId, and
504 all items in the collection. Returns true on success, or false otherwise. Any errors encountered
505 during this operation should be stored to \a error.
506
507 Note that removing the default collection should not be allowed and should result a
508 QContactManager::PermissionsError error.
509*/
510bool QContactManagerEngine::removeCollection(const QContactCollectionId& collectionId, QContactManager::Error* error)
511{
512 Q_UNUSED(collectionId);
513
514 *error = QContactManager::NotSupportedError;
515 return false;
516}
517
518/*!
519 Given an input \a filter, returns the canonical version of the filter.
520
521 Some of the following transformations may be applied:
522 \list
523 \li Any QContactActionFilters are transformed into the corresponding
524 QContactFilters returned by matching actions
525 \li Any QContactInvalidFilters contained in a union filter will be removed
526 \li Any default QContactFilters contained in an intersection filter will be removed
527 \li Any QContactIntersectionFilters with a QContactInvalidFilter contained will be
528 replaced with a QContactInvalidFilter
529 \li Any QContactUnionFilters with a default QContactFilter contained will be replaced
530 with a default QContactFilter
531 \li An empty QContactIntersectionFilter will be replaced with a QContactDefaultFilter
532 \li An empty QContactUnionFilter will be replaced with a QContactInvalidFilter
533 \li An empty QContactIdFilter will be replaced with a QContactInvalidFilter
534 \li An intersection or union filter with a single entry will be replaced by that entry
535 \li A QContactDetailFilter or QContactDetailRangeFilter with no detail type will be replaced with a QContactInvalidFilter
536 \li A QContactDetailRangeFilter with no range specified will be converted to a QContactDetailFilter
537 \endlist
538*/
539QContactFilter QContactManagerEngine::canonicalizedFilter(const QContactFilter &filter)
540{
541 switch(filter.type()) {
542 case QContactFilter::ActionFilter:
543 {
544 // Find any matching actions, and do a union filter on their filter objects
545 QContactActionFilter af(filter);
546 QList<QContactActionDescriptor> descriptors = QContactActionManager::instance()->actionDescriptors(actionName: af.actionName());
547
548 QList<QContactFilter> filters;
549 for (int j = 0; j < descriptors.count(); j++) {
550 // Action filters are not allowed to return action filters, at all
551 // it's too annoying to check for recursion
552 QContactFilter d = descriptors.at(i: j).contactFilter();
553 if (!validateActionFilter(filter: d))
554 continue;
555
556 filters.append(t: d);
557 }
558
559 if (filters.count() == 0)
560 return QContactInvalidFilter();
561 if (filters.count() == 1)
562 return filters.first();
563
564 QContactUnionFilter f;
565 f.setFilters(filters);
566 return canonicalizedFilter(filter: f);
567 }
568 // unreachable
569
570 case QContactFilter::IntersectionFilter:
571 {
572 QContactIntersectionFilter f(filter);
573 QList<QContactFilter> filters = f.filters();
574 QList<QContactFilter>::iterator it = filters.begin();
575
576 // XXX in theory we can remove duplicates in a set filter
577 while (it != filters.end()) {
578 QContactFilter canon = canonicalizedFilter(filter: *it);
579 if (canon.type() == QContactFilter::DefaultFilter) {
580 it = filters.erase(it);
581 } else if (canon.type() == QContactFilter::InvalidFilter) {
582 return QContactInvalidFilter();
583 } else {
584 *it = canon;
585 ++it;
586 }
587 }
588
589 if (filters.count() == 0)
590 return QContactFilter();
591 if (filters.count() == 1)
592 return filters.first();
593
594 f.setFilters(filters);
595 return f;
596 }
597 // unreachable
598
599 case QContactFilter::UnionFilter:
600 {
601 QContactUnionFilter f(filter);
602 QList<QContactFilter> filters = f.filters();
603 QList<QContactFilter>::iterator it = filters.begin();
604
605 // XXX in theory we can remove duplicates in a set filter
606 while (it != filters.end()) {
607 QContactFilter canon = canonicalizedFilter(filter: *it);
608 if (canon.type() == QContactFilter::InvalidFilter) {
609 it = filters.erase(it);
610 } else if (canon.type() == QContactFilter::DefaultFilter) {
611 return QContactFilter();
612 } else {
613 *it = canon;
614 ++it;
615 }
616 }
617
618 if (filters.count() == 0)
619 return QContactInvalidFilter();
620 if (filters.count() == 1)
621 return filters.first();
622
623 f.setFilters(filters);
624 return f;
625 }
626 // unreachable
627
628 case QContactFilter::IdFilter:
629 {
630 QContactIdFilter f(filter);
631 if (f.ids().count() == 0)
632 return QContactInvalidFilter();
633 }
634 break; // fall through to return at end
635
636 case QContactFilter::ContactDetailRangeFilter:
637 {
638 QContactDetailRangeFilter f(filter);
639 if (f.detailType() == QContactDetail::TypeUndefined)
640 return QContactInvalidFilter();
641 if (f.minValue() == f.maxValue()
642 && f.rangeFlags() == (QContactDetailRangeFilter::ExcludeLower | QContactDetailRangeFilter::ExcludeUpper))
643 return QContactInvalidFilter();
644 if ((f.minValue().isNull() && f.maxValue().isNull()) || (f.minValue() == f.maxValue())) {
645 QContactDetailFilter df;
646 df.setDetailType(type: f.detailType(), field: f.detailField());
647 df.setMatchFlags(f.matchFlags());
648 df.setValue(f.minValue());
649 return df;
650 }
651 }
652 break; // fall through to return at end
653
654 case QContactFilter::ContactDetailFilter:
655 {
656 QContactDetailFilter f(filter);
657 if (f.detailType() == QContactDetail::TypeUndefined)
658 return QContactInvalidFilter();
659 }
660 break; // fall through to return at end
661
662 default:
663 break; // fall through to return at end
664 }
665 return filter;
666}
667
668
669/*!
670 Returns a whether the supplied \a filter can be implemented
671 natively by this engine. If not, the base class implementation
672 will emulate the functionality.
673 */
674bool QContactManagerEngine::isFilterSupported(const QContactFilter& filter) const
675{
676 Q_UNUSED(filter);
677
678 return false;
679}
680
681/*!
682 Returns the list of data types supported by this engine.
683 */
684QList<QVariant::Type> QContactManagerEngine::supportedDataTypes() const
685{
686 return QList<QVariant::Type>();
687}
688
689/*!
690 Returns true if the manager supports the relationship type specified in \a relationshipType for
691 contacts whose type is the given \a contactType.
692
693 Note that some managers may support the relationship type for a contact in a limited manner
694 (for example, only as the first contact in the relationship, or only as the second contact
695 in the relationship). In this case, it will still return true. It will only return false
696 if the relationship is entirely unsupported for the given type of contact.
697 */
698bool QContactManagerEngine::isRelationshipTypeSupported(const QString& relationshipType, QContactType::TypeValues contactType) const
699{
700 Q_UNUSED(relationshipType);
701 Q_UNUSED(contactType);
702
703 return false;
704}
705
706/*!
707 Returns the list of contact types which are supported by this engine.
708 This is a convenience function, equivalent to retrieving the allowable values
709 for the \c QContactType::FieldType field of the QContactType detail
710 which is valid in this engine.
711 */
712QList<QContactType::TypeValues> QContactManagerEngine::supportedContactTypes() const
713{
714 QList<QContactType::TypeValues> list;
715 // By default, TypeFacet is not supported
716 list << QContactType::TypeContact
717 << QContactType::TypeGroup;
718 return list;
719}
720
721/*!
722 \fn int QContactManagerEngine::managerVersion() const
723
724 Returns the engine backend implementation version number
725 */
726
727/*!
728 Returns the list of contact detail types which are supported by this engine.
729 */
730QList<QContactDetail::DetailType> QContactManagerEngine::supportedContactDetailTypes() const
731{
732 QList<QContactDetail::DetailType> supportedDetails;
733 supportedDetails << QContactAddress::Type
734 << QContactAnniversary::Type
735 << QContactAvatar::Type
736 << QContactBirthday::Type
737 << QContactDisplayLabel::Type
738 << QContactEmailAddress::Type
739 << QContactExtendedDetail::Type
740 << QContactFamily::Type
741 << QContactFavorite::Type
742 << QContactGender::Type
743 << QContactGeoLocation::Type
744 << QContactGlobalPresence::Type
745 << QContactGuid::Type
746 << QContactHobby::Type
747 << QContactName::Type
748 << QContactNickname::Type
749 << QContactNote::Type
750 << QContactOnlineAccount::Type
751 << QContactOrganization::Type
752 << QContactPhoneNumber::Type
753 << QContactPresence::Type
754 << QContactRingtone::Type
755 << QContactSyncTarget::Type
756 << QContactTag::Type
757 << QContactTimestamp::Type
758 << QContactType::Type
759 << QContactUrl::Type
760 << QContactVersion::Type;
761 return supportedDetails;
762}
763
764/*!
765 Checks that the given contact \a contact does not have a type which
766 is not supported. It also checks if the details of the given
767 \a contact are valid or not.
768 Note that this function is unable to ensure that all the details of
769 \a contact are supported by a certain back-end. It also cannot
770 check that the access constraints (such as CreateOnly and ReadOnly)
771 are observed; backend specific code must be written if you wish to
772 enforce these constraints.
773
774 Returns true if the \a contact has a valid type, otherwise returns
775 false.
776
777 Any errors encountered during this operation should be stored to
778 \a error.
779 */
780bool QContactManagerEngine::validateContact(const QContact &contact, QContactManager::Error *error) const
781{
782 if (!supportedContactTypes().contains(t: contact.type())) {
783 *error = QContactManager::InvalidContactTypeError;
784 return false;
785 }
786 if ( (!contact.id().isNull()) && (contact.id().managerUri() != this->managerUri())) {
787 *error = QContactManager::DoesNotExistError;
788 return false;
789 }
790
791 QList<QContactDetail> contactDetailList = contact.details();
792 for (int i=0; i<contactDetailList.count(); i++)
793 {
794 QContactDetail currentDetail = contactDetailList.value(i);
795 if (!supportedContactDetailTypes().contains(t: currentDetail.type()))
796 {
797 *error = QContactManager::InvalidDetailError;
798 return false;
799 }
800 }
801
802 *error = QContactManager::NoError;
803 return true;
804}
805
806/*!
807 Sets the access constraints of \a detail to the supplied \a constraints.
808
809 This function is provided to allow engine implementations to report the
810 access constraints of retrieved details, without generally allowing the
811 access constraints to be modified after retrieval.
812
813 Application code should not call this function, since validation of the
814 detail will happen in the engine in any case.
815 */
816void QContactManagerEngine::setDetailAccessConstraints(QContactDetail *detail, QContactDetail::AccessConstraints constraints)
817{
818 if (detail) {
819 QContactDetailPrivate::setAccessConstraints(d: detail, constraint: constraints);
820 }
821}
822
823/*!
824 Sets the provenance of \a detail to the supplied \a provenance.
825
826 This function is provided to allow engine implementations to report the
827 provenance of retrieved details, without generally allowing the
828 provenance metadata to be modified after retrieval.
829
830 The provenance of a detail in an aggregate Contact should include the
831 id of the Facet contact and the detail id of the particular detail in
832 that Facet contact from which the aggregate Contact's detail was promoted.
833
834 Application code should not call this function, since validation of the
835 detail will happen in the engine in any case.
836 */
837void QContactManagerEngine::setDetailProvenance(QContactDetail *detail, const QString &provenance)
838{
839 if (detail) {
840 QContactDetailPrivate::setProvenance(d: detail, newProvenance: provenance);
841 }
842}
843
844
845/*!
846 Adds the given \a contact to the database if \a contact has a
847 null id, otherwise updates the contact in
848 the database which has the same id to be the given \a contact.
849 If the id is not null but does not identify any contact stored in the
850 manager, the function will return false and \a error will be set to
851 \c QContactManager::DoesNotExistError.
852
853 Returns true if the save operation completed successfully, otherwise
854 returns false. Any error which occurs will be saved in \a error.
855
856 The default implementation will convert this into a call to saveContacts.
857
858 \sa managerUri()
859 */
860bool QContactManagerEngine::saveContact(QContact* contact, QContactManager::Error* error)
861{
862 // Convert to a list op
863 if (contact) {
864 QList<QContact> list;
865 list.append(t: *contact);
866
867 QMap<int, QContactManager::Error> errors;
868 bool ret = saveContacts(contacts: &list, errorMap: &errors, error);
869
870 if (errors.count() > 0)
871 *error = errors.begin().value();
872
873 *contact = list.value(i: 0);
874 return ret;
875 } else {
876 *error = QContactManager::BadArgumentError;
877 return false;
878 }
879}
880
881/*!
882 Remove the contact identified by \a contactId from the database,
883 and also removes any relationships in which the contact was involved.
884 After the contact has been removed it can not be updated or re-created
885 with the same contact id anymore.
886 Returns true if the contact was removed successfully, otherwise
887 returns false.
888
889 Any error which occurs will be saved in \a error.
890
891 The default implementation will convert this into a call to removeContacts.
892 */
893bool QContactManagerEngine::removeContact(const QContactId& contactId, QContactManager::Error* error)
894{
895 // Convert to a list op
896 QList<QContactId> list;
897 list.append(t: contactId);
898
899 QMap<int, QContactManager::Error> errors;
900 bool ret = removeContacts(contactIds: list, errorMap: &errors, error);
901
902 if (errors.count() > 0)
903 *error = errors.begin().value();
904
905 return ret;
906}
907
908/*!
909 Adds the list of contacts given by \a contacts list to the database.
910 Returns true if the contacts were saved successfully, otherwise false.
911
912 The manager might populate \a errorMap (the map of indices of the \a contacts list to
913 the error which occurred when saving the contact at that index) for
914 every index for which the contact could not be saved, if it is able.
915
916 The supplied \a errorMap parameter may be null, if the client does not desire detailed error information.
917 If supplied, it will be empty upon entry to this function.
918
919 The \l QContactManager::error() function will only return \c QContactManager::NoError
920 if all contacts were saved successfully.
921
922 For each newly saved contact that was successful, the id of the contact
923 in the \a contacts list will be updated with the new value. If a failure occurs
924 when saving a new contact, the id will be cleared.
925
926 Any errors encountered during this operation should be stored to
927 \a error.
928
929 \sa QContactManager::saveContact()
930 */
931bool QContactManagerEngine::saveContacts(QList<QContact>* contacts, QMap<int, QContactManager::Error>* errorMap, QContactManager::Error* error)
932{
933 Q_UNUSED(contacts);
934 Q_UNUSED(errorMap);
935 *error = QContactManager::NotSupportedError;
936 return false;
937}
938
939/*!
940 Remove every contact whose id is contained in the list of contacts ids
941 \a contactIds. Returns true if all contacts were removed successfully,
942 otherwise false.
943
944 Any contact that was removed successfully will have the relationships
945 in which it was involved removed also.
946
947 The manager might populate \a errorMap (the map of indices of the \a contactIds list to
948 the error which occurred when saving the contact at that index) for every
949 index for which the contact could not be removed, if it is able.
950
951 The supplied \a errorMap parameter may be null, if the client does not desire detailed error information.
952 If supplied, it will be empty upon entry to this function.
953
954 The \l QContactManager::error() function will
955 only return \c QContactManager::NoError if all contacts were removed
956 successfully.
957
958 If the list contains ids which do not identify a valid contact in the manager, the function will
959 remove any contacts which are identified by ids in the \a contactIds list, insert
960 \c QContactManager::DoesNotExist entries into the \a errorMap for the indices of invalid ids
961 in the \a contactIds list, return false, and set the overall operation error to
962 \c QContactManager::DoesNotExistError.
963
964 Any errors encountered during this operation should be stored to
965 \a error.
966
967 \sa QContactManager::removeContact()
968 */
969bool QContactManagerEngine::removeContacts(const QList<QContactId>& contactIds, QMap<int, QContactManager::Error>* errorMap, QContactManager::Error* error)
970{
971 Q_UNUSED(contactIds);
972 Q_UNUSED(errorMap);
973 *error = QContactManager::NotSupportedError;
974 return false;
975}
976
977/* This implements the string comparison behaviour required for compareVariant, amongst others */
978static inline int compareStrings(const QString& left, const QString& right, Qt::CaseSensitivity sensitivity)
979{
980 if (sensitivity == Qt::CaseSensitive) {
981 return left.localeAwareCompare(s: right);
982 } else {
983 return left.toCaseFolded().localeAwareCompare(s: right.toCaseFolded());
984 }
985/*
986 // manual implementation of string comparison.
987 // should not be necessary / used, as locale aware compare should be sensible.
988 // this code exists here for testing / result comparison purposes.
989 int retn = -50;
990 for (int i = 0; i < left.size(); ++i) {
991 if (i >= right.size()) { retn = 1; break; } // right is a substring of left
992 const QChar &lc(left[i]);
993 const QChar &rc(right[i]);
994 const QChar lowerLC = lc.toLower();
995 const QChar lowerRC = rc.toLower();
996#if 0
997 // upper first (ascii-collation)
998 if (lc == rc) continue; // characters are identical.
999 if (sensitivity == Qt::CaseInsensitive && lowerLC == lowerRC) continue; // lowercase characters are identical.
1000 if (lc.isLower() && rc.isUpper()) { retn = 1; break; } // left is greater than right
1001 if (lc.isUpper() && rc.isLower()) { retn = -1; break; } // left is less than right
1002 retn = (lc < rc ? -1 : 1); break; // both lower, or both upper. return relative less-than-ism.
1003#elif 0
1004 // lower-first
1005 if (lc == rc) continue; // characters are identical.
1006 if (sensitivity == Qt::CaseInsensitive && lowerLC == lowerRC) continue; // lowercase characters are identical.
1007 if (lc.isLower() && rc.isUpper()) { retn = -1; break; } // left is less than right
1008 if (lc.isUpper() && rc.isLower()) { retn = 1; break; } // left is greater than right
1009 retn = (lc < rc ? -1 : 1); break; // both lower, or both upper. return relative less-than-ism.
1010#elif 0
1011 // interleaved-upper-first
1012 if (lc == rc) continue; // characters are identical.
1013 if (sensitivity == Qt::CaseInsensitive && lowerLC == lowerRC) continue; // lowercase characters are identical.
1014 if (lowerLC == lowerRC) {
1015 // we know that lc.isLower() != rc.isLower() otherwise the original lc==rc check would have been true.
1016 if (lc.isLower()) { retn = 1; break; } // same letter, but left is lowercase :. greater than right.
1017 else { retn = -1; break; } // same letter, but left is uppercase :. less than right
1018 } else if (lowerLC < lowerRC) {
1019 retn = -1; break;
1020 } else {
1021 retn = 1; break;
1022 }
1023#elif 0
1024 // interleaved-lower-first
1025 if (lc == rc) continue; // characters are identical.
1026 if (sensitivity == Qt::CaseInsensitive && lowerLC == lowerRC) continue; // lowercase characters are identical.
1027 if (lowerLC == lowerRC) {
1028 // we know that lc.isLower() != rc.isLower() otherwise the original lc==rc check would have been true.
1029 if (lc.isLower()) { retn = -1; break; } // same letter, but left is lowercase :. less than right.
1030 else { retn = 1; break; }// same letter, but left is uppercase :. greater than right
1031 } else if (lowerLC < lowerRC) {
1032 retn = -1; break;
1033 } else {
1034 retn = 1; break;
1035 }
1036#elif 0
1037 // interleaved-upper-first with first-pass case-insensitive comparison
1038 if (i == 0) {
1039 bool firstPassResult = false;
1040 for (int j = 0; j < qMin(left.size(), right.size()); ++j) {
1041 QChar firstpassLLC = left[j].toLower();
1042 QChar firstpassLRC = right[j].toLower();
1043 if (firstpassLLC < firstpassLRC) { retn = -1; firstPassResult = true; break; } // e.g. x < Y
1044 else if (firstpassLLC > firstpassLRC) { retn = 1; firstPassResult = true; break; } // e.g. x > P
1045 else { continue; } // e.g. x == X
1046 }
1047 if (firstPassResult) {
1048 break; // case-insensitive first pass already found result
1049 } else if (left.size() < right.size()) {
1050 retn = -1; break; // no difference in case-insensitive comparison, but left is a (case-insensitive) substring of right.
1051 } else if (left.size() > right.size()) {
1052 retn = 1; break; // no difference in case-insensitive comparison, but right is a (case-insensitive) substring of left.
1053 } else {
1054 }
1055 }
1056 // if we get here, the strings are the same length and differ
1057 // only by case. We use the upper-first semantic to resolve.
1058 if (lc == rc) continue; // characters are identical.
1059 if (sensitivity == Qt::CaseInsensitive && lowerLC == lowerRC) continue; // lowercase characters are identical.
1060 if (lc.isUpper() && rc.isLower()) {
1061 retn = -1; break;
1062 } else if (lc.isLower() && rc.isUpper()) {
1063 retn = 1; break;
1064 } else {
1065 // characters are equal in case, doesn't help us resolve ordering.
1066 }
1067#elif 0
1068 // interleaved-lower-first with first-pass case-insensitive comparison
1069 if (i == 0) {
1070 bool firstPassResult = false;
1071 for (int j = 0; j < qMin(left.size(), right.size()); ++j) {
1072 QChar firstpassLLC = left[j].toLower();
1073 QChar firstpassLRC = right[j].toLower();
1074 if (firstpassLLC < firstpassLRC) { retn = -1; firstPassResult = true; break; } // e.g. x < Y
1075 else if (firstpassLLC > firstpassLRC) { retn = 1; firstPassResult = true; break; } // e.g. x > P
1076 else { continue; } // e.g. x == X
1077 }
1078 if (firstPassResult) {
1079 break; // case-insensitive first pass already found result
1080 } else if (left.size() < right.size()) {
1081 retn = -1; break; // no difference in case-insensitive comparison, but left is a (case-insensitive) substring of right.
1082 } else if (left.size() > right.size()) {
1083 retn = 1; break; // no difference in case-insensitive comparison, but right is a (case-insensitive) substring of left.
1084 } else {
1085 }
1086 }
1087 // if we get here, the strings are the same length and differ
1088 // only by case. We use the lower-first semantic to resolve.
1089 if (lc == rc) continue; // characters are identical.
1090 if (sensitivity == Qt::CaseInsensitive && lowerLC == lowerRC) continue; // lowercase characters are identical.
1091 if (lc.isUpper() && rc.isLower()) {
1092 retn = 1; break;
1093 } else if (lc.isLower() && rc.isUpper()) {
1094 retn = -1; break;
1095 } else {
1096 // characters are equal in case, doesn't help us resolve ordering.
1097 }
1098#endif
1099 }
1100 if (retn == -50) {
1101 if (left.size() == right.size()) {
1102 retn = 0; // strings are the same
1103 } else {
1104 retn = -1; // left is a substr of right, therefore less.
1105 }
1106 }
1107 return retn;
1108*/
1109}
1110
1111/*!
1112 Compares \a first against \a second. If the types are
1113 strings (QVariant::String), the \a sensitivity argument controls
1114 case sensitivity when comparing. Also, when comparing strings,
1115 a locale aware comparison is used, and if the sensitivity is
1116 CaseSensitive, strings that are identical under a case insensitive
1117 sort are then sorted case sensitively within that context.
1118
1119 For example:
1120
1121 aaron
1122 Bob
1123 Aaron
1124 aAron
1125 Carol
1126
1127 would sort as:
1128
1129 aaron
1130 aAron
1131 Aaron
1132 Bob
1133 Carol
1134
1135 Returns:
1136 <0 if \a first is less than \a second
1137 0 if \a first is equal to \a second
1138 >0 if \a first is greater than \a second.
1139
1140 The results are undefined if the variants are different types, or
1141 cannot be compared.
1142 */
1143int QContactManagerEngine::compareVariant(const QVariant& first, const QVariant& second, Qt::CaseSensitivity sensitivity)
1144{
1145 switch(first.type()) {
1146 case QVariant::Int:
1147 {
1148 const int a = first.toInt();
1149 const int b = second.toInt();
1150 return (a < b) ? -1 : ((a == b) ? 0 : 1);
1151 }
1152
1153 case QVariant::LongLong:
1154 {
1155 const qlonglong a = first.toLongLong();
1156 const qlonglong b = second.toLongLong();
1157 return (a < b) ? -1 : ((a == b) ? 0 : 1);
1158 }
1159
1160 case QVariant::Bool:
1161 case QVariant::UInt:
1162 {
1163 const uint a = first.toUInt();
1164 const uint b = second.toUInt();
1165 return (a < b) ? -1 : ((a == b) ? 0 : 1);
1166 }
1167
1168 case QVariant::ULongLong:
1169 {
1170 const qulonglong a = first.toULongLong();
1171 const qulonglong b = second.toULongLong();
1172 return (a < b) ? -1 : ((a == b) ? 0 : 1);
1173 }
1174
1175 case QVariant::Char: // Needs to do proper string comparison
1176 case QVariant::String:
1177 return compareStrings(left: first.toString(), right: second.toString(), sensitivity);
1178
1179 case QVariant::Double:
1180 {
1181 const double a = first.toDouble();
1182 const double b = second.toDouble();
1183 return (a < b) ? -1 : ((a == b) ? 0 : 1);
1184 }
1185
1186 case QVariant::DateTime:
1187 {
1188 const QDateTime a = first.toDateTime();
1189 const QDateTime b = second.toDateTime();
1190 return (a < b) ? -1 : ((a == b) ? 0 : 1);
1191 }
1192
1193 case QVariant::Date:
1194 {
1195 const QDate a = first.toDate();
1196 const QDate b = second.toDate();
1197 return (a < b) ? -1 : ((a == b) ? 0 : 1);
1198 }
1199
1200 case QVariant::Time:
1201 {
1202 const QTime a = first.toTime();
1203 const QTime b = second.toTime();
1204 return (a < b) ? -1 : ((a == b) ? 0 : 1);
1205 }
1206
1207 case QVariant::StringList:
1208 {
1209 // We don't actually sort on these, I hope
1210 // {} < {"aa"} < {"aa","bb"} < {"aa", "cc"} < {"bb"}
1211
1212 int i;
1213 const QStringList a = first.toStringList();
1214 const QStringList b = second.toStringList();
1215 for (i = 0; i < a.size(); i++) {
1216 if (b.size() <= i)
1217 return 1; // first is longer
1218 int memberComp = compareStrings(left: a.at(i), right: b.at(i), sensitivity);
1219 if (memberComp != 0)
1220 return memberComp;
1221 // this element is the same, so loop again
1222 }
1223
1224 // Either a.size() < b.size() and they are equal all
1225 // the way, or a == b
1226 if (a.size() < b.size())
1227 return -1; // a is less than b;
1228 return 0; // they are equal
1229 }
1230
1231 default:
1232 return 0;
1233 }
1234}
1235
1236/*!
1237 Returns true if the supplied contact \a contact matches the supplied filter \a filter.
1238
1239 This function will test each condition in the filter, possibly recursing.
1240 */
1241bool QContactManagerEngine::testFilter(const QContactFilter &filter, const QContact &contact)
1242{
1243 switch(filter.type()) {
1244 case QContactFilter::InvalidFilter:
1245 return false;
1246
1247 case QContactFilter::DefaultFilter:
1248 return true;
1249
1250 case QContactFilter::IdFilter:
1251 {
1252 const QContactIdFilter idf(filter);
1253 if (idf.ids().contains(t: contact.id()))
1254 return true;
1255 }
1256 // Fall through to end
1257 break;
1258
1259 case QContactFilter::ContactDetailFilter:
1260 {
1261 const QContactDetailFilter cdf(filter);
1262 if (cdf.detailType() == QContactDetail::TypeUndefined)
1263 return false;
1264
1265 /* See if this contact has one of these details in it */
1266 const QList<QContactDetail>& details = contact.details(type: cdf.detailType());
1267
1268 if (details.count() == 0)
1269 return false; /* can't match */
1270
1271 /* See if we need to check the values */
1272 if (cdf.detailField() == -1)
1273 return true; /* just testing for the presence of a detail of the specified type */
1274
1275 /* Now figure out what tests we are doing */
1276 const bool valueTest = cdf.value().isValid();
1277 const bool presenceTest = !valueTest;
1278
1279 /* See if we need to test any values at all */
1280 if (presenceTest) {
1281 for(int j=0; j < details.count(); j++) {
1282 const QContactDetail& detail = details.at(i: j);
1283
1284 /* Check that the field is present and has a non-empty value */
1285 if (detail.values().contains(akey: cdf.detailField()) && !detail.value(field: cdf.detailField()).isNull())
1286 return true;
1287 }
1288 return false;
1289 }
1290
1291 /* Case sensitivity, for those parts that use it */
1292 Qt::CaseSensitivity cs = (cdf.matchFlags() & QContactFilter::MatchCaseSensitive) ? Qt::CaseSensitive : Qt::CaseInsensitive;
1293
1294 /* See what flags are requested, since we're looking at a value */
1295 if (cdf.matchFlags() & QContactFilter::MatchPhoneNumber) {
1296 /* Doing phone number filtering. We hand roll an implementation here, backends will obviously want to override this. */
1297 QString input = cdf.value().toString();
1298
1299 /* preprocess the input - ignore any non-digits (doesn't perform ITU-T collation */
1300 QString preprocessedInput;
1301 for (int i = 0; i < input.size(); i++) {
1302 QChar current = input.at(i).toLower();
1303 // XXX NOTE: we ignore characters like '+', 'p', 'w', '*' and '#' which may be important.
1304 if (current.isDigit()) {
1305 preprocessedInput.append(c: current);
1306 }
1307 }
1308
1309 /* Look at every detail in the set of details and compare */
1310 for (int j = 0; j < details.count(); j++) {
1311 const QContactDetail& detail = details.at(i: j);
1312 const QString& valueString = detail.value(field: cdf.detailField()).toString();
1313 QString preprocessedValueString;
1314 for (int i = 0; i < valueString.size(); i++) {
1315 QChar current = valueString.at(i).toLower();
1316 // note: we ignore characters like '+', 'p', 'w', '*' and '#' which may be important.
1317 if (current.isDigit()) {
1318 preprocessedValueString.append(c: current);
1319 }
1320 }
1321
1322 // if the matchflags input don't require a particular criteria to pass, we assume that it has passed.
1323 // the "default" match strategy is an "endsWith" strategy.
1324 bool me = (cdf.matchFlags() & 7) == QContactFilter::MatchExactly;
1325 bool mc = (cdf.matchFlags() & 7) == QContactFilter::MatchContains;
1326 bool msw = (cdf.matchFlags() & 7) == QContactFilter::MatchStartsWith;
1327 bool mew = (cdf.matchFlags() & 7) == QContactFilter::MatchEndsWith;
1328
1329 bool mer = (me ? preprocessedValueString == preprocessedInput : true);
1330 bool mcr = (mc ? preprocessedValueString.contains(s: preprocessedInput) : true);
1331 bool mswr = (msw ? preprocessedValueString.startsWith(s: preprocessedInput) : true);
1332 bool mewr = (mew ? preprocessedValueString.endsWith(s: preprocessedInput) : true);
1333 if (mewr && mswr && mcr && mer) {
1334 return true; // this detail meets all of the criteria which were required, and hence must match.
1335 }
1336
1337 // fallback case: default MatchPhoneNumber compares the rightmost 7 digits, ignoring other matchflags.
1338 if (preprocessedValueString.right(n: 7) == preprocessedInput.right(n: 7)) {
1339 return true;
1340 }
1341 }
1342 } else if (cdf.matchFlags() & QContactFilter::MatchKeypadCollation) {
1343 // XXX TODO: not sure about the filtering semantics for MatchKeypadCollation.
1344 QString input = cdf.value().toString();
1345
1346 /* Look at every detail in the set of details and compare */
1347 for (int j = 0; j < details.count(); j++) {
1348 const QContactDetail& detail = details.at(i: j);
1349 const QString& valueString = detail.value(field: cdf.detailField()).toString().toLower();
1350
1351 // preprocess the valueString
1352 QString preprocessedValue;
1353 for (int i = 0; i < valueString.size(); i++) {
1354 // we use ITU-T keypad collation by default.
1355 QChar currentValueChar = valueString.at(i);
1356 if (currentValueChar == QLatin1Char('a') || currentValueChar == QLatin1Char('b') || currentValueChar == QLatin1Char('c'))
1357 preprocessedValue.append(c: QLatin1Char('2'));
1358 else if (currentValueChar == QLatin1Char('d') || currentValueChar == QLatin1Char('e') || currentValueChar == QLatin1Char('f'))
1359 preprocessedValue.append(c: QLatin1Char('3'));
1360 else if (currentValueChar == QLatin1Char('g') || currentValueChar == QLatin1Char('h') || currentValueChar == QLatin1Char('i'))
1361 preprocessedValue.append(c: QLatin1Char('4'));
1362 else if (currentValueChar == QLatin1Char('j') || currentValueChar == QLatin1Char('k') || currentValueChar == QLatin1Char('l'))
1363 preprocessedValue.append(c: QLatin1Char('5'));
1364 else if (currentValueChar == QLatin1Char('m') || currentValueChar == QLatin1Char('n') || currentValueChar == QLatin1Char('o'))
1365 preprocessedValue.append(c: QLatin1Char('6'));
1366 else if (currentValueChar == QLatin1Char('p') || currentValueChar == QLatin1Char('q') || currentValueChar == QLatin1Char('r') || currentValueChar == QLatin1Char('s'))
1367 preprocessedValue.append(c: QLatin1Char('7'));
1368 else if (currentValueChar == QLatin1Char('t') || currentValueChar == QLatin1Char('u') || currentValueChar == QLatin1Char('v'))
1369 preprocessedValue.append(c: QLatin1Char('8'));
1370 else if (currentValueChar == QLatin1Char('w') || currentValueChar == QLatin1Char('x') || currentValueChar == QLatin1Char('y') || currentValueChar == QLatin1Char('z'))
1371 preprocessedValue.append(c: QLatin1Char('9'));
1372 else
1373 preprocessedValue.append(c: currentValueChar);
1374 }
1375
1376 bool me = (cdf.matchFlags() & 7) == QContactFilter::MatchExactly;
1377 bool mc = (cdf.matchFlags() & 7) == QContactFilter::MatchContains;
1378 bool msw = (cdf.matchFlags() & 7) == QContactFilter::MatchStartsWith;
1379 bool mew = (cdf.matchFlags() & 7) == QContactFilter::MatchEndsWith;
1380
1381 bool mer = (me ? preprocessedValue == input : true);
1382 bool mcr = (mc ? preprocessedValue.contains(s: input) : true);
1383 bool mswr = (msw ? preprocessedValue.startsWith(s: input) : true);
1384 bool mewr = (mew ? preprocessedValue.endsWith(s: input) : true);
1385 if (mewr && mswr && mcr && mer) {
1386 return true; // this detail meets all of the criteria which were required, and hence must match.
1387 }
1388 }
1389 } else if (cdf.matchFlags() & (QContactFilter::MatchEndsWith | QContactFilter::MatchStartsWith | QContactFilter::MatchContains | QContactFilter::MatchFixedString)) {
1390 /* We're strictly doing string comparisons here */
1391 bool matchStarts = (cdf.matchFlags() & 7) == QContactFilter::MatchStartsWith;
1392 bool matchEnds = (cdf.matchFlags() & 7) == QContactFilter::MatchEndsWith;
1393 bool matchContains = (cdf.matchFlags() & 7) == QContactFilter::MatchContains;
1394
1395 /* Value equality test */
1396 for(int j=0; j < details.count(); j++) {
1397 const QContactDetail& detail = details.at(i: j);
1398 const QString& var = detail.value(field: cdf.detailField()).toString();
1399 const QString& needle = cdf.value().toString();
1400 if (matchStarts && var.startsWith(s: needle, cs))
1401 return true;
1402 if (matchEnds && var.endsWith(s: needle, cs))
1403 return true;
1404 if (matchContains && var.contains(s: needle, cs))
1405 return true;
1406 if (compareStrings(left: var, right: needle, sensitivity: cs) == 0)
1407 return true;
1408 }
1409 return false;
1410 } else {
1411 /* Nope, testing the values as a variant */
1412 /* Value equality test */
1413 for(int j = 0; j < details.count(); j++) {
1414 const QContactDetail& detail = details.at(i: j);
1415 const QVariant& var = detail.value(field: cdf.detailField());
1416 if (!var.isNull() && compareVariant(first: var, second: cdf.value(), sensitivity: cs) == 0)
1417 return true;
1418 }
1419 }
1420 }
1421 break;
1422
1423 case QContactFilter::ContactDetailRangeFilter:
1424 {
1425 /* The only supported flags are: MatchExactly, MatchFixedString, MatchCaseSensitive */
1426
1427 const QContactDetailRangeFilter cdf(filter);
1428 if (cdf.detailType() == QContactDetail::TypeUndefined)
1429 return false; /* we do not know which field to check */
1430
1431 /* See if this contact has one of these details in it */
1432 const QList<QContactDetail>& details = contact.details(type: cdf.detailType());
1433
1434 if (details.count() == 0)
1435 return false; /* can't match */
1436
1437 /* Check for a detail presence test */
1438 if (cdf.detailField() == -1)
1439 return true;
1440
1441 /* See if this is a field presence test */
1442 if (!cdf.minValue().isValid() && !cdf.maxValue().isValid()) {
1443 for(int j=0; j < details.count(); j++) {
1444 const QContactDetail& detail = details.at(i: j);
1445 if (detail.values().contains(akey: cdf.detailField()))
1446 return true;
1447 }
1448 return false;
1449 }
1450
1451 /* open or closed interval testing support */
1452 const int minComp = cdf.rangeFlags() & QContactDetailRangeFilter::ExcludeLower ? 1 : 0;
1453 const int maxComp = cdf.rangeFlags() & QContactDetailRangeFilter::IncludeUpper ? 1 : 0;
1454
1455 /* Case sensitivity, for those parts that use it */
1456 Qt::CaseSensitivity cs = (cdf.matchFlags() & QContactFilter::MatchCaseSensitive) ? Qt::CaseSensitive : Qt::CaseInsensitive;
1457
1458 /* See what flags are requested, since we're looking at a value */
1459 if (cdf.matchFlags() & QContactFilter::MatchFixedString) {
1460 /* We're strictly doing string comparisons here */
1461 QString minVal = cdf.minValue().toString();
1462 QString maxVal = cdf.maxValue().toString();
1463
1464 const bool testMin = !minVal.isEmpty();
1465 const bool testMax = !maxVal.isEmpty();
1466
1467 for(int j=0; j < details.count(); j++) {
1468 const QContactDetail& detail = details.at(i: j);
1469
1470 // The detail has to have a field of this type in order to be compared.
1471 if (!detail.value(field: cdf.detailField()).isValid())
1472 continue;
1473 const QString& var = detail.value(field: cdf.detailField()).toString();
1474 if (testMin && compareStrings(left: var, right: minVal, sensitivity: cs) < minComp)
1475 continue;
1476 if (testMax && compareStrings(left: var, right: maxVal, sensitivity: cs) >= maxComp)
1477 continue;
1478 return true;
1479 }
1480 // Fall through to end
1481 } else {
1482 const bool testMin = cdf.minValue().isValid();
1483 const bool testMax = cdf.maxValue().isValid();
1484
1485 /* Nope, testing the values as a variant */
1486 for(int j=0; j < details.count(); j++) {
1487 const QContactDetail& detail = details.at(i: j);
1488 const QVariant& var = detail.value(field: cdf.detailField());
1489
1490 // The detail has to have a field of this type in order to be compared.
1491 if (!var.isValid())
1492 continue;
1493
1494 if (testMin && compareVariant(first: var, second: cdf.minValue(), sensitivity: cs) < minComp)
1495 continue;
1496 if (testMax && compareVariant(first: var, second: cdf.maxValue(), sensitivity: cs) >= maxComp)
1497 continue;
1498 return true;
1499 }
1500 // Fall through to end
1501 }
1502 }
1503 break;
1504
1505 case QContactFilter::RelationshipFilter:
1506 {
1507 // matches any contact that plays the specified role in a relationship
1508 // of the specified type with the specified other participant.
1509 const QContactRelationshipFilter rf(filter);
1510
1511 // first, retrieve contact IDs
1512 QContactId relatedId = rf.relatedContactId();
1513
1514 QContactId contactId = contact.id();
1515 if (relatedId == contactId) {
1516 return false;
1517 }
1518
1519 // get the relationships in which this contact is involved.
1520 QList<QContactRelationship> allRelationships;
1521 allRelationships = contact.relationships();
1522
1523 // now check to see if we have a match.
1524 foreach (const QContactRelationship& rel, allRelationships) {
1525 // perform the matching.
1526 if (rf.relatedContactRole() == QContactRelationship::Second) { // this is the role of the related contact; ie, to match, contact must be the first in the relationship.
1527 if ((rf.relationshipType().isEmpty() || rel.relationshipType() == rf.relationshipType())
1528 && (rel.first() == contactId) && (relatedId.isNull() || relatedId == rel.second())) {
1529 return true;
1530 }
1531 } else if (rf.relatedContactRole() == QContactRelationship::First) { // this is the role of the related contact; ie, to match, contact must be the second in the relationship.
1532 if ((rf.relationshipType().isEmpty() || rel.relationshipType() == rf.relationshipType())
1533 && (rel.second() == contactId) && (relatedId.isNull() || relatedId == rel.first())) {
1534 return true;
1535 }
1536 } else { // QContactRelationship::Either
1537 if ((rf.relationshipType().isEmpty() || rel.relationshipType() == rf.relationshipType())
1538 && (relatedId.isNull() || (relatedId == rel.first() || relatedId == rel.second()))) {
1539 return true;
1540 }
1541 }
1542 }
1543
1544 // if not found by now, it doesn't match the filter.
1545 return false;
1546 }
1547 //break; // unreachable.
1548
1549 case QContactFilter::ChangeLogFilter:
1550 {
1551 QContactChangeLogFilter ccf(filter);
1552
1553 // See what we can do...
1554 QContactTimestamp ts = contact.detail(type: QContactTimestamp::Type);
1555
1556 // See if timestamps are even supported
1557 if (ts.isEmpty())
1558 break;
1559
1560 if (ccf.eventType() == QContactChangeLogFilter::EventAdded)
1561 return ccf.since() <= ts.created();
1562 if (ccf.eventType() == QContactChangeLogFilter::EventChanged)
1563 return ccf.since() <= ts.lastModified();
1564
1565 // You can't emulate a removed..
1566 // Fall through to end
1567 }
1568 break;
1569
1570 case QContactFilter::ActionFilter:
1571 {
1572 // Find any matching actions, and do a union filter on their filter objects
1573 QContactActionFilter af(filter);
1574 QList<QContactActionDescriptor> descriptors = QContactActionManager::instance()->actionDescriptors(actionName: af.actionName());
1575
1576 // There's a small wrinkle if there's a value specified in the action filter
1577 // we have to adjust any contained QContactDetailFilters to have that value
1578 // or test if a QContactDetailRangeFilter contains this value already
1579 for (int j = 0; j < descriptors.count(); j++) {
1580 // Action filters are not allowed to return action filters, at all
1581 // it's too annoying to check for recursion
1582 QContactFilter d = descriptors.at(i: j).contactFilter();
1583 if (!validateActionFilter(filter: d))
1584 return false;
1585
1586 // Check for values etc...
1587 if (testFilter(filter: d, contact))
1588 return true;
1589 }
1590 // Fall through to end
1591 }
1592 break;
1593
1594 case QContactFilter::IntersectionFilter:
1595 {
1596 /* XXX In theory we could reorder the terms to put the native tests first */
1597 const QContactIntersectionFilter bf(filter);
1598 const QList<QContactFilter>& terms = bf.filters();
1599 if (terms.count() > 0) {
1600 for(int j = 0; j < terms.count(); j++) {
1601 if (!testFilter(filter: terms.at(i: j), contact)) {
1602 return false;
1603 }
1604 }
1605 return true;
1606 }
1607 // Fall through to end
1608 }
1609 break;
1610
1611 case QContactFilter::UnionFilter:
1612 {
1613 /* XXX In theory we could reorder the terms to put the native tests first */
1614 const QContactUnionFilter bf(filter);
1615 const QList<QContactFilter>& terms = bf.filters();
1616 if (terms.count() > 0) {
1617 for(int j = 0; j < terms.count(); j++) {
1618 if (testFilter(filter: terms.at(i: j), contact)) {
1619 return true;
1620 }
1621 }
1622 return false;
1623 }
1624 // Fall through to end
1625 }
1626 break;
1627
1628 case QContactFilter::CollectionFilter:
1629 {
1630 const QContactCollectionFilter cf(filter);
1631 const QSet<QContactCollectionId>& ids = cf.collectionIds();
1632 if (ids.contains(value: contact.collectionId()))
1633 return true;
1634 return false;
1635 }
1636 }
1637 return false;
1638}
1639
1640/*!
1641 Given a QContactFilter \a filter retrieved from a QContactAction,
1642 check that it is valid and cannot cause infinite recursion.
1643
1644 In particular, a filter from a QContactAction cannot contain
1645 any instances of a QContactActionFilter.
1646
1647 Returns true if \a filter seems ok, or false otherwise.
1648 */
1649
1650bool validateActionFilter(const QContactFilter& filter)
1651{
1652 QList<QContactFilter> toVerify;
1653 toVerify << filter;
1654
1655 while(toVerify.count() > 0) {
1656 QContactFilter f = toVerify.takeFirst();
1657 if (f.type() == QContactFilter::ActionFilter)
1658 return false;
1659 if (f.type() == QContactFilter::IntersectionFilter)
1660 toVerify.append(t: QContactIntersectionFilter(f).filters());
1661 if (f.type() == QContactFilter::UnionFilter)
1662 toVerify.append(t: QContactUnionFilter(f).filters());
1663 }
1664
1665 return true;
1666}
1667
1668/*!
1669 Sets the cached relationships in the given \a contact to \a relationships
1670 */
1671void QContactManagerEngine::setContactRelationships(QContact* contact, const QList<QContactRelationship>& relationships)
1672{
1673 contact->d->m_relationshipsCache = relationships;
1674}
1675
1676/*!
1677 Compares two contacts (\a a and \a b) using the given list of \a sortOrders. Returns a negative number if \a a should appear
1678 before \a b according to the sort order, a positive number if \a a should appear after \a b according to the sort order,
1679 and zero if the two are unable to be sorted.
1680 */
1681int QContactManagerEngine::compareContact(const QContact& a, const QContact& b, const QList<QContactSortOrder>& sortOrders)
1682{
1683 foreach(const QContactSortOrder& sortOrder, sortOrders) {
1684 if (!sortOrder.isValid())
1685 break;
1686
1687 const QContactDetail::DetailType detailType = sortOrder.detailType();
1688 const int detailField = sortOrder.detailField();
1689
1690 const QList<QContactDetail> aDetails = a.details(type: detailType);
1691 const QList<QContactDetail> bDetails = b.details(type: detailType);
1692 if (aDetails.isEmpty() && bDetails.isEmpty())
1693 continue; // use next sort criteria.
1694
1695 // See if we need to check the values
1696 if (detailField == -1) {
1697 // just testing for the presence of a detail of the specified definition
1698 if (aDetails.size() == bDetails.size())
1699 continue; // use next sort criteria.
1700 if (aDetails.isEmpty())
1701 return sortOrder.blankPolicy() == QContactSortOrder::BlanksFirst ? -1 : 1;
1702 if (bDetails.isEmpty())
1703 return sortOrder.blankPolicy() == QContactSortOrder::BlanksFirst ? 1 : -1;
1704 return 0;
1705 }
1706
1707 // obtain the values which this sort order concerns
1708 const QVariant aVal = !aDetails.isEmpty() ? aDetails.first().value(field: detailField) : QVariant();
1709 const QVariant bVal = !bDetails.isEmpty() ? bDetails.first().value(field: detailField) : QVariant();
1710
1711 bool aIsNull = false;
1712 bool bIsNull = false;
1713
1714 // treat empty strings as null qvariants.
1715 if ((aVal.type() == QVariant::String && aVal.toString().isEmpty()) || aVal.isNull()) {
1716 aIsNull = true;
1717 }
1718 if ((bVal.type() == QVariant::String && bVal.toString().isEmpty()) || bVal.isNull()) {
1719 bIsNull = true;
1720 }
1721
1722 // early exit error checking
1723 if (aIsNull && bIsNull)
1724 continue; // use next sort criteria.
1725 if (aIsNull)
1726 return (sortOrder.blankPolicy() == QContactSortOrder::BlanksFirst ? -1 : 1);
1727 if (bIsNull)
1728 return (sortOrder.blankPolicy() == QContactSortOrder::BlanksFirst ? 1 : -1);
1729
1730 // real comparison
1731 int comparison = compareVariant(first: aVal, second: bVal, sensitivity: sortOrder.caseSensitivity()) * (sortOrder.direction() == Qt::AscendingOrder ? 1 : -1);
1732 if (comparison == 0)
1733 continue;
1734 return comparison;
1735 }
1736
1737 return 0; // or according to id? return (a.id() < b.id() ? -1 : 1);
1738}
1739
1740/* A functor that returns true iff a is less than b, according to the sortOrders passed in to the
1741 * ctor. The sortOrders pointer passed in must remain valid for the lifetime of the functor. */
1742class ContactLessThan {
1743 public:
1744 ContactLessThan(const QList<QContactSortOrder>* sortOrders) : mSortOrders(sortOrders) {}
1745 bool operator()(const QContact& a, const QContact& b) const
1746 {
1747 return QContactManagerEngine::compareContact(a, b, sortOrders: *mSortOrders) < 0;
1748 }
1749 private:
1750 const QList<QContactSortOrder>* mSortOrders;
1751};
1752
1753/*!
1754 Performs insertion sort of the contact \a toAdd into the \a sorted list, according to the provided \a sortOrders list.
1755 The first QContactSortOrder in the list has the highest priority: if the contact \a toAdd is deemed equal to another
1756 in the \a sorted list according to the first QContactSortOrder, the second QContactSortOrder in the list is used (and
1757 so on until either the contact is inserted or there are no more sort order objects in the list).
1758
1759 If a contact is equal to another contact according to all sort orders, it is inserted after the previously-added contact.
1760 */
1761void QContactManagerEngine::addSorted(QList<QContact>* sorted, const QContact& toAdd, const QList<QContactSortOrder>& sortOrders)
1762{
1763 if (sortOrders.count() > 0) {
1764 ContactLessThan lessThan(&sortOrders);
1765 QList<QContact>::iterator it(std::upper_bound(first: sorted->begin(), last: sorted->end(), val: toAdd, comp: lessThan));
1766 sorted->insert(before: it, t: toAdd);
1767 } else {
1768 // no sort order? just add it to the end
1769 sorted->append(t: toAdd);
1770 }
1771}
1772
1773/*! Sorts the given list of contacts \a cs according to the provided \a sortOrders
1774*/
1775QList<QContactId> QContactManagerEngine::sortContacts(const QList<QContact>& cs, const QList<QContactSortOrder>& sortOrders)
1776{
1777 QList<QContactId> sortedIds;
1778 QList<QContact> sortedContacts = cs;
1779 if (!sortOrders.isEmpty()) {
1780 ContactLessThan lessThan(&sortOrders);
1781 std::stable_sort(first: sortedContacts.begin(), last: sortedContacts.end(), comp: lessThan);
1782 }
1783
1784 foreach(const QContact& c, sortedContacts) {
1785 sortedIds.append(t: c.id());
1786 }
1787 return sortedIds;
1788}
1789
1790/*!
1791 Notifies the manager engine that the given request \a req is in the process of being destroyed.
1792
1793 The request pointer \a req is still valid during this function call, but before returning
1794 from this call the engine should ensure that it no longer holds any references
1795 to the \a req pointer (for example, in a queue in another thread) because directly
1796 following this call the request will be deleted and this pointer will become invalid.
1797 In a multithreaded engine, this may mean blocking the calling thread while other
1798 threads clean up.
1799
1800 If a request is still in progress at this point, it is undefined what will
1801 happen to the operation requested, but in general it should either be
1802 fully completed or fully aborted. In any case, the client has signalled that
1803 they do not care about the outcome (by deleting the request).
1804 */
1805void QContactManagerEngine::requestDestroyed(QContactAbstractRequest* req)
1806{
1807 Q_UNUSED(req);
1808}
1809
1810/*!
1811 Asks the manager engine to begin the given request \a req which
1812 is currently in a (re)startable state.
1813 Returns true if the request was started successfully, else returns false.
1814
1815 \sa QContactAbstractRequest::start()
1816 */
1817bool QContactManagerEngine::startRequest(QContactAbstractRequest* req)
1818{
1819 Q_UNUSED(req);
1820 return false;
1821}
1822
1823/*!
1824 Asks the manager engine to cancel the given request \a req which was
1825 previously started and is currently in a cancellable state.
1826 Returns true if cancellation of the request was started successfully,
1827 otherwise returns false.
1828
1829 \sa startRequest(), QContactAbstractRequest::cancel()
1830 */
1831bool QContactManagerEngine::cancelRequest(QContactAbstractRequest* req)
1832{
1833 Q_UNUSED(req);
1834 return false;
1835}
1836
1837/*!
1838 Blocks until the manager engine has completed the given request \a req
1839 which was previously started, or until \a msecs milliseconds have passed.
1840 Returns true if the request was completed, and false if the request was not in the
1841 \c QContactAbstractRequest::Active state or no progress could be reported.
1842
1843 \sa startRequest()
1844 */
1845bool QContactManagerEngine::waitForRequestFinished(QContactAbstractRequest* req, int msecs)
1846{
1847 Q_UNUSED(req);
1848 Q_UNUSED(msecs);
1849 return false;
1850}
1851
1852/*!
1853 Updates the given asynchronous request \a req by setting the new \a state
1854 of the request. If the new state is different, the stateChanged() signal
1855 will be emitted by the request.
1856 */
1857void QContactManagerEngine::updateRequestState(QContactAbstractRequest* req, QContactAbstractRequest::State state)
1858{
1859 Q_ASSERT(req);
1860 QMutexLocker ml(&req->d_ptr->m_mutex);
1861 bool emitState = req->d_ptr->m_state != state;
1862 req->d_ptr->m_state = state;
1863 ml.unlock();
1864#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
1865 QPointer<QContactAbstractRequest> guard(req);
1866#endif
1867 Qt::ConnectionType connectionType = Qt::DirectConnection;
1868#ifdef QT_NO_THREAD
1869 if (req->thread() != QThread::currentThread())
1870 connectionType = Qt::BlockingQueuedConnection;
1871#endif
1872 if (emitState)
1873 QMetaObject::invokeMethod(obj: req, member: "stateChanged", type: connectionType, Q_ARG(QContactAbstractRequest::State, state));
1874#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
1875 Q_ASSERT(guard);
1876#endif
1877}
1878
1879
1880/*!
1881 Updates the given QContactIdFetchRequest \a req with the latest results \a result, and operation error \a error.
1882 In addition, the state of the request will be changed to \a newState.
1883
1884 It then causes the request to emit its resultsAvailable() signal to notify clients of the request progress.
1885
1886 If the new request state is different from the previous state, the stateChanged() signal will also be emitted from the request.
1887 */
1888void QContactManagerEngine::updateContactIdFetchRequest(QContactIdFetchRequest* req, const QList<QContactId>& result, QContactManager::Error error, QContactAbstractRequest::State newState)
1889{
1890 Q_ASSERT(req);
1891 QContactIdFetchRequestPrivate* rd = static_cast<QContactIdFetchRequestPrivate*>(req->d_ptr);
1892 QMutexLocker ml(&rd->m_mutex);
1893 bool emitState = rd->m_state != newState;
1894 rd->m_ids = result;
1895 rd->m_error = error;
1896 rd->m_state = newState;
1897 ml.unlock();
1898#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
1899 QPointer<QContactAbstractRequest> guard(req);
1900#endif
1901 Qt::ConnectionType connectionType = Qt::DirectConnection;
1902#ifdef QT_NO_THREAD
1903 if (req->thread() != QThread::currentThread())
1904 connectionType = Qt::BlockingQueuedConnection;
1905#endif
1906 QMetaObject::invokeMethod(obj: req, member: "resultsAvailable", type: connectionType);
1907#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
1908 Q_ASSERT(guard);
1909#endif
1910 if (emitState)
1911 QMetaObject::invokeMethod(obj: req, member: "stateChanged", type: connectionType, Q_ARG(QContactAbstractRequest::State, newState));
1912#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
1913 Q_ASSERT(guard);
1914#endif
1915}
1916
1917/*!
1918 Updates the given QContactFetchRequest \a req with the latest results \a result, and operation error \a error.
1919 In addition, the state of the request will be changed to \a newState.
1920
1921 It then causes the request to emit its resultsAvailable() signal to notify clients of the request progress.
1922
1923 If the new request state is different from the previous state, the stateChanged() signal will also be emitted from the request.
1924 */
1925void QContactManagerEngine::updateContactFetchRequest(QContactFetchRequest* req, const QList<QContact>& result, QContactManager::Error error, QContactAbstractRequest::State newState)
1926{
1927 Q_ASSERT(req);
1928 QContactFetchRequestPrivate* rd = static_cast<QContactFetchRequestPrivate*>(req->d_ptr);
1929 QMutexLocker ml(&rd->m_mutex);
1930 bool emitState = rd->m_state != newState;
1931 rd->m_contacts = result;
1932 rd->m_error = error;
1933 rd->m_state = newState;
1934 ml.unlock();
1935#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
1936 QPointer<QContactAbstractRequest> guard(req);
1937#endif
1938 Qt::ConnectionType connectionType = Qt::DirectConnection;
1939#ifdef QT_NO_THREAD
1940 if (req->thread() != QThread::currentThread())
1941 connectionType = Qt::BlockingQueuedConnection;
1942#endif
1943 QMetaObject::invokeMethod(obj: req, member: "resultsAvailable", type: connectionType);
1944#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
1945 Q_ASSERT(guard);
1946#endif
1947 if (emitState)
1948 QMetaObject::invokeMethod(obj: req, member: "stateChanged", type: connectionType, Q_ARG(QContactAbstractRequest::State, newState));
1949#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
1950 Q_ASSERT(guard);
1951#endif
1952}
1953
1954/*!
1955 Updates the given QContactRemoveRequest \a req with the operation error \a error, and map of input index to individual error \a errorMap.
1956 In addition, the state of the request will be changed to \a newState.
1957
1958 It then causes the request to emit its resultsAvailable() signal to notify clients of the request progress.
1959
1960 If the new request state is different from the previous state, the stateChanged() signal will also be emitted from the request.
1961 */
1962void QContactManagerEngine::updateContactRemoveRequest(QContactRemoveRequest* req, QContactManager::Error error, const QMap<int, QContactManager::Error>& errorMap, QContactAbstractRequest::State newState)
1963{
1964 Q_ASSERT(req);
1965 QContactRemoveRequestPrivate* rd = static_cast<QContactRemoveRequestPrivate*>(req->d_ptr);
1966 QMutexLocker ml(&rd->m_mutex);
1967 bool emitState = rd->m_state != newState;
1968 rd->m_errors = errorMap;
1969 rd->m_error = error;
1970 rd->m_state = newState;
1971 ml.unlock();
1972#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
1973 QPointer<QContactAbstractRequest> guard(req);
1974#endif
1975 Qt::ConnectionType connectionType = Qt::DirectConnection;
1976#ifdef QT_NO_THREAD
1977 if (req->thread() != QThread::currentThread())
1978 connectionType = Qt::BlockingQueuedConnection;
1979#endif
1980 QMetaObject::invokeMethod(obj: req, member: "resultsAvailable", type: connectionType);
1981#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
1982 Q_ASSERT(guard);
1983#endif
1984 if (emitState)
1985 QMetaObject::invokeMethod(obj: req, member: "stateChanged", type: connectionType, Q_ARG(QContactAbstractRequest::State, newState));
1986#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
1987 Q_ASSERT(guard);
1988#endif
1989}
1990
1991/*!
1992 Updates the given QContactSaveRequest \a req with the latest results \a result, operation error \a error, and map of input index to individual error \a errorMap.
1993 In addition, the state of the request will be changed to \a newState.
1994
1995 It then causes the request to emit its resultsAvailable() signal to notify clients of the request progress.
1996
1997 If the new request state is different from the previous state, the stateChanged() signal will also be emitted from the request.
1998 */
1999void QContactManagerEngine::updateContactSaveRequest(QContactSaveRequest* req, const QList<QContact>& result, QContactManager::Error error, const QMap<int, QContactManager::Error>& errorMap, QContactAbstractRequest::State newState)
2000{
2001 Q_ASSERT(req);
2002 QContactSaveRequestPrivate* rd = static_cast<QContactSaveRequestPrivate*>(req->d_ptr);
2003 QMutexLocker ml(&rd->m_mutex);
2004 bool emitState = rd->m_state != newState;
2005 rd->m_contacts = result;
2006 rd->m_errors = errorMap;
2007 rd->m_error = error;
2008 rd->m_state = newState;
2009 ml.unlock();
2010#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
2011 QPointer<QContactAbstractRequest> guard(req);
2012#endif
2013 Qt::ConnectionType connectionType = Qt::DirectConnection;
2014#ifdef QT_NO_THREAD
2015 if (req->thread() != QThread::currentThread())
2016 connectionType = Qt::BlockingQueuedConnection;
2017#endif
2018 QMetaObject::invokeMethod(obj: req, member: "resultsAvailable", type: connectionType);
2019#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
2020 Q_ASSERT(guard);
2021#endif
2022 if (emitState)
2023 QMetaObject::invokeMethod(obj: req, member: "stateChanged", type: connectionType, Q_ARG(QContactAbstractRequest::State, newState));
2024#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
2025 Q_ASSERT(guard);
2026#endif
2027}
2028
2029/*!
2030 Updates the given QContactRelationshipSaveRequest \a req with the latest results \a result, operation error \a error, and map of input index to individual error \a errorMap.
2031 In addition, the state of the request will be changed to \a newState.
2032
2033 It then causes the request to emit its resultsAvailable() signal to notify clients of the request progress.
2034
2035 If the new request state is different from the previous state, the stateChanged() signal will also be emitted from the request.
2036 */
2037void QContactManagerEngine::updateRelationshipSaveRequest(QContactRelationshipSaveRequest* req, const QList<QContactRelationship>& result, QContactManager::Error error, const QMap<int, QContactManager::Error>& errorMap, QContactAbstractRequest::State newState)
2038{
2039 Q_ASSERT(req);
2040 QContactRelationshipSaveRequestPrivate* rd = static_cast<QContactRelationshipSaveRequestPrivate*>(req->d_ptr);
2041 QMutexLocker ml(&rd->m_mutex);
2042 bool emitState = rd->m_state != newState;
2043 rd->m_relationships = result;
2044 rd->m_errors = errorMap;
2045 rd->m_error = error;
2046 rd->m_state = newState;
2047 ml.unlock();
2048#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
2049 QPointer<QContactAbstractRequest> guard(req);
2050#endif
2051 Qt::ConnectionType connectionType = Qt::DirectConnection;
2052#ifdef QT_NO_THREAD
2053 if (req->thread() != QThread::currentThread())
2054 connectionType = Qt::BlockingQueuedConnection;
2055#endif
2056 QMetaObject::invokeMethod(obj: req, member: "resultsAvailable", type: connectionType);
2057#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
2058 Q_ASSERT(guard);
2059#endif
2060 if (emitState)
2061 QMetaObject::invokeMethod(obj: req, member: "stateChanged", type: connectionType, Q_ARG(QContactAbstractRequest::State, newState));
2062#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
2063 Q_ASSERT(guard);
2064#endif
2065}
2066
2067/*!
2068 Updates the given QContactRelationshipRemoveRequest \a req with the operation error \a error, and map of input index to individual error \a errorMap.
2069 In addition, the state of the request will be changed to \a newState.
2070
2071 It then causes the request to emit its resultsAvailable() signal to notify clients of the request progress.
2072
2073 If the new request state is different from the previous state, the stateChanged() signal will also be emitted from the request.
2074 */
2075void QContactManagerEngine::updateRelationshipRemoveRequest(QContactRelationshipRemoveRequest* req, QContactManager::Error error, const QMap<int, QContactManager::Error>& errorMap, QContactAbstractRequest::State newState)
2076{
2077 Q_ASSERT(req);
2078 QContactRelationshipRemoveRequestPrivate* rd = static_cast<QContactRelationshipRemoveRequestPrivate*>(req->d_ptr);
2079 QMutexLocker ml(&rd->m_mutex);
2080 bool emitState = rd->m_state != newState;
2081 rd->m_errors = errorMap;
2082 rd->m_error = error;
2083 rd->m_state = newState;
2084 ml.unlock();
2085#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
2086 QPointer<QContactAbstractRequest> guard(req);
2087#endif
2088 Qt::ConnectionType connectionType = Qt::DirectConnection;
2089#ifdef QT_NO_THREAD
2090 if (req->thread() != QThread::currentThread())
2091 connectionType = Qt::BlockingQueuedConnection;
2092#endif
2093 QMetaObject::invokeMethod(obj: req, member: "resultsAvailable", type: connectionType);
2094#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
2095 Q_ASSERT(guard);
2096#endif
2097 if (emitState)
2098 QMetaObject::invokeMethod(obj: req, member: "stateChanged", type: connectionType, Q_ARG(QContactAbstractRequest::State, newState));
2099#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
2100 Q_ASSERT(guard);
2101#endif
2102}
2103
2104/*!
2105 Updates the given QContactRelationshipFetchRequest \a req with the latest results \a result, and operation error \a error.
2106 In addition, the state of the request will be changed to \a newState.
2107
2108 It then causes the request to emit its resultsAvailable() signal to notify clients of the request progress.
2109
2110 If the new request state is different from the previous state, the stateChanged() signal will also be emitted from the request.
2111 */
2112void QContactManagerEngine::updateRelationshipFetchRequest(QContactRelationshipFetchRequest* req, const QList<QContactRelationship>& result, QContactManager::Error error, QContactAbstractRequest::State newState)
2113{
2114 Q_ASSERT(req);
2115 QContactRelationshipFetchRequestPrivate* rd = static_cast<QContactRelationshipFetchRequestPrivate*>(req->d_ptr);
2116 QMutexLocker ml(&rd->m_mutex);
2117 bool emitState = rd->m_state != newState;
2118 rd->m_relationships = result;
2119 rd->m_error = error;
2120 rd->m_state = newState;
2121 ml.unlock();
2122#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
2123 QPointer<QContactAbstractRequest> guard(req);
2124#endif
2125 Qt::ConnectionType connectionType = Qt::DirectConnection;
2126#ifdef QT_NO_THREAD
2127 if (req->thread() != QThread::currentThread())
2128 connectionType = Qt::BlockingQueuedConnection;
2129#endif
2130 QMetaObject::invokeMethod(obj: req, member: "resultsAvailable", type: connectionType);
2131#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
2132 Q_ASSERT(guard);
2133#endif
2134 if (emitState)
2135 QMetaObject::invokeMethod(obj: req, member: "stateChanged", type: connectionType, Q_ARG(QContactAbstractRequest::State, newState));
2136#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
2137 Q_ASSERT(guard);
2138#endif
2139}
2140
2141/*!
2142 Updates the given QContactCollectionFetchRequest \a req with the latest results \a result and an operation error \a error.
2143 In addition, the state of the request will be changed to \a newState.
2144
2145 It then causes the request to emit its resultsAvailable() signal to notify clients of the request progress.
2146 If the new request state is different from the previous state, the stateChanged() signal will also be emitted from the request.
2147 */
2148void QContactManagerEngine::updateCollectionFetchRequest(QContactCollectionFetchRequest* req, const QList<QContactCollection>& result, QContactManager::Error error, QContactAbstractRequest::State newState)
2149{
2150 Q_ASSERT(req);
2151 QContactCollectionFetchRequestPrivate* rd = static_cast<QContactCollectionFetchRequestPrivate*>(req->d_ptr);
2152 QMutexLocker ml(&rd->m_mutex);
2153 bool emitState = rd->m_state != newState;
2154 rd->m_collections = result;
2155 rd->m_error = error;
2156 rd->m_state = newState;
2157 ml.unlock();
2158#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
2159 QPointer<QContactAbstractRequest> guard(req);
2160#endif
2161 Qt::ConnectionType connectionType = Qt::DirectConnection;
2162#ifdef QT_NO_THREAD
2163 if (req->thread() != QThread::currentThread())
2164 connectionType = Qt::BlockingQueuedConnection;
2165#endif
2166 QMetaObject::invokeMethod(obj: req, member: "resultsAvailable", type: connectionType);
2167#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
2168 Q_ASSERT(guard);
2169#endif
2170 if (emitState)
2171 QMetaObject::invokeMethod(obj: req, member: "stateChanged", type: connectionType, Q_ARG(QContactAbstractRequest::State, newState));
2172#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
2173 Q_ASSERT(guard);
2174#endif
2175}
2176
2177/*!
2178 Updates the given QContactCollectionRemoveRequest \a req with the operation error \a error, and map of input index to individual error \a errorMap.
2179 In addition, the state of the request will be changed to \a newState.
2180
2181 It then causes the request to emit its resultsAvailable() signal to notify clients of the request progress.
2182 If the new request state is different from the previous state, the stateChanged() signal will also be emitted from the request.
2183 */
2184void QContactManagerEngine::updateCollectionRemoveRequest(QContactCollectionRemoveRequest* req, QContactManager::Error error, const QMap<int, QContactManager::Error>& errorMap, QContactAbstractRequest::State newState)
2185{
2186 Q_ASSERT(req);
2187 QContactCollectionRemoveRequestPrivate* rd = static_cast<QContactCollectionRemoveRequestPrivate*>(req->d_ptr);
2188 QMutexLocker ml(&rd->m_mutex);
2189 bool emitState = rd->m_state != newState;
2190 rd->m_errors = errorMap;
2191 rd->m_error = error;
2192 rd->m_state = newState;
2193 ml.unlock();
2194#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
2195 QPointer<QContactAbstractRequest> guard(req);
2196#endif
2197 Qt::ConnectionType connectionType = Qt::DirectConnection;
2198#ifdef QT_NO_THREAD
2199 if (req->thread() != QThread::currentThread())
2200 connectionType = Qt::BlockingQueuedConnection;
2201#endif
2202 QMetaObject::invokeMethod(obj: req, member: "resultsAvailable", type: connectionType);
2203#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
2204 Q_ASSERT(guard);
2205#endif
2206 if (emitState)
2207 QMetaObject::invokeMethod(obj: req, member: "stateChanged", type: connectionType, Q_ARG(QContactAbstractRequest::State, newState));
2208#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
2209 Q_ASSERT(guard);
2210#endif
2211}
2212
2213/*!
2214 Updates the given QContactCollectionSaveRequest \a req with the latest results \a result, operation error \a error, and map of input index to individual error \a errorMap.
2215 In addition, the state of the request will be changed to \a newState.
2216
2217 It then causes the request to emit its resultsAvailable() signal to notify clients of the request progress.
2218 If the new request state is different from the previous state, the stateChanged() signal will also be emitted from the request.
2219 */
2220void QContactManagerEngine::updateCollectionSaveRequest(QContactCollectionSaveRequest* req, const QList<QContactCollection>& result, QContactManager::Error error, const QMap<int, QContactManager::Error>& errorMap, QContactAbstractRequest::State newState)
2221{
2222 Q_ASSERT(req);
2223 QContactCollectionSaveRequestPrivate* rd = static_cast<QContactCollectionSaveRequestPrivate*>(req->d_ptr);
2224 QMutexLocker ml(&rd->m_mutex);
2225 bool emitState = rd->m_state != newState;
2226 rd->m_collections = result;
2227 rd->m_errors = errorMap;
2228 rd->m_error = error;
2229 rd->m_state = newState;
2230 ml.unlock();
2231#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
2232 QPointer<QContactAbstractRequest> guard(req);
2233#endif
2234 Qt::ConnectionType connectionType = Qt::DirectConnection;
2235#ifdef QT_NO_THREAD
2236 if (req->thread() != QThread::currentThread())
2237 connectionType = Qt::BlockingQueuedConnection;
2238#endif
2239 QMetaObject::invokeMethod(obj: req, member: "resultsAvailable", type: connectionType);
2240#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
2241 Q_ASSERT(guard);
2242#endif
2243 if (emitState)
2244 QMetaObject::invokeMethod(obj: req, member: "stateChanged", type: connectionType, Q_ARG(QContactAbstractRequest::State, newState));
2245#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
2246 Q_ASSERT(guard);
2247#endif
2248}
2249
2250
2251/*!
2252 For each contact in \a contacts, either add it to the database or update an existing one.
2253
2254 This function accepts a \a typeMask, which specifies which details of the contacts should be
2255 updated. Details with types not included in the typeMask will not be updated
2256 or added.
2257
2258 The manager should populate \a errorMap (the map of indices of the \a contacts list to the error
2259 which occurred when saving the contact at that index) for every index for which the contact could
2260 not be saved, if it is able.
2261
2262 The supplied \a errorMap parameter may be null, if the client does not desire detailed error information.
2263 If supplied, it will be empty upon entry to this function.
2264
2265 The \l QContactManager::error() function will only return \c QContactManager::NoError if all
2266 contacts were saved successfully.
2267
2268 For each newly saved contact that was successful, the id of the contact in the \a contacts list
2269 will be updated with the new value. If a failure occurs when saving a new contact, the id will be
2270 cleared.
2271
2272 Any errors encountered during this operation should be stored to \a error.
2273 */
2274bool QContactManagerEngine::saveContacts(QList<QContact> *contacts, const QList<QContactDetail::DetailType> &typeMask, QMap<int, QContactManager::Error> *errorMap, QContactManager::Error *error)
2275{
2276 // TODO should the default implementation do the right thing, or return false?
2277 if (typeMask.isEmpty()) {
2278 // Non partial, just pass it on
2279 return saveContacts(contacts, errorMap, error);
2280 } else {
2281 // Partial contact save.
2282 // Basically
2283
2284 // Need to:
2285 // 1) fetch existing contacts
2286 // 2) strip out details in typeMask for existing contacts
2287 // 3) copy the details from the passed in list for existing contacts
2288 // 4) for any new contacts, copy the masked details to a blank contact
2289 // 5) save the modified ones
2290 // 6) update the id of any new contacts
2291 // 7) transfer any errors from saving to errorMap
2292
2293 QList<QContactId> existingContactIds;
2294
2295 // Error conditions:
2296 // 1) bad id passed in (can't fetch)
2297 // 2) bad fetch (can't save partial update)
2298 // 3) bad save error
2299 // all of which needs to be returned in the error map
2300
2301 QHash<int, int> existingIdMap; // contacts index to existingContacts index
2302
2303 // Try to figure out which of our arguments are new contacts
2304 for(int i = 0; i < contacts->count(); i++) {
2305 // See if there's a contactId that's not from this manager
2306 const QContact c = contacts->at(i);
2307 if (c.id().managerUri() == managerUri()) {
2308 existingIdMap.insert(akey: i, avalue: existingContactIds.count());
2309 existingContactIds.append(t: c.id());
2310 } else if (!c.id().isNull()) {
2311 // Hmm, error (wrong manager)
2312 errorMap->insert(akey: i, avalue: QContactManager::DoesNotExistError);
2313 } // else new contact
2314 }
2315
2316 // Now fetch the existing contacts
2317 QMap<int, QContactManager::Error> fetchErrors;
2318 QContactManager::Error fetchError = QContactManager::NoError;
2319 QList<QContact> existingContacts = this->contacts(contactIds: existingContactIds, fetchHint: QContactFetchHint(),
2320 errorMap: &fetchErrors, error: &fetchError);
2321
2322 // Prepare the list to save
2323 QList<QContact> contactsToSave;
2324 QList<int> savedToOriginalMap; // contactsToSave index to contacts index
2325 QSet<QContactDetail::DetailType> mask = typeMask.toSet();
2326
2327 for (int i = 0; i < contacts->count(); i++) {
2328 // See if this is an existing contact or a new one
2329 const int fetchedIdx = existingIdMap.value(akey: i, adefaultValue: -1);
2330 QContact contactToSave;
2331 if (fetchedIdx >= 0) {
2332 // See if we had an error
2333 if (fetchErrors[fetchedIdx] != QContactManager::NoError) {
2334 errorMap->insert(akey: i, avalue: fetchErrors[fetchedIdx]);
2335 continue;
2336 }
2337
2338 // Existing contact we should have fetched
2339 contactToSave = existingContacts.at(i: fetchedIdx);
2340
2341 QSharedDataPointer<QContactData>& cd = QContactData::contactData(contact&: contactToSave);
2342 cd->removeOnly(types: mask);
2343 } else if (errorMap->contains(akey: i)) {
2344 // A bad argument. Leave it out of the contactsToSave list
2345 continue;
2346 } // else new contact
2347
2348 // Now copy in the details from the arguments
2349 const QContact& c = contacts->at(i);
2350
2351 foreach (QContactDetail::DetailType type, mask) {
2352 QList<QContactDetail> details = c.details(type);
2353 foreach(QContactDetail detail, details) {
2354 contactToSave.saveDetail(detail: &detail);
2355 }
2356 }
2357
2358 savedToOriginalMap.append(t: i);
2359 contactsToSave.append(t: contactToSave);
2360 }
2361
2362 // Now save them
2363 QMap<int, QContactManager::Error> saveErrors;
2364 QContactManager::Error saveError = QContactManager::NoError;
2365 saveContacts(contacts: &contactsToSave, errorMap: &saveErrors, error: &saveError);
2366
2367 // Now update the passed in arguments, where necessary
2368
2369 // Update IDs of the contacts list
2370 for (int i = 0; i < contactsToSave.count(); i++) {
2371 (*contacts)[savedToOriginalMap[i]].setId(contactsToSave[i].id());
2372 }
2373 // Populate the errorMap with the errorMap of the attempted save
2374 QMap<int, QContactManager::Error>::iterator it(saveErrors.begin());
2375 while (it != saveErrors.end()) {
2376 if (it.value() != QContactManager::NoError) {
2377 errorMap->insert(akey: savedToOriginalMap[it.key()], avalue: it.value());
2378 }
2379 it++;
2380 }
2381
2382 return errorMap->isEmpty();
2383 }
2384}
2385
2386/*!
2387 Returns the list of contacts with the ids given by \a contactIds. There is a one-to-one
2388 correspondence between the returned contacts and the supplied \a contactIds.
2389
2390 If there is an invalid id in \a contactIds, then an empty QContact will take its place in the
2391 returned list and an entry will be inserted into \a errorMap.
2392
2393 The overall operation error will be saved in \a error.
2394
2395 The \a fetchHint parameter describes the optimization hints that a manager may take.
2396 If the \a fetchHint is the default constructed hint, all existing details, relationships and
2397 action preferences in the matching contacts will be returned.
2398
2399 If a non-default fetch hint is supplied, and the client wishes to make changes to the contacts,
2400 they should ensure that only a detail type hint is supplied and that when saving it back, a
2401 type mask should be used which corresponds to the detail type hint. This is to ensure
2402 that no data is lost by overwriting an existing contact with a restricted version of it.
2403
2404 \sa QContactFetchHint
2405 */
2406QList<QContact> QContactManagerEngine::contacts(const QList<QContactId> &contactIds, const QContactFetchHint &fetchHint, QMap<int, QContactManager::Error> *errorMap, QContactManager::Error *error) const
2407{
2408 QContactIdFilter lif;
2409 lif.setIds(contactIds);
2410
2411 QList<QContact> unsorted = contacts(filter: lif, sortOrders: QContactSortOrder(), fetchHint, error);
2412
2413 // Build an index into the results
2414 QHash<QContactId, int> idMap; // value is index into unsorted
2415 if (*error == QContactManager::NoError) {
2416 for (int i = 0; i < unsorted.size(); i++) {
2417 idMap.insert(akey: unsorted[i].id(), avalue: i);
2418 }
2419 }
2420
2421 // Build up the results and errors
2422 QList<QContact> results;
2423 for (int i = 0; i < contactIds.count(); i++) {
2424 QContactId id(contactIds[i]);
2425 if (!idMap.contains(akey: id)) {
2426 if (errorMap)
2427 errorMap->insert(akey: i, avalue: QContactManager::DoesNotExistError);
2428 if (*error == QContactManager::NoError)
2429 *error = QContactManager::DoesNotExistError;
2430 results.append(t: QContact());
2431 } else {
2432 results.append(t: unsorted[idMap[id]]);
2433 }
2434 }
2435
2436 return results;
2437}
2438
2439/*!
2440 Updates the given QContactFetchByIdRequest \a req with the latest results \a result, and operation error \a error, and map of input index to individual error \a errorMap.
2441 In addition, the state of the request will be changed to \a newState.
2442
2443 It then causes the request to emit its resultsAvailable() signal to notify clients of the request progress.
2444
2445 If the new request state is different from the previous state, the stateChanged() signal will also be emitted from the request.
2446 */
2447void QContactManagerEngine::updateContactFetchByIdRequest(QContactFetchByIdRequest *req, const QList<QContact> &result, QContactManager::Error error,
2448 const QMap<int, QContactManager::Error> &errorMap, QContactAbstractRequest::State newState)
2449{
2450 Q_ASSERT(req);
2451 QContactFetchByIdRequestPrivate* rd = static_cast<QContactFetchByIdRequestPrivate*>(req->d_ptr);
2452 QMutexLocker ml(&rd->m_mutex);
2453 bool emitState = rd->m_state != newState;
2454 rd->m_contacts = result;
2455 rd->m_errors = errorMap;
2456 rd->m_error = error;
2457 rd->m_state = newState;
2458 ml.unlock();
2459#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
2460 QPointer<QContactAbstractRequest> guard(req);
2461#endif
2462 Qt::ConnectionType connectionType = Qt::DirectConnection;
2463#ifdef QT_NO_THREAD
2464 if (req->thread() != QThread::currentThread())
2465 connectionType = Qt::BlockingQueuedConnection;
2466#endif
2467 QMetaObject::invokeMethod(obj: req, member: "resultsAvailable", type: connectionType);
2468#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
2469 Q_ASSERT(guard);
2470#endif
2471 if (emitState)
2472 QMetaObject::invokeMethod(obj: req, member: "stateChanged", type: connectionType, Q_ARG(QContactAbstractRequest::State, newState));
2473#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
2474 Q_ASSERT(guard);
2475#endif
2476}
2477
2478#include "moc_qcontactmanagerengine.cpp"
2479
2480QT_END_NAMESPACE_CONTACTS
2481

source code of qtpim/src/contacts/qcontactmanagerengine.cpp