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 "qdeclarativeorganizermodel_p.h"
35
36#include <QtCore/qfile.h>
37#include <QtCore/qmath.h>
38#include <QtCore/qurl.h>
39#include <QtCore/qpointer.h>
40#include <QtCore/qtimer.h>
41
42#include <QtQml/qqmlinfo.h>
43
44#include <QtOrganizer/qorganizeritemdetails.h>
45#include <QtOrganizer/qorganizeritemrequests.h>
46#include <QtOrganizer/qorganizermanager.h>
47
48#include <QtVersitOrganizer/qversitorganizerimporter.h>
49#include <QtVersitOrganizer/qversitorganizerexporter.h>
50
51#include "qdeclarativeorganizercollection_p.h"
52
53QTORGANIZER_USE_NAMESPACE
54QTVERSITORGANIZER_USE_NAMESPACE
55
56QT_BEGIN_NAMESPACE
57
58// TODO:
59// - Improve handling of itemsModified signal. Instead of fetching all items each time the
60// signal is received, only modified items should be fetched. Item based fetching allows easier
61// use of any item id based caches backends might have.
62// - Full update is not needed every time some model property changes. Collections should
63// be updated only if collections have been changed while autoUpdate is off.
64// - Changing the time period is by far the most common use case and should be optimized.
65// If new time period overlaps with the old, no need to fetch all the items in new time period.
66// - All changes happening during autoUpdate is off should be monitored. If only timePeriod changes
67// there is no need for full update after switching autoUpdate on.
68
69
70static QString urlToLocalFileName(const QUrl& url)
71{
72 if (!url.isValid()) {
73 return url.toString();
74 } else if (url.scheme() == "qrc") {
75 return url.toString().remove(i: 0, len: 5).prepend(c: ':');
76 } else {
77 return url.toLocalFile();
78 }
79
80}
81
82static const char ITEM_TO_SAVE_PROPERTY[] = {"ITEM_TO_SAVE_PROPERTY"};
83static const char MANUALLY_TRIGGERED_PROPERTY[] = {"MANUALLY_TRIGGERED"};
84
85class QDeclarativeOrganizerModelPrivate
86{
87public:
88 QDeclarativeOrganizerModelPrivate()
89 :m_manager(0),
90 m_fetchHint(0),
91 m_filter(0),
92 m_fetchRequest(0),
93 m_occurrenceFetchRequest(0),
94 m_reader(0),
95 m_writer(0),
96 m_startPeriod(QDateTime::currentDateTime()),
97 m_endPeriod(QDateTime::currentDateTime()),
98 m_error(QOrganizerManager::NoError),
99 m_autoUpdate(true),
100 m_updatePendingFlag(QDeclarativeOrganizerModelPrivate::NonePending),
101 m_componentCompleted(false),
102 m_initialUpdate(false),
103 m_lastRequestId(0)
104 {
105 }
106 ~QDeclarativeOrganizerModelPrivate()
107 {
108 if (m_manager)
109 delete m_manager;
110 delete m_reader;
111 delete m_writer;
112}
113
114 QList<QDeclarativeOrganizerItem*> m_items;
115 QHash<QString, QDeclarativeOrganizerItem *> m_itemIdHash;
116 QOrganizerManager* m_manager;
117 QDeclarativeOrganizerItemFetchHint* m_fetchHint;
118 QList<QOrganizerItemSortOrder> m_sortOrders;
119 QList<QDeclarativeOrganizerItemSortOrder*> m_declarativeSortOrders;
120 QDeclarativeOrganizerItemFilter* m_filter;
121 QOrganizerItemFetchRequest* m_fetchRequest;
122 QSet<QOrganizerItemId> m_addedItemIds;
123 QMap<QOrganizerAbstractRequest*, QSet<QOrganizerItemId> > m_notifiedItems;
124 QOrganizerItemOccurrenceFetchRequest* m_occurrenceFetchRequest;
125 QStringList m_importProfiles;
126 QVersitReader *m_reader;
127 QVersitWriter *m_writer;
128 QDateTime m_startPeriod;
129 QDateTime m_endPeriod;
130 QList<QDeclarativeOrganizerCollection*> m_collections;
131
132 QTimer m_updateTimer;
133 QTimer m_updateItemsTimer;
134 QTimer m_fetchCollectionsTimer;
135 QTimer m_modelChangedTimer;
136
137 QOrganizerManager::Error m_error;
138
139 bool m_autoUpdate;
140 enum UpdateTypePending {
141 NonePending = 0x0,
142 UpdatingItemsPending = 0x1,
143 UpdatingCollectionsPending = 0x2
144 };
145 int m_updatePendingFlag;
146 bool m_componentCompleted;
147 bool m_initialUpdate;
148
149 QAtomicInt m_lastRequestId;
150 QHash<QOrganizerAbstractRequest *, int> m_requestIdHash;
151 QUrl m_lastExportUrl;
152 QUrl m_lastImportUrl;
153};
154
155/*!
156 \qmltype OrganizerModel
157 \instantiates QDeclarativeOrganizerModel
158 \brief The OrganizerModel element provides access to organizer items from the organizer store.
159 \inqmlmodule QtOrganizer
160 \ingroup qml-organizer-main
161
162 OrganizerModel provides a model of organizer items from the organizer store.
163 The contents of the model can be specified with \l filter, \l sortOrders and \l fetchHint properties.
164 Whether the model is automatically updated when the store or
165 \l{Qt Organizer Overview} {C++ organizer} item changes, can be
166 controlled with \l OrganizerModel::autoUpdate property.
167
168 There are two ways of accessing the organizer item data: via the model by using views and delegates,
169 or alternatively via \l items list property. Of the two, the model access is preferred.
170 Direct list access (i.e. non-model) is not guaranteed to be in order set by \l sortOrder.
171
172 At the moment the model roles provided by OrganizerModel are \c display and \c item.
173 Through the \c item role can access any data provided by the OrganizerItem element.
174
175
176 \note Both the \c startPeriod and \c endPeriod are set by default to the current time (when the OrganizerModel was created).
177 In most cases, both (or at least one) of the startPeriod and endPeriod should be set; otherwise, the OrganizerModel will contain
178 zero items because the \c startPeriod and \c endPeriod are the same value. For example, if only \c endPeriod is provided,
179 the OrganizerModel will contain all items from now (the time of the OrganizerModel's creation) to the \c endPeriod time.
180
181 \sa OrganizerItem, {QOrganizerManager}
182*/
183
184/*!
185 \qmlsignal OrganizerModel::onModelChanged()
186
187 This signal is emitted, when there are changes in items contained by \l OrganizerModel's data model. Items have either
188 been added, removed or modified. This signal is also always emitted during OrganizerModel construction when data model is
189 ready for use, even in cases when data model is not having any items in it.
190 */
191QDeclarativeOrganizerModel::QDeclarativeOrganizerModel(QObject *parent) :
192 QAbstractListModel(parent),
193 d_ptr(new QDeclarativeOrganizerModelPrivate)
194{
195 QHash<int, QByteArray> roleNames;
196 roleNames = QAbstractItemModel::roleNames();
197 roleNames.insert(akey: OrganizerItemRole, avalue: "item");
198 setRoleNames(roleNames);
199
200 d_ptr->m_updateTimer.setSingleShot(true);
201 d_ptr->m_updateItemsTimer.setSingleShot(true);
202 d_ptr->m_fetchCollectionsTimer.setSingleShot(true);
203 d_ptr->m_modelChangedTimer.setSingleShot(true);
204 d_ptr->m_updateTimer.setInterval(1);
205 d_ptr->m_updateItemsTimer.setInterval(1);
206 d_ptr->m_fetchCollectionsTimer.setInterval(1);
207 d_ptr->m_modelChangedTimer.setInterval(1);
208 connect(sender: &d_ptr->m_updateTimer, signal: &QTimer::timeout, receiver: this, slot: &QDeclarativeOrganizerModel::doUpdate);
209 connect(sender: &d_ptr->m_updateItemsTimer, signal: &QTimer::timeout, receiver: this, slot: &QDeclarativeOrganizerModel::doUpdateItems);
210 connect(sender: &d_ptr->m_fetchCollectionsTimer, signal: &QTimer::timeout, receiver: this, slot: &QDeclarativeOrganizerModel::fetchCollections);
211 connect(sender: &d_ptr->m_modelChangedTimer, signal: &QTimer::timeout, receiver: this, slot: &QDeclarativeOrganizerModel::modelChanged);
212
213 connect(sender: this, signal: &QDeclarativeOrganizerModel::filterChanged, receiver: &d_ptr->m_updateItemsTimer, slot: static_cast<void (QTimer::*)(void)>(&QTimer::start));
214 connect(sender: this, signal: &QDeclarativeOrganizerModel::fetchHintChanged, receiver: &d_ptr->m_updateItemsTimer, slot: static_cast<void (QTimer::*)(void)>(&QTimer::start));
215 connect(sender: this, signal: &QDeclarativeOrganizerModel::sortOrdersChanged, receiver: &d_ptr->m_updateItemsTimer, slot: static_cast<void (QTimer::*)(void)>(&QTimer::start));
216 connect(sender: this, signal: &QDeclarativeOrganizerModel::startPeriodChanged, receiver: &d_ptr->m_updateItemsTimer, slot: static_cast<void (QTimer::*)(void)>(&QTimer::start));
217 connect(sender: this, signal: &QDeclarativeOrganizerModel::endPeriodChanged, receiver: &d_ptr->m_updateItemsTimer, slot: static_cast<void (QTimer::*)(void)>(&QTimer::start));
218}
219
220QDeclarativeOrganizerModel::~QDeclarativeOrganizerModel()
221{
222}
223
224/*!
225 \qmlproperty string OrganizerModel::manager
226
227 This property holds the manager name or manager uri of the organizer backend engine.
228 The manager uri format: qtorganizer:<managerid>:<key>=<value>&<key>=<value>.
229
230 For example, memory organizer engine has an optional id parameter, if user want to
231 share the same memory engine with multiple OrganizerModel instances, the manager property
232 should declared like this:
233 \code
234 model : OrganizerModel {
235 manager:"qtorganizer:memory:id=organizer1
236 }
237 \endcode
238
239 instead of just the manager name:
240 \code
241 model : OrganizerModel {
242 manager:"memory"
243 }
244 \endcode
245
246 \sa QOrganizerManager::fromUri()
247 */
248QString QDeclarativeOrganizerModel::manager() const
249{
250 Q_D(const QDeclarativeOrganizerModel);
251 if (d->m_manager)
252 return d->m_manager->managerUri();
253 return QString();
254}
255
256/*!
257 \qmlproperty string OrganizerModel::managerName
258
259 This property holds the manager name of the organizer backend engine.
260 This property is read only.
261 \sa QOrganizerManager::fromUri()
262 */
263QString QDeclarativeOrganizerModel::managerName() const
264{
265 Q_D(const QDeclarativeOrganizerModel);
266 if (d->m_manager)
267 return d->m_manager->managerName();
268 return QString();
269}
270
271/*!
272 \qmlproperty list<string> OrganizerModel::availableManagers
273
274 This property holds the list of available manager names.
275 This property is read only.
276 */
277QStringList QDeclarativeOrganizerModel::availableManagers() const
278{
279 return QOrganizerManager::availableManagers();
280}
281
282/*!
283 \qmlproperty bool OrganizerModel::autoUpdate
284
285 This property indicates whether or not the organizer model should be updated automatically, default value is true.
286
287 \sa OrganizerModel::update()
288 */
289void QDeclarativeOrganizerModel::setAutoUpdate(bool autoUpdate)
290{
291 Q_D(QDeclarativeOrganizerModel);
292 if (autoUpdate == d->m_autoUpdate)
293 return;
294 d->m_autoUpdate = autoUpdate;
295 emit autoUpdateChanged();
296}
297
298bool QDeclarativeOrganizerModel::autoUpdate() const
299{
300 Q_D(const QDeclarativeOrganizerModel);
301 return d->m_autoUpdate;
302}
303
304/*!
305 \qmlmethod OrganizerModel::update()
306
307 Manually update the organizer model content including both
308 items and collections.
309
310 \sa OrganizerModel::updateItems
311 \sa OrganizerModel::updateCollections
312 \sa OrganizerModel::autoUpdate
313 */
314void QDeclarativeOrganizerModel::update()
315{
316 Q_D(QDeclarativeOrganizerModel);
317 if (!d->m_componentCompleted || d->m_updatePendingFlag)
318 return;
319
320 // Disallow possible duplicate request triggering
321 d->m_updatePendingFlag = (QDeclarativeOrganizerModelPrivate::UpdatingItemsPending | QDeclarativeOrganizerModelPrivate::UpdatingCollectionsPending);
322 d->m_fetchCollectionsTimer.setProperty(name: MANUALLY_TRIGGERED_PROPERTY, value: QVariant::fromValue<bool>(value: true));
323 d->m_fetchCollectionsTimer.start();
324}
325
326void QDeclarativeOrganizerModel::doUpdate()
327{
328 Q_D(QDeclarativeOrganizerModel);
329 if (d->m_autoUpdate)
330 update();
331}
332
333void QDeclarativeOrganizerModel::doUpdateItems()
334{
335 Q_D(QDeclarativeOrganizerModel);
336 if (d->m_autoUpdate)
337 updateItems();
338}
339
340/*!
341 \qmlmethod OrganizerModel::updateItems()
342
343 Manually update the organizer model items.
344
345 \sa OrganizerModel::update
346 \sa OrganizerModel::updateCollections
347 \sa OrganizerModel::autoUpdate
348 */
349void QDeclarativeOrganizerModel::updateItems()
350{
351 Q_D(QDeclarativeOrganizerModel);
352 if (!d->m_componentCompleted || d->m_updatePendingFlag)
353 return;
354 d->m_updatePendingFlag = QDeclarativeOrganizerModelPrivate::UpdatingItemsPending;// Disallow possible duplicate request triggering
355 QMetaObject::invokeMethod(obj: this, member: "fetchAgain", type: Qt::QueuedConnection);
356}
357
358/*!
359 \qmlmethod OrganizerModel::updateCollections()
360
361 Manually update the organizer model collections.
362
363 \sa OrganizerModel::update
364 \sa OrganizerModel::updateItems
365 \sa OrganizerModel::autoUpdate
366 */
367void QDeclarativeOrganizerModel::updateCollections()
368{
369 Q_D(QDeclarativeOrganizerModel);
370 if (!d->m_componentCompleted || d->m_updatePendingFlag)
371 return;
372 d->m_updatePendingFlag = QDeclarativeOrganizerModelPrivate::UpdatingCollectionsPending;// Disallow possible duplicate request triggering
373 d->m_fetchCollectionsTimer.setProperty(name: MANUALLY_TRIGGERED_PROPERTY, value: QVariant::fromValue<bool>(value: true));
374 d->m_fetchCollectionsTimer.start();
375}
376
377/*!
378 \qmlmethod OrganizerModel::cancelUpdate()
379
380 Cancel the running organizer model content update request.
381
382 \sa OrganizerModel::autoUpdate, OrganizerModel::update
383 */
384void QDeclarativeOrganizerModel::cancelUpdate()
385{
386 Q_D(QDeclarativeOrganizerModel);
387 if (d->m_fetchRequest) {
388 d->m_fetchRequest->cancel();
389 d->m_fetchRequest->deleteLater();
390 d->m_fetchRequest = 0;
391 d->m_updatePendingFlag = QDeclarativeOrganizerModelPrivate::NonePending;
392 }
393}
394/*!
395 \qmlproperty date OrganizerModel::startPeriod
396
397 This property holds the start date and time period used by the organizer model to fetch organizer items.
398 The default value is the datetime of OrganizerModel creation.
399 */
400QDateTime QDeclarativeOrganizerModel::startPeriod() const
401{
402 Q_D(const QDeclarativeOrganizerModel);
403 return d->m_startPeriod;
404}
405void QDeclarativeOrganizerModel::setStartPeriod(const QDateTime& start)
406{
407 Q_D(QDeclarativeOrganizerModel);
408 if (start != d->m_startPeriod) {
409 d->m_startPeriod = start;
410 emit startPeriodChanged();
411 }
412}
413
414/*!
415 \qmlproperty date OrganizerModel::endPeriod
416
417 This property holds the end date and time period used by the organizer model to fetch organizer items.
418 The default value is the datetime of OrganizerModel creation.
419 */
420QDateTime QDeclarativeOrganizerModel::endPeriod() const
421{
422 Q_D(const QDeclarativeOrganizerModel);
423 return d->m_endPeriod;
424}
425void QDeclarativeOrganizerModel::setEndPeriod(const QDateTime& end)
426{
427 Q_D(QDeclarativeOrganizerModel);
428 if (end != d->m_endPeriod) {
429 d->m_endPeriod = end;
430 emit endPeriodChanged();
431 }
432}
433
434/*!
435 \qmlproperty enumeration OrganizerModel::ImportError
436
437 Defines the errors cases for \l OrganizerModel::importItems() -function.
438
439 \list
440 \li OrganizerModel::ImportNoError Completed successfully, no error.
441 \li OrganizerModel::ImportUnspecifiedError Unspecified error.
442 \li OrganizerModel::ImportIOError Input/output error.
443 \li OrganizerModel::ImportOutOfMemoryError Out of memory error.
444 \li OrganizerModel::ImportNotReadyError Not ready for importing. Only one import operation can be active at a time.
445 \li OrganizerModel::ImportParseError Error during parsing.
446 \endlist
447*/
448
449/*!
450 \qmlsignal OrganizerModel::onImportCompleted(ImportError error, URL url, list<string> ids)
451
452 This signal is emitted, when \l OrganizerModel::importItems() completes. The success of operation
453 can be seen on \a error which is defined in \l OrganizerModel::ImportError. \a url indicates the
454 file, which was imported. \a ids contains the imported items ids.
455
456 If the operation was successful, items are now imported to backend. If \l OrganizerModel::autoUpdate
457 is enabled, \l OrganizerModel::modelChanged will be emitted when imported items are also visible on
458 \l OrganizerModel's data model.
459
460 \sa OrganizerModel::importItems
461 */
462
463/*!
464 \qmlmethod OrganizerModel::importItems(url url, list<string> profiles)
465
466 Import organizer items from a vcalendar by the given \a url and optional \a profiles.
467 Only one import operation can be active at a time.
468 */
469void QDeclarativeOrganizerModel::importItems(const QUrl& url, const QStringList &profiles)
470{
471 Q_D(QDeclarativeOrganizerModel);
472
473 ImportError importError = ImportNotReadyError;
474
475 // Reader is capable of handling only one request at the time.
476 if (!d->m_reader || (d->m_reader->state() != QVersitReader::ActiveState)) {
477
478 d->m_importProfiles = profiles;
479
480 //TODO: need to allow download vcard from network
481 QFile *file = new QFile(urlToLocalFileName(url));
482 if (file->open(flags: QIODevice::ReadOnly)) {
483 if (!d->m_reader) {
484 d->m_reader = new QVersitReader;
485 connect(sender: d->m_reader, SIGNAL(stateChanged(QVersitReader::State)), receiver: this, SLOT(startImport(QVersitReader::State)));
486 }
487
488 d->m_reader->setDevice(file);
489 if (d->m_reader->startReading()) {
490 d->m_lastImportUrl = url;
491 return;
492 }
493 importError = QDeclarativeOrganizerModel::ImportError(d->m_reader->error());
494 } else {
495 importError = ImportIOError;
496 }
497 }
498
499 // If cannot startReading because already running then report the import error now
500 emit importCompleted(error: importError, url, ids: QStringList());
501}
502
503/*!
504 \qmlsignal OrganizerModel::onExportCompleted()
505
506 This signal is emitted, when \l OrganizerModel::exportItems() completes. The success of operation
507 can be seen on \a error which is defined in \l OrganizerModel::ExportError. \a url indicates the
508 file, which was exported.
509 */
510/*!
511 \qmlmethod OrganizerModel::exportItems(url url, list<string> profiles)
512 Export organizer items into a vcalendar file to the given \a url by optional \a profiles.
513 At the moment only the local file url is supported in export method.
514 */
515void QDeclarativeOrganizerModel::exportItems(const QUrl &url, const QStringList &profiles)
516{
517 Q_D(QDeclarativeOrganizerModel);
518 ExportError exportError = ExportNotReadyError;
519
520 // Writer is capable of handling only one request at the time.
521 if (!d->m_writer || (d->m_writer->state() != QVersitWriter::ActiveState)) {
522
523 QString profile = profiles.isEmpty() ? QString() : profiles.at(i: 0);
524
525 QVersitOrganizerExporter exporter(profile);
526 QList<QOrganizerItem> items;
527 foreach (QDeclarativeOrganizerItem *di, d->m_items)
528 items.append(t: di->item());
529
530 exporter.exportItems(items, versitType: QVersitDocument::ICalendar20Type);
531 QVersitDocument document = exporter.document();
532 QFile *file = new QFile(urlToLocalFileName(url));
533 if (file->open(flags: QIODevice::ReadWrite)) {
534 if (!d->m_writer) {
535 d->m_writer = new QVersitWriter;
536 connect(sender: d->m_writer, SIGNAL(stateChanged(QVersitWriter::State)), receiver: this, SLOT(itemsExported(QVersitWriter::State)));
537 }
538 d->m_writer->setDevice(file);
539 if (d->m_writer->startWriting(input: document)) {
540 d->m_lastExportUrl = url;
541 return;
542 }
543 exportError = QDeclarativeOrganizerModel::ExportError(d->m_writer->error());
544 } else {
545 exportError = ExportIOError;
546 }
547 }
548 emit exportCompleted(error: exportError, url);
549}
550
551void QDeclarativeOrganizerModel::itemsExported(QVersitWriter::State state)
552{
553 Q_D(QDeclarativeOrganizerModel);
554 if (state == QVersitWriter::FinishedState || state == QVersitWriter::CanceledState) {
555 emit exportCompleted(error: QDeclarativeOrganizerModel::ExportError(d->m_writer->error()), url: d->m_lastExportUrl);
556 delete d->m_writer->device();
557 d->m_writer->setDevice(0);
558 }
559}
560
561int QDeclarativeOrganizerModel::rowCount(const QModelIndex &parent) const
562{
563 Q_UNUSED(parent);
564 Q_D(const QDeclarativeOrganizerModel);
565 return d->m_items.count();
566}
567
568void QDeclarativeOrganizerModel::setManager(const QString& managerName)
569{
570 Q_D(QDeclarativeOrganizerModel);
571 if (d->m_manager && (managerName == d->m_manager->managerName() || managerName == d->m_manager->managerUri()))
572 return;
573
574 if (d->m_manager) {
575 cancelUpdate();
576 d->m_updatePendingFlag = QDeclarativeOrganizerModelPrivate::NonePending;
577 delete d->m_manager;
578 }
579
580 if (managerName.startsWith(s: "qtorganizer:")) {
581 d->m_manager = QOrganizerManager::fromUri(uri: managerName, parent: this);
582 } else {
583 d->m_manager = new QOrganizerManager(managerName, QMap<QString, QString>(), this);
584 }
585
586 connect(sender: d->m_manager, signal: &QOrganizerManager::collectionsAdded, receiver: &d->m_fetchCollectionsTimer, slot: static_cast<void (QTimer::*)(void)>(&QTimer::start));
587 connect(sender: d->m_manager, signal: &QOrganizerManager::collectionsChanged, receiver: &d->m_fetchCollectionsTimer, slot: static_cast<void (QTimer::*)(void)>(&QTimer::start));
588 connect(sender: d->m_manager, signal: &QOrganizerManager::collectionsRemoved, receiver: &d->m_fetchCollectionsTimer, slot: static_cast<void (QTimer::*)(void)>(&QTimer::start));
589 connect(sender: d->m_manager, signal: &QOrganizerManager::dataChanged, receiver: &d->m_updateTimer, slot: static_cast<void (QTimer::*)(void)>(&QTimer::start));
590 connect(sender: d->m_manager, SIGNAL(itemsModified(QList<QPair<QOrganizerItemId,QOrganizerManager::Operation> >)), receiver: this, SLOT(onItemsModified(QList<QPair<QOrganizerItemId,QOrganizerManager::Operation> >)));
591
592 const QOrganizerManager::Error managerError = d->m_manager->error();
593 if (QOrganizerManager::NoError != managerError && d->m_error != managerError) {
594 d->m_error = managerError;
595 emit errorChanged();
596 } else if (QOrganizerManager::NoError != d->m_error) {
597 d->m_error = QOrganizerManager::NoError;
598 emit errorChanged();
599 }
600
601 emit managerChanged();
602}
603
604void QDeclarativeOrganizerModel::componentComplete()
605{
606 Q_D(QDeclarativeOrganizerModel);
607 d->m_componentCompleted = true;
608 if (!d->m_manager)
609 setManager(QString());
610
611 if (d->m_autoUpdate) {
612 d->m_initialUpdate = true;
613 update();
614 } else {
615 emit modelChanged();
616 }
617}
618/*!
619 \qmlproperty Filter OrganizerModel::filter
620
621 This property holds the filter instance used by the organizer model.
622
623 Set filter property to 'null', when you want to reset it to default value.
624
625 \sa Filter
626 */
627QDeclarativeOrganizerItemFilter* QDeclarativeOrganizerModel::filter() const
628{
629 Q_D(const QDeclarativeOrganizerModel);
630 return d->m_filter;
631}
632
633void QDeclarativeOrganizerModel::setFilter(QDeclarativeOrganizerItemFilter* filter)
634{
635 Q_D(QDeclarativeOrganizerModel);
636 if (filter != d->m_filter) {
637 if (d->m_filter)
638 disconnect(sender: d->m_filter, SIGNAL(filterChanged()), receiver: this, SIGNAL(filterChanged()));
639 d->m_filter = filter;
640 if (d->m_filter)
641 connect(sender: d->m_filter, SIGNAL(filterChanged()), receiver: this, SIGNAL(filterChanged()), Qt::UniqueConnection);
642 emit filterChanged();
643 }
644}
645
646/*!
647 \qmlproperty FetchHint OrganizerModel::fetchHint
648
649 This property holds the fetch hint instance used by the organizer model.
650
651 \sa FetchHint
652 */
653QDeclarativeOrganizerItemFetchHint* QDeclarativeOrganizerModel::fetchHint() const
654{
655 Q_D(const QDeclarativeOrganizerModel);
656 return d->m_fetchHint;
657}
658
659void QDeclarativeOrganizerModel::setFetchHint(QDeclarativeOrganizerItemFetchHint* fetchHint)
660{
661 Q_D(QDeclarativeOrganizerModel);
662 if (fetchHint != d->m_fetchHint) {
663 if (d->m_fetchHint)
664 disconnect(sender: d->m_fetchHint, SIGNAL(fetchHintChanged()), receiver: this, SIGNAL(fetchHintChanged()));
665 d->m_fetchHint = fetchHint;
666 if (d->m_fetchHint)
667 connect(sender: d->m_fetchHint, SIGNAL(fetchHintChanged()), receiver: this, SIGNAL(fetchHintChanged()), Qt::UniqueConnection);
668 emit fetchHintChanged();
669 }
670}
671/*!
672 \qmlproperty int OrganizerModel::itemCount
673
674 This property holds the size of organizer items the OrganizerModel currently holds.
675
676 This property is read only.
677 */
678int QDeclarativeOrganizerModel::itemCount() const
679{
680 Q_D(const QDeclarativeOrganizerModel);
681 return d->m_items.size();
682}
683/*!
684 \qmlproperty string OrganizerModel::error
685
686 This property holds the latest error code returned by the organizer manager.
687
688 This property is read only.
689 */
690QString QDeclarativeOrganizerModel::error() const
691{
692 Q_D(const QDeclarativeOrganizerModel);
693 if (d->m_manager) {
694 switch (d->m_error) {
695 case QOrganizerManager::DoesNotExistError:
696 return QStringLiteral("DoesNotExist");
697 case QOrganizerManager::AlreadyExistsError:
698 return QStringLiteral("AlreadyExists");
699 case QOrganizerManager::InvalidDetailError:
700 return QStringLiteral("InvalidDetail");
701 case QOrganizerManager::InvalidCollectionError:
702 return QStringLiteral("InvalidCollection");
703 case QOrganizerManager::LockedError:
704 return QStringLiteral("LockedError");
705 case QOrganizerManager::DetailAccessError:
706 return QStringLiteral("DetailAccessError");
707 case QOrganizerManager::PermissionsError:
708 return QStringLiteral("PermissionsError");
709 case QOrganizerManager::OutOfMemoryError:
710 return QStringLiteral("OutOfMemory");
711 case QOrganizerManager::NotSupportedError:
712 return QStringLiteral("NotSupported");
713 case QOrganizerManager::BadArgumentError:
714 return QStringLiteral("BadArgument");
715 case QOrganizerManager::UnspecifiedError:
716 return QStringLiteral("UnspecifiedError");
717 case QOrganizerManager::LimitReachedError:
718 return QStringLiteral("LimitReached");
719 case QOrganizerManager::InvalidItemTypeError:
720 return QStringLiteral("InvalidItemType");
721 case QOrganizerManager::InvalidOccurrenceError:
722 return QStringLiteral("InvalidOccurrence");
723 default:
724 break;
725 }
726 }
727 return QStringLiteral("NoError");
728}
729
730/*!
731 \qmlproperty list<SortOrder> OrganizerModel::sortOrders
732
733 This property holds a list of sort orders used by the organizer model.
734
735 \sa SortOrder
736 */
737QQmlListProperty<QDeclarativeOrganizerItemSortOrder> QDeclarativeOrganizerModel::sortOrders()
738{
739 return QQmlListProperty<QDeclarativeOrganizerItemSortOrder>(this,
740 0,
741 sortOrder_append,
742 sortOrder_count,
743 sortOrder_at,
744 sortOrder_clear);
745}
746
747void QDeclarativeOrganizerModel::startImport(QVersitReader::State state)
748{
749 Q_D(QDeclarativeOrganizerModel);
750 if (state == QVersitReader::FinishedState || state == QVersitReader::CanceledState) {
751 QStringList ids;
752
753 if (!d->m_reader->results().isEmpty()) {
754 QVersitOrganizerImporter importer;
755 importer.importDocument(document: d->m_reader->results().at(i: 0));
756 QList<QOrganizerItem> items = importer.items();
757 delete d->m_reader->device();
758 d->m_reader->setDevice(0);
759
760 if (d->m_manager && !d->m_manager->saveItems(items: &items)) {
761 if (d->m_error != d->m_manager->error()) {
762 d->m_error = d->m_manager->error();
763 emit errorChanged();
764 }
765 } else {
766 foreach (const QOrganizerItem i, items) {
767 ids << i.id().toString();
768 }
769 }
770 }
771 emit importCompleted(error: QDeclarativeOrganizerModel::ImportError(d->m_reader->error()), url: d->m_lastImportUrl, ids);
772 }
773}
774
775bool QDeclarativeOrganizerModel::itemHasRecurrence(const QOrganizerItem& oi) const
776{
777 if (oi.type() == QOrganizerItemType::TypeEvent || oi.type() == QOrganizerItemType::TypeTodo) {
778 QOrganizerItemRecurrence recur = oi.detail(detailType: QOrganizerItemDetail::TypeRecurrence);
779 return !recur.recurrenceDates().isEmpty() || !recur.recurrenceRules().isEmpty();
780 }
781
782 return false;
783}
784
785QDeclarativeOrganizerItem* QDeclarativeOrganizerModel::createItem(const QOrganizerItem& item)
786{
787 QDeclarativeOrganizerItem* di;
788 if (item.type() == QOrganizerItemType::TypeEvent)
789 di = new QDeclarativeOrganizerEvent(this);
790 else if (item.type() == QOrganizerItemType::TypeEventOccurrence)
791 di = new QDeclarativeOrganizerEventOccurrence(this);
792 else if (item.type() == QOrganizerItemType::TypeTodo)
793 di = new QDeclarativeOrganizerTodo(this);
794 else if (item.type() == QOrganizerItemType::TypeTodoOccurrence)
795 di = new QDeclarativeOrganizerTodoOccurrence(this);
796 else if (item.type() == QOrganizerItemType::TypeJournal)
797 di = new QDeclarativeOrganizerJournal(this);
798 else if (item.type() == QOrganizerItemType::TypeNote)
799 di = new QDeclarativeOrganizerNote(this);
800 else
801 di = new QDeclarativeOrganizerItem(this);
802 di->setItem(item);
803 return di;
804}
805
806void QDeclarativeOrganizerModel::checkError(const QOrganizerAbstractRequest *request)
807{
808 Q_D(QDeclarativeOrganizerModel);
809 if (request && d->m_error != request->error()) {
810 d->m_error = request->error();
811 emit errorChanged();
812 }
813}
814
815/*!
816 \qmlsignal OrganizerModel::onItemsFetched(int requestId, list<OrganizerItem> fetchedItems)
817
818 This handler is called when request of the given \a requestId is finished with the \a fetchedItems.
819
820 \sa fetchItems
821 */
822
823/*!
824 \qmlmethod int OrganizerModel::fetchItems(date start, date end,
825 Filter filter,
826 int maxCount,
827 list<SortOrder> sortOrders,
828 FetchHint fetchHint)
829
830 This method will start a request to fetch items between the given \a start and \a end dates.
831 Optionally a \a sort order, \a filter, \a fetchHint and \a maxCount can
832 be specified to narrow the search. If nothing is set for these optional paramenters then
833 defaults are applied, essentially any sort order, default filter, default storage location and all items.
834
835 The unique ID of this request will be returned. If the request can't be started -1 is returned.
836 The end date must be greater than the start date for this method to start a fetch request.
837
838 Note that the items fetched won't be added to the model, but can be accessed through the onItemsFetched
839 handler. No properties in the model are updated at all.
840
841 \sa onItemsFetched
842 */
843int QDeclarativeOrganizerModel::fetchItems(const QDateTime &start, const QDateTime &end,
844 QDeclarativeOrganizerItemFilter *filter,
845 int maxCount,
846 const QVariantList &sortOrders,
847 QDeclarativeOrganizerItemFetchHint *fetchHint)
848{
849 Q_D(QDeclarativeOrganizerModel);
850 if (!start.isValid() || !end.isValid() || !(end > start))
851 {
852 return -1;
853 }
854
855 // Parameter validation left to fetch request method.
856 QOrganizerItemFetchRequest *fetchRequest = new QOrganizerItemFetchRequest(this);
857 connect(sender: fetchRequest, SIGNAL(stateChanged(QOrganizerAbstractRequest::State)),
858 receiver: this, SLOT(onFetchItemsRequestStateChanged(QOrganizerAbstractRequest::State)));
859
860 QList<QOrganizerItemSortOrder> sList;
861 QVariantList::const_iterator it = sortOrders.begin();
862 while (it != sortOrders.end()) {
863 if ((*it).canConvert<QObject *>()) {
864 QDeclarativeOrganizerItemSortOrder *sortOrderItem = (*it).value<QDeclarativeOrganizerItemSortOrder *>();
865 sList << sortOrderItem->sortOrder();
866 }
867 ++it;
868 }
869
870 const QOrganizerItemFilter &fetchFilter = filter->filter();
871 fetchRequest->setFilter( fetchFilter );
872 const QOrganizerItemFetchHint &hint = fetchHint->fetchHint();
873
874 fetchRequest->setManager(d->m_manager);
875 fetchRequest->setStartDate(start);
876 fetchRequest->setEndDate(end);
877 fetchRequest->setSorting(sList);
878 fetchRequest->setMaxCount(maxCount);
879 fetchRequest->setFetchHint(hint);
880
881 int requestId = d->m_lastRequestId.fetchAndAddOrdered(valueToAdd: 1);
882 d->m_requestIdHash.insert(akey: fetchRequest, avalue: requestId);
883 if (fetchRequest->start()) {
884 return requestId;
885 } else {
886 d->m_requestIdHash.remove(akey: fetchRequest);
887 return -1;
888 }
889}
890
891/*!
892 \qmlmethod int OrganizerModel::fetchItems(stringlist itemIds)
893
894 Starts a request to fetch items by the given \a itemIds, and returns the unique ID of this request.
895 -1 is returned if the request can't be started.
896
897 Note that the items fetched won't be added to the model, but can be accessed through the onItemsFetched
898 handler.
899
900 \sa onItemsFetched
901 */
902int QDeclarativeOrganizerModel::fetchItems(const QStringList &itemIds)
903{
904 Q_D(QDeclarativeOrganizerModel);
905 if (itemIds.isEmpty())
906 return -1;
907
908 QOrganizerItemFetchByIdRequest *fetchRequest = new QOrganizerItemFetchByIdRequest(this);
909 connect(sender: fetchRequest, SIGNAL(stateChanged(QOrganizerAbstractRequest::State)),
910 receiver: this, SLOT(onFetchItemsRequestStateChanged(QOrganizerAbstractRequest::State)));
911 fetchRequest->setManager(d->m_manager);
912
913 QList<QOrganizerItemId> ids;
914 foreach (const QString &itemId, itemIds)
915 ids.append(t: QOrganizerItemId::fromString(idString: itemId));
916 fetchRequest->setIds(ids);
917 int requestId = d->m_lastRequestId.fetchAndAddOrdered(valueToAdd: 1);
918 d->m_requestIdHash.insert(akey: fetchRequest, avalue: requestId);
919 if (fetchRequest->start()) {
920 return requestId;
921 } else {
922 d->m_requestIdHash.remove(akey: fetchRequest);
923 return -1;
924 }
925}
926
927/*!
928 \internal
929 */
930void QDeclarativeOrganizerModel::onFetchItemsRequestStateChanged(QOrganizerAbstractRequest::State state)
931{
932 Q_D(QDeclarativeOrganizerModel);
933
934 QOrganizerAbstractRequest *request=qobject_cast<QOrganizerAbstractRequest *>(object: sender());
935
936 if (state != QOrganizerAbstractRequest::FinishedState || !request)
937 return;
938
939 QOrganizerItemFetchRequest *itemFetchRequest = qobject_cast<QOrganizerItemFetchRequest *>(object: request);
940 QOrganizerItemFetchByIdRequest *itemByIdFetchRequest = qobject_cast<QOrganizerItemFetchByIdRequest *>(object: request);
941
942 if (!itemFetchRequest && !itemByIdFetchRequest)
943 return;
944
945 checkError(request);
946 const int requestId = d->m_requestIdHash.value(akey: request, adefaultValue: -1);
947 if (requestId == -1)
948 qWarning() << Q_FUNC_INFO << "transaction not found from the request hash";
949 else
950 d->m_requestIdHash.remove(akey: request);
951
952 QVariantList list;
953 if (request->error() == QOrganizerManager::NoError) {
954 const QList<QOrganizerItem> &items((!itemFetchRequest) ? itemByIdFetchRequest->items():itemFetchRequest->items());
955 QDeclarativeOrganizerItem *declarativeItem(0);
956 foreach (const QOrganizerItem &item, items) {
957 switch (item.type()) {
958 case QOrganizerItemType::TypeEvent:
959 declarativeItem = new QDeclarativeOrganizerEvent(this);
960 break;
961 case QOrganizerItemType::TypeEventOccurrence:
962 declarativeItem = new QDeclarativeOrganizerEventOccurrence(this);
963 break;
964 case QOrganizerItemType::TypeTodo:
965 declarativeItem = new QDeclarativeOrganizerTodo(this);
966 break;
967 case QOrganizerItemType::TypeTodoOccurrence:
968 declarativeItem = new QDeclarativeOrganizerTodoOccurrence(this);
969 break;
970 default:
971 declarativeItem = new QDeclarativeOrganizerItem(this);
972 break;
973 }
974 declarativeItem->setItem(item);
975 list.append(t: QVariant::fromValue(value: (QObject *)declarativeItem));
976 }
977 }
978 emit itemsFetched(requestId, fetchedItems: list);
979
980 request->deleteLater();
981}
982
983/*!
984 \qmlmethod list<bool> OrganizerModel::containsItems(date start, date end, int interval)
985
986 Returns a list of booleans telling if there is any item falling in the given time range.
987
988 For example, if the \a start time is 2011-12-08 14:00:00, the \a end time is 2011-12-08 20:00:00,
989 and the \a interval is 3600 (seconds), a list of size 6 is returned, telling if there is any item
990 falling in the range of 14:00:00 to 15:00:00, 15:00:00 to 16:00:00, ..., 19:00:00 to 20:00:00.
991 */
992QList<bool> QDeclarativeOrganizerModel::containsItems(const QDateTime &start, const QDateTime &end, int interval)
993{
994 Q_D(QDeclarativeOrganizerModel);
995
996 if (!(start.isValid() && end.isValid() && start < end && interval > 0))
997 return QList<bool>();
998
999 int i(0);
1000 int count = qCeil(v: start.secsTo(end) / static_cast<double>(interval));
1001 QVector<bool> occupiedTimeSlots(count, false);
1002
1003 QVector<QDateTime> dateTime(count + 1);
1004 dateTime[0] = start;
1005 for (i = 1; i < count; ++i)
1006 dateTime[i] = dateTime.at(i: i - 1).addSecs(secs: interval);
1007 dateTime[count] = end;
1008
1009 QDateTime startTime;
1010 QDateTime endTime;
1011 bool itemStartFound;
1012
1013 foreach (QDeclarativeOrganizerItem *item, d->m_items) {
1014 startTime = item->itemStartTime();
1015 endTime = item->itemEndTime();
1016
1017 // check if item is occurring between start and end
1018 if (!((!startTime.isNull() && startTime >= start && startTime < end)
1019 || (!endTime.isNull() && endTime > start && endTime <= end)
1020 || (!startTime.isNull() && !endTime.isNull() && startTime <= start && endTime >= end)))
1021 continue;
1022
1023 itemStartFound = (!startTime.isNull() && startTime <= start);
1024 for (i = 0; i < count; ++i) {
1025
1026 if (!endTime.isNull() && endTime > dateTime.at(i) && endTime <= dateTime.at(i: i + 1)) {
1027 // item end time found, no need to check more time slots
1028 occupiedTimeSlots[i] = true;
1029 break;
1030 }
1031 if (occupiedTimeSlots.at(i))
1032 continue;
1033
1034 if (itemStartFound) {
1035 occupiedTimeSlots[i] = true;
1036 } else if (!startTime.isNull() && startTime < dateTime.at(i: i + 1)) {
1037 if (startTime >= dateTime.at(i))
1038 occupiedTimeSlots[i] = true;
1039 if (endTime.isNull())
1040 break;
1041 itemStartFound = true;
1042 }
1043 }
1044 }
1045 return occupiedTimeSlots.toList();
1046}
1047
1048/*!
1049 \qmlmethod bool OrganizerModel::containsItems(date start, date end)
1050
1051 Returns true if there is at least one OrganizerItem between the given date range.
1052 Both the \a start and \a end parameters are optional, if no \a end parameter, returns true
1053 if there are item(s) after \a start, if neither start nor end date time provided, returns true if
1054 items in the current model is not empty, otherwise return false.
1055
1056 \sa itemIds()
1057 */
1058bool QDeclarativeOrganizerModel::containsItems(const QDateTime &start, const QDateTime &end)
1059{
1060 return !itemIds(start, end).isEmpty();
1061}
1062
1063/*!
1064 \qmlmethod list<OrganizerItem> OrganizerModel::itemsByTimePeriod(date start, date end)
1065
1066 Returns the list of organizer items between the given \a start and \a end period.
1067 */
1068QVariantList QDeclarativeOrganizerModel::itemsByTimePeriod(const QDateTime &start, const QDateTime &end)
1069{
1070 Q_D(QDeclarativeOrganizerModel);
1071 QVariantList list;
1072
1073 if (start.isValid() && end.isValid()) {
1074 QDateTime startTime;
1075 QDateTime endTime;
1076 foreach (QDeclarativeOrganizerItem *item, d->m_items) {
1077 startTime = item->itemStartTime();
1078 endTime = item->itemEndTime();
1079 if ((startTime.isValid() && startTime <= start && endTime >= end)
1080 || (startTime >= start && startTime <= end)
1081 || (endTime >= start && endTime <= end)) {
1082 list.append(t: QVariant::fromValue(value: (QObject *)item));
1083 }
1084 }
1085 } else if (start.isValid()) {
1086 foreach (QDeclarativeOrganizerItem *item, d->m_items) {
1087 if (item->itemEndTime() >= start)
1088 list.append(t: QVariant::fromValue(value: (QObject *)item));
1089 }
1090 } else if (end.isValid()) {
1091 foreach (QDeclarativeOrganizerItem *item, d->m_items) {
1092 if (item->itemStartTime() <= end)
1093 list.append(t: QVariant::fromValue(value: (QObject *)item));
1094 }
1095 } else {
1096 foreach (QDeclarativeOrganizerItem *item, d->m_items)
1097 list.append(t: QVariant::fromValue(value: (QObject *)item));
1098 }
1099
1100 return list;
1101}
1102
1103/*!
1104 \qmlmethod OrganizerItem OrganizerModel::item(string itemId)
1105
1106 Returns the OrganizerItem object with the given \a itemId.
1107 */
1108QDeclarativeOrganizerItem *QDeclarativeOrganizerModel::item(const QString &itemId)
1109{
1110 Q_D(QDeclarativeOrganizerModel);
1111 if (itemId.isEmpty())
1112 return 0;
1113
1114 return d->m_itemIdHash.value(akey: itemId, adefaultValue: 0);
1115}
1116
1117/*!
1118 \qmlmethod list<string> OrganizerModel::itemIds(date start, date end)
1119
1120 Returns the list of organizer item ids between the given date range \a start and \a end,
1121 excluding generated occurrences. Both the \a start and \a end parameters are optional,
1122 if no \a end parameter, returns all item ids from \a start, if neither start nor end date
1123 time provided, returns all item ids in the current model.
1124
1125 \sa containsItems()
1126 */
1127QStringList QDeclarativeOrganizerModel::itemIds(const QDateTime &start, const QDateTime &end)
1128{
1129 Q_D(QDeclarativeOrganizerModel);
1130 //TODO: quick search this
1131 QStringList ids;
1132 if (!end.isNull()) {
1133 // both start date and end date are valid
1134 foreach (QDeclarativeOrganizerItem* item, d->m_items) {
1135 if (item->generatedOccurrence())
1136 continue;
1137 if ( (item->itemStartTime() >= start && item->itemStartTime() <= end)
1138 || (item->itemEndTime() >= start && item->itemEndTime() <= end)
1139 || (item->itemEndTime() > end && item->itemStartTime() < start))
1140 ids << item->itemId();
1141 }
1142 } else if (!start.isNull()) {
1143 // only a valid start date is valid
1144 foreach (QDeclarativeOrganizerItem* item, d->m_items) {
1145 if (!item->generatedOccurrence() && item->itemStartTime() >= start)
1146 ids << item->itemId();
1147 }
1148 } else {
1149 // neither start nor end date is valid
1150 foreach (QDeclarativeOrganizerItem* item, d->m_items) {
1151 if (!item->generatedOccurrence())
1152 ids << item->itemId();
1153 }
1154 }
1155 return ids;
1156}
1157
1158void QDeclarativeOrganizerModel::fetchAgain()
1159{
1160 Q_D(QDeclarativeOrganizerModel);
1161 cancelUpdate();
1162
1163 d->m_fetchRequest = new QOrganizerItemFetchRequest(this);
1164 d->m_fetchRequest->setManager(d->m_manager);
1165 d->m_fetchRequest->setSorting(d->m_sortOrders);
1166 d->m_fetchRequest->setStartDate(d->m_startPeriod);
1167 d->m_fetchRequest->setEndDate(d->m_endPeriod);
1168
1169 if (d->m_filter){
1170 d->m_fetchRequest->setFilter(d->m_filter->filter());
1171 } else {
1172 d->m_fetchRequest->setFilter(QOrganizerItemFilter());
1173 }
1174 d->m_fetchRequest->setFetchHint(d->m_fetchHint ? d->m_fetchHint->fetchHint() : QOrganizerItemFetchHint());
1175
1176 connect(sender: d->m_fetchRequest, SIGNAL(stateChanged(QOrganizerAbstractRequest::State)), receiver: this, SLOT(requestUpdated()));
1177 d->m_fetchRequest->start();
1178}
1179
1180/*
1181 This slot function is connected with item fetch requests and item occurrence fetch requests,
1182 so the QObject::sender() must be checked for the right sender type.
1183 During update() function, the fetchAgain() will be invoked, inside fetchAgain(), a QOrganizerItemFetchRequest object
1184 is created and started, when this fetch request finished, this requestUpdate() slot will be invoked for the first time.
1185 Then check each of the organizer items returned by the item fetch request, if the item is a recurrence item,
1186 a QOrganizerItemOccurrenceFetchRequest object will be created and started. When each of these occurrence fetch requests
1187 finishes, this requestUpdated() slot will be invoked again and insert the returned occurrence items into the d->m_items
1188 list.
1189 */
1190void QDeclarativeOrganizerModel::requestUpdated()
1191{
1192 Q_D(QDeclarativeOrganizerModel);
1193 QList<QOrganizerItem> items;
1194 QOrganizerItemFetchRequest* ifr = qobject_cast<QOrganizerItemFetchRequest*>(object: QObject::sender());
1195 Q_ASSERT(ifr);
1196 if (ifr->isFinished()) {
1197 items = ifr->items();
1198 checkError(request: ifr);
1199 ifr->deleteLater();
1200 d->m_fetchRequest = 0;
1201 d->m_updatePendingFlag &= ~QDeclarativeOrganizerModelPrivate::UpdatingItemsPending;
1202 } else {
1203 return;
1204 }
1205
1206 if (!items.isEmpty() || !d->m_items.isEmpty() || d->m_initialUpdate) {
1207 // full update: first go through new items and check if they
1208 // existed earlier. if they did, use the existing declarative wrapper.
1209 // otherwise create new declarative item.
1210 // for occurrences new declarative item is always created.
1211 QList<QDeclarativeOrganizerItem *> newList;
1212 QHash<QString, QDeclarativeOrganizerItem *> newItemIdHash;
1213 QHash<QString, QDeclarativeOrganizerItem *>::iterator iterator;
1214 QOrganizerItem item;
1215 QString idString;
1216 QDeclarativeOrganizerItem *declarativeItem;
1217 d->m_initialUpdate = false;
1218
1219 int i;
1220 for (i = 0; i < items.size(); i++) {
1221 item = items[i];
1222 idString = item.id().toString();
1223 if (item.id().isNull()) {
1224 // this is occurrence
1225 declarativeItem = createItem(item);
1226 } else {
1227 iterator = d->m_itemIdHash.find(akey: idString);
1228 if (iterator != d->m_itemIdHash.end()) {
1229 declarativeItem = iterator.value();
1230 declarativeItem->setItem(item);
1231 } else {
1232 declarativeItem = createItem(item);
1233 }
1234 newItemIdHash.insert(akey: idString, avalue: declarativeItem);
1235 }
1236 newList.append(t: declarativeItem);
1237 }
1238
1239 // go through old items and delete items, which are not part of the
1240 // new item set. delete also all old occurrences.
1241 for (i = 0; i < d->m_items.size(); i++) {
1242 // FIXME: avoid unnecessary usage of item getter which copies all details...
1243 if (d->m_items[i]->item().id().isNull()) {
1244 d->m_items[i]->deleteLater();
1245 } else {
1246 iterator = newItemIdHash.find(akey: d->m_items[i]->itemId());
1247 if (iterator == newItemIdHash.end())
1248 d->m_items[i]->deleteLater();
1249 }
1250 }
1251 beginResetModel();
1252 d->m_items = newList;
1253 endResetModel();
1254
1255 d->m_itemIdHash = newItemIdHash;
1256 d->m_modelChangedTimer.start();
1257 }
1258}
1259
1260/*!
1261 \qmlmethod OrganizerModel::saveItem(OrganizerItem item)
1262
1263 Saves asynchronously the given \a item into the organizer backend.
1264 */
1265void QDeclarativeOrganizerModel::saveItem(QDeclarativeOrganizerItem* di)
1266{
1267 Q_D(QDeclarativeOrganizerModel);
1268 if (di) {
1269 QOrganizerItem item = di->item();
1270 QOrganizerItemSaveRequest* req = new QOrganizerItemSaveRequest(this);
1271 req->setManager(d->m_manager);
1272 req->setItem(item);
1273
1274 if (di->itemId().isEmpty()) {
1275 // if the item id is empty this means that this item is a new event
1276 // we need to keep trace of this declarative item to update with the
1277 // new Id as soon as this request finish
1278 QPointer<QDeclarativeOrganizerItem> pItem = di;
1279 req->setProperty(name: ITEM_TO_SAVE_PROPERTY, value: QVariant::fromValue(value: pItem));
1280 }
1281
1282 connect(sender: req, SIGNAL(stateChanged(QOrganizerAbstractRequest::State)), receiver: this, SLOT(onRequestStateChanged(QOrganizerAbstractRequest::State)));
1283
1284 req->start();
1285 }
1286}
1287
1288/*!
1289 \qmlmethod OrganizerModel::removeItem(string itemId)
1290 Removes the organizer item with the given \a itemId from the backend.
1291
1292 */
1293void QDeclarativeOrganizerModel::removeItem(const QString& id)
1294{
1295 QList<QString> ids;
1296 ids << id;
1297 removeItems(ids);
1298}
1299
1300/*!
1301 \qmlmethod OrganizerModel::removeItem(OrganizerItem item)
1302 Removes the given organizer \a item from the backend.
1303 */
1304void QDeclarativeOrganizerModel::removeItem(QDeclarativeOrganizerItem *item)
1305{
1306 Q_D(QDeclarativeOrganizerModel);
1307 QOrganizerItemRemoveRequest* req = new QOrganizerItemRemoveRequest(this);
1308 req->setManager(d->m_manager);
1309 req->setItem(item->item());
1310 connect(sender: req, SIGNAL(stateChanged(QOrganizerAbstractRequest::State)), receiver: this, SLOT(onRequestStateChanged(QOrganizerAbstractRequest::State)));
1311 req->start();
1312}
1313
1314/*!
1315 \qmlmethod OrganizerModel::removeItems(list<string> itemId)
1316 Removes asynchronously the organizer items with the given \a ids from the backend.
1317
1318 */
1319void QDeclarativeOrganizerModel::removeItems(const QStringList& ids)
1320{
1321 Q_D(QDeclarativeOrganizerModel);
1322 QOrganizerItemRemoveByIdRequest* req = new QOrganizerItemRemoveByIdRequest(this);
1323 req->setManager(d->m_manager);
1324 QList<QOrganizerItemId> oids;
1325
1326 // FIXME: no special format for occurrence ids
1327 foreach (const QString& id, ids) {
1328 if (id.startsWith(s: QString("qtorganizer:occurrence"))) {
1329 qmlInfo(me: this) << tr(s: "Can't remove an occurrence item, please modify the parent item's recurrence rule instead!");
1330 continue;
1331 }
1332 QOrganizerItemId itemId = QOrganizerItemId::fromString(idString: id);
1333 if (!itemId.isNull()) {
1334 oids.append(t: itemId);
1335 }
1336 }
1337
1338 req->setItemIds(oids);
1339
1340 connect(sender: req, SIGNAL(stateChanged(QOrganizerAbstractRequest::State)), receiver: this, SLOT(onRequestStateChanged(QOrganizerAbstractRequest::State)));
1341
1342 req->start();
1343}
1344
1345/*!
1346 \qmlmethod OrganizerModel::removeItems(list<OrganizerItem> items)
1347 Removes asynchronously the organizer items in the given \a items list from the backend.
1348 */
1349void QDeclarativeOrganizerModel::removeItems(const QList<QDeclarativeOrganizerItem> &items)
1350{
1351 Q_D(QDeclarativeOrganizerModel);
1352 QOrganizerItemRemoveRequest* req = new QOrganizerItemRemoveRequest(this);
1353 req->setManager(d->m_manager);
1354 QList<QOrganizerItem> ois;
1355
1356 for (int i = 0; i < items.size(); i++) {
1357 ois.append(t: items[i].item());
1358 }
1359
1360 req->setItems(ois);
1361 connect(sender: req, SIGNAL(stateChanged(QOrganizerAbstractRequest::State)), receiver: this, SLOT(onRequestStateChanged(QOrganizerAbstractRequest::State)));
1362 req->start();
1363}
1364
1365/*!
1366 \internal
1367 */
1368void QDeclarativeOrganizerModel::onRequestStateChanged(QOrganizerAbstractRequest::State newState)
1369{
1370 if (newState != QOrganizerAbstractRequest::FinishedState)
1371 return;
1372
1373 QOrganizerAbstractRequest *request = qobject_cast<QOrganizerAbstractRequest *>(object: sender());
1374 Q_ASSERT(request);
1375
1376 if (request->error() == QOrganizerManager::NoError &&
1377 request->type() == QOrganizerAbstractRequest::ItemSaveRequest) {
1378 QVariant vItem = request->property(name: ITEM_TO_SAVE_PROPERTY);
1379 if (vItem.isValid()) {
1380 QPointer<QDeclarativeOrganizerItem> pItem = vItem.value<QPointer<QDeclarativeOrganizerItem> >();
1381 // Fill declarative item id
1382 QOrganizerItemSaveRequest *sr = static_cast<QOrganizerItemSaveRequest *>(request);
1383 if (pItem && sr->items().length() == 1)
1384 pItem->setItem(sr->items()[0]);
1385 }
1386 }
1387
1388 checkError(request);
1389 request->deleteLater();
1390}
1391
1392void QDeclarativeOrganizerModel::removeItemsFromModel(const QList<QString> &itemIds)
1393{
1394 Q_D(QDeclarativeOrganizerModel);
1395 bool emitSignal = false;
1396 bool itemIdFound = false;
1397
1398 foreach (const QString &itemId, itemIds) {
1399 itemIdFound = false;
1400 // generated occurrences are not in m_itemIdHash
1401 if (d->m_itemIdHash.remove(akey: itemId) > 0)
1402 itemIdFound = true;
1403 for (int i = d->m_items.count() - 1; i >= 0; i--) {
1404 if (itemIdFound) {
1405 if (d->m_items.at(i)->itemId() == itemId) {
1406 beginRemoveRows(parent: QModelIndex(), first: i, last: i);
1407 d->m_items.removeAt(i);
1408 endRemoveRows();
1409 emitSignal = true;
1410 break;
1411 }
1412 } else if (d->m_items.at(i)->generatedOccurrence()) {
1413 QDeclarativeOrganizerItemDetail *parentDetail = d->m_items.at(i)->detail(type: QDeclarativeOrganizerItemDetail::Parent);
1414 if (parentDetail->value(key: QDeclarativeOrganizerItemParent::FieldParentId).toString() == itemId) {
1415 beginRemoveRows(parent: QModelIndex(), first: i, last: i);
1416 d->m_items.removeAt(i);
1417 endRemoveRows();
1418 emitSignal = true;
1419 }
1420 }
1421 }
1422 }
1423 if (emitSignal)
1424 d->m_modelChangedTimer.start();
1425}
1426
1427
1428/*!
1429 \internal
1430
1431 It's invoked upon the QOrganizerManager::itemsModified() signal.
1432 */
1433void QDeclarativeOrganizerModel::onItemsModified(const QList<QPair<QOrganizerItemId, QOrganizerManager::Operation> > &itemIds)
1434{
1435 Q_D(QDeclarativeOrganizerModel);
1436 if (!d->m_autoUpdate)
1437 return;
1438
1439 QSet<QOrganizerItemId> addedAndChangedItems;
1440 QList<QString> removedItems;
1441 for (int i = itemIds.size() - 1; i >= 0; i--) {
1442 if (itemIds[i].second == QOrganizerManager::Remove) {
1443 // check that item has not been added after removing it
1444 if (!addedAndChangedItems.contains(value: itemIds[i].first))
1445 removedItems.append(t: itemIds[i].first.toString());
1446 } else {
1447 addedAndChangedItems.insert(value: itemIds[i].first);
1448 }
1449 }
1450 if (!removedItems.isEmpty())
1451 removeItemsFromModel(itemIds: removedItems);
1452
1453 if (!addedAndChangedItems.isEmpty()) {
1454 // FIXME; to be optimized with fetching only the modified items
1455 // from the storage locations modified items are on
1456 QOrganizerItemFetchRequest *fetchRequest = new QOrganizerItemFetchRequest(this);
1457 connect(sender: fetchRequest, SIGNAL(stateChanged(QOrganizerAbstractRequest::State)),
1458 receiver: this, SLOT(onItemsModifiedFetchRequestStateChanged(QOrganizerAbstractRequest::State)));
1459 fetchRequest->setManager(d->m_manager);
1460 fetchRequest->setStartDate(d->m_startPeriod);
1461 fetchRequest->setEndDate(d->m_endPeriod);
1462 fetchRequest->setFilter(d->m_filter ? d->m_filter->filter() : QOrganizerItemFilter());
1463 fetchRequest->setSorting(d->m_sortOrders);
1464 fetchRequest->setFetchHint(d->m_fetchHint ? d->m_fetchHint->fetchHint() : QOrganizerItemFetchHint());
1465 d->m_notifiedItems.insert(akey: fetchRequest, avalue: addedAndChangedItems);
1466
1467 fetchRequest->start();
1468 }
1469}
1470
1471/*!
1472 \internal
1473
1474 It's invoked by the fetch request from onItemsModified().
1475 */
1476void QDeclarativeOrganizerModel::onItemsModifiedFetchRequestStateChanged(QOrganizerAbstractRequest::State state)
1477{
1478 // NOTE: this function assumes the sorting algorithm gives always the same result with
1479 // same data. E.g. items which have the identical sorting key must be sorted too.
1480
1481 Q_D(QDeclarativeOrganizerModel);
1482 if (state != QOrganizerAbstractRequest::FinishedState)
1483 return;
1484
1485 QOrganizerItemFetchRequest *request = qobject_cast<QOrganizerItemFetchRequest *>(object: sender());
1486 Q_ASSERT(request);
1487
1488 checkError(request);
1489
1490 QSet<QOrganizerItemId> notifiedItems = d->m_notifiedItems.value(akey: request);
1491 if (notifiedItems.isEmpty())
1492 return;
1493
1494 if (request->error() == QOrganizerManager::NoError) {
1495 bool emitSignal = false;
1496 QList<QOrganizerItem> fetchedItems = request->items();
1497 QOrganizerItem oldItem;
1498 QOrganizerItem newItem;
1499 QOrganizerItemParent oldParentDetail;
1500 QOrganizerItemParent newParentDetail;
1501 QDeclarativeOrganizerItem *declarativeItem;
1502 QSet<QOrganizerItemId> removedIds;
1503 QSet<QOrganizerItemId> addedIds;
1504 int oldInd = 0;
1505 int newInd = 0;
1506 while (newInd < fetchedItems.size()) {
1507 bool addNewItem = false;
1508 bool oldItemExists = false;
1509
1510 newItem = fetchedItems[newInd];
1511 if (oldInd < d->m_items.size()) {
1512 // quick check if items are same in old and new event lists
1513 // FIXME: avoid unnecessary usage of item getter which copies all details
1514 oldItem = d->m_items[oldInd]->item();
1515 oldItemExists = true;
1516 if (!newItem.id().isNull() && !oldItem.id().isNull() && newItem.id() == oldItem.id()) {
1517 if (notifiedItems.contains(value: newItem.id())) {
1518 d->m_items[oldInd]->setItem(newItem);
1519 const QModelIndex idx = index(row: oldInd, column: 0);
1520 emit dataChanged(topLeft: idx, bottomRight: idx);
1521 emitSignal = true;
1522 }
1523 newInd++;
1524 oldInd++;
1525 continue;
1526 }
1527 }
1528
1529 // check should we remove old item
1530 if (oldItemExists) {
1531 if (oldItem.id().isNull()) {
1532 // this is generated occurrence
1533 oldParentDetail = oldItem.detail(detailType: QOrganizerItemDetail::TypeParent);
1534 if (notifiedItems.contains(value: oldParentDetail.parentId())) {
1535 beginRemoveRows(parent: QModelIndex(), first: oldInd, last: oldInd);
1536 d->m_items.takeAt(i: oldInd)->deleteLater();
1537 endRemoveRows();
1538 emitSignal = true;
1539 continue;
1540 }
1541 } else if (notifiedItems.contains(value: oldItem.id())) {
1542 // if notifiedItems contains the oldItem id, it means the item has been
1543 // changed and we should reuse the declarative part and only remove
1544 // rows from abstract list model
1545 // it might also mean that oldItem has been changed so that it does not belong to
1546 // the model anymore (e.g. changing fron normal item to recurring item)
1547 beginRemoveRows(parent: QModelIndex(), first: oldInd, last: oldInd);
1548 d->m_items.removeAt(i: oldInd);
1549 endRemoveRows();
1550 removedIds.insert(value: oldItem.id());
1551 emitSignal = true;
1552 continue;
1553 } else if (notifiedItems.contains(value: newItem.id())) {
1554 // if newItem is a notified item and does not correspond to an oldItem
1555 // then find a correspondent item by id in the old items list
1556 // and remove it from the hash and list
1557 for (int removeInd = oldInd + 1; removeInd < d->m_items.size(); ++removeInd) {
1558 if (newItem.id() == d->m_items[removeInd]->item().id()) {
1559 beginRemoveRows(parent: QModelIndex(), first: removeInd, last: removeInd);
1560 d->m_itemIdHash.remove(akey: d->m_items[removeInd]->itemId());
1561 d->m_items.takeAt(i: removeInd)->deleteLater();
1562 endRemoveRows();
1563 emitSignal = true;
1564 break;
1565 }
1566 }
1567 }
1568 }
1569 // check should we add the new item
1570 if (newItem.id().isNull() && (newItem.type() == QOrganizerItemType::TypeEventOccurrence || newItem.type() == QOrganizerItemType::TypeTodoOccurrence)) {
1571 // this is occurrence (generated or exception)
1572 newParentDetail = newItem.detail(detailType: QOrganizerItemDetail::TypeParent);
1573 if (notifiedItems.contains(value: newParentDetail.parentId())) {
1574 declarativeItem = createItem(item: newItem);
1575 addNewItem = true;
1576 }
1577 } else if (notifiedItems.contains(value: newItem.id())) {
1578 QHash<QString, QDeclarativeOrganizerItem *>::const_iterator iterator = d->m_itemIdHash.find(akey: newItem.id().toString());
1579 if (iterator == d->m_itemIdHash.end()) {
1580 declarativeItem = createItem(item: newItem);
1581 d->m_itemIdHash.insert(akey: declarativeItem->itemId(), avalue: declarativeItem);
1582 } else {
1583 declarativeItem = d->m_itemIdHash.value(akey: newItem.id().toString());
1584 addedIds.insert(value: newItem.id());
1585 }
1586 addNewItem = true;
1587 }
1588
1589 if (addNewItem) {
1590 beginInsertRows(parent: QModelIndex(), first: oldInd, last: oldInd);
1591 d->m_items.insert(i: oldInd, t: declarativeItem);
1592 endInsertRows();
1593 emitSignal = true;
1594 }
1595 oldInd++;
1596 newInd++;
1597 }
1598 // remove the rest of the old items
1599 if (oldInd <= d->m_items.size() - 1) {
1600 beginRemoveRows(parent: QModelIndex(), first: oldInd, last: d->m_items.size() - 1);
1601 while (oldInd < d->m_items.size()) {
1602 d->m_itemIdHash.remove(akey: d->m_items[oldInd]->itemId());
1603 d->m_items.takeAt(i: oldInd)->deleteLater();
1604 emitSignal = true;
1605 oldInd++;
1606 }
1607 endRemoveRows();
1608 }
1609 // remove items which were changed so that they are no longer part of the model
1610 // they have been removed from the model earlier, but need to still be removed from the hash
1611 // and deleted
1612
1613 removedIds.subtract(other: addedIds);
1614 foreach (const QOrganizerItemId &id, removedIds) {
1615 QDeclarativeOrganizerItem *changedItem = d->m_itemIdHash.take(akey: id.toString());
1616 if (changedItem) {
1617 changedItem->deleteLater();
1618 emitSignal = true;
1619 }
1620 }
1621
1622 if (emitSignal)
1623 d->m_modelChangedTimer.start();
1624 }
1625 d->m_notifiedItems.remove(akey: request);
1626 request->deleteLater();
1627}
1628
1629/*!
1630 \qmlmethod OrganizerModel::fetchCollections()
1631 Fetch asynchronously a list of organizer collections from the organizer backend.
1632 */
1633void QDeclarativeOrganizerModel::fetchCollections()
1634{
1635 Q_D(QDeclarativeOrganizerModel);
1636 // fetchCollections() is used for both direct calls and
1637 // signals from model. For signal from model, check also the
1638 // autoupdate-flag.
1639 if (qobject_cast<QTimer*>(object: sender()) == &d->m_fetchCollectionsTimer) {
1640 if (!d->m_fetchCollectionsTimer.property(name: MANUALLY_TRIGGERED_PROPERTY).toBool() && !d->m_autoUpdate)
1641 return; // it was automatically triggered, but autoUpdate is false, so don't update the model data.
1642 // reset the state of the manually triggered properly, for next time.
1643 d->m_fetchCollectionsTimer.setProperty(name: MANUALLY_TRIGGERED_PROPERTY, value: QVariant::fromValue<bool>(value: false));
1644 }
1645
1646 QOrganizerCollectionFetchRequest* req = new QOrganizerCollectionFetchRequest(this);
1647 req->setManager(d->m_manager);
1648
1649 connect(sender: req,SIGNAL(stateChanged(QOrganizerAbstractRequest::State)), receiver: this, SLOT(collectionsFetched()));
1650
1651 req->start();
1652}
1653
1654void QDeclarativeOrganizerModel::collectionsFetched()
1655{
1656 Q_D(QDeclarativeOrganizerModel);
1657 QOrganizerCollectionFetchRequest* req = qobject_cast<QOrganizerCollectionFetchRequest*>(object: QObject::sender());
1658 Q_ASSERT(req);
1659 if (req->isFinished() && QOrganizerManager::NoError == req->error()) {
1660 d->m_updatePendingFlag &= ~QDeclarativeOrganizerModelPrivate::UpdatingCollectionsPending;
1661 // prepare tables
1662 QHash<QString, const QOrganizerCollection*> collections;
1663 foreach (const QOrganizerCollection& collection, req->collections()) {
1664 collections.insert(akey: collection.id().toString(), avalue: &collection);
1665 }
1666 QHash<QString, QDeclarativeOrganizerCollection*> declCollections;
1667 foreach(QDeclarativeOrganizerCollection* declCollection, d->m_collections) {
1668 declCollections.insert(akey: declCollection->collection().id().toString(), avalue: declCollection);
1669 }
1670 // go tables through
1671 QHashIterator<QString, const QOrganizerCollection*> collIterator(collections);
1672 while (collIterator.hasNext()) {
1673 collIterator.next();
1674 if (declCollections.contains(akey: collIterator.key())) {
1675 // collection on both sides, update the declarative collection
1676 declCollections.value(akey: collIterator.key())->setCollection(*collections.value(akey: collIterator.key()));
1677 } else {
1678 // new collection, add it to declarative collection list
1679 QDeclarativeOrganizerCollection* declCollection = new QDeclarativeOrganizerCollection(this);
1680 declCollection->setCollection(*collections.value(akey: collIterator.key()));
1681 d->m_collections.append(t: declCollection);
1682 }
1683 }
1684 QHashIterator<QString, QDeclarativeOrganizerCollection*> declCollIterator(declCollections);
1685 while (declCollIterator.hasNext()) {
1686 declCollIterator.next();
1687 if (!collections.contains(akey: declCollIterator.key())) {
1688 // collection deleted on the backend side, delete from declarative collection list
1689 QDeclarativeOrganizerCollection* toBeDeletedColl = declCollections.value(akey: declCollIterator.key());
1690 d->m_collections.removeOne(t: toBeDeletedColl);
1691 toBeDeletedColl->deleteLater();
1692 }
1693 }
1694 emit collectionsChanged();
1695 if (d->m_updatePendingFlag & QDeclarativeOrganizerModelPrivate::UpdatingItemsPending)
1696 QMetaObject::invokeMethod(obj: this, member: "fetchAgain", type: Qt::QueuedConnection);
1697 req->deleteLater();
1698 }
1699 checkError(request: req);
1700}
1701
1702/*!
1703 \qmlmethod OrganizerModel::saveCollection(Collection collection)
1704
1705 Saves asynchronously the given \a collection into the organizer backend.
1706 */
1707void QDeclarativeOrganizerModel::saveCollection(QDeclarativeOrganizerCollection* declColl)
1708{
1709 Q_D(QDeclarativeOrganizerModel);
1710 if (declColl) {
1711 QOrganizerCollection collection = declColl->collection();
1712 QOrganizerCollectionSaveRequest* req = new QOrganizerCollectionSaveRequest(this);
1713 req->setManager(d->m_manager);
1714 req->setCollection(collection);
1715
1716 connect(sender: req, SIGNAL(stateChanged(QOrganizerAbstractRequest::State)), receiver: this, SLOT(onRequestStateChanged(QOrganizerAbstractRequest::State)));
1717
1718 req->start();
1719 }
1720}
1721
1722/*!
1723 \qmlmethod OrganizerModel::removeCollection(string collectionId)
1724 Removes asynchronously the organizer collection with the given \a collectionId from the backend.
1725 */
1726void QDeclarativeOrganizerModel::removeCollection(const QString &collectionId)
1727{
1728 Q_D(QDeclarativeOrganizerModel);
1729 QOrganizerCollectionRemoveRequest* req = new QOrganizerCollectionRemoveRequest(this);
1730 req->setManager(d->m_manager);
1731 req->setCollectionId(QOrganizerCollectionId::fromString(idString: collectionId));
1732
1733 connect(sender: req, SIGNAL(stateChanged(QOrganizerAbstractRequest::State)), receiver: this, SLOT(onRequestStateChanged(QOrganizerAbstractRequest::State)));
1734
1735 req->start();
1736}
1737
1738/*!
1739 \qmlmethod string OrganizerModel::defaultCollectionId()
1740 Returns the id of a default Collection object.
1741 */
1742QString QDeclarativeOrganizerModel::defaultCollectionId() const
1743{
1744 Q_D(const QDeclarativeOrganizerModel);
1745 return d->m_manager->defaultCollectionId().toString();
1746}
1747
1748/*!
1749 \qmlmethod Collection OrganizerModel::collection(string collectionId)
1750 Returns the Collection object which collection id is the given \a collectionId and
1751 null if collection id is not found.
1752 */
1753QDeclarativeOrganizerCollection* QDeclarativeOrganizerModel::collection(const QString &collectionId)
1754{
1755 Q_D(QDeclarativeOrganizerModel);
1756 foreach (QDeclarativeOrganizerCollection* collection, d->m_collections) {
1757 if (collection->id() == collectionId)
1758 return collection;
1759 }
1760 return 0;
1761}
1762
1763QVariant QDeclarativeOrganizerModel::data(const QModelIndex &index, int role) const
1764{
1765 Q_D(const QDeclarativeOrganizerModel);
1766 //Check if QList itme's index is valid before access it, index should be between 0 and count - 1
1767 if (index.row() < 0 || index.row() >= d->m_items.count()) {
1768 return QVariant();
1769 }
1770
1771 QDeclarativeOrganizerItem* di = d->m_items.at(i: index.row());
1772 Q_ASSERT(di);
1773 QOrganizerItem item = di->item();
1774 switch(role) {
1775 case Qt::DisplayRole:
1776 return item.displayLabel();
1777 case Qt::DecorationRole:
1778 //return pixmap for this item type
1779 case OrganizerItemRole:
1780 return QVariant::fromValue(value: di);
1781 }
1782 return QVariant();
1783}
1784
1785/*!
1786 \qmlproperty list<OrganizerItem> OrganizerModel::items
1787
1788 This property holds a list of organizer items in the organizer model.
1789
1790 \sa OrganizerItem
1791 */
1792QQmlListProperty<QDeclarativeOrganizerItem> QDeclarativeOrganizerModel::items()
1793{
1794 return QQmlListProperty<QDeclarativeOrganizerItem>(this, 0, item_count, item_at);
1795}
1796
1797/*!
1798 \qmlproperty list<Collection> OrganizerModel::collections
1799
1800 This property holds a list of collections in the organizer model.
1801
1802 \sa Collection
1803 */
1804QQmlListProperty<QDeclarativeOrganizerCollection> QDeclarativeOrganizerModel::collections()
1805{
1806 return QQmlListProperty<QDeclarativeOrganizerCollection>(this, 0, collection_count, collection_at);
1807}
1808
1809int QDeclarativeOrganizerModel::item_count(QQmlListProperty<QDeclarativeOrganizerItem> *p)
1810{
1811 QDeclarativeOrganizerModel* model = qobject_cast<QDeclarativeOrganizerModel*>(object: p->object);
1812 if (model)
1813 return model->d_ptr->m_items.count();
1814 return 0;
1815}
1816
1817QDeclarativeOrganizerItem * QDeclarativeOrganizerModel::item_at(QQmlListProperty<QDeclarativeOrganizerItem> *p, int idx)
1818{
1819 QDeclarativeOrganizerModel* model = qobject_cast<QDeclarativeOrganizerModel*>(object: p->object);
1820 if (model && idx >= 0 && idx < model->d_ptr->m_items.size())
1821 return model->d_ptr->m_items.at(i: idx);
1822 return 0;
1823}
1824
1825void QDeclarativeOrganizerModel::sortOrder_append(QQmlListProperty<QDeclarativeOrganizerItemSortOrder> *p, QDeclarativeOrganizerItemSortOrder *sortOrder)
1826{
1827 QDeclarativeOrganizerModel* model = qobject_cast<QDeclarativeOrganizerModel*>(object: p->object);
1828 if (model && sortOrder) {
1829 QObject::connect(sender: sortOrder, SIGNAL(sortOrderChanged()), receiver: model, SIGNAL(sortOrdersChanged()));
1830 model->d_ptr->m_declarativeSortOrders.append(t: sortOrder);
1831 model->d_ptr->m_sortOrders.append(t: sortOrder->sortOrder());
1832 emit model->sortOrdersChanged();
1833 }
1834}
1835
1836int QDeclarativeOrganizerModel::sortOrder_count(QQmlListProperty<QDeclarativeOrganizerItemSortOrder> *p)
1837{
1838 QDeclarativeOrganizerModel* model = qobject_cast<QDeclarativeOrganizerModel*>(object: p->object);
1839 if (model)
1840 return model->d_ptr->m_declarativeSortOrders.size();
1841 return 0;
1842}
1843QDeclarativeOrganizerItemSortOrder * QDeclarativeOrganizerModel::sortOrder_at(QQmlListProperty<QDeclarativeOrganizerItemSortOrder> *p, int idx)
1844{
1845 QDeclarativeOrganizerModel* model = qobject_cast<QDeclarativeOrganizerModel*>(object: p->object);
1846
1847 QDeclarativeOrganizerItemSortOrder* sortOrder = 0;
1848 if (model) {
1849 int i = 0;
1850 foreach (QDeclarativeOrganizerItemSortOrder* s, model->d_ptr->m_declarativeSortOrders) {
1851 if (i == idx) {
1852 sortOrder = s;
1853 break;
1854 } else {
1855 i++;
1856 }
1857 }
1858 }
1859 return sortOrder;
1860}
1861void QDeclarativeOrganizerModel::sortOrder_clear(QQmlListProperty<QDeclarativeOrganizerItemSortOrder> *p)
1862{
1863 QDeclarativeOrganizerModel* model = qobject_cast<QDeclarativeOrganizerModel*>(object: p->object);
1864
1865 if (model) {
1866 model->d_ptr->m_sortOrders.clear();
1867 model->d_ptr->m_declarativeSortOrders.clear();
1868 emit model->sortOrdersChanged();
1869 }
1870}
1871
1872int QDeclarativeOrganizerModel::collection_count(QQmlListProperty<QDeclarativeOrganizerCollection> *p)
1873{
1874 QDeclarativeOrganizerModel* model = qobject_cast<QDeclarativeOrganizerModel*>(object: p->object);
1875 return model ? model->d_ptr->m_collections.count() : 0;
1876}
1877
1878QDeclarativeOrganizerCollection* QDeclarativeOrganizerModel::collection_at(QQmlListProperty<QDeclarativeOrganizerCollection> *p, int idx)
1879{
1880 QDeclarativeOrganizerModel* model = qobject_cast<QDeclarativeOrganizerModel*>(object: p->object);
1881 QDeclarativeOrganizerCollection* collection = 0;
1882 if (model) {
1883 if (!model->d_ptr->m_collections.isEmpty() && idx >= 0 && idx < model->d_ptr->m_collections.count())
1884 collection = model->d_ptr->m_collections.at(i: idx);
1885 }
1886 return collection;
1887}
1888
1889#include "moc_qdeclarativeorganizermodel_p.cpp"
1890
1891QT_END_NAMESPACE
1892

source code of qtpim/src/imports/organizer/qdeclarativeorganizermodel.cpp