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 | |
51 | QT_BEGIN_NAMESPACE_CONTACTS |
52 | |
53 | static 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 | */ |
186 | QString 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 | */ |
196 | QMap<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 | */ |
215 | QMap<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 | */ |
241 | QList<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 | */ |
266 | QList<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 | */ |
291 | QContact 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 | */ |
310 | bool 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 | */ |
325 | QContactId 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 | */ |
338 | QList<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 | */ |
359 | bool 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 | */ |
381 | bool 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 | */ |
410 | bool 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 | */ |
437 | bool 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 | */ |
449 | QContactCollectionId 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 | */ |
461 | QContactCollection 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 | */ |
472 | QList<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 | */ |
492 | bool 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 | */ |
510 | bool 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 | */ |
539 | QContactFilter 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 | */ |
674 | bool 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 | */ |
684 | QList<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 | */ |
698 | bool 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 | */ |
712 | QList<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 | */ |
730 | QList<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 | */ |
780 | bool 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 | */ |
816 | void 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 | */ |
837 | void 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 | */ |
860 | bool 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 | */ |
893 | bool 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 | */ |
931 | bool 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 | */ |
969 | bool 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 */ |
978 | static 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 | */ |
1143 | int 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 | */ |
1241 | bool 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 | |
1650 | bool 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 | */ |
1671 | void 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 | */ |
1681 | int 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. */ |
1742 | class 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 | */ |
1761 | void 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 | */ |
1775 | QList<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 | */ |
1805 | void 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 | */ |
1817 | bool 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 | */ |
1831 | bool 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 | */ |
1845 | bool 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 | */ |
1857 | void 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 | */ |
1888 | void 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 | */ |
1925 | void 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 | */ |
1962 | void 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 | */ |
1999 | void 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 | */ |
2037 | void 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 | */ |
2075 | void 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 | */ |
2112 | void 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 | */ |
2148 | void 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 | */ |
2184 | void 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 | */ |
2220 | void 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 | */ |
2274 | bool 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 | */ |
2406 | QList<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 | */ |
2447 | void 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 | |
2480 | QT_END_NAMESPACE_CONTACTS |
2481 | |