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 QtOrganizer 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 "qorganizermanagerengine.h"
35#include "qorganizeritems.h"
36#include "qorganizeritemdetails.h"
37#include "qorganizeritemfilters.h"
38#include "qorganizeritemrequests.h"
39#include "qorganizeritemrequests_p.h"
40
41#include <QtCore/qmutex.h>
42
43QT_BEGIN_NAMESPACE_ORGANIZER
44
45/*!
46 \class QOrganizerManagerEngine
47 \brief The QOrganizerManagerEngine class provides the interface to implement functionalities
48 of organizer managers.
49 \inmodule QtOrganizer
50 \ingroup organizer-backends
51
52 This class should only be used by backend developers. Instances of this class are provided to
53 QOrganizerManager by a QOrganizerManagerEngineFactory instance, which is loaded from a plugin.
54
55 The default implementation of this interface provides a backend doing nothing, so that backend
56 developers only need to reimplement the functionalities needed.
57
58 More information on writing a organizer engine plugin is available in the \l{Qt Organizer Manager Engines}
59 documentation.
60
61 \sa QOrganizerManager, QOrganizerManagerEngineFactory
62 */
63
64/*!
65 \fn QOrganizerManagerEngine::dataChanged()
66
67 This signal should be emitted if the internal state of the plugin changes, and it is unable to
68 determine the changes which occurred, or if it considers the changes to be radical enough to
69 require clients to reload all data.
70
71 If this signal is emitted, no other signals will be emitted for the associated changes.
72
73 \sa itemsAdded(), itemsChanged(), itemsRemoved()
74 */
75
76/*!
77 \fn QOrganizerManagerEngine::itemsAdded(const QList<QOrganizerItemId> &itemIds);
78
79 This signal should be emitted at some point once the items identified by \a itemIds have been
80 added to the backend.
81
82 This signal should not be emitted if the dataChanged() signal was previously emitted for these
83 changes.
84
85 \sa dataChanged()
86 */
87
88/*!
89 \fn QOrganizerManagerEngine::itemsChanged(const QList<QOrganizerItemId> &itemIds, const QList<QOrganizerItemDetail::DetailType> &typesChanged);
90
91 This signal should be emitted at some point once the items identified by \a itemIds have been
92 modified in the backend.
93
94 The set of item detail types modified in the reported changes is a subset of those listed in
95 \a typesChanged, unless \a typesChanged is empty, in which case no limitation on the reported
96 changes may be assumed.
97
98 This signal should not be emitted if the dataChanged() signal was previously emitted for these
99 changes.
100
101 \sa dataChanged()
102 */
103
104/*!
105 \fn QOrganizerManagerEngine::itemsRemoved(const QList<QOrganizerItemId> &itemIds);
106
107 This signal should be emitted at some point once the items identified by \a itemIds have been
108 removed from the backend.
109
110 This signal should not be emitted if the dataChanged() signal was previously emitted for these
111 changes.
112
113 \sa dataChanged()
114 */
115
116/*!
117 \fn QOrganizerManagerEngine::itemsModified(const QList<QPair<QOrganizerItemId, QOrganizerManager::Operation> > &itemIds)
118
119 This signal should be emitted at some point once the items identified by \a itemIds have been
120 modified in the backend.
121
122 This signal should not be emitted if the dataChanged() signal was previously emitted for these
123 changes.
124
125 \sa dataChanged()
126 */
127
128/*!
129 \fn QOrganizerManagerEngine::collectionsAdded(const QList<QOrganizerCollectionId> &collectionIds)
130
131 This signal should be emitted at some point once the collections identified by \a collectionIds
132 have been added to the backend.
133
134 This signal should not be emitted if the dataChanged() signal was previously emitted for these
135 changes.
136
137 \sa dataChanged()
138 */
139
140/*!
141 \fn QOrganizerManagerEngine::collectionsChanged(const QList<QOrganizerCollectionId> &collectionIds)
142
143 This signal should be emitted at some point once the collections identified by \a collectionIds
144 have been changed in the backend.
145
146 This signal should not be emitted if items in the collections have been added, modified, or
147 removed.
148
149 This signal should not be emitted if the dataChanged() signal was previously emitted for these
150 changes.
151
152 \sa dataChanged()
153 */
154
155/*!
156 \fn QOrganizerManagerEngine::collectionsRemoved(const QList<QOrganizerCollectionId> &collectionIds)
157
158 This signal should be emitted at some point once the collections identified by \a collectionIds
159 have been removed from the backend.
160
161 This signal should not be emitted if the dataChanged() signal was previously emitted for these
162 changes.
163
164 \sa dataChanged()
165 */
166
167/*!
168 \fn QOrganizerManagerEngine::collectionsModified(const QList<QPair<QOrganizerCollectionId, QOrganizerManager::Operation> > &collectionIds)
169
170 This signal should be emitted at some point once the collections identified by \a collectionIds
171 have been modified in the backend.
172
173 This signal should not be emitted if the dataChanged() signal was previously emitted for these
174 changes.
175
176 \sa dataChanged()
177 */
178
179/*!
180 Constructs an empty QOrganizerManagerEngine with the given \a parent.
181 */
182QOrganizerManagerEngine::QOrganizerManagerEngine(QObject *parent)
183 : QObject(parent)
184{
185}
186
187/*!
188 This function should be reimplemented to return the name of this backend. The default implementation
189 returns the name "invalid".
190*/
191QString QOrganizerManagerEngine::managerName() const
192{
193 return QString(QStringLiteral("invalid"));
194}
195
196/*!
197 Returns the parameters with which this engine was constructed. Note that
198 the engine may have discarded unused or invalid parameters at the time of
199 construction, and these will not be returned.
200 */
201QMap<QString, QString> QOrganizerManagerEngine::managerParameters() const
202{
203 return QMap<QString, QString>();
204}
205
206/*!
207 Returns the subset of the manager parameters that are relevant when interpreting
208 contact ID values. Since contact ID comparison involves equivalence of
209 managerUri values, parameters that do not differentiate contact IDs should not
210 be returned by this function.
211
212 For example, a manager engine may support 'user' and 'cachesize' parameters,
213 where the former distinguishes between separate user domains, and the latter
214 is for performance tuning. The 'user' parameter will be relevant to the interpretation
215 of contact IDs and thus should be returned by this function, whereas 'cachesize'
216 is not relevant and should be omitted.
217
218 \sa managerUri(), managerParamaters()
219 */
220QMap<QString, QString> QOrganizerManagerEngine::idInterpretationParameters() const
221{
222 return QMap<QString, QString>(); // default implementation returns no parameters.
223}
224
225/*!
226 \fn QString QOrganizerManagerEngine::managerUri() const
227
228 Returns the unique URI of this manager, which is built from the manager name and the
229 ID interpretation parameters used to construct it.
230
231 \sa idInterpretationParameters()
232 */
233
234/*!
235 \fn QOrganizerItemId QOrganizerManagerEngine::itemId(const QByteArray &localId) const
236
237 Returns the organizer item ID for this managerUri() and the given
238 engine specific ID part \a localId.
239*/
240
241/*!
242 \fn QOrganizerCollectionId QOrganizerManagerEngine::collectionId(const QByteArray &localId) const
243
244 Returns the organizer collection ID for this managerUri() and the given
245 engine specific ID part \a localId.
246*/
247
248/*!
249 This function should be reimplemented to support synchronous calls to fetch occurrences of the
250 given parent item.
251
252 This function is supposed to return a list of a maximum of \a maxCount organizer item instances
253 which are occurrences of the given \a parentItem recurring item, which occur between the given
254 \a startDateTime and the given \a endDateTime date, inclusive. Any error which occurs should be
255 saved in \a error.
256
257 A default-constructed (invalid) \a startDateTime specifies an open start date time (matches anything
258 which occurs up until the \a endDateTime), and a default-constructed (invalid) \a endDateTime
259 specifies an open end date time (matches anything which occurs after the \a startDateTime). If
260 both the \a startDateTime and \a endDateTime are invalid, this function will return the IDs of
261 all items.
262
263 It's up to the backend to decide how many occurrences are returned if the given \a maxCount is
264 negative.
265
266 It's up to the backend to decide if fetch hint is supported. If supported, only the details
267 defined by \a fetchHint will be fetched.
268 */
269QList<QOrganizerItem> QOrganizerManagerEngine::itemOccurrences(const QOrganizerItem &parentItem,
270 const QDateTime &startDateTime,
271 const QDateTime &endDateTime, int maxCount,
272 const QOrganizerItemFetchHint &fetchHint,
273 QOrganizerManager::Error *error)
274{
275 Q_UNUSED(parentItem);
276 Q_UNUSED(startDateTime);
277 Q_UNUSED(endDateTime);
278 Q_UNUSED(maxCount);
279 Q_UNUSED(fetchHint);
280
281 *error = QOrganizerManager::NotSupportedError;
282 return QList<QOrganizerItem>();
283}
284
285/*!
286 This function should be reimplemented to support synchronous calls to fetch organizer item IDs.
287
288 This function is supposed to return a list of item IDs of persisted organizer items that match
289 the given \a filter, sorted according to the given list of \a sortOrders, for any item which
290 occurs (or has an occurrence which occurs) in the range specified by the given \a startDateTime
291 and \a endDateTime, inclusive. Any error which occurs should be saved in \a error.
292
293 A default-constructed (invalid) \a startDateTime specifies an open start date time (matches anything
294 which occurs up until the \a endDateTime), and a default-constructed (invalid) \a endDateTime
295 specifies an open end date time (matches anything which occurs after the \a startDateTime). If
296 both the \a startDateTime and \a endDateTime are invalid, this function will return the IDs of
297 all items which match the \a filter criteria.
298
299 It's up to the backend to decide how filters are supported.
300 */
301QList<QOrganizerItemId> QOrganizerManagerEngine::itemIds(const QOrganizerItemFilter &filter,
302 const QDateTime &startDateTime,
303 const QDateTime &endDateTime,
304 const QList<QOrganizerItemSortOrder> &sortOrders,
305 QOrganizerManager::Error *error)
306{
307 Q_UNUSED(startDateTime)
308 Q_UNUSED(endDateTime)
309 Q_UNUSED(filter)
310 Q_UNUSED(sortOrders)
311
312 *error = QOrganizerManager::NotSupportedError;
313 return QList<QOrganizerItemId>();
314}
315
316/*!
317 This function should be reimplemented to support synchronous calls to fetch organizer items.
318
319 This function is supposed to return a list of a maximum of \a maxCount organizer items and
320 occurrences that match the given \a filter, which occur in the range specified by the given
321 \a startDateTime and \a endDateTime, inclusive, and sorted according to the given list of
322 \a sortOrders. Any operation error which occurs should be saved in \a error.
323
324 A default-constructed (invalid) \a startDateTime specifies an open start date time (matches anything
325 which occurs up until the \a endDateTime), and a default-constructed (invalid) \a endDateTime
326 specifies an open end date time (matches anything which occurs after the \a startDateTime). If
327 both the \a startDateTime and \a endDateTime are invalid, this function will return the IDs of
328 all items which match the \a filter criteria.
329
330 If no sort order is provided, the list is returned sorted by date.
331
332 It's up to the backend to decide how many items should be returned if \a maxCount is negative.
333
334 It's up to the backend to decide if filter and fetch hint are supported.
335 */
336QList<QOrganizerItem> QOrganizerManagerEngine::items(const QOrganizerItemFilter &filter, const QDateTime &startDateTime,
337 const QDateTime &endDateTime, int maxCount,
338 const QList<QOrganizerItemSortOrder> &sortOrders,
339 const QOrganizerItemFetchHint &fetchHint, QOrganizerManager::Error *error)
340{
341 Q_UNUSED(filter)
342 Q_UNUSED(startDateTime)
343 Q_UNUSED(endDateTime)
344 Q_UNUSED(maxCount)
345 Q_UNUSED(sortOrders)
346 Q_UNUSED(fetchHint)
347
348 *error = QOrganizerManager::NotSupportedError;
349 return QList<QOrganizerItem>();
350}
351
352/*!
353 This function should be reimplemented to support synchronous calls to fetch organizer items for
354 export.
355
356 This function is supposed to return a list of organizer items that match the given \a filter,
357 sorted according to the given list of \a sortOrders, for any item which occurs (or has an
358 occurrence which occurs) in the range specified by the given \a startDateTime and \a endDateTime,
359 inclusive. Any operation error which occurs should be saved in \a error.
360
361 Note that event occurrences and TODO occurrences should only be returned when they represent an
362 exceptional occurrence (i.e. the client has specifically saved the occurrence in the backend).
363
364 A default-constructed (invalid) \a startDateTime specifies an open start date time (matches anything
365 which occurs up until the \a endDateTime), and a default-constructed (invalid) \a endDateTime
366 specifies an open end date time (matches anything which occurs after the \a startDateTime). If
367 both the \a startDateTime and \a endDateTime are invalid, this function will return the IDs of
368 all items which match the \a filter criteria.
369
370 It's up to the backend to decide if filter and fetch hint are supported. If the fetch hint is
371 supported, only the details defined by \a fetchHint will be fetched.
372 */
373QList<QOrganizerItem> QOrganizerManagerEngine::itemsForExport(const QDateTime &startDateTime,
374 const QDateTime &endDateTime,
375 const QOrganizerItemFilter &filter,
376 const QList<QOrganizerItemSortOrder> &sortOrders,
377 const QOrganizerItemFetchHint &fetchHint,
378 QOrganizerManager::Error *error)
379{
380 Q_UNUSED(startDateTime)
381 Q_UNUSED(endDateTime)
382 Q_UNUSED(filter)
383 Q_UNUSED(sortOrders)
384 Q_UNUSED(fetchHint)
385
386 *error = QOrganizerManager::NotSupportedError;
387 return QList<QOrganizerItem>();
388}
389
390/*!
391 This function should be reimplemented to support synchronous calls to fetch organizer items by
392 their IDs \a itemIds.
393
394 The items fetched by the backend should have a one-to-one correspondence to the IDs passed into
395 this class. That is, the nth item in the returned list should have an ID which is equal to the
396 nth ID in the list of IDs. Any invalid ID should correspond to an empty QOrganizerItem.
397
398 It's up to the backend to decide if fetch hint is supported. If supported, only the details
399 defined by \a fetchHint will be fetched.
400
401 Any operation error which occurs should be saved in \a error. And the per-input errors should be
402 stored in \a errorMap.
403
404 */
405QList<QOrganizerItem> QOrganizerManagerEngine::items(const QList<QOrganizerItemId> &itemIds, const QOrganizerItemFetchHint &fetchHint,
406 QMap<int, QOrganizerManager::Error> *errorMap, QOrganizerManager::Error *error)
407{
408 Q_UNUSED(itemIds)
409 Q_UNUSED(fetchHint)
410 Q_UNUSED(errorMap)
411
412 *error = QOrganizerManager::NotSupportedError;
413 return QList<QOrganizerItem>();
414}
415
416/*!
417 This function should be reimplemented to return the list of filters supported by this backend.
418 The default implementation returns an empty list.
419 */
420QList<QOrganizerItemFilter::FilterType> QOrganizerManagerEngine::supportedFilters() const
421{
422 return QList<QOrganizerItemFilter::FilterType>();
423}
424
425/*!
426 This function should be reimplemented to return the list of details supported by this backend
427 for the given \a itemType. The default implementation returns an empty list.
428 */
429QList<QOrganizerItemDetail::DetailType> QOrganizerManagerEngine::supportedItemDetails(QOrganizerItemType::ItemType itemType) const
430{
431 Q_UNUSED(itemType)
432 return QList<QOrganizerItemDetail::DetailType>();
433}
434
435/*!
436 This function should be reimplemented to return the list of item types supported by this backend.
437 The default implementation returns an empty list.
438 */
439QList<QOrganizerItemType::ItemType> QOrganizerManagerEngine::supportedItemTypes() const
440{
441 return QList<QOrganizerItemType::ItemType>();
442}
443
444/*!
445 This function should be reimplemented to support synchronous calls to save organizer items.
446
447 This function is supposed to save the given list of \a items to the backend, and returns true on
448 success or false otherwise.
449
450 A new organizer item will be created in the backend store if the item ID of it is null. Otherwise,
451 an existing item with the same ID will be updated. If the given item ID does not exist in the
452 backend, it will result a QOrganizerManager::DoesNotExistError error.
453
454 If the collection ID of the item is null, it will be saved to the default collection. If the given
455 collection ID doesn't exist, the saving will fail and \a error will be set to QOrganizerManager::InvalidCollectionError.
456
457 If the \a detailMask is empty, only the details currently existing in the item will be saved.
458 Otherwise, only details masked by the \a detailMask will be saved or updated, others are kept
459 untouched. It's useful to avoid information loss if the items are retrieved with a fetch hint.
460
461 Note that upon successful saving, the backend may update the item, e.g. item ID for newly saved
462 items, GUID, timestamp, version, etc.
463
464 Any error which occurs should be saved in \a error, and per-input errors for the operation should
465 be stored in \a errorMap.
466 */
467bool QOrganizerManagerEngine::saveItems(QList<QOrganizerItem> *items, const QList<QOrganizerItemDetail::DetailType> &detailMask,
468 QMap<int, QOrganizerManager::Error> *errorMap, QOrganizerManager::Error *error)
469{
470 Q_UNUSED(items)
471 Q_UNUSED(detailMask)
472 Q_UNUSED(errorMap)
473
474 *error = QOrganizerManager::NotSupportedError;
475 return false;
476}
477
478/*!
479 This function should be reimplemented to support synchronous calls to remove organizer items.
480
481 This function is supposed to remove all the items whose ID is contained in the given list of
482 \a itemIds, and all the occurrences whose parent ID is containd in the \a itemIds. If the list
483 contains ids which do not identify a valid item in the manager \a error will be set to \c QOrganizerManager::DoesNotExist.
484 Returns true if all the items and occurrences are successfully removed, or false otherwise.
485
486 Any error which occurs should be saved in \a error, and per-input errors for the operation should
487 be stored in \a errorMap.
488 */
489bool QOrganizerManagerEngine::removeItems(const QList<QOrganizerItemId> &itemIds, QMap<int, QOrganizerManager::Error> *errorMap,
490 QOrganizerManager::Error *error)
491{
492 Q_UNUSED(itemIds)
493 Q_UNUSED(errorMap)
494
495 *error = QOrganizerManager::NotSupportedError;
496 return false;
497}
498
499/*!
500 This function should be reimplemented to support synchronous calls to remove organizer items.
501
502 This function is supposed to remove all the items in the given list of \a items, and all the
503 occurrences whose parent is containd in the \a items. If item in the list is a generated occurrence,
504 an exception date is added to the parent item. If the list contains ids which do not identify a valid
505 item in the manager \a error will be set to \c QOrganizerManager::DoesNotExist. Returns true if all
506 the items and occurrences are successfully removed, or false otherwise.
507
508 Any error which occurs should be saved in \a error, and per-input errors for the operation should
509 be stored in \a errorMap.
510 */
511bool QOrganizerManagerEngine::removeItems(const QList<QOrganizerItem> *items, QMap<int, QOrganizerManager::Error> *errorMap,
512 QOrganizerManager::Error *error)
513{
514 Q_UNUSED(items)
515 Q_UNUSED(errorMap)
516
517 *error = QOrganizerManager::NotSupportedError;
518 return false;
519}
520
521
522/*!
523 This function should be reimplemented to support synchronous calls to fetch the default collection id.
524*/
525QOrganizerCollectionId QOrganizerManagerEngine::defaultCollectionId() const
526{
527 return QOrganizerCollectionId();
528}
529
530/*!
531 This function should be reimplemented to support synchronous calls to fetch a collection based
532 on its ID. Any errors encountered during this operation should be stored to \a error. If the
533 given \a collectionId does not specify a valid collection, \a error will be set to
534 \c QOrganizerManager::DoesNotExistError.
535
536*/
537QOrganizerCollection QOrganizerManagerEngine::collection(const QOrganizerCollectionId& collectionId, QOrganizerManager::Error* error)
538{
539 Q_UNUSED(collectionId);
540 *error = QOrganizerManager::NotSupportedError;
541 return QOrganizerCollection();
542}
543
544/*!
545 This function should be reimplemented to support synchronous calls to fetch all the collections
546 managed by this backend. Any errors encountered during this operation should be stored to \a error.
547 */
548QList<QOrganizerCollection> QOrganizerManagerEngine::collections(QOrganizerManager::Error* error)
549{
550 *error = QOrganizerManager::NotSupportedError;
551 return QList<QOrganizerCollection>();
552}
553
554/*!
555 This function should be reimplemented to support synchronous calls to save a collection.
556
557 This function is supposed to save the given \a collection to the backend, and returns true on
558 success or false otherwise. Any errors encountered during this operation should be stored to
559 \a error.
560
561 A new collection will be created in the backend store if the collection ID of it is null.
562 Otherwise, an existing collection with the same ID will be updated. If the given collection ID
563 does not exist in the backend, it will result a QOrganizerManager::DoesNotExistError error.
564
565 Note that upon successful saving, the backend may update the collection, e.g. collection ID for
566 newly saved collections.
567*/
568bool QOrganizerManagerEngine::saveCollection(QOrganizerCollection* collection, QOrganizerManager::Error* error)
569{
570 Q_UNUSED(collection);
571
572 *error = QOrganizerManager::NotSupportedError;
573 return false;
574}
575
576/*!
577 This function should be reimplemented to support synchronous calls to remove a collection.
578
579 This function is supposed to remove the collection identified by the given \a collectionId, and
580 all items in the collection. Returns true on success, or false otherwise. Any errors encountered
581 during this operation should be stored to \a error.
582
583 Note that removing the default collection should not be allowed and should result a
584 QOrganizerManager::PermissionsError error.
585*/
586bool QOrganizerManagerEngine::removeCollection(const QOrganizerCollectionId& collectionId, QOrganizerManager::Error* error)
587{
588 Q_UNUSED(collectionId);
589
590 *error = QOrganizerManager::NotSupportedError;
591 return false;
592}
593
594/*!
595 Given an input \a filter, returns the canonical version of the filter.
596
597 Some of the following transformations may be applied:
598 \list
599 \li Any QOrganizerItemInvalidFilters contained in a union filter will be removed
600 \li Any default QOrganizerItemFilters contained in an intersection filter will be removed
601 \li Any QOrganizerItemIntersectionFilters with a QOrganizerItemInvalidFilter contained will be
602 replaced with a QOrganizerItemInvalidFilter
603 \li Any QOrganizerItemUnionFilters with a default QOrganizerItemFilter contained will be replaced
604 with a default QOrganizerItemFilter
605 \li An empty QOrganizerItemIntersectionFilter will be replaced with a QOrganizerItemDefaultFilter
606 \li An empty QOrganizerItemUnionFilter will be replaced with a QOrganizerItemInvalidFilter
607 \li An empty QOrganizerItemIdFilter will be replaced with a QOrganizerItemInvalidFilter
608 \li An intersection or union filter with a single entry will be replaced by that entry
609 \li A QOrganizerItemDetailFieldFilter or QOrganizerItemDetailRangeFilter with no definition name will be replaced with a QOrganizerItemInvalidFilter
610 \li A QOrganizerItemDetailRangeFilter with no range specified will be converted to a QOrganizerItemDetailFieldFilter
611 \endlist
612*/
613QOrganizerItemFilter QOrganizerManagerEngine::canonicalizedFilter(const QOrganizerItemFilter &filter)
614{
615 switch (filter.type()) {
616 case QOrganizerItemFilter::IntersectionFilter:
617 {
618 QOrganizerItemIntersectionFilter f(filter);
619 QList<QOrganizerItemFilter> filters = f.filters();
620 QList<QOrganizerItemFilter>::iterator it = filters.begin();
621
622 // XXX in theory we can remove duplicates in a set filter
623 while (it != filters.end()) {
624 QOrganizerItemFilter canon = canonicalizedFilter(filter: *it);
625 if (canon.type() == QOrganizerItemFilter::DefaultFilter) {
626 it = filters.erase(it);
627 } else if (canon.type() == QOrganizerItemFilter::InvalidFilter) {
628 return QOrganizerItemInvalidFilter();
629 } else {
630 *it = canon;
631 ++it;
632 }
633 }
634
635 if (filters.count() == 0)
636 return QOrganizerItemFilter();
637 if (filters.count() == 1)
638 return filters.first();
639
640 f.setFilters(filters);
641 return f;
642 }
643 // unreachable
644
645 case QOrganizerItemFilter::UnionFilter:
646 {
647 QOrganizerItemUnionFilter f(filter);
648 QList<QOrganizerItemFilter> filters = f.filters();
649 QList<QOrganizerItemFilter>::iterator it = filters.begin();
650
651 // XXX in theory we can remove duplicates in a set filter
652 while (it != filters.end()) {
653 QOrganizerItemFilter canon = canonicalizedFilter(filter: *it);
654 if (canon.type() == QOrganizerItemFilter::InvalidFilter) {
655 it = filters.erase(it);
656 } else if (canon.type() == QOrganizerItemFilter::DefaultFilter) {
657 return QOrganizerItemFilter();
658 } else {
659 *it = canon;
660 ++it;
661 }
662 }
663
664 if (filters.count() == 0)
665 return QOrganizerItemInvalidFilter();
666 if (filters.count() == 1)
667 return filters.first();
668
669 f.setFilters(filters);
670 return f;
671 }
672 // unreachable
673
674 case QOrganizerItemFilter::IdFilter:
675 {
676 QOrganizerItemIdFilter f(filter);
677 if (f.ids().count() == 0)
678 return QOrganizerItemInvalidFilter();
679 }
680 break; // fall through to return at end
681
682 case QOrganizerItemFilter::DetailRangeFilter:
683 {
684 QOrganizerItemDetailRangeFilter f(filter);
685 if (f.detailType() == QOrganizerItemDetail::TypeUndefined)
686 return QOrganizerItemInvalidFilter();
687 if (f.minValue() == f.maxValue()
688 && f.rangeFlags() == (QOrganizerItemDetailRangeFilter::ExcludeLower | QOrganizerItemDetailRangeFilter::ExcludeUpper))
689 return QOrganizerItemInvalidFilter();
690 if ((f.minValue().isNull() && f.maxValue().isNull()) || (f.minValue() == f.maxValue())) {
691 QOrganizerItemDetailFieldFilter df;
692 df.setDetail(detailType: f.detailType(), field: f.detailField());
693 df.setMatchFlags(f.matchFlags());
694 df.setValue(f.minValue());
695 return df;
696 }
697 }
698 break; // fall through to return at end
699
700 case QOrganizerItemFilter::DetailFieldFilter:
701 {
702 QOrganizerItemDetailFieldFilter f(filter);
703 if (f.detailType() == QOrganizerItemDetail::TypeUndefined)
704 return QOrganizerItemInvalidFilter();
705 }
706 break; // fall through to return at end
707
708 default:
709 break; // fall through to return at end
710 }
711 return filter;
712}
713
714/*!
715 Compares \a first against \a second. If the types are
716 strings (QVariant::String), the \a sensitivity argument controls
717 case sensitivity when comparing.
718
719 Returns:
720 <0 if \a first is less than \a second
721 0 if \a first is equal to \a second
722 >0 if \a first is greater than \a second.
723
724 The results are undefined if the variants are different types, or
725 cannot be compared.
726 */
727int QOrganizerManagerEngine::compareVariant(const QVariant& first, const QVariant& second, Qt::CaseSensitivity sensitivity)
728{
729 switch(first.type()) {
730 case QVariant::Int:
731 return first.toInt() - second.toInt();
732
733 case QVariant::LongLong:
734 return first.toLongLong() - second.toLongLong();
735
736 case QVariant::Bool:
737 case QVariant::Char:
738 case QVariant::UInt:
739 return first.toUInt() - second.toUInt();
740
741 case QVariant::ULongLong:
742 return first.toULongLong() - second.toULongLong();
743
744 case QVariant::String:
745 return first.toString().compare(s: second.toString(), cs: sensitivity);
746
747 case QVariant::Double:
748 {
749 const double a = first.toDouble();
750 const double b = second.toDouble();
751 return (a < b) ? -1 : ((a == b) ? 0 : 1);
752 }
753
754 case QVariant::DateTime:
755 {
756 const QDateTime a = first.toDateTime();
757 const QDateTime b = second.toDateTime();
758 return (a < b) ? -1 : ((a == b) ? 0 : 1);
759 }
760
761 case QVariant::Date:
762 return first.toDate().toJulianDay() - second.toDate().toJulianDay();
763
764 case QVariant::Time:
765 {
766 const QTime a = first.toTime();
767 const QTime b = second.toTime();
768 return (a < b) ? -1 : ((a == b) ? 0 : 1);
769 }
770
771 default:
772 return 0;
773 }
774}
775
776/*!
777 Returns true if the supplied item \a item matches the supplied filter \a filter.
778
779 This function will test each condition in the filter, possibly recursing.
780 */
781bool QOrganizerManagerEngine::testFilter(const QOrganizerItemFilter &filter, const QOrganizerItem &item)
782{
783 switch(filter.type()) {
784 case QOrganizerItemFilter::InvalidFilter:
785 return false;
786
787 case QOrganizerItemFilter::DefaultFilter:
788 return true;
789
790 case QOrganizerItemFilter::IdFilter:
791 {
792 const QOrganizerItemIdFilter idf(filter);
793 if (idf.ids().contains(t: item.id()))
794 return true;
795 }
796 // Fall through to end
797 break;
798 case QOrganizerItemFilter::DetailFilter:
799 {
800 const QOrganizerItemDetailFilter cdf(filter);
801
802 QOrganizerItemDetail matchingDetail = cdf.detail();
803 if ( (matchingDetail.isEmpty()) || (matchingDetail.type() == QOrganizerItemDetail::TypeUndefined) )
804 return false;
805
806 /* See if this organizer item has one of these details in it */
807 const QList<QOrganizerItemDetail>& details = item.details(detailType: cdf.detail().type());
808 if (details.count() == 0)
809 return false; /* can't match */
810
811 /* Value equality test */
812 for (int j=0; j < details.count(); j++) {
813 if (details.at(i: j) == matchingDetail)
814 return true;
815 }
816 return false;
817 }
818 // Fall through to end
819 break;
820 case QOrganizerItemFilter::DetailFieldFilter:
821 {
822 const QOrganizerItemDetailFieldFilter cdf(filter);
823 if (cdf.detailType() == QOrganizerItemDetail::TypeUndefined)
824 return false;
825
826 /* See if this organizer item has one of these details in it */
827 const QList<QOrganizerItemDetail>& details = item.details(detailType: cdf.detailType());
828
829 if (details.count() == 0)
830 return false; /* can't match */
831
832 /* See if we need to check the values */
833 if (cdf.detailField() == -1)
834 return true; /* just testing for the presence of a detail of the specified definition */
835
836 /* Now figure out what tests we are doing */
837 const bool valueTest = cdf.value().isValid();
838 const bool presenceTest = !valueTest;
839
840 /* See if we need to test any values at all */
841 if (presenceTest) {
842 for(int j=0; j < details.count(); j++) {
843 const QOrganizerItemDetail& detail = details.at(i: j);
844
845 /* Check that the field is present and has a non-empty value */
846 if (detail.values().contains(akey: cdf.detailField()) && !detail.value(field: cdf.detailField()).isNull())
847 return true;
848 }
849 return false;
850 }
851
852 /* Case sensitivity, for those parts that use it */
853 Qt::CaseSensitivity cs = (cdf.matchFlags() & QOrganizerItemFilter::MatchCaseSensitive) ? Qt::CaseSensitive : Qt::CaseInsensitive;
854
855 /* See what flags are requested, since we're looking at a value */
856 if (cdf.matchFlags() & (QOrganizerItemFilter::MatchEndsWith | QOrganizerItemFilter::MatchStartsWith | QOrganizerItemFilter::MatchContains | QOrganizerItemFilter::MatchFixedString)) {
857 /* We're strictly doing string comparisons here */
858 bool matchStarts = (cdf.matchFlags() & 7) == QOrganizerItemFilter::MatchStartsWith;
859 bool matchEnds = (cdf.matchFlags() & 7) == QOrganizerItemFilter::MatchEndsWith;
860 bool matchContains = (cdf.matchFlags() & 7) == QOrganizerItemFilter::MatchContains;
861
862 /* Value equality test */
863 for(int j=0; j < details.count(); j++) {
864 const QOrganizerItemDetail& detail = details.at(i: j);
865 const QString& var = detail.value(field: cdf.detailField()).toString();
866 const QString& needle = cdf.value().toString();
867 if (matchStarts && var.startsWith(s: needle, cs))
868 return true;
869 if (matchEnds && var.endsWith(s: needle, cs))
870 return true;
871 if (matchContains && var.contains(s: needle, cs))
872 return true;
873 if (QString::compare(s1: var, s2: needle, cs) == 0)
874 return true;
875 }
876 return false;
877 } else {
878 /* Nope, testing the values as a variant */
879 /* Value equality test */
880 for(int j = 0; j < details.count(); j++) {
881 const QOrganizerItemDetail& detail = details.at(i: j);
882 const QVariant& var = detail.value(field: cdf.detailField());
883 if (!var.isNull() && compareVariant(first: var, second: cdf.value(), sensitivity: cs) == 0)
884 return true;
885 }
886 }
887 }
888 break;
889
890 case QOrganizerItemFilter::DetailRangeFilter:
891 {
892 const QOrganizerItemDetailRangeFilter cdf(filter);
893 if (cdf.detailType() == QOrganizerItemDetail::TypeUndefined)
894 return false; /* we do not know which field to check */
895
896 /* See if this organizer item has one of these details in it */
897 const QList<QOrganizerItemDetail>& details = item.details(detailType: cdf.detailType());
898
899 if (details.count() == 0)
900 return false; /* can't match */
901
902 /* Check for a detail presence test */
903 if (cdf.detailField() == -1)
904 return true;
905
906 /* See if this is a field presence test */
907 if (!cdf.minValue().isValid() && !cdf.maxValue().isValid()) {
908 for(int j=0; j < details.count(); j++) {
909 const QOrganizerItemDetail& detail = details.at(i: j);
910 if (detail.values().contains(akey: cdf.detailField()))
911 return true;
912 }
913 return false;
914 }
915
916 /* open or closed interval testing support */
917 const int minComp = cdf.rangeFlags() & QOrganizerItemDetailRangeFilter::ExcludeLower ? 1 : 0;
918 const int maxComp = cdf.rangeFlags() & QOrganizerItemDetailRangeFilter::IncludeUpper ? 1 : 0;
919
920 const bool testMin = cdf.minValue().isValid();
921 const bool testMax = cdf.maxValue().isValid();
922
923 /* At this point we know that at least of testMin & testMax is true */
924
925 /* Case sensitivity, for those parts that use it */
926 Qt::CaseSensitivity cs = (cdf.matchFlags() & QOrganizerItemFilter::MatchCaseSensitive) ? Qt::CaseSensitive : Qt::CaseInsensitive;
927
928 /* See what flags are requested, since we're looking at a value */
929 if (cdf.matchFlags() & (QOrganizerItemFilter::MatchEndsWith | QOrganizerItemFilter::MatchStartsWith | QOrganizerItemFilter::MatchContains | QOrganizerItemFilter::MatchFixedString)) {
930 /* We're strictly doing string comparisons here */
931 //bool matchStarts = (cdf.matchFlags() & 7) == QOrganizerItemFilter::MatchStartsWith;
932 bool matchEnds = (cdf.matchFlags() & 7) == QOrganizerItemFilter::MatchEndsWith;
933 bool matchContains = (cdf.matchFlags() & 7) == QOrganizerItemFilter::MatchContains;
934
935 /* Min/Max and contains do not make sense */
936 if (matchContains)
937 return false;
938
939 QString minVal = cdf.minValue().toString();
940 QString maxVal = cdf.maxValue().toString();
941
942 /* Starts with is the normal compare case, endsWith is a bit trickier */
943 for(int j=0; j < details.count(); j++) {
944 const QOrganizerItemDetail& detail = details.at(i: j);
945 const QString& var = detail.value(field: cdf.detailField()).toString();
946 if (!matchEnds) {
947 // MatchStarts or MatchFixedString
948 if (testMin && QString::compare(s1: var, s2: minVal, cs) < minComp)
949 continue;
950 if (testMax && QString::compare(s1: var, s2: maxVal, cs) >= maxComp)
951 continue;
952 return true;
953 } else {
954 /* Have to test the length of min & max */
955 // using refs means the parameter order is backwards, so negate the result of compare
956 if (testMin && -QString::compare(s1: minVal, s2: var.rightRef(n: minVal.length()), cs) < minComp)
957 continue;
958 if (testMax && -QString::compare(s1: maxVal, s2: var.rightRef(n: maxVal.length()), cs) >= maxComp)
959 continue;
960 return true;
961 }
962 }
963 // Fall through to end
964 } else {
965 /* Nope, testing the values as a variant */
966 for(int j=0; j < details.count(); j++) {
967 const QOrganizerItemDetail& detail = details.at(i: j);
968 const QVariant& var = detail.value(field: cdf.detailField());
969
970 if (testMin && compareVariant(first: var, second: cdf.minValue(), sensitivity: cs) < minComp)
971 continue;
972 if (testMax && compareVariant(first: var, second: cdf.maxValue(), sensitivity: cs) >= maxComp)
973 continue;
974 return true;
975 }
976 // Fall through to end
977 }
978 }
979 break;
980
981 case QOrganizerItemFilter::IntersectionFilter:
982 {
983 /* XXX In theory we could reorder the terms to put the native tests first */
984 const QOrganizerItemIntersectionFilter bf(filter);
985 const QList<QOrganizerItemFilter>& terms = bf.filters();
986 if (terms.count() > 0) {
987 for(int j = 0; j < terms.count(); j++) {
988 if (!testFilter(filter: terms.at(i: j), item)) {
989 return false;
990 }
991 }
992 return true;
993 }
994 // Fall through to end
995 }
996 break;
997
998 case QOrganizerItemFilter::UnionFilter:
999 {
1000 /* XXX In theory we could reorder the terms to put the native tests first */
1001 const QOrganizerItemUnionFilter bf(filter);
1002 const QList<QOrganizerItemFilter>& terms = bf.filters();
1003 if (terms.count() > 0) {
1004 for(int j = 0; j < terms.count(); j++) {
1005 if (testFilter(filter: terms.at(i: j), item)) {
1006 return true;
1007 }
1008 }
1009 return false;
1010 }
1011 // Fall through to end
1012 }
1013 break;
1014
1015 case QOrganizerItemFilter::CollectionFilter:
1016 {
1017 const QOrganizerItemCollectionFilter cf(filter);
1018 const QSet<QOrganizerCollectionId>& ids = cf.collectionIds();
1019 if (ids.contains(value: item.collectionId()))
1020 return true;
1021 return false;
1022 }
1023 }
1024 return false;
1025}
1026
1027/*!
1028 Returns true if the given \a item (or an occurrence of the item) occurs within the range
1029 specified by the \a startPeriod and the \a endPeriod, inclusive.
1030 A default-constructed \a startPeriod signifies that the lower bound of the range is
1031 infinitely small (i.e., will match anything up to the \a endPeriod) and a default-constructed
1032 \a endPeriod signifies that the upper bound of the range is infinitely large
1033 (i.e., will match anything which occurs after the \a startPeriod).
1034 */
1035bool QOrganizerManagerEngine::isItemBetweenDates(const QOrganizerItem& item, const QDateTime& startPeriod, const QDateTime& endPeriod)
1036{
1037 if (startPeriod.isNull() && endPeriod.isNull())
1038 return true;
1039
1040 QDateTime itemDateStart;
1041 QDateTime itemDateEnd;
1042
1043 if (item.type() == QOrganizerItemType::TypeEvent || item.type() == QOrganizerItemType::TypeEventOccurrence) {
1044 QOrganizerEventTime etr = item.detail(detailType: QOrganizerItemDetail::TypeEventTime);
1045 itemDateStart = etr.startDateTime();
1046 itemDateEnd = etr.endDateTime();
1047 } else if (item.type() == QOrganizerItemType::TypeTodo || item.type() == QOrganizerItemType::TypeTodoOccurrence) {
1048 QOrganizerTodoTime ttr = item.detail(detailType: QOrganizerItemDetail::TypeTodoTime);
1049 itemDateStart = ttr.startDateTime();
1050 itemDateEnd = ttr.dueDateTime();
1051 } else if (item.type() == QOrganizerItemType::TypeJournal) {
1052 QOrganizerJournal journal = item;
1053 itemDateStart = itemDateEnd = journal.dateTime();
1054 } else if (item.type() == QOrganizerItemType::TypeNote) {
1055 //for note, there is no such start/end datetime so we always return false
1056 return false;
1057 }
1058
1059 // if period start date is not given, check that item is starting or ending before period end
1060 if (startPeriod.isNull()) // endPeriod must be non-null because of initial test
1061 return (!itemDateStart.isNull() && itemDateStart <= endPeriod) ||
1062 (!itemDateEnd.isNull() && itemDateEnd <= endPeriod);
1063
1064 // if period end date is not given, check that item is starting or ending after the period start
1065 if (endPeriod.isNull()) // startPeriod must be non-null because of initial test
1066 return (!itemDateEnd.isNull() && itemDateEnd >= startPeriod) ||
1067 (!itemDateStart.isNull() && itemDateStart >= startPeriod);
1068
1069 // Both startPeriod and endPeriod are not null
1070 // check if item start date is between the period start and end date
1071 if (!itemDateStart.isNull() && itemDateStart >= startPeriod && itemDateStart <= endPeriod)
1072 return true;
1073
1074 // check if item end date is between the period start and end date
1075 if (!itemDateEnd.isNull() && itemDateEnd >= startPeriod && itemDateEnd <= endPeriod)
1076 return true;
1077
1078 // check if item interval is including the period interval
1079 if (!itemDateStart.isNull() && !itemDateEnd.isNull() && itemDateStart <= startPeriod && itemDateEnd >= endPeriod)
1080 return true;
1081
1082 return false;
1083}
1084
1085/*!
1086 \internal
1087
1088 Returns the date associated with \a item that can be used for the purpose of date-sorting the item.
1089 */
1090QDateTime getDateForSorting(const QOrganizerItem& item)
1091{
1092 QDateTime retn;
1093 {
1094 QOrganizerEventTime detail = item.detail(detailType: QOrganizerItemDetail::TypeEventTime);
1095 if (!detail.isEmpty()) {
1096 retn = detail.startDateTime();
1097 if (!retn.isValid())
1098 retn = detail.endDateTime();
1099 if (retn.isValid() && detail.isAllDay()) {
1100 // set it to a millisecond before the given date to have it sorted correctly
1101 retn.setTime(QTime(23, 59, 59, 999));
1102 retn.addDays(days: -1);
1103 }
1104 return retn;
1105 }
1106 }
1107 {
1108 QOrganizerTodoTime detail = item.detail(detailType: QOrganizerItemDetail::TypeTodoTime);
1109 if (!detail.isEmpty()) {
1110 retn = detail.startDateTime();
1111 if (!retn.isValid())
1112 retn = detail.dueDateTime();
1113 if (retn.isValid() && detail.isAllDay()) {
1114 // set it to a millisecond before the given date to have it sorted correctly
1115 retn.setTime(QTime(23, 59, 59, 999));
1116 retn.addDays(days: -1);
1117 }
1118 return retn;
1119 }
1120 }
1121
1122 // If it's a note, this will just return null, as expected
1123 return item.detail(detailType: QOrganizerItemDetail::TypeJournalTime).value(field: QOrganizerJournalTime::FieldEntryDateTime).toDateTime();
1124}
1125
1126/*!
1127 Returns true if and only if \a a is temporally less than \a b. Items with an earlier date are
1128 temporally less than items with a later date, or items with no date. All day items are
1129 temporally less than non-all day items on the same date. For events and todos, the
1130 start date is used, or if null, the end date is used. This function defines a total ordering
1131 suitable for use in a sort function.
1132 */
1133bool QOrganizerManagerEngine::itemLessThan(const QOrganizerItem& a, const QOrganizerItem& b)
1134{
1135 QDateTime date1 = getDateForSorting(item: a);
1136 if (!date1.isValid()) {
1137 return false;
1138 } else {
1139 QDateTime date2 = getDateForSorting(item: b);
1140 if (!date2.isValid())
1141 return true;
1142 else
1143 return date1 < date2;
1144 }
1145}
1146
1147/*!
1148 Compares two organizer items (\a a and \a b) using the given list of \a sortOrders. Returns a negative number if \a a should appear
1149 before \a b according to the sort order, a positive number if \a a should appear after \a b according to the sort order,
1150 and zero if the two are unable to be sorted.
1151 */
1152int QOrganizerManagerEngine::compareItem(const QOrganizerItem& a, const QOrganizerItem& b, const QList<QOrganizerItemSortOrder>& sortOrders)
1153{
1154 foreach (const QOrganizerItemSortOrder &sortOrder, sortOrders) {
1155 if (!sortOrder.isValid())
1156 break;
1157
1158 const QOrganizerItemDetail::DetailType detailType = sortOrder.detailType();
1159 const int detailField = sortOrder.detailField();
1160
1161 const QList<QOrganizerItemDetail> aDetails = a.details(detailType);
1162 const QList<QOrganizerItemDetail> bDetails = b.details(detailType);
1163 if (aDetails.isEmpty() && bDetails.isEmpty())
1164 continue; // use next sort criteria.
1165
1166 // See if we need to check the values
1167 if (detailField == -1) {
1168 // just testing for the presence of a detail of the specified definition
1169 if (aDetails.size() == bDetails.size())
1170 continue; // use next sort criteria.
1171 if (aDetails.isEmpty())
1172 return sortOrder.blankPolicy() == QOrganizerItemSortOrder::BlanksFirst ? -1 : 1;
1173 if (bDetails.isEmpty())
1174 return sortOrder.blankPolicy() == QOrganizerItemSortOrder::BlanksFirst ? 1 : -1;
1175 return 0;
1176 }
1177
1178 // obtain the values which this sort order concerns
1179 const QVariant aVal = !aDetails.isEmpty() ? aDetails.first().value(field: detailField) : QVariant();
1180 const QVariant bVal = !bDetails.isEmpty() ? bDetails.first().value(field: detailField) : QVariant();
1181
1182 bool aIsNull = false;
1183 bool bIsNull = false;
1184
1185 // treat empty strings as null qvariants.
1186 if ((aVal.type() == QVariant::String && aVal.toString().isEmpty()) || aVal.isNull()) {
1187 aIsNull = true;
1188 }
1189 if ((bVal.type() == QVariant::String && bVal.toString().isEmpty()) || bVal.isNull()) {
1190 bIsNull = true;
1191 }
1192
1193 // early exit error checking
1194 if (aIsNull && bIsNull)
1195 continue; // use next sort criteria.
1196 if (aIsNull)
1197 return (sortOrder.blankPolicy() == QOrganizerItemSortOrder::BlanksFirst ? -1 : 1);
1198 if (bIsNull)
1199 return (sortOrder.blankPolicy() == QOrganizerItemSortOrder::BlanksFirst ? 1 : -1);
1200
1201 // real comparison
1202 int comparison = compareVariant(first: aVal, second: bVal, sensitivity: sortOrder.caseSensitivity()) * (sortOrder.direction() == Qt::AscendingOrder ? 1 : -1);
1203 if (comparison == 0)
1204 continue;
1205 return comparison;
1206 }
1207
1208 return 0; // or according to id? return (a.id() < b.id() ? -1 : 1);
1209}
1210
1211/*!
1212 A functor that returns true iff \a a is less than \a b, according to
1213 \a sortOrders passed in to the ctor.
1214*/
1215class OrganizerItemLessThan
1216{
1217 const QList<QOrganizerItemSortOrder> &m_sortOrders;
1218
1219public:
1220 inline OrganizerItemLessThan(const QList<QOrganizerItemSortOrder> &sortOrders)
1221 : m_sortOrders(sortOrders)
1222 {}
1223
1224 inline bool operator()(const QOrganizerItem &a, const QOrganizerItem &b) const
1225 { return QOrganizerManagerEngine::compareItem(a, b, sortOrders: m_sortOrders) < 0; }
1226};
1227
1228/*!
1229 Insert \a toAdd to the \a sorted list, according to the provided \a sortOrders. The index where \a toAdd is inserted
1230 is returned.
1231
1232 The first one in the \a sortOrders list has the highest priority.
1233 */
1234int QOrganizerManagerEngine::addSorted(QList<QOrganizerItem> *sorted, const QOrganizerItem &toAdd, const QList<QOrganizerItemSortOrder> &sortOrders)
1235{
1236 QList<QOrganizerItem>::iterator it;
1237 if (sortOrders.count() > 0)
1238 it = std::upper_bound(first: sorted->begin(), last: sorted->end(), val: toAdd, comp: OrganizerItemLessThan(sortOrders));
1239 else
1240 it = sorted->end(); // no sort order? just add it to the end
1241 it = sorted->insert(before: it, t: toAdd);
1242 return it - sorted->begin();
1243}
1244
1245/*!
1246 Insert \a toAdd to the \a defaultSorted map. If \a toAdd does not have valid start or end date,
1247 returns false and does not insert \a toAdd to \a defaultSorted map.
1248
1249 This function provides default sorting, which should be used for sorting fetch results, if no sort order
1250 was defined for the fetch. The default sorting algorithm is to sort based on start time of an item. If start time
1251 does not exist, end time or due time is used instead. For allday events, time 00:00 is used for sorting purposes.
1252 Items with no start or end time are last in the sorting order.
1253
1254 This function sorts items using QMultiMap, where QDateTime is used as a key. To get a sorted list of items,
1255 QMultiMap::values function should be called and items without start and end date added to the end of the list.
1256 */
1257bool QOrganizerManagerEngine::addDefaultSorted(QMultiMap<QDateTime, QOrganizerItem> *defaultSorted, const QOrganizerItem &toAdd)
1258{
1259 QDateTime sortTime;
1260 if (toAdd.type() == QOrganizerItemType::TypeEvent || toAdd.type() == QOrganizerItemType::TypeEventOccurrence) {
1261 QOrganizerEventTime eventTime = toAdd.detail(detailType: QOrganizerItemDetail::TypeEventTime);
1262 if (eventTime.startDateTime().isValid())
1263 sortTime = eventTime.startDateTime();
1264 else if (eventTime.endDateTime().isValid())
1265 sortTime = eventTime.endDateTime();
1266
1267 if (eventTime.isAllDay() && sortTime.isValid())
1268 sortTime.setTime(QTime(0, 0, 0));
1269
1270 } else if (toAdd.type() == QOrganizerItemType::TypeTodo || toAdd.type() == QOrganizerItemType::TypeTodoOccurrence) {
1271 QOrganizerTodoTime todoTime = toAdd.detail(detailType: QOrganizerItemDetail::TypeTodoTime);
1272 if (todoTime.startDateTime().isValid())
1273 sortTime = todoTime.startDateTime();
1274 else if (todoTime.dueDateTime().isValid())
1275 sortTime = todoTime.dueDateTime();
1276
1277 if (todoTime.isAllDay() && sortTime.isValid())
1278 sortTime.setTime(QTime(0, 0, 0));
1279 }
1280
1281 if (sortTime.isValid()) {
1282 // FIXME: sorting of events with exactly the same key
1283 defaultSorted->insert(akey: sortTime, avalue: toAdd);
1284 return true;
1285 } else {
1286 return false;
1287 }
1288}
1289
1290/*!
1291 Generates a new occurrence for \a parentItem. All \a parentItem details, except for \l QOrganizerItemType and
1292 \l QOrganizerItemRecurrence copied to the occurrence. Occurrence start date is set to the date given in \a rdate.
1293 End date is modified accordingly. Occurrence's \l QOrganizerItemParent detail contains the id of \a parentItem
1294 and the original date given in \a rdate.
1295 */
1296QOrganizerItem QOrganizerManagerEngine::generateOccurrence(const QOrganizerItem &parentItem, const QDateTime &rdate)
1297{
1298 QOrganizerItem instanceItem;
1299 if (parentItem.type() == QOrganizerItemType::TypeEvent) {
1300 instanceItem = QOrganizerEventOccurrence();
1301 } else {
1302 instanceItem = QOrganizerTodoOccurrence();
1303 }
1304
1305 instanceItem.setCollectionId(parentItem.collectionId());
1306
1307 // XXX TODO: something better than this linear search...
1308 // Grab all details from the parent item except the recurrence information, and event/todo time range
1309 QList<QOrganizerItemDetail> allDetails = parentItem.details();
1310 QList<QOrganizerItemDetail> occDetails;
1311 foreach (const QOrganizerItemDetail &detail, allDetails) {
1312 if (detail.type() != QOrganizerItemDetail::TypeRecurrence
1313 && detail.type() != QOrganizerItemDetail::TypeEventTime
1314 && detail.type() != QOrganizerItemDetail::TypeTodoTime) {
1315 occDetails.append(t: detail);
1316 }
1317 }
1318
1319 const QDate localRDate(rdate.toLocalTime().date());
1320
1321 // add the detail which identifies exactly which instance this item is.
1322 QOrganizerItemParent parentDetail;
1323 parentDetail.setParentId(parentItem.id());
1324 parentDetail.setOriginalDate(localRDate);
1325 occDetails.append(t: parentDetail);
1326
1327 // save those details in the instance.
1328 foreach (const QOrganizerItemDetail &detail, occDetails) {
1329 // copy every detail except the type
1330 if (detail.type() != QOrganizerItemDetail::TypeItemType) {
1331 QOrganizerItemDetail modifiable = detail;
1332 instanceItem.saveDetail(detail: &modifiable);
1333 }
1334 }
1335
1336 // and update the time range in the instance based on the current instance date
1337 if (parentItem.type() == QOrganizerItemType::TypeEvent) {
1338 QOrganizerEventTime etr = parentItem.detail(detailType: QOrganizerItemDetail::TypeEventTime);
1339 if (!etr.isEmpty()) {
1340 int eventDayCount = 0;
1341 if (etr.startDateTime().isValid() && etr.endDateTime().isValid())
1342 eventDayCount = etr.startDateTime().daysTo(etr.endDateTime());
1343 // Perform time manipulations in local time
1344 QDateTime temp = etr.startDateTime().toLocalTime();
1345 temp.setDate(localRDate);
1346 etr.setStartDateTime(temp.toUTC());
1347 temp = etr.endDateTime().toLocalTime();
1348 QDate endDate = localRDate.addDays(days: eventDayCount);
1349 temp.setDate(endDate);
1350 etr.setEndDateTime(temp.toUTC());
1351 instanceItem.saveDetail(detail: &etr);
1352 }
1353 }
1354
1355 // for todo's
1356 if (parentItem.type() == QOrganizerItemType::TypeTodo) {
1357 QOrganizerTodoTime ttr = parentItem.detail(detailType: QOrganizerItemDetail::TypeTodoTime);
1358 if (!ttr.isEmpty()) {
1359 int todoDayCount = 0;
1360 if (ttr.startDateTime().isValid() && ttr.dueDateTime().isValid())
1361 todoDayCount = ttr.startDateTime().daysTo(ttr.dueDateTime());
1362 QDateTime temp = ttr.startDateTime().toLocalTime();
1363 temp.setDate(localRDate);
1364 ttr.setStartDateTime(temp.toUTC());
1365 temp = ttr.dueDateTime().toLocalTime();
1366 QDate endDate = localRDate.addDays(days: todoDayCount);
1367 temp.setDate(endDate);
1368 ttr.setDueDateTime(temp.toUTC());
1369 instanceItem.saveDetail(detail: &ttr);
1370 }
1371 }
1372
1373 return instanceItem;
1374}
1375
1376/*!
1377 Generates all start times for recurrence \a rrule during the given time period. The time period is defined by
1378 \a periodStart and \a periodEnd. \a initialDateTime is the start time of the event, which defines the first
1379 start time for \a rrule. \a maxCount can be used to limit the amount of generated start times.
1380 */
1381QList<QDateTime> QOrganizerManagerEngine::generateDateTimes(const QDateTime &initialDateTime, QOrganizerRecurrenceRule rrule, const QDateTime &periodStart, const QDateTime &periodEnd, int maxCount)
1382{
1383 QList<QDateTime> retn;
1384 if (periodEnd.isValid() || maxCount <= 0)
1385 maxCount = INT_MAX; // count of returned items is unlimited
1386
1387 // Perform calculations in local time, for meaningful comparison with date values
1388 const QDateTime localInitialDateTime = initialDateTime.toLocalTime();
1389 const QDateTime localPeriodStart = periodStart.toLocalTime();
1390 const QDateTime localPeriodEnd = periodEnd.toLocalTime();
1391
1392 QDateTime realPeriodEnd(localPeriodEnd);
1393 if (rrule.limitType() == QOrganizerRecurrenceRule::DateLimit
1394 && rrule.limitDate() < realPeriodEnd.date()) {
1395 realPeriodEnd.setDate(rrule.limitDate());
1396 realPeriodEnd.setTime(QTime(23,59,59,999)); // the last instant of the limit date, since it's prior to the periodEnd.
1397 }
1398
1399 QDate nextDate;
1400 if (rrule.limitType() == QOrganizerRecurrenceRule::CountLimit)
1401 nextDate = localInitialDateTime.date();
1402 else
1403 nextDate = localPeriodStart.date();
1404
1405 inferMissingCriteria(rrule: &rrule, initialDate: localInitialDateTime.date());
1406 int countLimitDates = 0;
1407 bool periodEndReached = false;
1408 while (!periodEndReached && nextDate <= realPeriodEnd.date() && retn.size() < maxCount) {
1409 if (rrule.limitType() == QOrganizerRecurrenceRule::CountLimit && countLimitDates >= rrule.limitCount())
1410 break; // reached limit count defined in the recurrence rule
1411 // Skip nextDate if it is not the right multiple of intervals away from initialDateTime.
1412 if (inMultipleOfInterval(date: nextDate, initialDate: localInitialDateTime.date(), frequency: rrule.frequency(), interval: rrule.interval(), firstDayOfWeek: rrule.firstDayOfWeek())) {
1413 // Calculate the inclusive start and inclusive end of nextDate's week/month/year
1414 QDate subPeriodStart(firstDateInPeriod(date: nextDate, frequency: rrule.frequency(), firstDayOfWeek: rrule.firstDayOfWeek()));
1415 QDate subPeriodEnd(firstDateInNextPeriod(date: nextDate, frequency: rrule.frequency(), firstDayOfWeek: rrule.firstDayOfWeek()).addDays(days: -1));
1416 // Compute matchesInPeriod to be the set of dates in the current week/month/year that match the rrule
1417 QList<QDate> matchesInPeriod(filterByPosition(
1418 dates: matchingDates(periodStart: subPeriodStart, periodEnd: subPeriodEnd, rrule),
1419 positions: rrule.positions()));
1420 // A final filter over the dates list before adding it to the returned list
1421 foreach (const QDate &match, matchesInPeriod) {
1422 nextDate = match;
1423 if (match < localInitialDateTime.date())
1424 continue;
1425 if (match > realPeriodEnd.date() || retn.size() >= maxCount)
1426 break;
1427
1428 QDateTime generatedDateTime(localInitialDateTime);
1429
1430 generatedDateTime.setDate(match);
1431 countLimitDates++;
1432 if (generatedDateTime >= localPeriodStart && generatedDateTime <= realPeriodEnd) {
1433 // Convert back to UTC for returned value
1434 retn.append(t: generatedDateTime.toUTC());
1435 } else if (generatedDateTime > realPeriodEnd) {
1436 // We've gone past the end of the period. Ensure we break both the foreach and
1437 // the while loop
1438 periodEndReached = true;
1439 break;
1440 }
1441 if (rrule.limitType() == QOrganizerRecurrenceRule::CountLimit && countLimitDates >= rrule.limitCount())
1442 break; // reached limit count defined in the recurrence rule
1443 }
1444 }
1445 nextDate = firstDateInNextPeriod(date: nextDate, frequency: rrule.frequency(), firstDayOfWeek: rrule.firstDayOfWeek());
1446 }
1447 return retn;
1448}
1449
1450/*!
1451 Determines if \a rrule is underspecified and if so, fills in missing information based on \a
1452 initialDate.
1453 */
1454void QOrganizerManagerEngine::inferMissingCriteria(QOrganizerRecurrenceRule *rrule, const QDate &initialDate)
1455{
1456 switch (rrule->frequency()) {
1457 case QOrganizerRecurrenceRule::Weekly:
1458 if (rrule->daysOfWeek().isEmpty()) {
1459 // derive day of week
1460 QSet<Qt::DayOfWeek> days;
1461 days << static_cast<Qt::DayOfWeek>(initialDate.dayOfWeek());
1462 rrule->setDaysOfWeek(days);
1463 }
1464 break;
1465 case QOrganizerRecurrenceRule::Monthly:
1466 if (rrule->daysOfWeek().isEmpty() && rrule->daysOfMonth().isEmpty()) {
1467 // derive day of month
1468 QSet<int> days;
1469 days << initialDate.day();
1470 rrule->setDaysOfMonth(days);
1471 }
1472 break;
1473 case QOrganizerRecurrenceRule::Yearly:
1474 if (rrule->monthsOfYear().isEmpty()
1475 && rrule->weeksOfYear().isEmpty()
1476 && rrule->daysOfYear().isEmpty()
1477 && rrule->daysOfMonth().isEmpty()
1478 && rrule->daysOfWeek().isEmpty()) {
1479 // derive day of month and month of year
1480 QSet<int> daysOfMonth;
1481 daysOfMonth << initialDate.day();
1482 rrule->setDaysOfMonth(daysOfMonth);
1483 QSet<QOrganizerRecurrenceRule::Month> months;
1484 months << static_cast<QOrganizerRecurrenceRule::Month>(initialDate.month());
1485 rrule->setMonthsOfYear(months);
1486 } else if (!rrule->monthsOfYear().isEmpty()
1487 && rrule->weeksOfYear().isEmpty()
1488 && rrule->daysOfYear().isEmpty()
1489 && rrule->daysOfMonth().isEmpty()
1490 && rrule->daysOfWeek().isEmpty()) {
1491 // derive day of month
1492 QSet<int> daysOfMonth;
1493 daysOfMonth << initialDate.day();
1494 rrule->setDaysOfMonth(daysOfMonth);
1495 } else if (!rrule->weeksOfYear().isEmpty()
1496 && rrule->daysOfYear().isEmpty()
1497 && rrule->daysOfMonth().isEmpty()
1498 && rrule->daysOfWeek().isEmpty()) {
1499 // derive day of week
1500 QSet<Qt::DayOfWeek> days;
1501 days << static_cast<Qt::DayOfWeek>(initialDate.dayOfWeek());
1502 rrule->setDaysOfWeek(days);
1503 }
1504 break;
1505 case QOrganizerRecurrenceRule::Daily:
1506 break;
1507 case QOrganizerRecurrenceRule::Invalid:
1508 Q_ASSERT(false);
1509 }
1510}
1511
1512/*!
1513 Returns true if the calendar period (specified by \a frequency) of \a date is an \a
1514 interval multiple of periods ahead of the calendar period of \a initialDate. For Weekly frequencies,
1515 \a firstDayOfWeek is used to determine when the week boundary is. eg. If \a frequency is Monthly
1516 and \a interval is 3, then true is returned iff \a date is in the same month as \a initialDate,
1517 in a month 3 months ahead, 6 months ahead, etc.
1518 */
1519bool QOrganizerManagerEngine::inMultipleOfInterval(const QDate &date, const QDate &initialDate, QOrganizerRecurrenceRule::Frequency frequency, int interval, Qt::DayOfWeek firstDayOfWeek)
1520{
1521 Q_ASSERT(date >= initialDate);
1522 switch (frequency) {
1523 case QOrganizerRecurrenceRule::Yearly: {
1524 uint yearsDelta = date.year() - initialDate.year();
1525 return (yearsDelta % interval == 0);
1526 }
1527 case QOrganizerRecurrenceRule::Monthly: {
1528 uint monthsDelta = date.month() - initialDate.month() + (12 * (date.year() - initialDate.year()));
1529 return (monthsDelta % interval == 0);
1530 }
1531 case QOrganizerRecurrenceRule::Weekly: {
1532 // we need to adjust for the week start specified by the client if the interval is greater than 1
1533 // ie, every time we hit the day specified, we increment the week count.
1534 uint weekCount = 0;
1535 QDate tempDate = initialDate;
1536 while (tempDate < date) {
1537 tempDate = tempDate.addDays(days: 1);
1538 if (static_cast<Qt::DayOfWeek>(tempDate.dayOfWeek()) == firstDayOfWeek) {
1539 weekCount += 1;
1540 }
1541 }
1542 return (weekCount % interval == 0);
1543 }
1544 case QOrganizerRecurrenceRule::Daily: {
1545 uint daysDelta = initialDate.daysTo(date);
1546 return (daysDelta % interval == 0);
1547 }
1548 case QOrganizerRecurrenceRule::Invalid:
1549 Q_ASSERT(false);
1550 }
1551 return true;
1552}
1553
1554/*!
1555 Returns the date which is the first date of the calendar period that \a date resides in. eg. if
1556 the \a frequency is Monthly, then this returns the first day of \a date's month. If the \a
1557 frequency is Weekly, then it returns the first day of \a date's week, considering the week to
1558 start on \a firstDayOfWeek
1559 */
1560QDate QOrganizerManagerEngine::firstDateInPeriod(const QDate &date, QOrganizerRecurrenceRule::Frequency frequency, Qt::DayOfWeek firstDayOfWeek)
1561{
1562 QDate retn(date);
1563 switch (frequency) {
1564 case QOrganizerRecurrenceRule::Yearly:
1565 retn.setDate(year: date.year(), month: 1, day: 1);
1566 return retn;
1567 case QOrganizerRecurrenceRule::Monthly:
1568 retn.setDate(year: date.year(), month: date.month(), day: 1);
1569 return retn;
1570 case QOrganizerRecurrenceRule::Weekly:
1571 while (retn.dayOfWeek() != firstDayOfWeek) {
1572 retn = retn.addDays(days: -1);
1573 }
1574 return retn;
1575 case QOrganizerRecurrenceRule::Daily:
1576 return retn;
1577 default:
1578 Q_ASSERT(false);
1579 return retn;
1580 }
1581}
1582
1583/*!
1584 Returns the date which is the first date of the next calendar period after \a date specified by
1585 \a frequency. eg. if \a frequency is Monthly, then this returns the first day of the next month.
1586 If \a frequency is Weekly, then it returns the first \a firstDayOfWeek after \a date.
1587 */
1588QDate QOrganizerManagerEngine::firstDateInNextPeriod(const QDate &date, QOrganizerRecurrenceRule::Frequency frequency, Qt::DayOfWeek firstDayOfWeek)
1589{
1590 QDate retn(date);
1591 switch (frequency) {
1592 case QOrganizerRecurrenceRule::Yearly:
1593 retn.setDate(year: date.year()+1, month: 1, day: 1);
1594 return retn;
1595 case QOrganizerRecurrenceRule::Monthly:
1596 {
1597 int newMonth = date.month() + 1;
1598 int newYear = date.year() + (newMonth==13 ? 1 : 0);
1599 retn.setDate(year: newYear, month: newMonth==13 ? 1 : newMonth, day: 1);
1600 }
1601 return retn;
1602 case QOrganizerRecurrenceRule::Weekly:
1603 do {
1604 retn = retn.addDays(days: 1);
1605 } while (retn.dayOfWeek() != firstDayOfWeek);
1606 return retn;
1607 case QOrganizerRecurrenceRule::Daily:
1608 retn = retn.addDays(days: 1);
1609 return retn;
1610 case QOrganizerRecurrenceRule::Invalid:
1611 Q_ASSERT(false);
1612 }
1613 return retn;
1614}
1615
1616/*!
1617 Returns a list of dates between \a periodStart (inclusive) and \a periodEnd (inclusive) which
1618 match the \a rrule. Only daysOfWeek, daysOfMonth, daysOfYear, weeksOfYear and months from the \a
1619 rrule are matched.
1620 */
1621QList<QDate> QOrganizerManagerEngine::matchingDates(const QDate &periodStart, const QDate &periodEnd, const QOrganizerRecurrenceRule &rrule)
1622{
1623 QList<QDate> retn;
1624
1625 QSet<Qt::DayOfWeek> daysOfWeek = rrule.daysOfWeek();
1626 QSet<int> daysOfMonth = rrule.daysOfMonth();
1627 QSet<int> daysOfYear = rrule.daysOfYear();
1628 QSet<int> weeksOfYear = rrule.weeksOfYear();
1629 QSet<QOrganizerRecurrenceRule::Month> monthsOfYear = rrule.monthsOfYear();
1630
1631 QDate tempDate = periodStart;
1632 while (tempDate <= periodEnd) {
1633 if ((monthsOfYear.isEmpty() || monthsOfYear.contains(value: static_cast<QOrganizerRecurrenceRule::Month>(tempDate.month())))
1634 && (weeksOfYear.isEmpty() || weeksOfYear.contains(value: tempDate.weekNumber()))
1635 && (daysOfYear.isEmpty() || daysOfYear.contains(value: tempDate.dayOfYear()))
1636 && (daysOfMonth.isEmpty() || daysOfMonth.contains(value: tempDate.day()))
1637 && (daysOfWeek.isEmpty() || daysOfWeek.contains(value: static_cast<Qt::DayOfWeek>(tempDate.dayOfWeek())))) {
1638 retn.append(t: tempDate);
1639 }
1640 tempDate = tempDate.addDays(days: 1);
1641 }
1642 return retn;
1643}
1644
1645/*!
1646 Returns a list of dates from \a dates which are at the indices specified by \a positions.
1647 For positive values in \a positions, the values represent a 1-based index into \a dates.
1648 For negative values, they represent indices counting from the end of \a dates (eg. -1 means the
1649 last value of \a dates).
1650 */
1651QList<QDate> QOrganizerManagerEngine::filterByPosition(const QList<QDate> &dates, const QSet<int> positions)
1652{
1653 if (positions.isEmpty()) {
1654 return dates;
1655 }
1656
1657 QList<QDate> retn;
1658 foreach (int i, positions) {
1659 if (i >= 1 && i <= dates.size()) {
1660 // positions is 1-indexed, but the QList is 0-indexed
1661 retn.append(t: dates[i-1]);
1662 } else if (i <= -1 && i >= -dates.size()) {
1663 // for negative values, count from the end of the list
1664 retn.append(t: dates[dates.size() + i]);
1665 }
1666 }
1667 return retn;
1668}
1669
1670/*!
1671 Returns true if the given organizer item \a oi has any recurrence.
1672 */
1673bool QOrganizerManagerEngine::itemHasReccurence(const QOrganizerItem& oi)
1674{
1675 if (oi.type() == QOrganizerItemType::TypeEvent || oi.type() == QOrganizerItemType::TypeTodo) {
1676 QOrganizerItemRecurrence recur = oi.detail(detailType: QOrganizerItemDetail::TypeRecurrence);
1677 return !recur.recurrenceDates().isEmpty() || !recur.recurrenceRules().isEmpty();
1678 }
1679
1680 return false;
1681}
1682
1683/*!
1684 This function is called when the given \a request has been destroyed by the client.
1685
1686 When this function is called, it means for the backend:
1687 \list
1688 \li The client doesn't care about the request any more. The engine can still complete it, but
1689 completion is not required.
1690 \li It can't reliably access any properties of the request pointer any more. The pointer will
1691 be invalid once this function returns.
1692 \endlist
1693
1694 Note that since the \a request may run in another thread, this function should be blocked until
1695 the worker thread gets fully notified.
1696 */
1697void QOrganizerManagerEngine::requestDestroyed(QOrganizerAbstractRequest *request)
1698{
1699 Q_UNUSED(request);
1700}
1701
1702/*!
1703 This function is called when the client tries to start the given asynchronous \a request. Returns
1704 true if the request is started successfully, or false otherwise.
1705
1706 Note that the request is supposed to run in an asynchronous manner that this function should
1707 return as soon as possible. Therefore, it the operation would last sometime, a worker thread
1708 should be used to queue and process the request. In such cases, backend should be aware that
1709 the request may be deleted by the client, and requestDestroyed() function will be called.
1710 */
1711bool QOrganizerManagerEngine::startRequest(QOrganizerAbstractRequest* request)
1712{
1713 Q_UNUSED(request);
1714 return false;
1715}
1716
1717/*!
1718 This function is called when the client tries to cancel the given asynchronous \a request. Returns
1719 true if the request is calcelled successfully, or false otherwise.
1720 */
1721bool QOrganizerManagerEngine::cancelRequest(QOrganizerAbstractRequest* request)
1722{
1723 Q_UNUSED(request);
1724 return false;
1725}
1726
1727/*!
1728 This function is called when the client wants to be blocked until the given \a request is completed,
1729 or until \a msecs milliseconds have passed. Returns true when the request is completed, or false
1730 otherwise.
1731 */
1732bool QOrganizerManagerEngine::waitForRequestFinished(QOrganizerAbstractRequest* request, int msecs)
1733{
1734 Q_UNUSED(request);
1735 Q_UNUSED(msecs);
1736 return false;
1737}
1738
1739/*!
1740 Updates the given asynchronous request \a req by setting the new \a state
1741 of the request. If the new state is different, the stateChanged() signal
1742 will be emitted by the request.
1743 */
1744void QOrganizerManagerEngine::updateRequestState(QOrganizerAbstractRequest* req, QOrganizerAbstractRequest::State state)
1745{
1746 Q_ASSERT(req);
1747 QMutexLocker ml(&req->d_ptr->m_mutex);
1748 bool emitState = req->d_ptr->m_state != state;
1749 req->d_ptr->m_state = state;
1750 ml.unlock();
1751#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
1752 QPointer<QOrganizerAbstractRequest> guard(req);
1753#endif
1754 Qt::ConnectionType connectionType = Qt::DirectConnection;
1755#ifdef QT_NO_THREAD
1756 if (req->thread() != QThread::currentThread())
1757 connectionType = Qt::BlockingQueuedConnection;
1758#endif
1759 if (emitState)
1760 QMetaObject::invokeMethod(obj: req, member: "stateChanged", type: connectionType, Q_ARG(QOrganizerAbstractRequest::State, state));
1761#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
1762 Q_ASSERT(guard);
1763#endif
1764}
1765
1766/*!
1767 Updates the given QOrganizerItemOccurrenceFetchRequest \a req with the latest results \a result, and operation error \a error.
1768 In addition, the state of the request will be changed to \a newState.
1769
1770 It then causes the request to emit its resultsAvailable() signal to notify clients of the request progress.
1771
1772 If the new request state is different from the previous state, the stateChanged() signal will also be emitted from the request.
1773 */
1774void QOrganizerManagerEngine::updateItemOccurrenceFetchRequest(QOrganizerItemOccurrenceFetchRequest* req, const QList<QOrganizerItem>& result, QOrganizerManager::Error error, QOrganizerAbstractRequest::State newState)
1775{
1776 Q_ASSERT(req);
1777 QOrganizerItemOccurrenceFetchRequestPrivate* rd = static_cast<QOrganizerItemOccurrenceFetchRequestPrivate*>(req->d_ptr);
1778 QMutexLocker ml(&rd->m_mutex);
1779 bool emitState = rd->m_state != newState;
1780 rd->m_organizeritems = result;
1781 rd->m_error = error;
1782 rd->m_state = newState;
1783 ml.unlock();
1784#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
1785 QPointer<QOrganizerAbstractRequest> guard(req);
1786#endif
1787 Qt::ConnectionType connectionType = Qt::DirectConnection;
1788#ifdef QT_NO_THREAD
1789 if (req->thread() != QThread::currentThread())
1790 connectionType = Qt::BlockingQueuedConnection;
1791#endif
1792 QMetaObject::invokeMethod(obj: req, member: "resultsAvailable", type: connectionType);
1793#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
1794 Q_ASSERT(guard);
1795#endif
1796 if (emitState)
1797 QMetaObject::invokeMethod(obj: req, member: "stateChanged", type: connectionType, Q_ARG(QOrganizerAbstractRequest::State, newState));
1798#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
1799 Q_ASSERT(guard);
1800#endif
1801}
1802
1803/*!
1804 Updates the given QOrganizerItemIdFetchRequest \a req with the latest results \a result, and operation error \a error.
1805 In addition, the state of the request will be changed to \a newState.
1806
1807 It then causes the request to emit its resultsAvailable() signal to notify clients of the request progress.
1808
1809 If the new request state is different from the previous state, the stateChanged() signal will also be emitted from the request.
1810 */
1811void QOrganizerManagerEngine::updateItemIdFetchRequest(QOrganizerItemIdFetchRequest* req, const QList<QOrganizerItemId>& result, QOrganizerManager::Error error, QOrganizerAbstractRequest::State newState)
1812{
1813 Q_ASSERT(req);
1814 QOrganizerItemIdFetchRequestPrivate* rd = static_cast<QOrganizerItemIdFetchRequestPrivate*>(req->d_ptr);
1815 QMutexLocker ml(&rd->m_mutex);
1816 bool emitState = rd->m_state != newState;
1817 rd->m_ids = result;
1818 rd->m_error = error;
1819 rd->m_state = newState;
1820 ml.unlock();
1821#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
1822 QPointer<QOrganizerAbstractRequest> guard(req);
1823#endif
1824 Qt::ConnectionType connectionType = Qt::DirectConnection;
1825#ifdef QT_NO_THREAD
1826 if (req->thread() != QThread::currentThread())
1827 connectionType = Qt::BlockingQueuedConnection;
1828#endif
1829 QMetaObject::invokeMethod(obj: req, member: "resultsAvailable", type: connectionType);
1830#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
1831 Q_ASSERT(guard);
1832#endif
1833 if (emitState)
1834 QMetaObject::invokeMethod(obj: req, member: "stateChanged", type: connectionType, Q_ARG(QOrganizerAbstractRequest::State, newState));
1835#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
1836 Q_ASSERT(guard);
1837#endif
1838}
1839
1840/*!
1841 Updates the given QOrganizerItemFetchByIdRequest \a req with the latest results \a result, and
1842 operation error \a error, and map of input index to individual error \a errorMap. In addition,
1843 the state of the request will be changed to \a newState.
1844
1845 It then causes the request to emit its resultsAvailable() signal to notify clients of the request
1846 progress.
1847
1848 If the new request state is different from the previous state, the stateChanged() signal will
1849 also be emitted from the request.
1850 */
1851void QOrganizerManagerEngine::updateItemFetchByIdRequest(QOrganizerItemFetchByIdRequest *req, const QList<QOrganizerItem> &result, QOrganizerManager::Error error, const QMap<int, QOrganizerManager::Error> &errorMap, QOrganizerAbstractRequest::State newState)
1852{
1853 Q_ASSERT(req);
1854 QOrganizerItemFetchByIdRequestPrivate *rd = static_cast<QOrganizerItemFetchByIdRequestPrivate *>(req->d_ptr);
1855 QMutexLocker ml(&rd->m_mutex);
1856 bool emitState = rd->m_state != newState;
1857 rd->m_items = result;
1858 rd->m_errors = errorMap;
1859 rd->m_error = error;
1860 rd->m_state = newState;
1861 ml.unlock();
1862#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
1863 QPointer<QOrganizerAbstractRequest> guard(req);
1864#endif
1865 Qt::ConnectionType connectionType = Qt::DirectConnection;
1866#ifdef QT_NO_THREAD
1867 if (req->thread() != QThread::currentThread())
1868 connectionType = Qt::BlockingQueuedConnection;
1869#endif
1870 QMetaObject::invokeMethod(obj: req, member: "resultsAvailable", type: connectionType);
1871#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
1872 Q_ASSERT(guard);
1873#endif
1874 if (emitState)
1875 QMetaObject::invokeMethod(obj: req, member: "stateChanged", type: connectionType, Q_ARG(QOrganizerAbstractRequest::State, newState));
1876#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
1877 Q_ASSERT(guard);
1878#endif
1879}
1880
1881/*!
1882 Updates the given QOrganizerItemFetchRequest \a req with the latest results \a result, and operation error \a error.
1883 In addition, the state of the request will be changed to \a newState.
1884
1885 It then causes the request to emit its resultsAvailable() signal to notify clients of the request progress.
1886
1887 If the new request state is different from the previous state, the stateChanged() signal will also be emitted from the request.
1888 */
1889void QOrganizerManagerEngine::updateItemFetchRequest(QOrganizerItemFetchRequest* req, const QList<QOrganizerItem>& result, QOrganizerManager::Error error, QOrganizerAbstractRequest::State newState)
1890{
1891 Q_ASSERT(req);
1892 QOrganizerItemFetchRequestPrivate* rd = static_cast<QOrganizerItemFetchRequestPrivate*>(req->d_ptr);
1893 QMutexLocker ml(&rd->m_mutex);
1894 bool emitState = rd->m_state != newState;
1895 rd->m_organizeritems = result;
1896 rd->m_error = error;
1897 rd->m_state = newState;
1898 ml.unlock();
1899#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
1900 QPointer<QOrganizerAbstractRequest> guard(req);
1901#endif
1902 Qt::ConnectionType connectionType = Qt::DirectConnection;
1903#ifdef QT_NO_THREAD
1904 if (req->thread() != QThread::currentThread())
1905 connectionType = Qt::BlockingQueuedConnection;
1906#endif
1907 QMetaObject::invokeMethod(obj: req, member: "resultsAvailable", type: connectionType);
1908#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
1909 Q_ASSERT(guard);
1910#endif
1911 if (emitState)
1912 QMetaObject::invokeMethod(obj: req, member: "stateChanged", type: connectionType, Q_ARG(QOrganizerAbstractRequest::State, newState));
1913#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
1914 Q_ASSERT(guard);
1915#endif
1916}
1917
1918/*!
1919 Updates the given QOrganizerItemFetchForExportRequest \a req with the latest results \a result, and operation error \a error.
1920 In addition, the state of the request will be changed to \a newState.
1921
1922 It then causes the request to emit its resultsAvailable() signal to notify clients of the request progress.
1923
1924 If the new request state is different from the previous state, the stateChanged() signal will also be emitted from the request.
1925 */
1926void QOrganizerManagerEngine::updateItemFetchForExportRequest(QOrganizerItemFetchForExportRequest* req, const QList<QOrganizerItem>& result, QOrganizerManager::Error error, QOrganizerAbstractRequest::State newState)
1927{
1928 Q_ASSERT(req);
1929 QOrganizerItemFetchForExportRequestPrivate* rd = static_cast<QOrganizerItemFetchForExportRequestPrivate*>(req->d_ptr);
1930 QMutexLocker ml(&rd->m_mutex);
1931 bool emitState = rd->m_state != newState;
1932 rd->m_organizeritems = result;
1933 rd->m_error = error;
1934 rd->m_state = newState;
1935 ml.unlock();
1936#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
1937 QPointer<QOrganizerAbstractRequest> guard(req);
1938#endif
1939 Qt::ConnectionType connectionType = Qt::DirectConnection;
1940#ifdef QT_NO_THREAD
1941 if (req->thread() != QThread::currentThread())
1942 connectionType = Qt::BlockingQueuedConnection;
1943#endif
1944 QMetaObject::invokeMethod(obj: req, member: "resultsAvailable", type: connectionType);
1945#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
1946 Q_ASSERT(guard);
1947#endif
1948 if (emitState)
1949 QMetaObject::invokeMethod(obj: req, member: "stateChanged", type: connectionType, Q_ARG(QOrganizerAbstractRequest::State, newState));
1950#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
1951 Q_ASSERT(guard);
1952#endif
1953}
1954
1955/*!
1956 Updates the given QOrganizerItemRemoveRequest \a req with the operation error \a error, and map of input index to individual error \a errorMap.
1957 In addition, the state of the request will be changed to \a newState.
1958
1959 It then causes the request to emit its resultsAvailable() signal to notify clients of the request progress.
1960
1961 If the new request state is different from the previous state, the stateChanged() signal will also be emitted from the request.
1962 */
1963void QOrganizerManagerEngine::updateItemRemoveRequest(QOrganizerItemRemoveRequest* req, QOrganizerManager::Error error, const QMap<int, QOrganizerManager::Error>& errorMap, QOrganizerAbstractRequest::State newState)
1964{
1965 Q_ASSERT(req);
1966 QOrganizerItemRemoveRequestPrivate* rd = static_cast<QOrganizerItemRemoveRequestPrivate*>(req->d_ptr);
1967 QMutexLocker ml(&rd->m_mutex);
1968 bool emitState = rd->m_state != newState;
1969 rd->m_errors = errorMap;
1970 rd->m_error = error;
1971 rd->m_state = newState;
1972 ml.unlock();
1973#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
1974 QPointer<QOrganizerAbstractRequest> guard(req);
1975#endif
1976 Qt::ConnectionType connectionType = Qt::DirectConnection;
1977#ifdef QT_NO_THREAD
1978 if (req->thread() != QThread::currentThread())
1979 connectionType = Qt::BlockingQueuedConnection;
1980#endif
1981 QMetaObject::invokeMethod(obj: req, member: "resultsAvailable", type: connectionType);
1982#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
1983 Q_ASSERT(guard);
1984#endif
1985 if (emitState)
1986 QMetaObject::invokeMethod(obj: req, member: "stateChanged", type: connectionType, Q_ARG(QOrganizerAbstractRequest::State, newState));
1987#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
1988 Q_ASSERT(guard);
1989#endif
1990}
1991
1992/*!
1993 Updates the given QOrganizerItemRemoveByIdRequest \a req with the operation error \a error, and map of input index to individual error \a errorMap.
1994 In addition, the state of the request will be changed to \a newState.
1995
1996 It then causes the request to emit its resultsAvailable() signal to notify clients of the request progress.
1997
1998 If the new request state is different from the previous state, the stateChanged() signal will also be emitted from the request.
1999 */
2000void QOrganizerManagerEngine::updateItemRemoveByIdRequest(QOrganizerItemRemoveByIdRequest* req, QOrganizerManager::Error error, const QMap<int, QOrganizerManager::Error>& errorMap, QOrganizerAbstractRequest::State newState)
2001{
2002 Q_ASSERT(req);
2003 QOrganizerItemRemoveByIdRequestPrivate* rd = static_cast<QOrganizerItemRemoveByIdRequestPrivate*>(req->d_ptr);
2004 QMutexLocker ml(&rd->m_mutex);
2005 bool emitState = rd->m_state != newState;
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<QOrganizerAbstractRequest> 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(QOrganizerAbstractRequest::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 QOrganizerItemSaveRequest \a req with the latest results \a result, operation error \a error, and map of input index to individual error \a errorMap.
2031 In addition, the state of the request will be changed to \a newState.
2032
2033 It then causes the request to emit its resultsAvailable() signal to notify clients of the request progress.
2034
2035 If the new request state is different from the previous state, the stateChanged() signal will also be emitted from the request.
2036 */
2037void QOrganizerManagerEngine::updateItemSaveRequest(QOrganizerItemSaveRequest* req, const QList<QOrganizerItem>& result, QOrganizerManager::Error error, const QMap<int, QOrganizerManager::Error>& errorMap, QOrganizerAbstractRequest::State newState)
2038{
2039 Q_ASSERT(req);
2040 QOrganizerItemSaveRequestPrivate* rd = static_cast<QOrganizerItemSaveRequestPrivate*>(req->d_ptr);
2041 QMutexLocker ml(&rd->m_mutex);
2042 bool emitState = rd->m_state != newState;
2043 rd->m_organizeritems = 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<QOrganizerAbstractRequest> 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(QOrganizerAbstractRequest::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 QOrganizerCollectionFetchRequest \a req with the latest results \a result and an operation error \a error.
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 If the new request state is different from the previous state, the stateChanged() signal will also be emitted from the request.
2073 */
2074void QOrganizerManagerEngine::updateCollectionFetchRequest(QOrganizerCollectionFetchRequest* req, const QList<QOrganizerCollection>& result, QOrganizerManager::Error error, QOrganizerAbstractRequest::State newState)
2075{
2076 Q_ASSERT(req);
2077 QOrganizerCollectionFetchRequestPrivate* rd = static_cast<QOrganizerCollectionFetchRequestPrivate*>(req->d_ptr);
2078 QMutexLocker ml(&rd->m_mutex);
2079 bool emitState = rd->m_state != newState;
2080 rd->m_collections = result;
2081 rd->m_error = error;
2082 rd->m_state = newState;
2083 ml.unlock();
2084#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
2085 QPointer<QOrganizerAbstractRequest> guard(req);
2086#endif
2087 Qt::ConnectionType connectionType = Qt::DirectConnection;
2088#ifdef QT_NO_THREAD
2089 if (req->thread() != QThread::currentThread())
2090 connectionType = Qt::BlockingQueuedConnection;
2091#endif
2092 QMetaObject::invokeMethod(obj: req, member: "resultsAvailable", type: connectionType);
2093#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
2094 Q_ASSERT(guard);
2095#endif
2096 if (emitState)
2097 QMetaObject::invokeMethod(obj: req, member: "stateChanged", type: connectionType, Q_ARG(QOrganizerAbstractRequest::State, newState));
2098#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
2099 Q_ASSERT(guard);
2100#endif
2101}
2102
2103/*!
2104 Updates the given QOrganizerCollectionRemoveRequest \a req with the operation error \a error, and map of input index to individual error \a errorMap.
2105 In addition, the state of the request will be changed to \a newState.
2106
2107 It then causes the request to emit its resultsAvailable() signal to notify clients of the request progress.
2108 If the new request state is different from the previous state, the stateChanged() signal will also be emitted from the request.
2109 */
2110void QOrganizerManagerEngine::updateCollectionRemoveRequest(QOrganizerCollectionRemoveRequest* req, QOrganizerManager::Error error, const QMap<int, QOrganizerManager::Error>& errorMap, QOrganizerAbstractRequest::State newState)
2111{
2112 Q_ASSERT(req);
2113 QOrganizerCollectionRemoveRequestPrivate* rd = static_cast<QOrganizerCollectionRemoveRequestPrivate*>(req->d_ptr);
2114 QMutexLocker ml(&rd->m_mutex);
2115 bool emitState = rd->m_state != newState;
2116 rd->m_errors = errorMap;
2117 rd->m_error = error;
2118 rd->m_state = newState;
2119 ml.unlock();
2120#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
2121 QPointer<QOrganizerAbstractRequest> guard(req);
2122#endif
2123 Qt::ConnectionType connectionType = Qt::DirectConnection;
2124#ifdef QT_NO_THREAD
2125 if (req->thread() != QThread::currentThread())
2126 connectionType = Qt::BlockingQueuedConnection;
2127#endif
2128 QMetaObject::invokeMethod(obj: req, member: "resultsAvailable", type: connectionType);
2129#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
2130 Q_ASSERT(guard);
2131#endif
2132 if (emitState)
2133 QMetaObject::invokeMethod(obj: req, member: "stateChanged", type: connectionType, Q_ARG(QOrganizerAbstractRequest::State, newState));
2134#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
2135 Q_ASSERT(guard);
2136#endif
2137}
2138
2139/*!
2140 Updates the given QOrganizerCollectionSaveRequest \a req with the latest results \a result, operation error \a error, and map of input index to individual error \a errorMap.
2141 In addition, the state of the request will be changed to \a newState.
2142
2143 It then causes the request to emit its resultsAvailable() signal to notify clients of the request progress.
2144 If the new request state is different from the previous state, the stateChanged() signal will also be emitted from the request.
2145 */
2146void QOrganizerManagerEngine::updateCollectionSaveRequest(QOrganizerCollectionSaveRequest* req, const QList<QOrganizerCollection>& result, QOrganizerManager::Error error, const QMap<int, QOrganizerManager::Error>& errorMap, QOrganizerAbstractRequest::State newState)
2147{
2148 Q_ASSERT(req);
2149 QOrganizerCollectionSaveRequestPrivate* rd = static_cast<QOrganizerCollectionSaveRequestPrivate*>(req->d_ptr);
2150 QMutexLocker ml(&rd->m_mutex);
2151 bool emitState = rd->m_state != newState;
2152 rd->m_collections = result;
2153 rd->m_errors = errorMap;
2154 rd->m_error = error;
2155 rd->m_state = newState;
2156 ml.unlock();
2157#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
2158 QPointer<QOrganizerAbstractRequest> guard(req);
2159#endif
2160 Qt::ConnectionType connectionType = Qt::DirectConnection;
2161#ifdef QT_NO_THREAD
2162 if (req->thread() != QThread::currentThread())
2163 connectionType = Qt::BlockingQueuedConnection;
2164#endif
2165 QMetaObject::invokeMethod(obj: req, member: "resultsAvailable", type: connectionType);
2166#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
2167 Q_ASSERT(guard);
2168#endif
2169 if (emitState)
2170 QMetaObject::invokeMethod(obj: req, member: "stateChanged", type: connectionType, Q_ARG(QOrganizerAbstractRequest::State, newState));
2171#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
2172 Q_ASSERT(guard);
2173#endif
2174}
2175
2176#include "moc_qorganizermanagerengine.cpp"
2177
2178QT_END_NAMESPACE_ORGANIZER
2179

source code of qtpim/src/organizer/qorganizermanagerengine.cpp