summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin Wu Won <kevin.wuwon@nokia.com>2010-11-11 16:19:56 +1000
committerKevin Wu Won <kevin.wuwon@nokia.com>2010-11-11 16:21:44 +1000
commit72311748bc808813e9b2c70a5141407018e4cef9 (patch)
tree12b0ae4b8cfb93ba76f9c09beb0f6aece549ebe6
parentc63c926b9b4c098e1fe4c5500c2416af3c40c585 (diff)
Finish implementing mkcal engine
This represents a squashed rebase of the harmattan branch up to commit c5a489c9b43ad8df052e373d18895d99e55240bf Change-Id: I698ffa23442487c8b651fc329fb42c4016c5446c
-rw-r--r--plugins/organizer/maemo6/qorganizermaemo6.cpp826
-rw-r--r--plugins/organizer/maemo6/qorganizermaemo6.h203
-rw-r--r--plugins/organizer/mkcal/mkcal.pro (renamed from plugins/organizer/maemo6/maemo6.pro)15
-rw-r--r--plugins/organizer/mkcal/mkcalengine.cpp1385
-rw-r--r--plugins/organizer/mkcal/mkcalengine.h230
-rw-r--r--plugins/organizer/mkcal/mkcalid.h205
-rw-r--r--plugins/organizer/mkcal/qorganizerasynchmanager.cpp489
-rw-r--r--plugins/organizer/mkcal/qorganizerasynchmanager.h (renamed from plugins/organizer/maemo6/maemo6itemlocalid.h)89
-rw-r--r--plugins/organizer/organizer.pro3
-rw-r--r--src/organizer/items/qorganizerjournal.h1
-rw-r--r--src/organizer/organizer.pro2
-rw-r--r--tests/auto/qorganizermanager/tst_qorganizermanager.cpp636
12 files changed, 2874 insertions, 1210 deletions
diff --git a/plugins/organizer/maemo6/qorganizermaemo6.cpp b/plugins/organizer/maemo6/qorganizermaemo6.cpp
deleted file mode 100644
index e7040957f3..0000000000
--- a/plugins/organizer/maemo6/qorganizermaemo6.cpp
+++ /dev/null
@@ -1,826 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the Qt Mobility Components.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the Technology Preview License Agreement accompanying
-** this package.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qorganizermaemo6.h"
-#include "qtorganizer.h"
-#include "maemo6itemlocalid.h"
-
-//QTM_USE_NAMESPACE
-
-QOrganizerManagerEngine* QOrganizerItemMaemo6Factory::engine(const QMap<QString, QString>& parameters, QOrganizerManager::Error* error)
-{
- Q_UNUSED(parameters);
-
- Q_UNUSED(error);
-
- /* TODO - if you understand any specific parameters. save them in the engine so that engine::managerParameters can return them */
-
- QOrganizerItemMaemo6Engine* ret = new QOrganizerItemMaemo6Engine(); // manager takes ownership and will clean up.
- return ret;
-}
-
-QString QOrganizerItemMaemo6Factory::managerName() const
-{
- return QLatin1String("maemo6");
-}
-
-QOrganizerItemEngineLocalId* QOrganizerItemMaemo6Factory::createItemEngineLocalId() const
-{
- return new Maemo6ItemLocalId;
-}
-
-QOrganizerCollectionEngineLocalId* QOrganizerItemMaemo6Factory::createCollectionEngineLocalId() const
-{
- return NULL;
-}
-
-Q_EXPORT_PLUGIN2(qtorganizer_maemo6, QOrganizerItemMaemo6Factory);
-
-
-QOrganizerItemMaemo6Engine::QOrganizerItemMaemo6Engine()
- : d(new QOrganizerItemMaemo6EngineData)
-{
-}
-
-QOrganizerItemMaemo6Engine::~QOrganizerItemMaemo6Engine()
-{
- /* TODO clean up your stuff. Perhaps a QScopedPointer or QSharedDataPointer would be in order */
-}
-
-QString QOrganizerItemMaemo6Engine::managerName() const
-{
- return QLatin1String("maemo6");
-}
-
-QMap<QString, QString> QOrganizerItemMaemo6Engine::managerParameters() const
-{
- /* TODO - in case you have any actual parameters that are relevant that you saved in the factory method, return them here */
- return QMap<QString, QString>();
-}
-
-int QOrganizerItemMaemo6Engine::managerVersion() const
-{
- /* TODO - implement this appropriately. This is strictly defined by the engine, so return whatever you like */
- return 1;
-}
-
-QList<QOrganizerItem> QOrganizerItemMaemo6Engine::itemInstances(const QOrganizerItem& generator, const QDateTime& periodStart, const QDateTime& periodEnd, int maxCount, QOrganizerManager::Error* error) const
-{
- /*
- TODO
-
- This function should create a list of instances that occur in the time period from the supplied item.
- The periodStart should always be valid, and either the periodEnd or the maxCount will be valid (if periodEnd is
- valid, use that. Otherwise use the count). It's permissible to limit the number of items returned...
-
- Basically, if the generator item is an Event, a list of EventOccurrences should be returned. Similarly for
- Todo/TodoOccurrence.
-
- If there are no instances, return an empty list.
-
- The returned items should have a QOrganizerItemInstanceOrigin detail that points to the generator and the
- original instance that the event would have occurred on (e.g. with an exception).
-
- They should not have recurrence information details in them.
-
- We might change the signature to split up the periodStart + periodEnd / periodStart + maxCount cases.
- */
-
- QOrganizerItemLocalId generatorId = generator.localId();
- QString kId = static_cast<Maemo6ItemLocalId*>(QOrganizerManagerEngine::engineLocalItemId(generatorId))->toString();
- Incidence* generatorIncidence = d->m_calendarBackend.incidence(kId);
- Incidence::List generatorList;
- generatorList.append(generatorIncidence);
- ExtendedCalendar::ExpandedIncidenceList incidenceList = d->m_calendarBackend.expandRecurrences(
- &generatorList,
- KDateTime(periodStart),
- KDateTime(periodEnd));
- QList<QOrganizerItem> instances;
- foreach (const ExtendedCalendar::ExpandedIncidence& expandedIncidence, incidenceList) {
- QDateTime incidenceDateTime = expandedIncidence.first;
- Incidence* incidence = expandedIncidence.second;
- IncidenceToItemConverter converter(managerUri());
- QOrganizerItem instance;
- if (converter.convertIncidenceToItem(incidence, &instance)) {
- if (instance.type() == QOrganizerItemType::TypeEvent) {
- QOrganizerEventOccurrence* event = static_cast<QOrganizerEventOccurrence*>(&instance);
- event->setType(QOrganizerItemType::TypeEventOccurrence);
- event->setStartDateTime(incidenceDateTime);
- event->setParentLocalId(generatorId);
- } else if (instance.type() == QOrganizerItemType::TypeTodo) {
- QOrganizerTodoOccurrence* todo = static_cast<QOrganizerTodoOccurrence*>(&instance);
- todo->setType(QOrganizerItemType::TypeTodo);
- todo->setStartDateTime(incidenceDateTime);
- todo->setParentLocalId(generatorId);
- }
- if (incidence == generatorIncidence) {
- QOrganizerItemId id;
- id.setManagerUri(managerUri());
- id.setLocalId(QOrganizerItemLocalId());
- instance.setId(id);
- }
- instances << instance;
- }
- }
- return instances;
-}
-
-QList<QOrganizerItemLocalId> QOrganizerItemMaemo6Engine::itemIds(const QOrganizerItemFilter& filter, const QList<QOrganizerItemSortOrder>& sortOrders, QOrganizerManager::Error* error) const
-{
- QList<QOrganizerItem> ret = items(filter, sortOrders, QOrganizerItemFetchHint(), error);
-
- // TODO: we don't have to sort again since items() has done it for us
- return QOrganizerManagerEngine::sortItems(ret, sortOrders);
-}
-
-QList<QOrganizerItem> QOrganizerItemMaemo6Engine::items(const QOrganizerItemFilter& filter, const QList<QOrganizerItemSortOrder>& sortOrders, const QOrganizerItemFetchHint& fetchHint, QOrganizerManager::Error* error) const
-{
- Q_UNUSED(fetchHint);
- // TODO: optimise by using our own filters
-
- // Just naively get all the incidences
- d->m_calendarBackend.setFilter(0);
- Incidence::List incidences = d->m_calendarBackend.incidences();
- QList<QOrganizerItem> partiallyFilteredItems;
-
- // Convert them all to QOrganizerItems
- IncidenceToItemConverter converter(managerUri());
- foreach (Incidence* incidence, incidences) {
- QOrganizerItem item;
- if (converter.convertIncidenceToItem(incidence, &item))
- partiallyFilteredItems << item;
- }
- QList<QOrganizerItem> ret;
-
- // Now filter them
- foreach(const QOrganizerItem& item, partiallyFilteredItems) {
- if (QOrganizerManagerEngine::testFilter(filter, item)) {
- QOrganizerManagerEngine::addSorted(&ret, item, sortOrders);
- }
- }
-
- return ret;
-}
-
-QOrganizerItem QOrganizerItemMaemo6Engine::item(const QOrganizerItemLocalId& itemId, const QOrganizerItemFetchHint& fetchHint, QOrganizerManager::Error* error) const
-{
- Q_UNUSED(fetchHint);
- Incidence* theIncidence = incidence(itemId);
- if (!theIncidence) {
- *error = QOrganizerManager::DoesNotExistError;
- return QOrganizerItem();
- }
- IncidenceToItemConverter converter(managerUri());
- QOrganizerItem item;
- if (converter.convertIncidenceToItem(theIncidence, &item)) {
- return item;
- } else {
- *error = QOrganizerManager::DoesNotExistError;
- return QOrganizerItem();
- }
-}
-
-bool QOrganizerItemMaemo6Engine::saveItems(QList<QOrganizerItem>* items, const QOrganizerCollectionLocalId& collectionId, QMap<int, QOrganizerManager::Error>* errorMap, QOrganizerManager::Error* error)
-{
- if (!items || collectionId != QOrganizerCollectionLocalId()) {
- *error = QOrganizerManager::BadArgumentError;
- }
-
- /*
- TODO
- The item passed in should be validated according to the schema.
- */
- *error = QOrganizerManager::NoError;
- for (int i = 0; i < items->size(); i++) {
- QOrganizerManager::Error thisError;
- QOrganizerItem item = items->at(i);
- if (saveItem(&item, &thisError)) {
- items->replace(i, item);
- } else {
- *error = thisError;
- errorMap->insert(i, thisError);
- }
- }
- return *error == QOrganizerManager::NoError;
-}
-
-bool QOrganizerItemMaemo6Engine::saveItem(QOrganizerItem* item, QOrganizerManager::Error* error)
-{
- // ensure that the organizeritem's details conform to their definitions
- if (!validateItem(*item, error)) {
- return false;
- }
-
- Incidence* theIncidence = softSaveItem(item, error);
- if (theIncidence) {
- d->m_calendarBackend.save();
- QString kId = theIncidence->uid();
- QOrganizerItemLocalId qLocalId = QOrganizerItemLocalId(new Maemo6ItemLocalId(kId));
- QOrganizerItemId qId;
- qId.setManagerUri(managerUri());
- qId.setLocalId(qLocalId);
- item->setId(qId);
- return true;
- }
- return false;
-}
-
-bool QOrganizerItemMaemo6Engine::removeItems(const QList<QOrganizerItemLocalId>& itemIds, QMap<int, QOrganizerManager::Error>* errorMap, QOrganizerManager::Error* error)
-{
- *error = QOrganizerManager::NoError;
- for (int i = 0; i < itemIds.size(); i++) {
- QOrganizerItemLocalId id = itemIds[i];
- Incidence* theIncidence = incidence(id);
- if (!theIncidence) {
- *error = QOrganizerManager::DoesNotExistError;
- errorMap->insert(i, QOrganizerManager::DoesNotExistError);
- continue;
- }
- if (!d->m_calendarBackend.deleteIncidence(theIncidence)) {
- *error = QOrganizerManager::UnspecifiedError;
- errorMap->insert(i, QOrganizerManager::UnspecifiedError);
- }
- }
- return *error == QOrganizerManager::NoError;
-}
-
-QMap<QString, QOrganizerItemDetailDefinition> QOrganizerItemMaemo6Engine::detailDefinitions(const QString& itemType, QOrganizerManager::Error* error) const
-{
- *error = QOrganizerManager::NoError;
- return schemaDefinitions().value(itemType);
-}
-
-QOrganizerItemDetailDefinition QOrganizerItemMaemo6Engine::detailDefinition(const QString& definitionId, const QString& itemType, QOrganizerManager::Error* error) const
-{
- /* TODO - the default implementation just calls the base detailDefinitions function. If that's inefficent, implement this */
- return QOrganizerManagerEngine::detailDefinition(definitionId, itemType, error);
-}
-
-bool QOrganizerItemMaemo6Engine::saveDetailDefinition(const QOrganizerItemDetailDefinition& def, const QString& itemType, QOrganizerManager::Error* error)
-{
- /* TODO - if you support adding custom fields, do that here. Otherwise call the base functionality. */
- return QOrganizerManagerEngine::saveDetailDefinition(def, itemType, error);
-}
-
-bool QOrganizerItemMaemo6Engine::removeDetailDefinition(const QString& definitionId, const QString& itemType, QOrganizerManager::Error* error)
-{
- /* TODO - if you support removing custom fields, do that here. Otherwise call the base functionality. */
- return QOrganizerManagerEngine::removeDetailDefinition(definitionId, itemType, error);
-}
-
-QOrganizerCollectionLocalId QOrganizerItemMaemo6Engine::defaultCollectionId(QOrganizerManager::Error* error) const
-{
- *error = QOrganizerManager::NoError;
- return QOrganizerCollectionLocalId(0);
-}
-
-QList<QOrganizerCollectionLocalId> QOrganizerItemMaemo6Engine::collectionIds(QOrganizerManager::Error* error) const
-{
- *error = QOrganizerManager::NoError;
- QList<QOrganizerCollectionLocalId> retn;
- retn << QOrganizerCollectionLocalId(0);
- return retn;
-}
-
-QList<QOrganizerCollection> QOrganizerItemMaemo6Engine::collections(const QList<QOrganizerCollectionLocalId>& collectionIds, QMap<int, QOrganizerManager::Error>* errorMap, QOrganizerManager::Error* error) const
-{
- Q_UNUSED(errorMap);
- // XXX TODO: use error map, and fix implementation as per docs.
-
- *error = QOrganizerManager::NoError;
- QOrganizerCollection defaultCollection;
- defaultCollection.setId(QOrganizerCollectionId());
- QList<QOrganizerCollection> retn;
-
- if (collectionIds.contains(QOrganizerCollectionLocalId(0)))
- retn << defaultCollection;
-
- return retn;
-}
-
-bool QOrganizerItemMaemo6Engine::saveCollection(QOrganizerCollection* collection, QOrganizerManager::Error* error)
-{
- Q_UNUSED(collection)
- *error = QOrganizerManager::NotSupportedError;
- return false;
-}
-
-bool QOrganizerItemMaemo6Engine::removeCollection(const QOrganizerCollectionLocalId& collectionId, QOrganizerManager::Error* error)
-{
- Q_UNUSED(collectionId)
- *error = QOrganizerManager::NotSupportedError;
- return false;
-}
-
-bool QOrganizerItemMaemo6Engine::startRequest(QOrganizerAbstractRequest* req)
-{
- /*
- TODO
-
- This is the entry point to the async API. The request object describes the
- type of request (switch on req->type()). Req will not be null when called
- by the framework.
-
- Generally, you can queue the request and process them at some later time
- (probably in another thread).
-
- Once you start a request, call the updateRequestState and/or the
- specific updateXXXXXRequest functions to mark it in the active state.
-
- If your engine is particularly fast, or the operation involves only in
- memory data, you can process and complete the request here. That is
- probably not the case, though.
-
- Note that when the client is threaded, and the request might live on a
- different thread, you might need to be careful with locking. In particular,
- the request might be deleted while you are still working on it. In this case,
- your requestDestroyed function will be called while the request is still valid,
- and you should block in that function until your worker thread (etc) has been
- notified not to touch that request any more.
-
- We plan to provide some boiler plate code that will allow you to:
-
- 1) implement the sync functions, and have the async versions call the sync
- in another thread
-
- 2) or implement the async versions of the function, and have the sync versions
- call the async versions.
-
- It's not ready yet, though.
-
- Return true if the request can be started, false otherwise. You can set an error
- in the request if you like.
- */
- return QOrganizerManagerEngine::startRequest(req);
-}
-
-bool QOrganizerItemMaemo6Engine::cancelRequest(QOrganizerAbstractRequest* req)
-{
- /*
- TODO
-
- Cancel an in progress async request. If not possible, return false from here.
- */
- return QOrganizerManagerEngine::cancelRequest(req);
-}
-
-bool QOrganizerItemMaemo6Engine::waitForRequestFinished(QOrganizerAbstractRequest* req, int msecs)
-{
- /*
- TODO
-
- Wait for a request to complete (up to a max of msecs milliseconds).
-
- Return true if the request is finished (including if it was already). False otherwise.
-
- You should really implement this function, if nothing else than as a delay, since clients
- may call this in a loop.
-
- It's best to avoid processing events, if you can, or at least only process non-UI events.
- */
- return QOrganizerManagerEngine::waitForRequestFinished(req, msecs);
-}
-
-void QOrganizerItemMaemo6Engine::requestDestroyed(QOrganizerAbstractRequest* req)
-{
- /*
- TODO
-
- This is called when a request is being deleted. It lets you know:
-
- 1) the client doesn't care about the request any more. You can still complete it if
- you feel like it.
- 2) you can't reliably access any properties of the request pointer any more. The pointer will
- be invalid once this function returns.
-
- This means that if you have a worker thread, you need to let that thread know that the
- request object is not valid and block until that thread acknowledges it. One way to do this
- is to have a QSet<QOIAR*> (or QMap<QOIAR, MyCustomRequestState>) that tracks active requests, and
- insert into that set in startRequest, and remove in requestDestroyed (or when it finishes or is
- cancelled). Protect that set/map with a mutex, and make sure you take the mutex in the worker
- thread before calling any of the QOIAR::updateXXXXXXRequest functions. And be careful of lock
- ordering problems :D
-
- */
- return QOrganizerManagerEngine::requestDestroyed(req);
-}
-
-bool QOrganizerItemMaemo6Engine::hasFeature(QOrganizerManager::ManagerFeature feature, const QString& itemType) const
-{
- // TODO - the answer to the question may depend on the type
- Q_UNUSED(itemType);
- switch(feature) {
- case QOrganizerManager::MutableDefinitions:
- // TODO If you support save/remove detail definition, return true
- return false;
-
- case QOrganizerManager::Anonymous:
- // TODO if this engine is anonymous (e.g. no other engine can share the data) return true
- // (mostly for an in memory engine)
- return false;
- case QOrganizerManager::ChangeLogs:
- // TODO if this engine supports filtering by last modified/created/removed timestamps, return true
- return false;
- }
- return false;
-}
-
-bool QOrganizerItemMaemo6Engine::isFilterSupported(const QOrganizerItemFilter& filter) const
-{
- // TODO if you engine can natively support the filter, return true. Otherwise you should emulate support in the item{Ids} functions.
- Q_UNUSED(filter);
- return false;
-}
-
-QList<int> QOrganizerItemMaemo6Engine::supportedDataTypes() const
-{
- QList<int> ret;
- // TODO - tweak which data types this engine understands
- ret << QVariant::String;
- ret << QVariant::Date;
- ret << QVariant::DateTime;
- ret << QVariant::Time;
-
- return ret;
-}
-
-QStringList QOrganizerItemMaemo6Engine::supportedItemTypes() const
-{
- // TODO - return which [predefined] types this engine supports
- QStringList ret;
-
- ret << QOrganizerItemType::TypeEvent;
- ret << QOrganizerItemType::TypeEventOccurrence;
- ret << QOrganizerItemType::TypeJournal;
- ret << QOrganizerItemType::TypeNote;
- ret << QOrganizerItemType::TypeTodo;
- ret << QOrganizerItemType::TypeTodoOccurrence;
-
- return ret;
-}
-
-QMap<QString, QMap<QString, QOrganizerItemDetailDefinition> > QOrganizerItemMaemo6Engine::schemaDefinitions() const {
- // lazy initialisation of schema definitions.
- if (d->m_definitions.isEmpty()) {
- // Loop through default schema definitions
- QMap<QString, QMap<QString, QOrganizerItemDetailDefinition> > schema
- = QOrganizerManagerEngine::schemaDefinitions();
- foreach (const QString& itemType, schema.keys()) {
- // Only add the item types that we support
- if (itemType == QOrganizerItemType::TypeEvent ||
- itemType == QOrganizerItemType::TypeEventOccurrence ||
- itemType == QOrganizerItemType::TypeTodo ||
- itemType == QOrganizerItemType::TypeTodoOccurrence ||
- itemType == QOrganizerItemType::TypeJournal ||
- itemType == QOrganizerItemType::TypeNote) {
- QMap<QString, QOrganizerItemDetailDefinition> definitions
- = schema.value(itemType);
-
- QMap<QString, QOrganizerItemDetailDefinition> supportedDefinitions;
-
- QMapIterator<QString, QOrganizerItemDetailDefinition> it(definitions);
- while (it.hasNext()) {
- it.next();
- // Only add the definitions that we support
- if (it.key() == QOrganizerItemType::DefinitionName ||
- it.key() == QOrganizerItemDescription::DefinitionName ||
- it.key() == QOrganizerItemDisplayLabel::DefinitionName ||
- it.key() == QOrganizerItemRecurrence::DefinitionName ||
- it.key() == QOrganizerEventTime::DefinitionName ||
- it.key() == QOrganizerItemGuid::DefinitionName ||
- it.key() == QOrganizerItemInstanceOrigin::DefinitionName) {
- supportedDefinitions.insert(it.key(), it.value());
- }
- }
- d->m_definitions.insert(itemType, supportedDefinitions);
- }
- }
- }
- return d->m_definitions;
-}
-
-Incidence* QOrganizerItemMaemo6Engine::incidence(const QOrganizerItemLocalId& itemId) const
-{
- QString kId = static_cast<Maemo6ItemLocalId*>(QOrganizerManagerEngine::engineLocalItemId(itemId))->toString();
- return d->m_calendarBackend.incidence(kId);
-}
-
-/*!
- * Saves \a item to the manager, but doesn't persist the change to disk.
- * Sets \a error appropriately if if couldn't be saved.
- */
-Incidence* QOrganizerItemMaemo6Engine::softSaveItem(QOrganizerItem* item, QOrganizerManager::Error* error)
-{
- bool itemIsNew = (managerUri() != item->id().managerUri()
- || item->localId().isNull());
- bool itemIsOccurrence = (item->type() == QOrganizerItemType::TypeEventOccurrence) ||
- (item->type() == QOrganizerItemType::TypeTodoOccurrence);
- Incidence* newIncidence = 0;
-
- // valid iff itemIsOccurrence (hack!)
- QOrganizerItemLocalId parentLocalId;
- QDate originalDate;
-
- if (item->type() == QOrganizerItemType::TypeEvent) {
- QOrganizerEvent* event = static_cast<QOrganizerEvent*>(item);
- newIncidence = createKEvent(*event);
- } else if (item->type() == QOrganizerItemType::TypeTodo) {
- QOrganizerTodo* todo = static_cast<QOrganizerTodo*>(item);
- newIncidence = createKTodo(*todo);
- } else if (item->type() == QOrganizerItemType::TypeEventOccurrence) {
- QOrganizerEvent* event = static_cast<QOrganizerEvent*>(item);
- newIncidence = createKEvent(*event);
- QOrganizerEventOccurrence* eventOccurrence = static_cast<QOrganizerEventOccurrence*>(item);
- parentLocalId = eventOccurrence->parentLocalId();
- originalDate = eventOccurrence->originalDate();
- } else if (item->type() == QOrganizerItemType::TypeTodoOccurrence) {
- QOrganizerTodo* todo = static_cast<QOrganizerTodo*>(item);
- newIncidence = createKTodo(*todo);
- QOrganizerTodoOccurrence* todoOccurrence = static_cast<QOrganizerTodoOccurrence*>(item);
- parentLocalId = todoOccurrence->parentLocalId();
- originalDate = todoOccurrence->originalDate();
- } else if (item->type() == QOrganizerItemType::TypeNote) {
- QOrganizerNote* note = static_cast<QOrganizerNote*>(item);
- newIncidence = createKNote(*note);
- } else if (item->type() == QOrganizerItemType::TypeJournal) {
- QOrganizerJournal* journal = static_cast<QOrganizerJournal*>(item);
- newIncidence = createKJournal(*journal);
- } else {
- *error = QOrganizerManager::InvalidItemTypeError;
- return 0;
- }
- if (itemIsNew) {
- if (itemIsOccurrence) {
- Incidence* parentIncidence = incidence(parentLocalId);
- if (!parentIncidence) {
- *error = QOrganizerManager::InvalidOccurrenceError;
- return 0;
- }
- Incidence* detachedIncidence = d->m_calendarBackend.dissociateOccurrence(
- parentIncidence, originalDate, KDateTime::LocalZone, true);
- *detachedIncidence = *newIncidence;
- newIncidence = detachedIncidence;
- } else {
- // nothing needs to be done
- }
- } else {
- if (itemIsOccurrence) {
- // TODO
- } else {
- Incidence* oldIncidence = incidence(item->localId());
- if (!oldIncidence) {
- *error = QOrganizerManager::DoesNotExistError;
- return 0;
- }
- QString uid = oldIncidence->uid();
- // is this right? shouldn't we modify oldIncidence inplace rather than delete/add?
- d->m_calendarBackend.deleteIncidence(oldIncidence);
- newIncidence->setUid(uid);
- }
- }
- d->m_calendarBackend.addIncidence(newIncidence);
- *error = QOrganizerManager::NoError;
- return newIncidence;
-}
-
-/*!
- * Converts \a qEvent into an Incidence which is of subclass Event. The caller is responsible
- * for deleting the object.
- */
-Event* QOrganizerItemMaemo6Engine::createKEvent(const QOrganizerEvent& qEvent)
-{
- Event* kEvent = new Event;
- convertCommonDetailsToIncidenceFields(qEvent, kEvent);
- kEvent->setDtStart(KDateTime(qEvent.startDateTime()));
- kEvent->setDtEnd(KDateTime(qEvent.endDateTime()));
- convertQRecurrenceToKRecurrence(qEvent.detail<QOrganizerItemRecurrence>(), kEvent->recurrence());
- return kEvent;
-}
-
-/*!
- * Converts \a qTodo into an Incidence which is of subclass Todo. The caller is responsible
- * for deleting the object.
- */
-Todo* QOrganizerItemMaemo6Engine::createKTodo(const QOrganizerTodo& qTodo)
-{
- Todo* kTodo = new Todo;
- convertCommonDetailsToIncidenceFields(qTodo, kTodo);
- kTodo->setDtStart(KDateTime(qTodo.startDateTime()));
- kTodo->setDtDue(KDateTime(qTodo.dueDateTime()));
- convertQRecurrenceToKRecurrence(qTodo.detail<QOrganizerItemRecurrence>(), kTodo->recurrence());
- return kTodo;
-}
-
-/*!
- * Converts \a qJournal into an Incidence which is of subclass Journal. The caller is responsible
- * for deleting the object.
- */
-Journal* QOrganizerItemMaemo6Engine::createKJournal(const QOrganizerJournal& qJournal)
-{
- Journal* kJournal = new Journal;
- convertCommonDetailsToIncidenceFields(qJournal, kJournal);
- return kJournal;
-}
-
-/*!
- * Converts \a qNote into an Incidence which is of subclass Journal. The caller is responsible
- * for deleting the object.
- */
-Journal* QOrganizerItemMaemo6Engine::createKNote(const QOrganizerNote& qNote)
-{
- Journal* kJournal = new Journal;
- convertCommonDetailsToIncidenceFields(qNote, kJournal);
- return kJournal;
-}
-
-/*!
- * Converts the item-common details of \a item to fields to set in \a incidence.
- */
-void QOrganizerItemMaemo6Engine::convertCommonDetailsToIncidenceFields(
- const QOrganizerItem& item, Incidence* incidence)
-{
- incidence->setDescription(item.description());
- incidence->setSummary(item.displayLabel());
-}
-
-/*! Converts \a qRecurrence into the libkcal equivalent, stored in \a kRecurrence. kRecurrence must
- * point to an initialized Recurrence.
- */
-void QOrganizerItemMaemo6Engine::convertQRecurrenceToKRecurrence(
- const QOrganizerItemRecurrence& qRecurrence,
- Recurrence* kRecurrence)
-{
- // Remove all recurrence rules in kRecurrence
- foreach (RecurrenceRule* rrule, kRecurrence->rRules()) {
- kRecurrence->deleteRRule(rrule);
- }
-
- foreach (const QOrganizerRecurrenceRule& rrule, qRecurrence.recurrenceRules()) {
- RecurrenceRule* krrule = createKRecurrenceRule(kRecurrence, rrule);
- kRecurrence->addRRule(krrule);
- }
-}
-
-RecurrenceRule* QOrganizerItemMaemo6Engine::createKRecurrenceRule(
- Recurrence* kRecurrence,
- const QOrganizerRecurrenceRule& qRRule)
-{
- RecurrenceRule* kRRule = kRecurrence->defaultRRule(true);
- switch (qRRule.frequency()) {
- case QOrganizerRecurrenceRule::Daily:
- kRRule->setRecurrenceType(RecurrenceRule::rDaily);
- break;
- case QOrganizerRecurrenceRule::Weekly:
- kRRule->setRecurrenceType(RecurrenceRule::rWeekly);
- break;
- case QOrganizerRecurrenceRule::Monthly:
- kRRule->setRecurrenceType(RecurrenceRule::rMonthly);
- break;
- case QOrganizerRecurrenceRule::Yearly:
- kRRule->setRecurrenceType(RecurrenceRule::rYearly);
- break;
- }
- kRRule->setFrequency(qRRule.interval());
- kRRule->setDuration(qRRule.count() > 1 ? qRRule.count() : -1);
-
- QList<RecurrenceRule::WDayPos> daysOfWeek;
- foreach (Qt::DayOfWeek dayOfWeek, qRRule.daysOfWeek()) {
- // 0 argument is setByPos (unimplemented for now)
- daysOfWeek.append(RecurrenceRule::WDayPos(0, (short)dayOfWeek));
- }
- kRRule->setByDays(daysOfWeek);
-
- kRRule->setByMonthDays(qRRule.daysOfMonth());
-
- kRRule->setByYearDays(qRRule.daysOfYear());
-
- kRRule->setByWeekNumbers(qRRule.weeksOfYear());
-
- QList<int> months;
- foreach (QOrganizerRecurrenceRule::Month month, qRRule.months()) {
- months.append((int)month);
- }
- kRRule->setByMonths(months);
-
- QDate endDate = qRRule.endDate();
- if (endDate.isValid()) {
- // The endDate is non-inclusive, as per iCalendar
- kRRule->setEndDt(KDateTime(endDate.addDays(-1)));
- }
- return kRRule;
-}
-
-
-/*! \class IncidenceToItemConverter:
- *
- * This class converts a single kcal Incidence to a QOrganizerItem
- */
-
-/*!
- * Converts a kcal \a incidence into a QOrganizer \a item.
- * \a incidence and \a item must both not be null.
- * Whatever was in \a item before will be ignored and lost.
- */
-bool QOrganizerItemMaemo6Engine::IncidenceToItemConverter::convertIncidenceToItem(
- Incidence* incidence, QOrganizerItem* item)
-{
- if (incidence->accept(m_visitor)) {
- *item = m_converted;
- return true;
- } else {
- return false;
- }
-}
-
-/*!
- * Don't call this directly unless you are an Incidence::AddVisitor.
- * Converts a kcal Event.
- */
-bool QOrganizerItemMaemo6Engine::IncidenceToItemConverter::addEvent(Event* e)
-{
- m_converted = QOrganizerEvent();
- QOrganizerEvent* event = static_cast<QOrganizerEvent*>(&m_converted);
- convertCommonDetails(e, event);
- event->setStartDateTime(e->dtStart().dateTime());
- event->setEndDateTime(e->dtEnd().dateTime());
- return true;
-}
-
-/*!
- * Don't call this directly unless you are an Incidence::AddVisitor.
- * Converts a kcal Todo.
- */
-bool QOrganizerItemMaemo6Engine::IncidenceToItemConverter::addTodo(Todo* t)
-{
- m_converted = QOrganizerTodo();
- convertCommonDetails(t, &m_converted);
- return true;
-}
-
-/*!
- * Don't call this directly unless you are an Incidence::AddVisitor.
- * Converts a kcal Journal.
- */
-bool QOrganizerItemMaemo6Engine::IncidenceToItemConverter::addJournal(Journal* j)
-{
- if (j->dtStart().isValid())
- m_converted = QOrganizerJournal();
- else
- m_converted = QOrganizerNote();
- convertCommonDetails(j, &m_converted);
- return true;
-}
-
-/*!
- * Adds details to \a item based on fields found in \a incidence.
- */
-void QOrganizerItemMaemo6Engine::IncidenceToItemConverter::convertCommonDetails(
- Incidence* incidence, QOrganizerItem* item)
-{
- QOrganizerItemId id;
- id.setManagerUri(m_managerUri);
- id.setLocalId(QOrganizerItemLocalId(new Maemo6ItemLocalId(incidence->uid())));
- item->setId(id);
- item->setDisplayLabel(incidence->summary());
- item->setDescription(incidence->description());
- item->setGuid(incidence->uid());
-}
-
diff --git a/plugins/organizer/maemo6/qorganizermaemo6.h b/plugins/organizer/maemo6/qorganizermaemo6.h
deleted file mode 100644
index 894fe6b6cc..0000000000
--- a/plugins/organizer/maemo6/qorganizermaemo6.h
+++ /dev/null
@@ -1,203 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the Qt Mobility Components.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the Technology Preview License Agreement accompanying
-** this package.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QORGANIZERMAEMO6_H
-#define QORGANIZERMAEMO6_H
-
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QSharedData>
-#include <QMap>
-#include <QMultiMap>
-#include <QList>
-#include <QQueue>
-#include <QPair>
-#include <QSet>
-#include <QDateTime>
-#include <QString>
-#include <QObject>
-
-#include <extendedcalendar.h>
-
-#include "qorganizeritem.h"
-#include "qorganizermanager.h"
-#include "qorganizermanagerengine.h"
-#include "qorganizermanagerenginefactory.h"
-#include "qorganizeritemdetaildefinition.h"
-#include "qorganizerabstractrequest.h"
-#include "qorganizeritemchangeset.h"
-
-QTM_BEGIN_NAMESPACE
-class QOrganizerEvent;
-class QOrganizerTodo;
-class QOrganizerNote;
-class QOrganizerJournal;
-class QOrganizerItemRecurrence;
-class QOrganizerRecurrenceRule;
-QTM_END_NAMESPACE
-
-QTM_USE_NAMESPACE
-using namespace KCal;
-
-class QOrganizerItemMaemo6Factory : public QObject, public QOrganizerManagerEngineFactory
-{
- Q_OBJECT
- Q_INTERFACES(QtMobility::QOrganizerManagerEngineFactory)
- public:
- QOrganizerManagerEngine* engine(const QMap<QString, QString>& parameters, QOrganizerManager::Error*);
- QString managerName() const;
- QOrganizerItemEngineLocalId* createItemEngineLocalId() const;
- QOrganizerCollectionEngineLocalId* createCollectionEngineLocalId() const;
-};
-
-class QOrganizerItemMaemo6EngineData : public QSharedData
-{
-public:
- QOrganizerItemMaemo6EngineData()
- : QSharedData(),
- m_calendarBackend(KDateTime::Spec::LocalZone())
- {
- }
-
- ~QOrganizerItemMaemo6EngineData()
- {
- }
-
- // map of organizeritem type to map of definition name to definitions:
- mutable QMap<QString, QMap<QString, QOrganizerItemDetailDefinition> > m_definitions;
-
- ExtendedCalendar m_calendarBackend;
-};
-
-class QOrganizerItemMaemo6Engine : public QOrganizerManagerEngine
-{
- Q_OBJECT
-
-public:
- ~QOrganizerItemMaemo6Engine();
-
- /* URI reporting */
- QString managerName() const;
- QMap<QString, QString> managerParameters() const;
- int managerVersion() const;
-
- QList<QOrganizerItem> itemInstances(const QOrganizerItem& generator, const QDateTime& periodStart, const QDateTime& periodEnd, int maxCount, QOrganizerManager::Error* error) const;
- QList<QOrganizerItemLocalId> itemIds(const QOrganizerItemFilter& filter, const QList<QOrganizerItemSortOrder>& sortOrders, QOrganizerManager::Error* error) const;
- QList<QOrganizerItem> items(const QOrganizerItemFilter& filter, const QList<QOrganizerItemSortOrder>& sortOrders, const QOrganizerItemFetchHint& fetchHint, QOrganizerManager::Error* error) const;
- QOrganizerItem item(const QOrganizerItemLocalId& itemId, const QOrganizerItemFetchHint& fetchHint, QOrganizerManager::Error* error) const;
-
- bool saveItems(QList<QOrganizerItem>* items, const QOrganizerCollectionLocalId& collectionId, QMap<int, QOrganizerManager::Error>* errorMap, QOrganizerManager::Error* error);
- bool saveItem(QOrganizerItem* item, QOrganizerManager::Error* error);
- bool removeItems(const QList<QOrganizerItemLocalId>& itemIds, QMap<int, QOrganizerManager::Error>* errorMap, QOrganizerManager::Error* error);
-
- /* Definitions - Accessors and Mutators */
- QMap<QString, QOrganizerItemDetailDefinition> detailDefinitions(const QString& itemType, QOrganizerManager::Error* error) const;
- QOrganizerItemDetailDefinition detailDefinition(const QString& definitionId, const QString& itemType, QOrganizerManager::Error* error) const;
- bool saveDetailDefinition(const QOrganizerItemDetailDefinition& def, const QString& itemType, QOrganizerManager::Error* error);
- bool removeDetailDefinition(const QString& definitionId, const QString& itemType, QOrganizerManager::Error* error);
-
- /* Collections - every item belongs to exactly one collection */
- QOrganizerCollectionLocalId defaultCollectionId(QOrganizerManager::Error* error) const;
- QList<QOrganizerCollectionLocalId> collectionIds(QOrganizerManager::Error* error) const;
- QList<QOrganizerCollection> collections(const QList<QOrganizerCollectionLocalId>& collectionIds, QMap<int, QOrganizerManager::Error>* errorMap, QOrganizerManager::Error* error) const;
- bool saveCollection(QOrganizerCollection* collection, QOrganizerManager::Error* error);
- bool removeCollection(const QOrganizerCollectionLocalId& collectionId, QOrganizerManager::Error* error);
-
- /* Capabilities reporting */
- bool hasFeature(QOrganizerManager::ManagerFeature feature, const QString& itemType) const;
- bool isFilterSupported(const QOrganizerItemFilter& filter) const;
- QList<int> supportedDataTypes() const;
- QStringList supportedItemTypes() const;
-
- /* Asynchronous Request Support */
- void requestDestroyed(QOrganizerAbstractRequest* req);
- bool startRequest(QOrganizerAbstractRequest* req);
- bool cancelRequest(QOrganizerAbstractRequest* req);
- bool waitForRequestFinished(QOrganizerAbstractRequest* req, int msecs);
-
-private:
- QOrganizerItemMaemo6Engine();
- QMap<QString, QMap<QString, QOrganizerItemDetailDefinition> > schemaDefinitions() const;
- Incidence* incidence(const QOrganizerItemLocalId& itemId) const;
- Incidence* softSaveItem(QOrganizerItem* item, QOrganizerManager::Error* error);
- Event* createKEvent(const QOrganizerEvent& note);
- Todo* createKTodo(const QOrganizerTodo& note);
- Journal* createKJournal(const QOrganizerJournal& note);
- Journal* createKNote(const QOrganizerNote& note);
- void convertCommonDetailsToIncidenceFields(const QOrganizerItem& item, Incidence* incidence);
- void convertQRecurrenceToKRecurrence(const QOrganizerItemRecurrence& qRecurrence,
- Recurrence* kRecurrence);
- RecurrenceRule* createKRecurrenceRule(Recurrence* kRecurrence,
- const QOrganizerRecurrenceRule& rrule);
-
- QOrganizerItemMaemo6EngineData* d;
-
- friend class QOrganizerItemMaemo6Factory;
-
- class IncidenceToItemConverter {
- public:
- IncidenceToItemConverter(const QString managerUri)
- : m_managerUri(managerUri), m_visitor(this) {}
- bool convertIncidenceToItem(Incidence* incidence, QOrganizerItem* item);
- bool addEvent(Event* e);
- bool addTodo(Todo* t);
- bool addJournal(Journal* j);
- private:
- void convertCommonDetails(Incidence* incidence, QOrganizerItem* item);
-
- QString m_managerUri;
- QOrganizerItem m_converted;
- Incidence::AddVisitor<IncidenceToItemConverter> m_visitor;
- };
-};
-
-#endif
-
diff --git a/plugins/organizer/maemo6/maemo6.pro b/plugins/organizer/mkcal/mkcal.pro
index 5928c856ad..ddb7528572 100644
--- a/plugins/organizer/maemo6/maemo6.pro
+++ b/plugins/organizer/mkcal/mkcal.pro
@@ -1,13 +1,13 @@
TEMPLATE = lib
CONFIG += plugin
-TARGET = $$qtLibraryTarget(qtorganizer_maemo6)
+TARGET = $$qtLibraryTarget(qtorganizer_mkcal)
PLUGIN_TYPE=organizer
CONFIG += mobility
MOBILITY = organizer
CONFIG += link_pkgconfig
-PKGCONFIG += libextendedkcal
+PKGCONFIG += libmkcal
include(../../../common.pri)
@@ -18,11 +18,10 @@ INCLUDEPATH += ../../../src/organizer \
../../../src/organizer/details
HEADERS += \
- qorganizermaemo6.h \
- maemo6itemlocalid.h
+ mkcalengine.h \
+ qorganizerasynchmanager.h \
+ mkcalid.h
SOURCES += \
- qorganizermaemo6.cpp
+ mkcalengine.cpp \
+ qorganizerasynchmanager.cpp
-# Once we know what the pkgconfig deps are
-# CONFIG += link_pkgconfig
-PKGCONFIG +=
diff --git a/plugins/organizer/mkcal/mkcalengine.cpp b/plugins/organizer/mkcal/mkcalengine.cpp
new file mode 100644
index 0000000000..c49f902ced
--- /dev/null
+++ b/plugins/organizer/mkcal/mkcalengine.cpp
@@ -0,0 +1,1385 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "mkcalengine.h"
+#include "qtorganizer.h"
+#include "mkcalid.h"
+#include "qorganizerasynchmanager.h"
+
+Q_DEFINE_LATIN1_CONSTANT(NotebookSyncDate, "SyncDate");
+Q_DEFINE_LATIN1_CONSTANT(NotebookModifiedDate, "ModifiedDate");
+Q_DEFINE_LATIN1_CONSTANT(NotebookPluginName, "PluginName");
+Q_DEFINE_LATIN1_CONSTANT(NotebookAccount, "Account");
+Q_DEFINE_LATIN1_CONSTANT(NotebookSharedWith, "SharedWith");
+Q_DEFINE_LATIN1_CONSTANT(NotebookSharedWithStr, "SharedWithStr");
+Q_DEFINE_LATIN1_CONSTANT(NotebookSyncProfile, "SyncProfile");
+Q_DEFINE_LATIN1_CONSTANT(NotebookAttachmentSize, "AttachmentSize");
+Q_DEFINE_LATIN1_CONSTANT(NotebookIsDefault, "IsDefault");
+Q_DEFINE_LATIN1_CONSTANT(NotebookIsShareable, "IsShareable");
+Q_DEFINE_LATIN1_CONSTANT(NotebookIsShared, "IsShared");
+Q_DEFINE_LATIN1_CONSTANT(NotebookIsMaster, "IsMaster");
+Q_DEFINE_LATIN1_CONSTANT(NotebookIsOviSync, "IsOviSync");
+Q_DEFINE_LATIN1_CONSTANT(NotebookIsReadOnly, "IsReadOnly");
+Q_DEFINE_LATIN1_CONSTANT(NotebookIsVisible, "IsVisible");
+Q_DEFINE_LATIN1_CONSTANT(NotebookIsRunTimeOnly, "IsRunTimeOnly");
+Q_DEFINE_LATIN1_CONSTANT(NotebookEventsAllowed, "EventsAllowed");
+Q_DEFINE_LATIN1_CONSTANT(NotebookJournalsAllowed, "JournalsAllowed");
+Q_DEFINE_LATIN1_CONSTANT(NotebookTodosAllowed, "TodosAllowed");
+
+//QTM_USE_NAMESPACE
+
+QOrganizerManagerEngine* MKCalEngineFactory::engine(const QMap<QString, QString>& parameters, QOrganizerManager::Error* error)
+{
+ Q_UNUSED(parameters);
+
+ *error = QOrganizerManager::NoError;
+ QString managerUri = QOrganizerManager::buildUri("mkcal", QMap<QString, QString>());
+ MKCalEngine* ret = new MKCalEngine(managerUri); // manager takes ownership and will clean up.
+
+ return ret;
+}
+
+QString MKCalEngineFactory::managerName() const
+{
+ return QLatin1String("mkcal");
+}
+
+QOrganizerItemEngineId* MKCalEngineFactory::createItemEngineId(const QMap<QString, QString>& parameters, const QString& engineIdString) const
+{
+ Q_UNUSED(parameters);
+ int col1 = engineIdString.indexOf(QLatin1String(":"), 0);
+ int col2 = engineIdString.indexOf(QLatin1String(":"), col1+1);
+ if (col1 < 0 || col2 < 0)
+ return NULL;
+ KDateTime rid;
+ QString tmp = engineIdString.mid(col1+1, col2-col1-1);
+ if (!tmp.isEmpty())
+ rid.setTime_t(tmp.toLongLong());
+ //ignore the managerUri parameter
+ MKCalItemId* retn = new MKCalItemId(engineIdString.mid(0, col1), rid);
+
+ return retn;
+}
+
+QOrganizerCollectionEngineId* MKCalEngineFactory::createCollectionEngineId(const QMap<QString, QString>& parameters, const QString& engineIdString) const
+{
+ Q_UNUSED(parameters);
+ int col1 = engineIdString.indexOf(QLatin1String(":"), 0);
+ if (col1 < 0)
+ return NULL;
+ MKCalCollectionId* retn = new MKCalCollectionId(engineIdString.mid(0, col1));
+
+ return retn;
+}
+
+Q_EXPORT_PLUGIN2(qtorganizer_mkcal, MKCalEngineFactory);
+
+
+MKCalEngine::MKCalEngine(const QString& managerUri)
+ : d(new MKCalEngineData)
+{
+ // set our manager uri.
+ d->m_managerUri = managerUri;
+
+ // ensure we build up our hashes of collections.
+ storageModified(d->m_storagePtr.data(), QString());
+
+ // register ourselves as an observer of any changes to the db.
+ d->m_storagePtr->registerObserver(this);
+
+ // and start our asynchronous request helper
+ d->m_asynchProcess = new OrganizerAsynchManager(this);
+}
+
+MKCalEngine::~MKCalEngine()
+{
+ delete d->m_asynchProcess;
+ d->m_storagePtr->unregisterObserver(this);
+}
+
+QString MKCalEngine::managerName() const
+{
+ return QLatin1String("mkcal");
+}
+
+QMap<QString, QString> MKCalEngine::managerParameters() const
+{
+ return QMap<QString, QString>();
+}
+
+int MKCalEngine::managerVersion() const
+{
+ return 1;
+}
+
+QList<QOrganizerItem> MKCalEngine::itemOccurrences(const QOrganizerItem& parentItem, const QDateTime& periodStart, const QDateTime& periodEnd, int maxCount, const QOrganizerItemFetchHint& fetchHint, QOrganizerManager::Error* error) const
+{
+ return internalItemOccurrences(parentItem, periodStart, periodEnd, maxCount, fetchHint, error, true);
+}
+
+QList<QOrganizerItem> MKCalEngine::internalItemOccurrences(const QOrganizerItem& parentItem, const QDateTime& periodStart, const QDateTime& periodEnd, int maxCount, const QOrganizerItemFetchHint& fetchHint, QOrganizerManager::Error* error, bool includeInstances) const
+{
+ Q_UNUSED(fetchHint); // XXX TODO: why do we not use this?
+
+ //for the moment we support generating of 1000 occurrences. 1000 is a random value
+ if (maxCount < 0)
+ maxCount = 1000;
+
+ QOrganizerItemId generatorId = parentItem.id();
+ QString kId = MKCalItemId::id_cast(generatorId)->id();
+ KCalCore::Incidence::Ptr generatorIncidence;
+ if (kId.isEmpty() || !(generatorIncidence = d->m_calendarBackendPtr->incidence(kId))) {
+ *error = QOrganizerManager::DoesNotExistError;
+ return QList<QOrganizerItem>();
+ }
+
+ //TODO: Until QOrganizerItem will include a startDt, we will store a QPair of QDateTime and QOrganizerItem for faster mergeSort
+ QList<QPair<QDateTime, QOrganizerItem> > persistentExceptions;
+ QList<QPair<QDateTime, QOrganizerItem> > instances;
+ QList<QOrganizerItem> res;
+
+ //if includeInstances is true, then first add to the list all persistent exceptions
+ if (includeInstances && generatorIncidence->recurs()) {
+ if (generatorIncidence->type() == KCalCore::Incidence::TypeEvent) {
+ KCalCore::Event::List events(d->m_calendarBackendPtr->eventInstances(generatorIncidence, KCalCore::EventSortStartDate));
+ foreach(const KCalCore::Event::Ptr& ev, events) {
+ if (persistentExceptions.count() > maxCount)
+ break;
+ QOrganizerItem instance;
+ if (convertIncidenceToItem(ev, &instance) &&
+ QOrganizerManagerEngine::isItemBetweenDates(instance, periodStart, periodEnd))
+ persistentExceptions.append(QPair<QDateTime, QOrganizerItem>(ev->dtStart().dateTime(), instance));
+ }
+ } else if (generatorIncidence->type() == KCalCore::Incidence::TypeTodo) {
+ KCalCore::Todo::List todos(d->m_calendarBackendPtr->todoInstances(generatorIncidence));
+ foreach(const KCalCore::Todo::Ptr& t, todos) {
+ if (persistentExceptions.count() > maxCount)
+ break;
+ QOrganizerItem instance;
+ if (convertIncidenceToItem(t, &instance) &&
+ QOrganizerManagerEngine::isItemBetweenDates(instance, periodStart, periodEnd))
+ persistentExceptions.append(QPair<QDateTime, QOrganizerItem>(t->dtStart().dateTime(), instance));
+ }
+ }
+ }
+
+ KCalCore::Incidence::List generatorList;
+ generatorList.append(generatorIncidence);
+ mKCal::ExtendedCalendar::ExpandedIncidenceList incidenceList = d->m_calendarBackendPtr->expandRecurrences(
+ &generatorList,
+ KDateTime(periodStart),
+ KDateTime(periodEnd),
+ maxCount);
+ KCalCore::Recurrence *recurrence = generatorIncidence->recurrence();
+ foreach (const mKCal::ExtendedCalendar::ExpandedIncidence& expandedIncidence, incidenceList) {
+ QDateTime incidenceDateTime = expandedIncidence.first;
+ KCalCore::Incidence::Ptr incidence = expandedIncidence.second;
+ QOrganizerItem instance;
+ if (!recurrence->exDates().containsSorted(incidenceDateTime.date()) && convertIncidenceToItem(incidence, &instance)) {
+ QDateTime startDT;
+ if (instance.type() == QOrganizerItemType::TypeEvent) {
+ QOrganizerEventOccurrence* event = static_cast<QOrganizerEventOccurrence*>(&instance);
+ event->setType(QOrganizerItemType::TypeEventOccurrence);
+ startDT = event->startDateTime();
+ int duration = startDT.secsTo(event->endDateTime());
+ startDT = QDateTime(incidenceDateTime.date(), startDT.time());
+ event->setStartDateTime(startDT);
+ event->setEndDateTime(startDT.addSecs(duration));
+ event->setOriginalDate(incidenceDateTime.date());
+ event->setParentId(generatorId);
+ foreach (QOrganizerItemDetail recurrence, event->details<QOrganizerItemRecurrence>()) {
+ event->removeDetail(&recurrence);
+ }
+ } else if (instance.type() == QOrganizerItemType::TypeTodo) {
+ QOrganizerTodoOccurrence* todo = static_cast<QOrganizerTodoOccurrence*>(&instance);
+ todo->setType(QOrganizerItemType::TypeTodoOccurrence);
+ startDT = todo->startDateTime();
+ int duration = todo->dueDateTime().isNull() ? -1 : startDT.secsTo(todo->dueDateTime());
+ startDT = QDateTime(incidenceDateTime.date(), startDT.time());
+ todo->setStartDateTime(startDT);
+ todo->setDueDateTime(duration >= 0 ? startDT.addSecs(duration) : QDateTime());
+ todo->setOriginalDate(incidenceDateTime.date());
+ todo->setParentId(generatorId);
+ foreach (QOrganizerItemDetail recurrence, todo->details<QOrganizerItemRecurrence>()) {
+ todo->removeDetail(&recurrence);
+ }
+ }
+
+ // if the incidence is the generating event itself then clear its id
+ if (incidence == generatorIncidence) {
+ instance.setId(QOrganizerItemId());
+ }
+
+ //if the result needs to include the permanent exceptions then the instance need to be inserted
+ //into a temporal list to be able to merge sort in the end
+ if (includeInstances)
+ instances.append(QPair<QDateTime, QOrganizerItem>(startDT, instance));
+ else
+ res.append(instance);
+ }
+ }
+
+ if (includeInstances) {
+ res.reserve(qMin(maxCount, instances.count() + persistentExceptions.count()));
+
+ //mergeSort the results based on the start time
+ QList<QPair<QDateTime, QOrganizerItem> >::const_iterator itExceptions = persistentExceptions.constBegin();
+ QList<QPair<QDateTime, QOrganizerItem> >::const_iterator itInstances = instances.constBegin();
+ while (itExceptions != persistentExceptions.constEnd() && itInstances != instances.constEnd() && res.count() < maxCount) {
+ if (itExceptions->first < itInstances->first) {
+ res.append(itExceptions->second);
+ ++itExceptions;
+ } else {
+ res.append(itInstances->second);
+ ++itInstances;
+ }
+ }
+ for (; itExceptions != persistentExceptions.constEnd() && res.count() < maxCount; ++itExceptions) {
+ res.append(itExceptions->second);
+ }
+ for (; itInstances != instances.constEnd() && res.count() < maxCount; ++itInstances) {
+ res.append(itInstances->second);
+ }
+ }
+
+ *error = QOrganizerManager::NoError;
+ return res;
+}
+
+QList<QOrganizerItemId> MKCalEngine::itemIds(const QDateTime& startDate, const QDateTime& endDate, const QOrganizerItemFilter& filter, const QList<QOrganizerItemSortOrder>& sortOrders, QOrganizerManager::Error* error) const
+{
+ //small optimization for the default case when startDate, endDate, filter, sortOrders are the default values
+ if (startDate.isNull() && endDate.isNull() && filter == QOrganizerItemFilter() && sortOrders.count() == 0) {
+ QList<QOrganizerItemId> ids;
+ KCalCore::Incidence::List rawIncidences = d->m_calendarBackendPtr->rawIncidences();
+ foreach(const KCalCore::Incidence::Ptr& i, rawIncidences) {
+ ids.append(QOrganizerItemId(new MKCalItemId(i->uid(),
+ i->hasRecurrenceId() ? i->recurrenceId() : KDateTime())));
+ }
+
+ return ids;
+ }
+
+ QList<QOrganizerItem> ret = itemsForExport(startDate, endDate, filter, sortOrders, QOrganizerItemFetchHint(), error);
+
+ return QOrganizerManager::extractIds(ret);
+}
+
+QList<QOrganizerItem> MKCalEngine::itemsForExport(const QDateTime& startDate, const QDateTime& endDate, const QOrganizerItemFilter& filter, const QList<QOrganizerItemSortOrder>& sortOrders, const QOrganizerItemFetchHint& fetchHint, QOrganizerManager::Error* error) const
+{
+ return internalItems(startDate, endDate, filter, sortOrders, fetchHint, error, false);
+}
+
+QList<QOrganizerItem> MKCalEngine::items(const QDateTime& startDate, const QDateTime& endDate, const QOrganizerItemFilter& filter, const QList<QOrganizerItemSortOrder>& sortOrders, const QOrganizerItemFetchHint& fetchHint, QOrganizerManager::Error* error) const
+{
+ return internalItems(startDate, endDate, filter, sortOrders, fetchHint, error, true);
+}
+
+QList<QOrganizerItem> MKCalEngine::internalItems(const QDateTime& startDate, const QDateTime& endDate, const QOrganizerItemFilter& filter, const QList<QOrganizerItemSortOrder>& sortOrders, const QOrganizerItemFetchHint& fetchHint, QOrganizerManager::Error* error, bool expand) const
+{
+ Q_UNUSED(fetchHint);
+ Q_UNUSED(error);
+ // TODO: optimise by using our own filters
+
+ // Just naively get all the incidences between the given startDate and endDate
+ d->m_calendarBackendPtr->setFilter(0);
+ KCalCore::Incidence::List incidences = d->m_calendarBackendPtr->incidences(startDate.date(), endDate.date());
+ QList<QOrganizerItem> partiallyFilteredItems;
+ QList<QOrganizerItem> ret;
+
+ // Convert them all to QOrganizerItems
+ foreach (KCalCore::Incidence::Ptr incidence, incidences) {
+ QOrganizerItem item;
+ if (convertIncidenceToItem(incidence, &item)) {
+ if (incidence->recurs()) {
+ if (expand) {
+ partiallyFilteredItems << internalItemOccurrences(item, startDate, endDate, 100, fetchHint, error, false);
+ } else {
+ if (itemHasRecurringChild(incidence, startDate, endDate, filter))
+ QOrganizerManagerEngine::addSorted(&ret, item, sortOrders);
+ }
+ } else {
+ partiallyFilteredItems << item;
+ }
+ }
+ }
+
+ // Now filter them
+ foreach(const QOrganizerItem& item, partiallyFilteredItems) {
+ if (QOrganizerManagerEngine::testFilter(filter, item) &&
+ QOrganizerManagerEngine::isItemBetweenDates(item, startDate, endDate)) {
+ QOrganizerManagerEngine::addSorted(&ret, item, sortOrders);
+ }
+ }
+
+ return ret;
+}
+
+
+bool MKCalEngine::itemHasRecurringChild(KCalCore::Incidence::Ptr incidence, QDateTime startDate, QDateTime endDate, QOrganizerItemFilter filter) const
+{
+ //TODO: FIXME: check for filter
+ Q_UNUSED(filter);
+
+ // if interval is null always return true
+ if (startDate.isNull() && endDate.isNull())
+ return true;
+
+ // if start interval is null, check if the incidence start date is before the interval end date
+ if (startDate.isNull())
+ return incidence->dtStart().dateTime() <= endDate;
+
+ int duration = 0;
+ if (incidence->type() == KCalCore::Incidence::TypeEvent) {
+ KCalCore::Event::Ptr ev = incidence.staticCast<KCalCore::Event>();
+ if (!ev->dtEnd().isNull())
+ duration = ev->dtStart().secsTo(ev->dtEnd());
+ } else if (incidence->type() == KCalCore::Incidence::TypeTodo) {
+ //TODO: Is this correct? Todos have duration?
+ KCalCore::Todo::Ptr todo = incidence.staticCast<KCalCore::Todo>();
+ if (!todo->dtDue().isNull())
+ duration = todo->dtStart().secsTo(todo->dtDue());
+ }
+
+ QDateTime next(incidence->recurrence()->getNextDateTime(KDateTime(startDate)).dateTime());
+ //fail if there are no recurrences after the start date
+ if (next.isNull())
+ return false;
+
+ //if end date is empty, check if the calculated recurrence + duration of the event is after the start date
+ if (endDate.isNull())
+ return next.addSecs(duration) >= startDate;
+
+ //in last case just check if a recurrence is before the interval end
+ return next <= endDate;
+}
+
+QOrganizerItem MKCalEngine::item(const QOrganizerItemId& itemId, const QOrganizerItemFetchHint& fetchHint, QOrganizerManager::Error* error) const
+{
+ Q_UNUSED(fetchHint);
+ KCalCore::Incidence::Ptr theIncidence = incidence(itemId);
+ if (!theIncidence) {
+ *error = QOrganizerManager::DoesNotExistError;
+ return QOrganizerItem();
+ }
+ QOrganizerItem item;
+ if (convertIncidenceToItem(theIncidence, &item)) {
+ return item;
+ } else {
+ *error = QOrganizerManager::DoesNotExistError;
+ return QOrganizerItem();
+ }
+}
+
+bool MKCalEngine::saveItems(QList<QOrganizerItem>* items, QMap<int, QOrganizerManager::Error>* errorMap, QOrganizerManager::Error* error)
+{
+ if (!items) {
+ *error = QOrganizerManager::BadArgumentError;
+ return false;
+ }
+
+ QOrganizerItemChangeSet ics;
+ QOrganizerManager::Error tempError = QOrganizerManager::NoError;
+ *error = QOrganizerManager::NoError;
+ for (int i = 0; i < items->size(); i++) {
+ QOrganizerItem item = items->at(i);
+ if (internalSaveItem(&ics, &item, &tempError)) {
+ items->replace(i, item);
+ } else {
+ *error = tempError;
+ errorMap->insert(i, tempError);
+ }
+ }
+
+ d->m_storagePtr->save(); // commit all changes to the database.
+ ics.emitSignals(this);
+ return *error == QOrganizerManager::NoError;
+}
+
+bool MKCalEngine::saveItem(QOrganizerItem* item, QOrganizerManager::Error* error)
+{
+ QOrganizerItemChangeSet ics;
+ bool retn = internalSaveItem(&ics, item, error);
+ if (retn) {
+ d->m_storagePtr->save(); // commit all changes to the database.
+ ics.emitSignals(this);
+ }
+
+ return retn;
+}
+
+bool MKCalEngine::internalSaveItem(QOrganizerItemChangeSet* ics, QOrganizerItem* item, QOrganizerManager::Error* error)
+{
+ // ensure that the organizeritem's details conform to their definitions
+ if (!validateItem(*item, error)) {
+ return false;
+ }
+
+ KCalCore::Incidence::Ptr theIncidence = softSaveItem(ics, item, error);
+ return (!theIncidence.isNull());
+}
+
+bool MKCalEngine::removeItems(const QList<QOrganizerItemId>& itemIds, QMap<int, QOrganizerManager::Error>* errorMap, QOrganizerManager::Error* error)
+{
+ QOrganizerItemChangeSet ics;
+ *error = QOrganizerManager::NoError;
+ for (int i = 0; i < itemIds.size(); i++) {
+ QOrganizerItemId id = itemIds[i];
+ KCalCore::Incidence::Ptr theIncidence = incidence(id);
+ if (!theIncidence) {
+ *error = QOrganizerManager::DoesNotExistError;
+ errorMap->insert(i, QOrganizerManager::DoesNotExistError);
+ continue;
+ }
+ if (theIncidence->recurs()) {
+ if (theIncidence->type() == KCalCore::IncidenceBase::TypeEvent) {
+ if (!d->m_calendarBackendPtr->deleteEventInstances(
+ theIncidence.staticCast<KCalCore::Event>())) {
+ *error = QOrganizerManager::UnspecifiedError;
+ errorMap->insert(i, QOrganizerManager::UnspecifiedError);
+ }
+ } else if (theIncidence->type() == KCalCore::IncidenceBase::TypeTodo) {
+ if (!d->m_calendarBackendPtr->deleteTodoInstances(
+ theIncidence.staticCast<KCalCore::Todo>())) {
+ *error = QOrganizerManager::UnspecifiedError;
+ errorMap->insert(i, QOrganizerManager::UnspecifiedError);
+ }
+ }
+ }
+ if (!d->m_calendarBackendPtr->deleteIncidence(theIncidence)) {
+ *error = QOrganizerManager::UnspecifiedError;
+ errorMap->insert(i, QOrganizerManager::UnspecifiedError);
+ } else {
+ ics.insertRemovedItem(id);
+ }
+ }
+
+ d->m_storagePtr->save();
+ ics.emitSignals(this);
+ return *error == QOrganizerManager::NoError;
+}
+
+QMap<QString, QOrganizerItemDetailDefinition> MKCalEngine::detailDefinitions(const QString& itemType, QOrganizerManager::Error* error) const
+{
+ *error = QOrganizerManager::NoError;
+ return schemaDefinitions().value(itemType);
+}
+
+QOrganizerItemDetailDefinition MKCalEngine::detailDefinition(const QString& definitionId, const QString& itemType, QOrganizerManager::Error* error) const
+{
+ /* TODO - the default implementation just calls the base detailDefinitions function. If that's inefficent, implement this */
+ return QOrganizerManagerEngine::detailDefinition(definitionId, itemType, error);
+}
+
+bool MKCalEngine::saveDetailDefinition(const QOrganizerItemDetailDefinition& def, const QString& itemType, QOrganizerManager::Error* error)
+{
+ /* TODO - if you support adding custom fields, do that here. Otherwise call the base functionality. */
+ return QOrganizerManagerEngine::saveDetailDefinition(def, itemType, error);
+}
+
+bool MKCalEngine::removeDetailDefinition(const QString& definitionId, const QString& itemType, QOrganizerManager::Error* error)
+{
+ /* TODO - if you support removing custom fields, do that here. Otherwise call the base functionality. */
+ return QOrganizerManagerEngine::removeDetailDefinition(definitionId, itemType, error);
+}
+
+QOrganizerCollection MKCalEngine::defaultCollection(QOrganizerManager::Error* error) const
+{
+ *error = QOrganizerManager::NoError;
+ mKCal::Notebook::Ptr defaultNotebook = d->m_storagePtr->defaultNotebook();
+ if (defaultNotebook) {
+ return convertNotebookToCollection(defaultNotebook);
+ }
+
+ // no default collection; create one.
+ return convertNotebookToCollection(d->m_storagePtr->createDefaultNotebook("defaultNotebook"));
+}
+
+QOrganizerCollection MKCalEngine::collection(const QOrganizerCollectionId& collectionId, QOrganizerManager::Error* error) const
+{
+ QString notebookUid = MKCalCollectionId::id_cast(collectionId)->uid();
+ mKCal::Notebook::Ptr notebookPtr;
+ if (notebookUid.isEmpty() || !(notebookPtr = d->m_storagePtr->notebook(notebookUid))) {
+ *error = QOrganizerManager::DoesNotExistError;
+ return QOrganizerCollection();
+ }
+ *error = QOrganizerManager::NoError;
+ return convertNotebookToCollection(notebookPtr);
+}
+
+QList<QOrganizerCollection> MKCalEngine::collections(QOrganizerManager::Error* error) const
+{
+ QList<QOrganizerCollection> retn;
+ mKCal::Notebook::List allNotebooks(d->m_storagePtr->notebooks());
+ foreach(mKCal::Notebook::Ptr currNotebook, allNotebooks) {
+ retn.append(convertNotebookToCollection(currNotebook));
+ }
+
+ *error = QOrganizerManager::NoError;
+ return retn;
+}
+
+bool MKCalEngine::saveCollection(QOrganizerCollection* collection, QOrganizerManager::Error* error)
+{
+ *error = QOrganizerManager::NoError;
+ bool retn = false;
+ QOrganizerCollectionId colId = collection->id();
+
+ if (colId.isNull()) {
+ // new collection.
+ mKCal::Notebook::Ptr notebookPtr(new mKCal::Notebook);
+ convertCollectionToNotebook(*collection, notebookPtr);
+ retn = d->m_storagePtr->addNotebook(notebookPtr);
+ if (!retn) {
+ *error = QOrganizerManager::UnspecifiedError;
+ } else {
+ // update the collection with its id.
+ QOrganizerCollectionId newId(new MKCalCollectionId(notebookPtr->uid()));
+ collection->setId(newId);
+ }
+
+ return retn;
+ }
+
+ // retrieve the uid from the collection id
+ // to try and get a pre-existing notebook.
+ QString notebookUid = MKCalCollectionId::id_cast(colId)->uid();
+ mKCal::Notebook::Ptr notebookPtr;
+ if (notebookUid.isEmpty() || !(notebookPtr = d->m_storagePtr->notebook(notebookUid))) {
+ // this notebook has been deleted (or never existed).
+ *error = QOrganizerManager::DoesNotExistError;
+ return false;
+ }
+ convertCollectionToNotebook(*collection, notebookPtr);
+ retn = d->m_storagePtr->updateNotebook(notebookPtr);
+ if (!retn) {
+ *error = QOrganizerManager::UnspecifiedError;
+ }
+
+ return retn;
+}
+
+bool MKCalEngine::removeCollection(const QOrganizerCollectionId& collectionId, QOrganizerManager::Error* error)
+{
+ // first, check to see if it's the default collection.
+ if (defaultCollection(error).id() == collectionId) {
+ *error = QOrganizerManager::PermissionsError;
+ return false;
+ }
+
+ // otherwise, it's a potentially removable collection.
+ QString notebookUid = MKCalCollectionId::id_cast(collectionId)->uid();
+ mKCal::Notebook::Ptr notebookPtr;
+ if (!notebookUid.isEmpty() && (notebookPtr = d->m_storagePtr->notebook(notebookUid))) {
+ if (!d->m_storagePtr->deleteNotebook(notebookPtr)) {
+ *error = QOrganizerManager::UnspecifiedError;
+ return false;
+ } else {
+ // success.
+ *error = QOrganizerManager::NoError;
+ d->m_storagePtr->save(); // commit all changes to the database.
+ return true;
+ }
+ }
+
+ *error = QOrganizerManager::DoesNotExistError;
+ return false;
+}
+
+bool MKCalEngine::startRequest(QOrganizerAbstractRequest* req)
+{
+ d->m_asynchProcess->addRequest(req);
+ return true;
+}
+
+bool MKCalEngine::cancelRequest(QOrganizerAbstractRequest* req)
+{
+ return d->m_asynchProcess->cancelRequest(req);
+}
+
+bool MKCalEngine::waitForRequestFinished(QOrganizerAbstractRequest* req, int msecs)
+{
+ return d->m_asynchProcess->waitForRequestFinished(req, msecs);
+}
+
+void MKCalEngine::requestDestroyed(QOrganizerAbstractRequest* req)
+{
+ return d->m_asynchProcess->requestDestroyed(req);
+}
+
+bool MKCalEngine::hasFeature(QOrganizerManager::ManagerFeature feature, const QString& itemType) const
+{
+ // TODO - the answer to the question may depend on the type
+ Q_UNUSED(itemType);
+ switch(feature) {
+ case QOrganizerManager::MutableDefinitions:
+ // TODO If you support save/remove detail definition, return true
+ return false;
+
+ case QOrganizerManager::Anonymous:
+ // TODO if this engine is anonymous (e.g. no other engine can share the data) return true
+ // (mostly for an in memory engine)
+ return false;
+ case QOrganizerManager::ChangeLogs:
+ // TODO if this engine supports filtering by last modified/created/removed timestamps, return true
+ return false;
+ }
+ return false;
+}
+
+bool MKCalEngine::isFilterSupported(const QOrganizerItemFilter& filter) const
+{
+ // TODO if you engine can natively support the filter, return true. Otherwise you should emulate support in the item{Ids} functions.
+ Q_UNUSED(filter);
+ return false;
+}
+
+QList<int> MKCalEngine::supportedDataTypes() const
+{
+ QList<int> ret;
+ // TODO - tweak which data types this engine understands
+ ret << QVariant::String;
+ ret << QVariant::Date;
+ ret << QVariant::DateTime;
+ ret << QVariant::Time;
+
+ return ret;
+}
+
+QStringList MKCalEngine::supportedItemTypes() const
+{
+ // TODO - return which [predefined] types this engine supports
+ QStringList ret;
+
+ ret << QOrganizerItemType::TypeEvent;
+ ret << QOrganizerItemType::TypeEventOccurrence;
+ ret << QOrganizerItemType::TypeJournal;
+ ret << QOrganizerItemType::TypeNote;
+ ret << QOrganizerItemType::TypeTodo;
+ ret << QOrganizerItemType::TypeTodoOccurrence;
+
+ return ret;
+}
+
+QMap<QString, QMap<QString, QOrganizerItemDetailDefinition> > MKCalEngine::schemaDefinitions() const {
+ // lazy initialisation of schema definitions.
+ if (d->m_definitions.isEmpty()) {
+ // Loop through default schema definitions
+ QMap<QString, QMap<QString, QOrganizerItemDetailDefinition> > schema
+ = QOrganizerManagerEngine::schemaDefinitions();
+ foreach (const QString& itemType, schema.keys()) {
+ // Only add the item types that we support
+ if (itemType == QOrganizerItemType::TypeEvent ||
+ itemType == QOrganizerItemType::TypeEventOccurrence ||
+ itemType == QOrganizerItemType::TypeTodo ||
+ itemType == QOrganizerItemType::TypeTodoOccurrence ||
+ itemType == QOrganizerItemType::TypeJournal ||
+ itemType == QOrganizerItemType::TypeNote) {
+ QMap<QString, QOrganizerItemDetailDefinition> definitions
+ = schema.value(itemType);
+
+ QMap<QString, QOrganizerItemDetailDefinition> supportedDefinitions;
+
+ QMapIterator<QString, QOrganizerItemDetailDefinition> it(definitions);
+ while (it.hasNext()) {
+ it.next();
+ // Only add the definitions that we support
+ if (it.key() == QOrganizerItemType::DefinitionName ||
+ it.key() == QOrganizerItemDescription::DefinitionName ||
+ it.key() == QOrganizerItemDisplayLabel::DefinitionName ||
+ it.key() == QOrganizerItemRecurrence::DefinitionName ||
+ it.key() == QOrganizerEventTime::DefinitionName ||
+ it.key() == QOrganizerItemGuid::DefinitionName ||
+ it.key() == QOrganizerItemParent::DefinitionName ||
+ it.key() == QOrganizerTodoTime::DefinitionName ||
+ it.key() == QOrganizerItemLocation::DefinitionName) {
+ supportedDefinitions.insert(it.key(), it.value());
+ }
+ }
+ d->m_definitions.insert(itemType, supportedDefinitions);
+ }
+ }
+ }
+ return d->m_definitions;
+}
+
+// observer for changes from mKCal.
+void MKCalEngine::storageModified(mKCal::ExtendedStorage* storage, const QString& info)
+{
+ Q_UNUSED(info);
+ if (storage != d->m_storagePtr) {
+ qWarning("MKCalEngine::storageModified() received change notification from unknown storage!");
+ return;
+ }
+
+ // XXX The mKCal docs says to not use this function because it's too slow!
+ // Can we optimise by only loading items from the date range required, perhaps lazily?
+ d->m_storagePtr->load();
+
+ emit dataChanged();
+}
+
+// observer for changes from mKCal.
+void MKCalEngine::storageProgress(mKCal::ExtendedStorage* storage, const QString& info)
+{
+ Q_UNUSED(storage);
+ Q_UNUSED(info);
+ // do nothing.
+}
+
+// observer for changes from mKCal.
+void MKCalEngine::storageFinished(mKCal::ExtendedStorage* storage, bool error, const QString& info)
+{
+ Q_UNUSED(storage);
+ Q_UNUSED(error);
+ Q_UNUSED(info);
+ // do nothing.
+}
+
+KCalCore::Incidence::Ptr MKCalEngine::incidence(const QOrganizerItemId& itemId) const
+{
+ const MKCalItemId *id = MKCalItemId::id_cast(itemId);
+ return id->id().isEmpty() ? KCalCore::Incidence::Ptr() : d->m_calendarBackendPtr->incidence(id->id(), id->rid());
+}
+
+KCalCore::Incidence::Ptr MKCalEngine::detachedIncidenceFromItem(const QOrganizerItem& item) const
+{
+ QOrganizerItemParent parentDetail(item.detail<QOrganizerItemParent>());
+ QOrganizerItemId parentId(parentDetail.parentId());
+ QDate originalDate(parentDetail.originalDate());
+ QString guid(item.guid());
+
+ KCalCore::Incidence::Ptr parentIncidence;
+ if (!parentId.isNull()) {
+ QString parentUid(MKCalItemId::id_cast(parentId)->id());
+ if (!guid.isEmpty() && guid != parentUid)
+ return KCalCore::Incidence::Ptr();
+ parentIncidence = incidence(parentId);
+ } else if (!guid.isEmpty()) {
+ parentIncidence = d->m_calendarBackendPtr->incidence(guid);
+ }
+ if (parentIncidence.isNull() || !originalDate.isValid())
+ return KCalCore::Incidence::Ptr();
+ return d->m_calendarBackendPtr->dissociateSingleOccurrence(
+ parentIncidence, KDateTime(originalDate), KDateTime::LocalZone);
+}
+
+/*!
+ * Saves \a item to the manager, but doesn't persist the change to disk.
+ * Sets \a error appropriately if if couldn't be saved.
+ */
+KCalCore::Incidence::Ptr MKCalEngine::softSaveItem(QOrganizerItemChangeSet* ics, QOrganizerItem* item, QOrganizerManager::Error* error)
+{
+ bool itemIsNew = item->id().isNull() || d->m_managerUri != item->id().managerUri();
+ bool itemIsOccurrence = (item->type() == QOrganizerItemType::TypeEventOccurrence) ||
+ (item->type() == QOrganizerItemType::TypeTodoOccurrence);
+ KCalCore::Incidence::Ptr newIncidence(0);
+
+ // extract the collection id and ensure that we save it in the correct notebook
+ QOrganizerCollectionId destinationCollectionId = item->collectionId();
+ QString destinationNotebookUid;
+
+ if (destinationCollectionId.isNull()) {
+ // save to default collection.
+ destinationNotebookUid = d->m_storagePtr->defaultNotebook()->uid();
+ // note that we readjust the destinationNotebookUid if the item is an occurrence, so that it is always saved in the parent's notebook.
+ } else {
+ // save to the specified collection (if possible)
+ destinationNotebookUid = MKCalCollectionId::id_cast(destinationCollectionId)->uid();
+ }
+
+ // mkCal backend does not support setting of notebooks for item occurrences, because of this the item collection id either should be null
+ // or equal with it's parent collection id
+ if (itemIsOccurrence && !destinationCollectionId.isNull()) {
+ // find parent id
+ QOrganizerItemParent parentDetail(item->detail<QOrganizerItemParent>());
+ QOrganizerItemId parentId(parentDetail.parentId());
+ QString parentUid = parentId.isNull() ? item->guid() : MKCalItemId::id_cast(parentId)->id();
+
+ // if item collection id and parent id are not null, then item collection id must be equal with parent collection id
+ if (!destinationNotebookUid.isEmpty() && !parentUid.isEmpty() && d->m_calendarBackendPtr->notebook(parentUid) != destinationNotebookUid) {
+ *error = QOrganizerManager::InvalidCollectionError;
+ return KCalCore::Incidence::Ptr();
+ }
+ } else if (!(d->m_calendarBackendPtr->hasValidNotebook(destinationNotebookUid))) {
+ // fail if destination notebook does not exist in the storage
+ *error = QOrganizerManager::InvalidCollectionError;
+ return KCalCore::Incidence::Ptr();
+ }
+
+
+ // First, either create the incidence or get the correct existing one
+ if (itemIsNew) {
+ if (itemIsOccurrence) {
+ newIncidence = detachedIncidenceFromItem(*item);
+ if (newIncidence.isNull()) {
+ *error = QOrganizerManager::InvalidOccurrenceError;
+ return KCalCore::Incidence::Ptr(0);
+ }
+ } else {
+ if (item->type() == QOrganizerItemType::TypeEvent) {
+ newIncidence = KCalCore::Event::Ptr(new KCalCore::Event);
+ } else if (item->type() == QOrganizerItemType::TypeTodo) {
+ newIncidence = KCalCore::Todo::Ptr(new KCalCore::Todo);
+ } else if (item->type() == QOrganizerItemType::TypeNote
+ || item->type() == QOrganizerItemType::TypeJournal) {
+ newIncidence = KCalCore::Journal::Ptr(new KCalCore::Journal);
+ } else {
+ *error = QOrganizerManager::InvalidItemTypeError;
+ return KCalCore::Incidence::Ptr(0);
+ }
+ }
+ } else {
+ newIncidence = incidence(item->id());
+ if (!newIncidence) {
+ *error = QOrganizerManager::DoesNotExistError;
+ return KCalCore::Incidence::Ptr(0);
+ }
+ }
+
+ Q_ASSERT(!newIncidence.isNull());
+
+ // second, populate the incidence with the item's details
+ if (item->type() == QOrganizerItemType::TypeEvent) {
+ convertQEventToKEvent(*item, newIncidence, true);
+ } else if (item->type() == QOrganizerItemType::TypeEventOccurrence) {
+ convertQEventToKEvent(*item, newIncidence, false);
+ } else if (item->type() == QOrganizerItemType::TypeTodo) {
+ convertQTodoToKTodo(*item, newIncidence, true);
+ } else if (item->type() == QOrganizerItemType::TypeTodoOccurrence) {
+ convertQTodoToKTodo(*item, newIncidence, false);
+ } else if (item->type() == QOrganizerItemType::TypeNote) {
+ convertQNoteToKNote(*item, newIncidence);
+ } else if (item->type() == QOrganizerItemType::TypeJournal) {
+ convertQJournalToKJournal(*item, newIncidence);
+ }
+
+ // third, add it if it is new
+ if (itemIsNew) {
+ d->m_calendarBackendPtr->addIncidence(newIncidence);
+ } // if it is not new, nothing needs to be done (incidences are live objects)
+
+ bool success = itemIsOccurrence || d->m_calendarBackendPtr->setNotebook(newIncidence, destinationNotebookUid);
+ if (!success) {
+ // unable to save to the correct notebook.
+ *error = QOrganizerManager::InvalidCollectionError;
+ // XXX TODO: roll back the save from memory.
+ } else {
+ *error = QOrganizerManager::NoError;
+ }
+
+ // set the id of the item.
+ QString kId = newIncidence->uid();
+ item->setId(QOrganizerItemId(new MKCalItemId(
+ kId,
+ newIncidence->hasRecurrenceId() ? newIncidence->recurrenceId() : KDateTime())));
+ item->setGuid(kId);
+
+ // modify the changeset as required.
+ if (itemIsNew) {
+ ics->insertAddedItem(item->id());
+ } else {
+ ics->insertChangedItem(item->id());
+ }
+
+ return newIncidence;
+}
+
+/*!
+ * Converts \a qEvent into an Incidence which is of subclass Event. The caller is responsible
+ * for deleting the object.
+ */
+void MKCalEngine::convertQEventToKEvent(const QOrganizerItem& item, KCalCore::Incidence::Ptr incidence, bool recurs)
+{
+ KCalCore::Event::Ptr kEvent(incidence.staticCast<KCalCore::Event>());
+ convertCommonDetailsToIncidenceFields(item, kEvent);
+ QOrganizerEventTime eventTime(item.detail<QOrganizerEventTime>());
+ kEvent->setDtStart(KDateTime(eventTime.startDateTime()));
+ kEvent->setDtEnd(KDateTime(eventTime.endDateTime()));
+ if (recurs)
+ convertQRecurrenceToKRecurrence(item.detail<QOrganizerItemRecurrence>(),
+ eventTime.startDateTime().date(),
+ kEvent->recurrence());
+}
+
+/*!
+ * Converts \a qTodo into an Incidence which is of subclass Todo. The caller is responsible
+ * for deleting the object.
+ */
+void MKCalEngine::convertQTodoToKTodo(const QOrganizerItem& item, KCalCore::Incidence::Ptr incidence, bool recurs)
+{
+ KCalCore::Todo::Ptr kTodo(incidence.staticCast<KCalCore::Todo>());
+ convertCommonDetailsToIncidenceFields(item, kTodo);
+ QOrganizerTodoTime todoTime(item.detail<QOrganizerTodoTime>());
+ kTodo->setDtStart(KDateTime(todoTime.startDateTime()));
+ kTodo->setDtDue(KDateTime(todoTime.dueDateTime()));
+ if (recurs)
+ convertQRecurrenceToKRecurrence(item.detail<QOrganizerItemRecurrence>(),
+ todoTime.startDateTime().date(),
+ kTodo->recurrence());
+}
+
+/*!
+ * Converts \a qJournal into an Incidence which is of subclass Journal. The caller is responsible
+ * for deleting the object.
+ */
+void MKCalEngine::convertQJournalToKJournal(const QOrganizerItem& item, KCalCore::Incidence::Ptr incidence)
+{
+ KCalCore::Journal::Ptr kJournal(incidence.staticCast<KCalCore::Journal>());
+ convertCommonDetailsToIncidenceFields(item, kJournal);
+}
+
+/*!
+ * Converts \a qNote into an Incidence which is of subclass Journal. The caller is responsible
+ * for deleting the object.
+ */
+void MKCalEngine::convertQNoteToKNote(const QOrganizerItem& item, KCalCore::Incidence::Ptr incidence)
+{
+ KCalCore::Journal::Ptr kJournal(incidence.staticCast<KCalCore::Journal>());
+ convertCommonDetailsToIncidenceFields(item, kJournal);
+}
+
+/*!
+ * Converts the item-common details of \a item to fields to set in \a incidence.
+ */
+void MKCalEngine::convertCommonDetailsToIncidenceFields(
+ const QOrganizerItem& item, KCalCore::Incidence::Ptr incidence)
+{
+ if (item.id().isNull() && !item.guid().isEmpty())
+ incidence->setUid(item.guid());
+ incidence->setDescription(item.description());
+ incidence->setSummary(item.displayLabel());
+ QOrganizerItemLocation loc = static_cast<QOrganizerItemLocation>(item.detail(QOrganizerItemLocation::DefinitionName));
+ incidence->setLocation(loc.label());
+}
+
+/*! Converts \a qRecurrence into the libkcal equivalent, stored in \a kRecurrence. kRecurrence must
+ * point to an initialized Recurrence.
+ */
+void MKCalEngine::convertQRecurrenceToKRecurrence(
+ const QOrganizerItemRecurrence& qRecurrence, const QDate& startDate,
+ KCalCore::Recurrence* kRecurrence)
+{
+ kRecurrence->clear();
+
+ foreach (const QOrganizerRecurrenceRule& rrule, qRecurrence.recurrenceRules()) {
+ if (rrule.frequency() != QOrganizerRecurrenceRule::Invalid) {
+ KCalCore::RecurrenceRule* krrule = createKRecurrenceRule(kRecurrence, startDate, rrule);
+ kRecurrence->addRRule(krrule);
+ }
+ }
+
+ foreach (const QOrganizerRecurrenceRule& exrule, qRecurrence.exceptionRules()) {
+ if (exrule.frequency() != QOrganizerRecurrenceRule::Invalid) {
+ KCalCore::RecurrenceRule* kexrule = createKRecurrenceRule(kRecurrence, startDate, exrule);
+ kRecurrence->addExRule(kexrule);
+ }
+ }
+
+ foreach (const QDate& rdate, qRecurrence.recurrenceDates())
+ kRecurrence->addRDate(rdate);
+
+ foreach (const QDate& exdate, qRecurrence.exceptionDates())
+ kRecurrence->addExDate(exdate);
+}
+
+KCalCore::RecurrenceRule* MKCalEngine::createKRecurrenceRule(
+ KCalCore::Recurrence* kRecurrence,
+ const QDate& startDate,
+ const QOrganizerRecurrenceRule& qRRule)
+{
+ Q_UNUSED(kRecurrence);
+ KCalCore::RecurrenceRule* kRRule = new KCalCore::RecurrenceRule();
+ switch (qRRule.frequency()) {
+ case QOrganizerRecurrenceRule::Invalid:
+ break;
+ case QOrganizerRecurrenceRule::Daily:
+ kRRule->setRecurrenceType(KCalCore::RecurrenceRule::rDaily);
+ break;
+ case QOrganizerRecurrenceRule::Weekly:
+ kRRule->setRecurrenceType(KCalCore::RecurrenceRule::rWeekly);
+ break;
+ case QOrganizerRecurrenceRule::Monthly:
+ kRRule->setRecurrenceType(KCalCore::RecurrenceRule::rMonthly);
+ break;
+ case QOrganizerRecurrenceRule::Yearly:
+ kRRule->setRecurrenceType(KCalCore::RecurrenceRule::rYearly);
+ break;
+ }
+ kRRule->setFrequency(qRRule.interval());
+ if (qRRule.limitCount() > 0) {
+ kRRule->setDuration(qRRule.limitCount());
+ }
+ kRRule->setStartDt(KDateTime(startDate));
+ QDate endDate = qRRule.limitDate();
+ if (endDate.isValid()) {
+ kRRule->setEndDt(KDateTime(endDate));
+ }
+
+ //QOrganizerRecurrenceRule does not support position associated with dayOfWeek so we will always
+ //take the first position. When this will be implemented in the future please fix the code below.
+ int pos = qRRule.positions().size() ? *qRRule.positions().begin() : 0;
+
+ QList<KCalCore::RecurrenceRule::WDayPos> daysOfWeek;
+ foreach (Qt::DayOfWeek dayOfWeek, qRRule.daysOfWeek()) {
+ daysOfWeek.append(KCalCore::RecurrenceRule::WDayPos(pos, (short)dayOfWeek));
+ }
+ kRRule->setByDays(daysOfWeek);
+
+ kRRule->setByMonthDays(qRRule.daysOfMonth().toList());
+
+ kRRule->setByYearDays(qRRule.daysOfYear().toList());
+
+ kRRule->setByWeekNumbers(qRRule.weeksOfYear().toList());
+
+ QList<int> months;
+ foreach (QOrganizerRecurrenceRule::Month month, qRRule.monthsOfYear()) {
+ months.append((int)month);
+ }
+ kRRule->setByMonths(months);
+
+ kRRule->setWeekStart((short)qRRule.firstDayOfWeek());
+
+ return kRRule;
+}
+
+/*!
+ * Converts a kcal \a incidence into a QOrganizer \a item.
+ * \a incidence and \a item must both not be null.
+ * \item must point to a default-constructed item.
+ */
+bool MKCalEngine::convertIncidenceToItem(
+ KCalCore::Incidence::Ptr incidence, QOrganizerItem* item) const
+{
+ convertCommonIncidenceFieldsToDetails(incidence, item);
+ if (incidence->type() == KCalCore::IncidenceBase::TypeEvent) {
+ convertKEventToQEvent(incidence.staticCast<KCalCore::Event>(), item);
+ } else if (incidence->type() == KCalCore::IncidenceBase::TypeTodo) {
+ convertKTodoToQTodo(incidence.staticCast<KCalCore::Todo>(), item);
+ } else if (incidence->type() == KCalCore::IncidenceBase::TypeJournal) {
+ convertKJournalToQJournal(incidence.staticCast<KCalCore::Journal>(), item);
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+/*!
+ * Converts a kcal Event.
+ */
+void MKCalEngine::convertKEventToQEvent(KCalCore::Event::Ptr e, QOrganizerItem* item) const
+{
+ QOrganizerEvent* event = static_cast<QOrganizerEvent*>(item);
+ if (!e->dtStart().isNull())
+ event->setStartDateTime(e->dtStart().dateTime());
+ if (!e->dtEnd().isNull())
+ event->setEndDateTime(e->dtEnd().dateTime());
+
+ if (e->hasRecurrenceId()) {
+ item->setType(QOrganizerItemType::TypeEventOccurrence);
+ QOrganizerEventOccurrence* eventOccurrence = static_cast<QOrganizerEventOccurrence*>(item);
+ eventOccurrence->setOriginalDate(e->recurrenceId().date());
+ eventOccurrence->setParentId(QOrganizerItemId(new MKCalItemId(
+ e->uid(),
+ KDateTime())));
+ } else {
+ item->setType(QOrganizerItemType::TypeEvent);
+ convertKRecurrenceToQRecurrence(e->recurrence(), item);
+ }
+}
+
+/*!
+ * Converts a kcal Todo.
+ */
+void MKCalEngine::convertKTodoToQTodo(KCalCore::Todo::Ptr t, QOrganizerItem* item) const
+{
+ QOrganizerTodo* todo = static_cast<QOrganizerTodo*>(item);
+ if (!t->dtStart().isNull())
+ todo->setStartDateTime(t->dtStart().dateTime());
+ if (!t->dtDue().isNull())
+ todo->setDueDateTime(t->dtDue().dateTime());
+
+ if (t->hasRecurrenceId()) {
+ item->setType(QOrganizerItemType::TypeTodoOccurrence);
+ QOrganizerTodoOccurrence* todoOccurrence = static_cast<QOrganizerTodoOccurrence*>(item);
+ todoOccurrence->setOriginalDate(t->recurrenceId().date());
+ todoOccurrence->setParentId(QOrganizerItemId(new MKCalItemId(
+ t->uid(),
+ KDateTime())));
+ } else {
+ item->setType(QOrganizerItemType::TypeTodo);
+ convertKRecurrenceToQRecurrence(t->recurrence(), item);
+ }
+}
+
+/*!
+ * Converts a kcal Journal.
+ */
+void MKCalEngine::convertKJournalToQJournal(KCalCore::Journal::Ptr j, QOrganizerItem* item) const
+{
+ if (j->dtStart().isValid()) {
+ item->setType(QOrganizerItemType::TypeJournal);
+ static_cast<QOrganizerJournal*>(item)->setDateTime(j->dtStart().dateTime());
+ } else {
+ item->setType(QOrganizerItemType::TypeNote);
+ }
+}
+
+/*!
+ * Adds details to \a item based on fields found in \a incidence.
+ */
+void MKCalEngine::convertCommonIncidenceFieldsToDetails(
+ KCalCore::Incidence::Ptr incidence, QOrganizerItem* item) const
+{
+ item->setId(QOrganizerItemId(new MKCalItemId(
+ incidence->uid(),
+ incidence->hasRecurrenceId() ? incidence->recurrenceId() : KDateTime())));
+ item->setCollectionId(QOrganizerCollectionId(new MKCalCollectionId(
+ d->m_calendarBackendPtr->notebook(incidence))));
+
+ if (!incidence->summary().isEmpty())
+ item->setDisplayLabel(incidence->summary());
+ if (!incidence->description().isEmpty())
+ item->setDescription(incidence->description());
+
+ if (!incidence->location().isEmpty()) {
+ QOrganizerItemLocation location;
+ location.setLabel(incidence->location());
+ item->saveDetail(&location);
+ }
+
+ item->setGuid(incidence->uid());
+}
+
+void MKCalEngine::convertKRecurrenceToQRecurrence(const KCalCore::Recurrence* kRecurrence, QOrganizerItem* item) const
+{
+ bool modified = false;
+ QOrganizerItemRecurrence recurrence;
+ foreach (const KCalCore::RecurrenceRule* kRRule, kRecurrence->rRules()) {
+ QOrganizerRecurrenceRule rrule(createQRecurrenceRule(kRRule));
+ if (rrule.frequency() != QOrganizerRecurrenceRule::Invalid) {
+ recurrence.setRecurrenceRules(QSet<QOrganizerRecurrenceRule>() << rrule);
+ modified = true;
+ }
+ }
+ foreach (const KCalCore::RecurrenceRule* kExRule, kRecurrence->exRules()) {
+ QOrganizerRecurrenceRule exrule(createQRecurrenceRule(kExRule));
+ if (exrule.frequency() != QOrganizerRecurrenceRule::Invalid) {
+ recurrence.setExceptionRules(QSet<QOrganizerRecurrenceRule>() << exrule);
+ modified = true;
+ }
+ }
+ if (!kRecurrence->rDates().isEmpty()) {
+ recurrence.setRecurrenceDates(kRecurrence->rDates().toSet());
+ modified = true;
+ }
+ if (!kRecurrence->exDates().isEmpty()) {
+ recurrence.setExceptionDates(kRecurrence->exDates().toSet());
+ modified = true;
+ }
+ if (modified)
+ item->saveDetail(&recurrence);
+}
+
+QOrganizerRecurrenceRule MKCalEngine::createQRecurrenceRule(const KCalCore::RecurrenceRule* kRRule) const
+{
+ QOrganizerRecurrenceRule qRRule;
+ switch (kRRule->recurrenceType()) {
+ case KCalCore::RecurrenceRule::rDaily:
+ qRRule.setFrequency(QOrganizerRecurrenceRule::Daily);
+ break;
+ case KCalCore::RecurrenceRule::rWeekly:
+ qRRule.setFrequency(QOrganizerRecurrenceRule::Weekly);
+ break;
+ case KCalCore::RecurrenceRule::rMonthly:
+ qRRule.setFrequency(QOrganizerRecurrenceRule::Monthly);
+ break;
+ case KCalCore::RecurrenceRule::rYearly:
+ qRRule.setFrequency(QOrganizerRecurrenceRule::Yearly);
+ break;
+ default:
+ return qRRule;
+ }
+
+ qRRule.setInterval(kRRule->frequency());
+
+ if (kRRule->duration() > 0) {
+ qRRule.setLimit(kRRule->duration());
+ } else {
+ QDate limitDate(kRRule->endDt().dateTime().date());
+ if (limitDate.isValid())
+ qRRule.setLimit(limitDate);
+ }
+
+ QSet<Qt::DayOfWeek> daysOfWeek;
+ foreach (KCalCore::RecurrenceRule::WDayPos wday, kRRule->byDays())
+ daysOfWeek.insert(static_cast<Qt::DayOfWeek>(wday.day()));
+ qRRule.setDaysOfWeek(daysOfWeek);
+
+ qRRule.setDaysOfMonth(kRRule->byMonthDays().toSet());
+
+ qRRule.setDaysOfYear(kRRule->byYearDays().toSet());
+
+ qRRule.setWeeksOfYear(kRRule->byWeekNumbers().toSet());
+
+ QSet<QOrganizerRecurrenceRule::Month> months;
+ foreach (int month, kRRule->byMonths()) {
+ months.insert(static_cast<QOrganizerRecurrenceRule::Month>(month));
+ }
+ qRRule.setMonthsOfYear(months);
+
+ qRRule.setFirstDayOfWeek(static_cast<Qt::DayOfWeek>(kRRule->weekStart()));
+
+ return qRRule;
+}
+
+/*!
+ * Convert mKCal notebook to QOrganizerCollection
+ */
+QOrganizerCollection MKCalEngine::convertNotebookToCollection(mKCal::Notebook::Ptr notebook) const
+{
+ QOrganizerCollection retn;
+
+ QString string;
+ QStringList stringList;
+ QDateTime dateTime;
+
+ if (!(string = notebook->name()).isEmpty())
+ retn.setMetaData(QOrganizerCollection::KeyName, string);
+ if (!(string = notebook->color()).isEmpty())
+ retn.setMetaData(QOrganizerCollection::KeyColor, string);
+ if (!(string = notebook->description()).isEmpty())
+ retn.setMetaData(QOrganizerCollection::KeyDescription, string);
+ // XXX We lose the timezone information here!:
+ if ((dateTime = notebook->syncDate().dateTime()).isValid())
+ retn.setMetaData(NotebookSyncDate, dateTime);
+ if ((dateTime = notebook->modifiedDate().dateTime()).isValid())
+ retn.setMetaData(NotebookModifiedDate, dateTime);
+ if (!(string = notebook->pluginName()).isEmpty())
+ retn.setMetaData(NotebookPluginName, string);
+ if (!(string = notebook->account()).isEmpty())
+ retn.setMetaData(NotebookAccount, string);
+ if (!(stringList = notebook->sharedWith()).isEmpty())
+ retn.setMetaData(NotebookSharedWith, stringList);
+ if (!(string = notebook->sharedWithStr()).isEmpty())
+ retn.setMetaData(NotebookSharedWithStr, string);
+ if (!(string = notebook->syncProfile()).isEmpty())
+ retn.setMetaData(NotebookSyncProfile, string);
+ int attachmentSize = notebook->attachmentSize();
+ if (attachmentSize >= 0)
+ retn.setMetaData(NotebookAttachmentSize, attachmentSize);
+
+ // Boolean flags that we always store
+ retn.setMetaData(NotebookIsDefault, notebook->isDefault());
+ retn.setMetaData(NotebookIsShareable, notebook->isShareable());
+ retn.setMetaData(NotebookIsShared, notebook->isShared());
+ retn.setMetaData(NotebookIsMaster, notebook->isMaster());
+ retn.setMetaData(NotebookIsOviSync, notebook->isOviSync());
+ retn.setMetaData(NotebookIsReadOnly, notebook->isReadOnly());
+ retn.setMetaData(NotebookIsVisible, notebook->isVisible());
+ retn.setMetaData(NotebookIsRunTimeOnly, notebook->isRunTimeOnly());
+ retn.setMetaData(NotebookEventsAllowed, notebook->eventsAllowed());
+ retn.setMetaData(NotebookJournalsAllowed, notebook->journalsAllowed());
+ retn.setMetaData(NotebookTodosAllowed, notebook->todosAllowed());
+
+ // now set the id of the collection.
+ QOrganizerCollectionId colId(new MKCalCollectionId(notebook->uid()));
+ retn.setId(colId);
+
+ // done
+ return retn;
+}
+
+/*!
+ * Convert QOrganizerCollection to mKCal notebook
+ */
+void MKCalEngine::convertCollectionToNotebook(const QOrganizerCollection& collection, mKCal::Notebook::Ptr notebook) const
+{
+ QVariant variant;
+ if (!(variant = collection.metaData(QOrganizerCollection::KeyName)).isNull())
+ notebook->setName(variant.toString());
+
+ if (!(variant = collection.metaData(QOrganizerCollection::KeyColor)).isNull())
+ notebook->setColor(variant.toString());
+ if (!(variant = collection.metaData(QOrganizerCollection::KeyDescription)).isNull())
+ notebook->setDescription(variant.toString());
+ if (!(variant = collection.metaData(NotebookSyncDate)).isNull())
+ notebook->setSyncDate(KDateTime(variant.toDateTime()));
+ if (!(variant = collection.metaData(NotebookModifiedDate)).isNull())
+ notebook->setModifiedDate(KDateTime(variant.toDateTime()));
+ if (!(variant = collection.metaData(NotebookPluginName)).isNull())
+ notebook->setPluginName(variant.toString());
+ if (!(variant = collection.metaData(NotebookAccount)).isNull())
+ notebook->setAccount(variant.toString());
+ if (!(variant = collection.metaData(NotebookAttachmentSize)).isNull())
+ notebook->setAttachmentSize(variant.toInt());
+ if (!(variant = collection.metaData(NotebookSharedWith)).isNull())
+ notebook->setSharedWith(variant.toStringList());
+ if (!(variant = collection.metaData(NotebookSharedWithStr)).isNull())
+ notebook->setSharedWithStr(variant.toString());
+ if (!(variant = collection.metaData(NotebookSyncProfile)).isNull())
+ notebook->setSyncProfile(variant.toString());
+
+ // Boolean flags
+ if (!(variant = collection.metaData(NotebookIsDefault)).isNull())
+ notebook->setIsDefault(variant.toBool());
+ if (!(variant = collection.metaData(NotebookIsShareable)).isNull())
+ notebook->setIsShareable(variant.toBool());
+ if (!(variant = collection.metaData(NotebookIsShared)).isNull())
+ notebook->setIsShared(variant.toBool());
+ if (!(variant = collection.metaData(NotebookIsMaster)).isNull())
+ notebook->setIsMaster(variant.toBool());
+ if (!(variant = collection.metaData(NotebookIsOviSync)).isNull())
+ notebook->setIsOviSync(variant.toBool());
+ if (!(variant = collection.metaData(NotebookIsReadOnly)).isNull())
+ notebook->setIsReadOnly(variant.toBool());
+ if (!(variant = collection.metaData(NotebookIsVisible)).isNull())
+ notebook->setIsVisible(variant.toBool());
+ if (!(variant = collection.metaData(NotebookIsRunTimeOnly)).isNull())
+ notebook->setRunTimeOnly(variant.toBool());
+ if (!(variant = collection.metaData(NotebookEventsAllowed)).isNull())
+ notebook->setEventsAllowed(variant.toBool());
+ if (!(variant = collection.metaData(NotebookJournalsAllowed)).isNull())
+ notebook->setJournalsAllowed(variant.toBool());
+ if (!(variant = collection.metaData(NotebookTodosAllowed)).isNull())
+ notebook->setTodosAllowed(variant.toBool());
+}
diff --git a/plugins/organizer/mkcal/mkcalengine.h b/plugins/organizer/mkcal/mkcalengine.h
new file mode 100644
index 0000000000..10b9738fa9
--- /dev/null
+++ b/plugins/organizer/mkcal/mkcalengine.h
@@ -0,0 +1,230 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MKCALENGINE_H
+#define MKCALENGINE_H
+
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QSharedData>
+#include <QMap>
+#include <QMultiMap>
+#include <QList>
+#include <QQueue>
+#include <QPair>
+#include <QSet>
+#include <QDateTime>
+#include <QString>
+#include <QObject>
+
+#include <extendedcalendar.h>
+#include <extendedstorage.h>
+#include <notebook.h>
+
+#include "qorganizeritem.h"
+#include "qorganizermanager.h"
+#include "qorganizermanagerengine.h"
+#include "qorganizermanagerenginefactory.h"
+#include "qorganizeritemdetaildefinition.h"
+#include "qorganizerabstractrequest.h"
+#include "qorganizeritemchangeset.h"
+
+QTM_BEGIN_NAMESPACE
+class QOrganizerEvent;
+class QOrganizerTodo;
+class QOrganizerNote;
+class QOrganizerJournal;
+class QOrganizerItemRecurrence;
+class QOrganizerRecurrenceRule;
+QTM_END_NAMESPACE
+
+QTM_USE_NAMESPACE
+
+class OrganizerAsynchManager; // helper class to process async requests
+
+class MKCalEngineFactory : public QObject, public QOrganizerManagerEngineFactory
+{
+ Q_OBJECT
+ Q_INTERFACES(QtMobility::QOrganizerManagerEngineFactory)
+ public:
+ QOrganizerManagerEngine* engine(const QMap<QString, QString>& parameters, QOrganizerManager::Error*);
+ QString managerName() const;
+ QOrganizerItemEngineId* createItemEngineId(const QMap<QString, QString>& parameters, const QString& engineIdString) const;
+ QOrganizerCollectionEngineId* createCollectionEngineId(const QMap<QString, QString>& parameters, const QString& engineIdString) const;
+};
+
+class MKCalEngineData : public QSharedData
+{
+public:
+ MKCalEngineData()
+ : QSharedData(),
+ m_calendarBackendPtr(new mKCal::ExtendedCalendar(KDateTime::Spec::LocalZone())),
+ m_storagePtr(mKCal::ExtendedCalendar::defaultStorage(m_calendarBackendPtr))
+ {
+ m_storagePtr->open();
+ m_storagePtr->load();
+ mKCal::Notebook::Ptr defaultNotebook = m_storagePtr->defaultNotebook();
+ if (!defaultNotebook)
+ m_storagePtr->createDefaultNotebook("defaultNotebook");
+ }
+
+ ~MKCalEngineData()
+ {
+ }
+
+ // map of organizeritem type to map of definition name to definitions:
+ mutable QMap<QString, QMap<QString, QOrganizerItemDetailDefinition> > m_definitions;
+
+ mKCal::ExtendedCalendar::Ptr m_calendarBackendPtr;
+ mKCal::ExtendedStorage::Ptr m_storagePtr;
+
+ // asynchronous request handler instance
+ OrganizerAsynchManager *m_asynchProcess;
+
+ QString m_managerUri;
+ QOrganizerItem m_converted;
+};
+
+class MKCalEngine : public QOrganizerManagerEngine, public mKCal::ExtendedStorageObserver
+{
+ Q_OBJECT
+
+public:
+ ~MKCalEngine();
+
+ /* URI reporting */
+ QString managerName() const;
+ QMap<QString, QString> managerParameters() const;
+ int managerVersion() const;
+
+ QList<QOrganizerItem> itemOccurrences(const QOrganizerItem& parentItem, const QDateTime& periodStart, const QDateTime& periodEnd, int maxCount, const QOrganizerItemFetchHint& fetchHint, QOrganizerManager::Error* error) const;
+ QList<QOrganizerItemId> itemIds(const QDateTime& startDate, const QDateTime& endDate, const QOrganizerItemFilter& filter, const QList<QOrganizerItemSortOrder>& sortOrders, QOrganizerManager::Error* error) const;
+ QList<QOrganizerItem> itemsForExport(const QDateTime& startDate, const QDateTime& endDate, const QOrganizerItemFilter& filter, const QList<QOrganizerItemSortOrder>& sortOrders, const QOrganizerItemFetchHint& fetchHint, QOrganizerManager::Error* error) const;
+ QList<QOrganizerItem> items(const QDateTime& startDate, const QDateTime& endDate, const QOrganizerItemFilter& filter, const QList<QOrganizerItemSortOrder>& sortOrders, const QOrganizerItemFetchHint& fetchHint, QOrganizerManager::Error* error) const;
+ QOrganizerItem item(const QOrganizerItemId& itemId, const QOrganizerItemFetchHint& fetchHint, QOrganizerManager::Error* error) const;
+
+ bool saveItems(QList<QOrganizerItem>* items, QMap<int, QOrganizerManager::Error>* errorMap, QOrganizerManager::Error* error);
+ bool saveItem(QOrganizerItem* item, QOrganizerManager::Error* error);
+ bool removeItems(const QList<QOrganizerItemId>& itemIds, QMap<int, QOrganizerManager::Error>* errorMap, QOrganizerManager::Error* error);
+
+ /* Definitions - Accessors and Mutators */
+ QMap<QString, QOrganizerItemDetailDefinition> detailDefinitions(const QString& itemType, QOrganizerManager::Error* error) const;
+ QOrganizerItemDetailDefinition detailDefinition(const QString& definitionId, const QString& itemType, QOrganizerManager::Error* error) const;
+ bool saveDetailDefinition(const QOrganizerItemDetailDefinition& def, const QString& itemType, QOrganizerManager::Error* error);
+ bool removeDetailDefinition(const QString& definitionId, const QString& itemType, QOrganizerManager::Error* error);
+
+ /* Collections - every item belongs to exactly one collection */
+ QOrganizerCollection defaultCollection(QOrganizerManager::Error* error) const;
+ QOrganizerCollection collection(const QOrganizerCollectionId& collectionId, QOrganizerManager::Error* error) const;
+ QList<QOrganizerCollection> collections(QOrganizerManager::Error* error) const;
+ bool saveCollection(QOrganizerCollection* collection, QOrganizerManager::Error* error);
+ bool removeCollection(const QOrganizerCollectionId& collectionId, QOrganizerManager::Error* error);
+
+ /* Capabilities reporting */
+ bool hasFeature(QOrganizerManager::ManagerFeature feature, const QString& itemType) const;
+ bool isFilterSupported(const QOrganizerItemFilter& filter) const;
+ QList<int> supportedDataTypes() const;
+ QStringList supportedItemTypes() const;
+
+ /* Asynchronous Request Support */
+ void requestDestroyed(QOrganizerAbstractRequest* req);
+ bool startRequest(QOrganizerAbstractRequest* req);
+ bool cancelRequest(QOrganizerAbstractRequest* req);
+ bool waitForRequestFinished(QOrganizerAbstractRequest* req, int msecs);
+
+ /* mKCal Change Notification Support (ExtendedStorageObserver) */
+ void storageModified(mKCal::ExtendedStorage* storage, const QString& info);
+ void storageProgress(mKCal::ExtendedStorage* storage, const QString& info);
+ void storageFinished(mKCal::ExtendedStorage* storage, bool error, const QString& info);
+
+private:
+ MKCalEngine(const QString& managerUri = QString());
+ QMap<QString, QMap<QString, QOrganizerItemDetailDefinition> > schemaDefinitions() const;
+ KCalCore::Incidence::Ptr incidence(const QOrganizerItemId& itemId) const;
+ KCalCore::Incidence::Ptr detachedIncidenceFromItem(const QOrganizerItem& item) const;
+ bool internalSaveItem(QOrganizerItemChangeSet* ics, QOrganizerItem* item, QOrganizerManager::Error* error);
+ KCalCore::Incidence::Ptr softSaveItem(QOrganizerItemChangeSet* ics, QOrganizerItem* item, QOrganizerManager::Error* error);
+ void convertQEventToKEvent(const QOrganizerItem& item, KCalCore::Incidence::Ptr incidence, bool recurs);
+ void convertQTodoToKTodo(const QOrganizerItem& item, KCalCore::Incidence::Ptr incidence, bool recurs);
+ void convertQJournalToKJournal(const QOrganizerItem& item, KCalCore::Incidence::Ptr incidence);
+ void convertQNoteToKNote(const QOrganizerItem& item, KCalCore::Incidence::Ptr incidence);
+ void convertCommonDetailsToIncidenceFields(const QOrganizerItem& item, KCalCore::Incidence::Ptr incidence);
+ void convertQRecurrenceToKRecurrence(
+ const QOrganizerItemRecurrence& qRecurrence,
+ const QDate& startDate,
+ KCalCore::Recurrence* kRecurrence);
+ KCalCore::RecurrenceRule* createKRecurrenceRule(
+ KCalCore::Recurrence* kRecurrence,
+ const QDate& startDate,
+ const QOrganizerRecurrenceRule& qRRule);
+
+ bool convertIncidenceToItem(KCalCore::Incidence::Ptr i, QOrganizerItem* item) const;
+ void convertKEventToQEvent(KCalCore::Event::Ptr e, QOrganizerItem* item) const;
+ void convertKTodoToQTodo(KCalCore::Todo::Ptr t, QOrganizerItem* item) const;
+ void convertKJournalToQJournal(KCalCore::Journal::Ptr j, QOrganizerItem* item) const;
+ void convertCommonIncidenceFieldsToDetails(KCalCore::Incidence::Ptr i, QOrganizerItem* item) const;
+ void convertKRecurrenceToQRecurrence(const KCalCore::Recurrence* kRecurrence, QOrganizerItem* item) const;
+ QOrganizerRecurrenceRule createQRecurrenceRule(const KCalCore::RecurrenceRule* kRRule) const;
+
+ QOrganizerCollection convertNotebookToCollection(mKCal::Notebook::Ptr notebook) const;
+ void convertCollectionToNotebook(const QOrganizerCollection& collection, mKCal::Notebook::Ptr notebook) const;
+
+ QList<QOrganizerItem> internalItemOccurrences(const QOrganizerItem& parentItem, const QDateTime& periodStart, const QDateTime& periodEnd, int maxCount, const QOrganizerItemFetchHint& fetchHint, QOrganizerManager::Error* error, bool includeInstances) const;
+ QList<QOrganizerItem> internalItems(const QDateTime& startDate, const QDateTime& endDate, const QOrganizerItemFilter& filter, const QList<QOrganizerItemSortOrder>& sortOrders, const QOrganizerItemFetchHint& fetchHint, QOrganizerManager::Error* error, bool expand) const;
+ bool itemHasRecurringChild(KCalCore::Incidence::Ptr incidence, QDateTime startDate, QDateTime endDate, QOrganizerItemFilter filter) const;
+
+ MKCalEngineData* d;
+
+ friend class MKCalEngineFactory;
+};
+
+#endif
+
diff --git a/plugins/organizer/mkcal/mkcalid.h b/plugins/organizer/mkcal/mkcalid.h
new file mode 100644
index 0000000000..5987f9e4db
--- /dev/null
+++ b/plugins/organizer/mkcal/mkcalid.h
@@ -0,0 +1,205 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MKCALID_H
+#define MKCALID_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qorganizeritemengineid.h"
+
+QTM_USE_NAMESPACE
+
+class MKCalEngineFactory; // forward decl. for friend decl.
+
+class MKCalItemId : public QOrganizerItemEngineId
+{
+public:
+ MKCalItemId() {}
+ MKCalItemId(const QString& id, const KDateTime& rid) : m_id(id), m_rid(rid) {}
+ bool isEqualTo(const QOrganizerItemEngineId* other) const
+ {
+ const MKCalItemId* otherid = static_cast<const MKCalItemId*>(other);
+ if (managerUri() != otherid->managerUri())
+ return false;
+ if (m_id != otherid->m_id)
+ return false;
+ if (m_rid != otherid->m_rid)
+ return false;
+ return true;
+ }
+ bool isLessThan(const QOrganizerItemEngineId* other) const
+ {
+ const MKCalItemId* otherid = static_cast<const MKCalItemId*>(other);
+ if (m_id < otherid->m_id)
+ return true;
+ if (m_rid < otherid->m_rid)
+ return true;
+ return false;
+ }
+ QOrganizerItemEngineId* clone() const
+ {
+ return new MKCalItemId(m_id, m_rid);
+ }
+ QString managerUri() const
+ {
+ static QString uri(QLatin1String("qtorganizer:mkcal:"));
+ return uri;
+ }
+#ifndef QT_NO_DEBUG_STREAM
+ QDebug& debugStreamOut(QDebug& dbg) const
+ {
+ return dbg << m_id << m_rid.dateTime() << managerUri();
+ }
+#endif
+ uint hash() const
+ {
+ return qHash(m_id);
+ }
+
+ QString toString() const
+ {
+ QString retn;
+ retn += m_id;
+ if (m_rid.isNull()) {
+ retn += QLatin1String("::");
+ } else {
+ retn += QString(":%1:").arg(m_rid.toTime_t());
+ }
+ retn += managerUri();
+ return retn;
+ }
+ QString id() const
+ {
+ return m_id;
+ }
+ KDateTime rid() const
+ {
+ return m_rid;
+ }
+
+ static const MKCalItemId* id_cast(const QOrganizerItemId& itemId)
+ {
+ static MKCalItemId empty;
+ if (itemId.isNull() || itemId.managerUri() != empty.managerUri())
+ return &empty;
+ return static_cast<const MKCalItemId *>(QOrganizerManagerEngine::engineItemId(itemId));
+ }
+
+private:
+ QString m_id;
+ KDateTime m_rid;
+};
+
+
+class MKCalCollectionId : public QOrganizerCollectionEngineId
+{
+public:
+ MKCalCollectionId() {}
+ MKCalCollectionId(const QString& uid) : m_uid(uid) {}
+ bool isEqualTo(const QOrganizerCollectionEngineId* other) const
+ {
+ const MKCalCollectionId* otherid = static_cast<const MKCalCollectionId*>(other);
+ if (m_uid != otherid->m_uid)
+ return false;
+ return true;
+ }
+ bool isLessThan(const QOrganizerCollectionEngineId* other) const
+ {
+ const MKCalCollectionId* otherid = static_cast<const MKCalCollectionId*>(other);
+ if (managerUri() < otherid->managerUri())
+ return true;
+ if (m_uid < otherid->m_uid)
+ return true;
+ return false;
+ }
+ QOrganizerCollectionEngineId* clone() const
+ {
+ return new MKCalCollectionId(m_uid);
+ }
+ QString managerUri() const
+ {
+ static QString uri(QLatin1String("qtorganizer:mkcal:"));
+ return uri;
+ }
+#ifndef QT_NO_DEBUG_STREAM
+ QDebug& debugStreamOut(QDebug& dbg) const
+ {
+ return dbg << m_uid << ":" << managerUri();
+ }
+#endif
+ uint hash() const
+ {
+ return qHash(m_uid);
+ }
+
+ QString toString() const
+ {
+ return m_uid + QLatin1String(":") + managerUri();
+ }
+
+ static const MKCalCollectionId* id_cast(const QOrganizerCollectionId& collId)
+ {
+ static MKCalCollectionId empty;
+ if (collId.isNull() || collId.managerUri() != empty.managerUri())
+ return &empty;
+ return static_cast<const MKCalCollectionId *>(QOrganizerManagerEngine::engineCollectionId(collId));
+ }
+
+ QString uid() const
+ {
+ return m_uid;
+ }
+
+private:
+ QString m_uid;
+};
+
+#endif
diff --git a/plugins/organizer/mkcal/qorganizerasynchmanager.cpp b/plugins/organizer/mkcal/qorganizerasynchmanager.cpp
new file mode 100644
index 0000000000..aeadaa990b
--- /dev/null
+++ b/plugins/organizer/mkcal/qorganizerasynchmanager.cpp
@@ -0,0 +1,489 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qorganizerasynchmanager.h"
+#include "qtorganizer.h"
+#include "mkcalengine.h"
+#include "mkcalid.h"
+
+QTM_USE_NAMESPACE
+
+class AsyncWorker: public QThread
+{
+public:
+ AsyncWorker(OrganizerAsynchManager* manager): m_manager(manager), m_req(0), m_kill(false) {};
+
+ void assignRequest(QOrganizerAbstractRequest* r);
+ void kill();
+protected:
+ void run();
+private:
+ OrganizerAsynchManager* m_manager;
+ QOrganizerAbstractRequest* m_req;
+ QMutex m_lock;
+ QWaitCondition m_wait;
+ bool m_kill;
+
+ void processRequest(QOrganizerAbstractRequest *req);
+
+ void handleItemFetchRequest(QOrganizerItemFetchRequest *req);
+ void handleItemFetchForExportRequest(QOrganizerItemFetchForExportRequest *req);
+ void handleItemOccurrenceFetchRequest(QOrganizerItemOccurrenceFetchRequest *req);
+ void handleIdFetchRequest(QOrganizerItemIdFetchRequest *req);
+ void handleItemRemoveRequest(QOrganizerItemRemoveRequest *req);
+ void handleSaveRequest(QOrganizerItemSaveRequest *req);
+ void handleDefinitionFetchRequest(QOrganizerItemDetailDefinitionFetchRequest *req);
+ void handleDefinitionRemoveRequest(QOrganizerItemDetailDefinitionRemoveRequest *req);
+ void handleDefinitionSaveRequest(QOrganizerItemDetailDefinitionSaveRequest *req);
+ void handleCollectionFetchRequest(QOrganizerCollectionFetchRequest *req);
+ void handleCollectionRemoveRequest(QOrganizerCollectionRemoveRequest *req);
+ void handleCollectionSaveRequest(QOrganizerCollectionSaveRequest *req);
+};
+
+void AsyncWorker::assignRequest(QOrganizerAbstractRequest* r)
+{
+ QMutexLocker lock(&m_lock);
+ Q_ASSERT_X(!m_req, "Worker", "Something is wrong with locking mechanism!");
+ m_req = r;
+
+ //either start the thread if is not running or wake up the sleeping thread
+ if (!isRunning())
+ start();
+ else
+ m_wait.wakeAll();
+}
+
+void AsyncWorker::kill()
+{
+ //mark the exit flag and wake up the thread if is sleeping
+ m_kill = true;
+ m_wait.wakeAll();
+
+ //wait the thread to finish
+ wait();
+}
+
+void AsyncWorker::run()
+{
+ QMutexLocker locker(&m_lock);
+
+ //until manager destructor is called
+ while (!m_kill) {
+ //obtain a request
+ QOrganizerAbstractRequest *r = m_req;
+ m_req = 0;
+
+ //if there are no requests sleep
+ if (!r)
+ m_wait.wait(&m_lock);
+ else {
+ locker.unlock();
+ //process the request
+ processRequest(r);
+ //signal the manager
+ if (!m_kill)
+ m_manager->workerDone(this, r);
+ locker.relock();
+ }
+ }
+}
+
+void AsyncWorker::processRequest(QOrganizerAbstractRequest* req)
+{
+ //if the request state is not active no need to do anything
+ QOrganizerAbstractRequest::State state = req->state();
+
+ //if the request is in inactive state, start the request (this could happen due to thread scheduling)
+ if (state == QOrganizerAbstractRequest::InactiveState) {
+ QOrganizerManagerEngine::updateRequestState(req, QOrganizerAbstractRequest::ActiveState);
+ } else if (state != QOrganizerAbstractRequest::ActiveState) {
+ return;
+ }
+
+ //process the request
+ switch(req->type()) {
+ case QOrganizerAbstractRequest::ItemFetchRequest:
+ handleItemFetchRequest(static_cast<QOrganizerItemFetchRequest *>(req));
+ break;
+ case QOrganizerAbstractRequest::ItemFetchForExportRequest:
+ handleItemFetchForExportRequest(static_cast<QOrganizerItemFetchForExportRequest *>(req));
+ break;
+ case QOrganizerAbstractRequest::ItemOccurrenceFetchRequest:
+ handleItemOccurrenceFetchRequest(static_cast<QOrganizerItemOccurrenceFetchRequest *>(req));
+ break;
+ case QOrganizerAbstractRequest::ItemIdFetchRequest:
+ handleIdFetchRequest(static_cast<QOrganizerItemIdFetchRequest *>(req));
+ break;
+ case QOrganizerAbstractRequest::ItemRemoveRequest:
+ handleItemRemoveRequest(static_cast<QOrganizerItemRemoveRequest *>(req));
+ break;
+ case QOrganizerAbstractRequest::ItemSaveRequest:
+ handleSaveRequest(static_cast<QOrganizerItemSaveRequest *>(req));
+ break;
+ case QOrganizerAbstractRequest::DetailDefinitionFetchRequest:
+ handleDefinitionFetchRequest(static_cast<QOrganizerItemDetailDefinitionFetchRequest *>(req));
+ break;
+ case QOrganizerAbstractRequest::DetailDefinitionRemoveRequest:
+ handleDefinitionRemoveRequest(static_cast<QOrganizerItemDetailDefinitionRemoveRequest *>(req));
+ break;
+ case QOrganizerAbstractRequest::DetailDefinitionSaveRequest:
+ handleDefinitionSaveRequest(static_cast<QOrganizerItemDetailDefinitionSaveRequest *>(req));
+ break;
+ case QOrganizerAbstractRequest::CollectionFetchRequest:
+ handleCollectionFetchRequest(static_cast<QOrganizerCollectionFetchRequest *>(req));
+ break;
+ case QOrganizerAbstractRequest::CollectionRemoveRequest:
+ handleCollectionRemoveRequest(static_cast<QOrganizerCollectionRemoveRequest *>(req));
+ break;
+ case QOrganizerAbstractRequest::CollectionSaveRequest:
+ handleCollectionSaveRequest(static_cast<QOrganizerCollectionSaveRequest *>(req));
+ break;
+
+ default:
+ // invalid request
+ break;
+ }
+}
+
+void AsyncWorker::handleItemFetchRequest(QOrganizerItemFetchRequest *req)
+{
+ QOrganizerManager::Error err = QOrganizerManager::NoError;
+ QList<QOrganizerItem> items = m_manager->m_engine->items(req->startDate(), req->endDate(), req->filter(), req->sorting(), req->fetchHint(), &err);
+ QOrganizerManagerEngine::updateItemFetchRequest(req, items, err, QOrganizerAbstractRequest::FinishedState);
+}
+
+void AsyncWorker::handleItemFetchForExportRequest(QOrganizerItemFetchForExportRequest *req)
+{
+ QOrganizerManager::Error err = QOrganizerManager::NoError;
+ QList<QOrganizerItem> items = m_manager->m_engine->itemsForExport(req->startDate(), req->endDate(), req->filter(), req->sorting(), req->fetchHint(), &err);
+ QOrganizerManagerEngine::updateItemFetchForExportRequest(req, items, err, QOrganizerAbstractRequest::FinishedState);
+}
+
+void AsyncWorker::handleItemOccurrenceFetchRequest(QOrganizerItemOccurrenceFetchRequest *req)
+{
+ QOrganizerManager::Error err = QOrganizerManager::NoError;
+ QList<QOrganizerItem> items = m_manager->m_engine->itemOccurrences(req->parentItem(), req->startDate(), req->endDate(), req->maxOccurrences(), req->fetchHint(), &err);
+ QOrganizerManagerEngine::updateItemOccurrenceFetchRequest(req, items, err, QOrganizerAbstractRequest::FinishedState);
+}
+
+void AsyncWorker::handleIdFetchRequest(QOrganizerItemIdFetchRequest *req)
+{
+ QOrganizerManager::Error err = QOrganizerManager::NoError;
+ QList<QOrganizerItemId> ids = m_manager->m_engine->itemIds(req->startDate(), req->endDate(), req->filter(), req->sorting(), &err);
+ QOrganizerManagerEngine::updateItemIdFetchRequest(req, ids, err, QOrganizerAbstractRequest::FinishedState);
+}
+
+void AsyncWorker::handleItemRemoveRequest(QOrganizerItemRemoveRequest *req)
+{
+ QOrganizerManager::Error err = QOrganizerManager::NoError;
+ QMap<int, QOrganizerManager::Error> errorMap;
+ m_manager->m_engine->removeItems(req->itemIds(), &errorMap, &err);
+ QOrganizerManagerEngine::updateItemRemoveRequest(req, err, errorMap, QOrganizerAbstractRequest::FinishedState);
+}
+
+void AsyncWorker::handleSaveRequest(QOrganizerItemSaveRequest *req)
+{
+ QOrganizerManager::Error err = QOrganizerManager::NoError;
+ QMap<int, QOrganizerManager::Error> errorMap;
+ QList<QOrganizerItem> items = req->items();
+ m_manager->m_engine->saveItems(&items, &errorMap, &err);
+ QOrganizerManagerEngine::updateItemSaveRequest(req, items, err, errorMap, QOrganizerAbstractRequest::FinishedState);
+}
+
+void AsyncWorker::handleDefinitionFetchRequest(QOrganizerItemDetailDefinitionFetchRequest *req)
+{
+ QOrganizerManager::Error err = QOrganizerManager::NoError;
+ QMap<QString, QOrganizerItemDetailDefinition> definitions = m_manager->m_engine->detailDefinitions(req->itemType(), &err);
+ QMap<QString, QOrganizerItemDetailDefinition> retn;
+ QMap<int, QOrganizerManager::Error> errorMap;
+ QStringList keys = req->definitionNames();
+ if (keys.isEmpty())
+ keys = definitions.keys();
+ int definitionsCount = keys.count();
+ for (int i = 0; i < definitionsCount; ++i) {
+ if (definitions.contains(keys.at(i)))
+ retn.insert(keys.at(i), definitions[keys.at(i)]);
+ else
+ errorMap.insert(i, QOrganizerManager::DoesNotExistError);
+ }
+ QOrganizerManagerEngine::updateDefinitionFetchRequest(req, retn, err, errorMap, QOrganizerAbstractRequest::FinishedState);
+}
+
+void AsyncWorker::handleDefinitionRemoveRequest(QOrganizerItemDetailDefinitionRemoveRequest *req)
+{
+ QOrganizerManager::Error tempError = QOrganizerManager::NoError;
+ QOrganizerManager::Error operationError = QOrganizerManager::NoError;
+ QMap<int, QOrganizerManager::Error> errorMap;
+ QStringList definitionNames = req->definitionNames();
+ int nameCount = definitionNames.count();
+ for(int i = 0; i < nameCount; ++i) {
+ m_manager->m_engine->removeDetailDefinition(definitionNames.at(i), req->itemType(), &tempError);
+ if (tempError != QOrganizerManager::NoError) {
+ errorMap.insert(i, tempError);
+ operationError = tempError;
+ }
+ }
+ QOrganizerManagerEngine::updateDefinitionRemoveRequest(req, operationError, errorMap, QOrganizerAbstractRequest::FinishedState);
+}
+
+void AsyncWorker::handleDefinitionSaveRequest(QOrganizerItemDetailDefinitionSaveRequest *req)
+{
+ QOrganizerManager::Error tempError = QOrganizerManager::NoError;
+ QOrganizerManager::Error operationError = QOrganizerManager::NoError;
+ QMap<int, QOrganizerManager::Error> errorMap;
+ QList<QOrganizerItemDetailDefinition> definitions = req->definitions();
+ int definitionCount = definitions.count();
+ for (int i = 0; i < definitionCount; ++i) {
+ m_manager->m_engine->saveDetailDefinition(definitions.at(i), req->itemType(), &tempError);
+ if (tempError != QOrganizerManager::NoError) {
+ errorMap.insert(i, tempError);
+ operationError = tempError;
+ }
+ }
+ QOrganizerManagerEngine::updateDefinitionSaveRequest(req, definitions, operationError, errorMap, QOrganizerAbstractRequest::FinishedState);
+}
+
+void AsyncWorker::handleCollectionFetchRequest(QOrganizerCollectionFetchRequest *req)
+{
+ QOrganizerManager::Error err = QOrganizerManager::NoError;
+ QList<QOrganizerCollection> collections = m_manager->m_engine->collections(&err);
+ QOrganizerManagerEngine::updateCollectionFetchRequest(req, collections, err, QOrganizerAbstractRequest::FinishedState);
+}
+
+void AsyncWorker::handleCollectionRemoveRequest(QOrganizerCollectionRemoveRequest *req)
+{
+ QOrganizerManager::Error tempError = QOrganizerManager::NoError;
+ QOrganizerManager::Error operationError = QOrganizerManager::NoError;
+ QMap<int, QOrganizerManager::Error> errorMap;
+ QOrganizerCollectionId currentId;
+ QList<QOrganizerCollectionId> colsToRemove = req->collectionIds();
+ int collectionsCount = colsToRemove.count();
+ for (int i = 0; i < collectionsCount; ++i) {
+ currentId = colsToRemove.at(i);
+ m_manager->m_engine->removeCollection(currentId, &tempError);
+ if (tempError != QOrganizerManager::NoError) {
+ errorMap.insert(i, tempError);
+ operationError = tempError;
+ }
+ }
+ QOrganizerManagerEngine::updateCollectionRemoveRequest(req, operationError, errorMap, QOrganizerAbstractRequest::FinishedState);
+}
+
+void AsyncWorker::handleCollectionSaveRequest(QOrganizerCollectionSaveRequest *req)
+{
+ QOrganizerManager::Error tempError = QOrganizerManager::NoError;
+ QOrganizerManager::Error operationError = QOrganizerManager::NoError;
+ QMap<int, QOrganizerManager::Error> errorMap;
+ QList<QOrganizerCollection> collections = req->collections();
+ QList<QOrganizerCollection> retn;
+ int collectionsCount = collections.count();
+ for (int i = 0; i < collectionsCount; ++i) {
+ QOrganizerCollection collection = collections.at(i);
+ m_manager->m_engine->saveCollection(&collection, &tempError);
+ retn << collection;
+ if (tempError != QOrganizerManager::NoError) {
+ errorMap.insert(i, tempError);
+ operationError = tempError;
+ }
+ }
+ QOrganizerManagerEngine::updateCollectionSaveRequest(req, retn, operationError, errorMap, QOrganizerAbstractRequest::FinishedState);
+}
+
+OrganizerAsynchManager::OrganizerAsynchManager(QOrganizerManagerEngine* engine, int maxWorkers)
+ : m_engine(engine), m_maxWorkers(maxWorkers)
+{
+}
+
+OrganizerAsynchManager::~OrganizerAsynchManager()
+{
+ QMutexLocker locker(&m_mutex);
+
+ //kill all idle workers
+ foreach(AsyncWorker* worker, m_idleWorkers)
+ worker->kill();
+
+ //kill all active workers
+ foreach(AsyncWorker* worker, m_activeWorkers)
+ worker->kill();
+
+ //delete all workers
+ foreach(AsyncWorker* worker, m_idleWorkers) {
+ delete worker;
+ }
+}
+
+void OrganizerAsynchManager::requestDestroyed(QOrganizerAbstractRequest *req)
+{
+ //request was deleted somewhere
+ m_mutex.lock();
+
+ //if is in the queued requests it means it has not been processed yet, so remove it
+ if (m_queuedRequests.contains(req)) {
+ m_queuedRequests.removeOne(req);
+ m_mutex.unlock();
+ } else {
+ //wait until the request is processed
+ m_mutex.unlock();
+ waitForRequestFinished(req);
+ }
+}
+
+bool OrganizerAsynchManager::addRequest(QOrganizerAbstractRequest *req)
+{
+ QMutexLocker locker(&m_mutex);
+
+ AsyncWorker *worker = 0;
+
+ //first check if there is a lazy, idle worker around
+ if (m_idleWorkers.size() > 0) {
+ worker = m_idleWorkers.dequeue();
+ } else
+ //if the active workers number is less then maxWorkers create an additional worker
+ if (m_activeWorkers.size() < m_maxWorkers) {
+ worker = new AsyncWorker(this);
+ }
+
+ //if we found a worker assign him the request
+ if (worker) {
+ m_activeWorkers.enqueue(worker);
+ m_activeRequests.insert(req);
+ worker->assignRequest(req);
+ } else {
+ //no free worker is available, enqueue the request
+ m_queuedRequests.enqueue(req);
+ }
+
+ locker.unlock();
+
+ //update the request state to active
+ QOrganizerManagerEngine::updateRequestState(req, QOrganizerAbstractRequest::ActiveState);
+
+ return true;
+}
+
+bool OrganizerAsynchManager::cancelRequest(QOrganizerAbstractRequest *req)
+{
+ QMutexLocker locker(&m_mutex);
+
+ //if the request is still in the queue cancel and remove it
+ if (m_queuedRequests.contains(req)) {
+ m_queuedRequests.removeOne(req);
+ locker.unlock();
+ QOrganizerManagerEngine::updateRequestState(req, QOrganizerAbstractRequest::CanceledState);
+
+ return true;
+ }
+
+ // cannot cancel request when processing has already begun
+ return false;
+}
+
+bool OrganizerAsynchManager::waitForRequestFinished(QOrganizerAbstractRequest *req, int msecs)
+{
+ QOrganizerAbstractRequest::State state = req->state();
+
+ //check the request state, and if is not active return
+ if (state == QOrganizerAbstractRequest::FinishedState) {
+ return true;
+ }
+ else if (state == QOrganizerAbstractRequest::CanceledState
+ || state == QOrganizerAbstractRequest::InactiveState) {
+ return false;
+ }
+
+ {
+ QMutexLocker locker(&m_mutex);
+
+ //check if this request is known to the manager
+ if (!m_activeRequests.contains(req) && !m_queuedRequests.contains(req)) {
+ qWarning() << "Request was never queued: " << req;
+ return false;
+ }
+ }
+
+ QMutexLocker locker(&m_mutexMap);
+
+ //create or fetch an existing wait condition for this requests from
+ //the map to be able to block this thread until the condition is signaled
+ QSharedPointer<QWaitCondition> cond(m_waitMap.value(req));
+ if (!cond) {
+ cond = QSharedPointer<QWaitCondition>(new QWaitCondition);
+ m_waitMap.insert(req, cond);
+ }
+
+ //wait for the request to be finished or timeout
+ bool res = cond->wait(&m_mutexMap, msecs <= 0 ? ULONG_MAX : msecs);
+
+ m_waitMap.remove(req);
+
+ return res;
+}
+
+void OrganizerAsynchManager::workerDone(AsyncWorker *worker, QOrganizerAbstractRequest *req)
+{
+ if (req) {
+ {
+ QMutexLocker locker(&m_mutexMap);
+
+ //if somebody is waiting for this request wake him up
+ QSharedPointer<QWaitCondition> cond(m_waitMap.value(req));
+ if (cond) {
+ cond->wakeAll();
+ }
+ }
+
+ QMutexLocker locker(&m_mutex);
+
+ m_activeRequests.remove(req);
+
+ //check if there is more job for this worker
+ if (m_queuedRequests.count() > 0) {
+ req = m_queuedRequests.dequeue();
+ m_activeRequests.insert(req);
+ worker->assignRequest(req);
+ } else {
+ //remove from the active workers list and add it to the idle one
+ m_activeWorkers.removeOne(worker);
+ m_idleWorkers.enqueue(worker);
+ }
+ }
+
+}
diff --git a/plugins/organizer/maemo6/maemo6itemlocalid.h b/plugins/organizer/mkcal/qorganizerasynchmanager.h
index ee8525da02..f2e3fe98d2 100644
--- a/plugins/organizer/maemo6/maemo6itemlocalid.h
+++ b/plugins/organizer/mkcal/qorganizerasynchmanager.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
@@ -39,8 +39,8 @@
**
****************************************************************************/
-#ifndef MAEMO6ITEMLOCALID_H
-#define MAEMO6ITEMLOCALID_H
+#ifndef QORGANIZERASYNCHMANAGER_H
+#define QORGANIZERASYNCHMANAGER_H
//
// W A R N I N G
@@ -53,61 +53,48 @@
// We mean it.
//
-#include "qorganizeritemenginelocalid.h"
+#include "qtorganizer.h"
+#include <QtCore/qthread.h>
+#include <QtCore/qqueue.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qmap.h>
+#include <QSharedPointer>
+#include <QWaitCondition>
QTM_USE_NAMESPACE
-class Maemo6ItemLocalId : public QOrganizerItemEngineLocalId
+class QOrganizerItemMKCalEngine;
+class AsyncWorker;
+
+class OrganizerAsynchManager
{
public:
- Maemo6ItemLocalId() {}
- Maemo6ItemLocalId(const QString& id) : m_id(id) {}
- bool isEqualTo(const QOrganizerItemEngineLocalId* other) const
- {
- return m_id == static_cast<const Maemo6ItemLocalId*>(other)->m_id;
- }
- bool isLessThan(const QOrganizerItemEngineLocalId* other) const
- {
- return m_id < static_cast<const Maemo6ItemLocalId*>(other)->m_id;
- }
- uint engineLocalIdType() const
- {
- static uint t = qHash("maemo6");
- return t;
- }
- QOrganizerItemEngineLocalId* clone() const
- {
- return new Maemo6ItemLocalId(m_id);
- }
-#ifndef QT_NO_DEBUG_STREAM
- QDebug debugStreamOut(QDebug dbg)
- {
- return dbg << m_id;
- }
-#endif
-#ifndef QT_NO_DATASTREAM
- QDataStream& dataStreamOut(QDataStream& out)
- {
- return out << m_id;
- }
- QDataStream& dataStreamIn(QDataStream& in)
- {
- in >> m_id;
- return in;
- }
-#endif
- uint hash() const
- {
- return qHash(m_id);
- }
+ OrganizerAsynchManager(QOrganizerManagerEngine *engine, int maxWorkers = 1);
+ ~OrganizerAsynchManager();
- QString toString() const
- {
- return m_id;
- }
+ void requestDestroyed(QOrganizerAbstractRequest *req);
+ bool addRequest(QOrganizerAbstractRequest *req);
+ bool cancelRequest(QOrganizerAbstractRequest *req);
+ bool waitForRequestFinished(QOrganizerAbstractRequest *req, int msecs = -1);
private:
- QString m_id;
+ QOrganizerManagerEngine* m_engine;
+
+ int m_maxWorkers;
+ QQueue<AsyncWorker *> m_idleWorkers;
+ QQueue<AsyncWorker *> m_activeWorkers;
+
+ QQueue<QOrganizerAbstractRequest *> m_queuedRequests;
+ QSet<QOrganizerAbstractRequest *> m_activeRequests;
+
+ QMap<QOrganizerAbstractRequest*, QSharedPointer<QWaitCondition> > m_waitMap;
+ QMutex m_mutexMap;
+
+ QMutex m_mutex;
+
+ void workerDone(AsyncWorker *worker, QOrganizerAbstractRequest *req);
+
+ friend class AsyncWorker;
};
-#endif
+#endif // QORGANIZERASYNCHMANAGER_H
diff --git a/plugins/organizer/organizer.pro b/plugins/organizer/organizer.pro
index 45a9457f9c..af52059bde 100644
--- a/plugins/organizer/organizer.pro
+++ b/plugins/organizer/organizer.pro
@@ -9,8 +9,7 @@ symbian {
SUBDIRS += symbian
contains(build_unit_tests, yes):SUBDIRS += symbian/tsrc
}
-# Disable this for now
-# maemo6:SUBDIRS += maemo6
+maemo6:SUBDIRS += mkcal
maemo5 {
contains(maemo5-calendar_enabled, yes) {
SUBDIRS += maemo5
diff --git a/src/organizer/items/qorganizerjournal.h b/src/organizer/items/qorganizerjournal.h
index c397fbee20..01c5ebf5bb 100644
--- a/src/organizer/items/qorganizerjournal.h
+++ b/src/organizer/items/qorganizerjournal.h
@@ -53,7 +53,6 @@ public:
Q_DECLARE_CUSTOM_ORGANIZER_ITEM(QOrganizerJournal, QOrganizerItemType::TypeJournal)
#endif
- // XXX TODO: research whether journal is a single point in time, or can cover a period of time...
void setDateTime(const QDateTime& dateTime);
QDateTime dateTime() const;
};
diff --git a/src/organizer/organizer.pro b/src/organizer/organizer.pro
index 5dc413f2bd..9d34e1a73c 100644
--- a/src/organizer/organizer.pro
+++ b/src/organizer/organizer.pro
@@ -84,7 +84,7 @@ maemo5 {
}
maemo6 {
- isEmpty(ORGANIZER_DEFAULT_ENGINE): ORGANIZER_DEFAULT_ENGINE=maemo6
+ isEmpty(ORGANIZER_DEFAULT_ENGINE): ORGANIZER_DEFAULT_ENGINE=mkcal
}
symbian {
diff --git a/tests/auto/qorganizermanager/tst_qorganizermanager.cpp b/tests/auto/qorganizermanager/tst_qorganizermanager.cpp
index 50c241b37e..a24b65cdee 100644
--- a/tests/auto/qorganizermanager/tst_qorganizermanager.cpp
+++ b/tests/auto/qorganizermanager/tst_qorganizermanager.cpp
@@ -154,12 +154,15 @@ private slots:
void uriParsing();
void compatibleItem();
void recurrenceWithGenerator();
+ void todoRecurrenceWithGenerator();
void dateRange();
/* Tests that are run on all managers */
void metadata();
void nullIdOperations();
void add();
+ void saveRecurrence();
+ void persistence();
void addExceptions();
void addExceptionsWithGuid();
void update();
@@ -172,6 +175,7 @@ private slots:
void collections();
void dataSerialization();
void itemFetch();
+ void todoItemFetch();
void spanOverDays();
void recurrence();
void idComparison();
@@ -191,11 +195,14 @@ private slots:
void uriParsing_data();
void compatibleItem_data();
void recurrenceWithGenerator_data();
+ void todoRecurrenceWithGenerator_data();
void dateRange_data();
/* Tests that are run on all managers */
void metadata_data() {addManagers();}
void nullIdOperations_data() {addManagers();}
void add_data() {addManagers();}
+ void saveRecurrence_data() {addManagers();}
+ void persistence_data() {addManagers();}
void addExceptions_data() {addManagers();}
void addExceptionsWithGuid_data() {addManagers();}
void update_data() {addManagers();}
@@ -208,6 +215,7 @@ private slots:
void collections_data() {addManagers();}
void dataSerialization_data() {addManagers();}
void itemFetch_data() {addManagers();}
+ void todoItemFetch_data() {addManagers();}
void spanOverDays_data() {addManagers();}
void recurrence_data() {addManagers();}
void idComparison_data() {addManagers();}
@@ -743,7 +751,7 @@ void tst_QOrganizerManager::ctors()
#if defined(Q_OS_SYMBIAN)
QCOMPARE(defaultStore, QString("symbian"));
#elif defined(Q_WS_MAEMO_6)
- QCOMPARE(defaultStore, QString("tracker"));
+ QCOMPARE(defaultStore, QString("mkcal"));
#elif defined(Q_WS_MAEMO_5)
QCOMPARE(defaultStore, QString("maemo5"));
#elif defined(Q_OS_WINCE)
@@ -956,6 +964,95 @@ void tst_QOrganizerManager::add()
// XXX TODO.
}
+void tst_QOrganizerManager::saveRecurrence()
+{
+ QFETCH(QString, uri);
+ QScopedPointer<QOrganizerManager> cm(QOrganizerManager::fromUri(uri));
+
+ QOrganizerEvent event;
+ event.setDisplayLabel(QLatin1String("meeting"));
+ event.setStartDateTime(QDateTime(QDate(2010, 1, 1), QTime(11, 0, 0)));
+ event.setEndDateTime(QDateTime(QDate(2010, 1, 1), QTime(12, 0, 0)));
+ QOrganizerRecurrenceRule rrule;
+ rrule.setFrequency(QOrganizerRecurrenceRule::Weekly);
+ rrule.setLimit(QDate(2011, 1, 1));
+ rrule.setInterval(2);
+ rrule.setDaysOfWeek(QSet<Qt::DayOfWeek>() << Qt::Monday << Qt::Tuesday);
+ rrule.setDaysOfMonth(QSet<int>() << 1 << 2);
+ rrule.setDaysOfYear(QSet<int>() << 1 << 2);
+ rrule.setMonthsOfYear(QSet<QOrganizerRecurrenceRule::Month>()
+ << QOrganizerRecurrenceRule::January
+ << QOrganizerRecurrenceRule::February);
+ rrule.setWeeksOfYear(QSet<int>() << 1 << 2);
+ rrule.setFirstDayOfWeek(Qt::Tuesday);
+ // this is disabled because mkcal doesn't support it:
+ //rrule.setPositions(QSet<int>() << 1 << 2);
+ event.setRecurrenceRule(rrule);
+ event.setExceptionRule(rrule);
+ QSet<QDate> rdates;
+ rdates << QDate(2010, 1, 4) << QDate(2010, 4, 1);
+ event.setRecurrenceDates(rdates);
+ event.setExceptionDates(rdates);
+
+ QVERIFY(cm->saveItem(&event));
+ QOrganizerEvent savedEvent(cm->item(event.id()));
+ QCOMPARE(event.recurrenceRule(), savedEvent.recurrenceRule());
+ QCOMPARE(event.exceptionRule(), savedEvent.exceptionRule());
+ QCOMPARE(event.recurrenceDates(), savedEvent.recurrenceDates());
+ QCOMPARE(event.exceptionDates(), savedEvent.exceptionDates());
+}
+
+void tst_QOrganizerManager::persistence()
+{
+ // Test that changes in one manager are visible from another
+ QFETCH(QString, uri);
+ QScopedPointer<QOrganizerManager> cm(QOrganizerManager::fromUri(uri));
+ if (cm->managerName() == "memory")
+ return; // memory engine is not persistent
+
+ cm->removeItems(cm->itemIds());
+ QScopedPointer<QOrganizerManager> cm2(QOrganizerManager::fromUri(uri));
+ QCOMPARE(cm->items().size(), 0);
+
+ // Add an event
+ QOrganizerEvent event;
+ event.setDisplayLabel(QLatin1String("meeting"));
+ event.setStartDateTime(QDateTime(QDate(2010, 1, 1), QTime(11, 0, 0)));
+ event.setEndDateTime(QDateTime(QDate(2010, 1, 1), QTime(12, 0, 0)));
+ QVERIFY(cm->saveItem(&event));
+ QTest::qWait(500);
+ QCOMPARE(cm->items().size(), 1);
+ QCOMPARE(cm2->items().size(), 1);
+
+ // Remove the event
+ cm->removeItems(cm->itemIds());
+ QTest::qWait(500);
+ QCOMPARE(cm->items().size(), 0);
+ qDebug() << cm2->items();
+ QCOMPARE(cm2->items().size(), 0);
+
+#if 0
+ // This is disabled because it'll fail on managers that don't support collections
+
+ // Remove all non-default collections
+ QList<QOrganizerCollection> collections(cm->collections());
+ QOrganizerCollectionId defaultCollectionId(cm->defaultCollection().id());
+ foreach (const QOrganizerCollection &col, collections) {
+ QOrganizerCollectionId id(col.id());
+ if (id != defaultCollectionId)
+ cm->removeCollection(id);
+ }
+ QTest::qWait(500);
+ QCOMPARE(cm2->collections().size(), cm->collections().size());
+
+ QOrganizerCollection collection;
+ collection.setMetaData(QOrganizerCollection::KeyName, QLatin1String("test collection"));
+ QVERIFY(cm->saveCollection(&collection));
+ QTest::qWait(500);
+ QCOMPARE(cm2->collections().size(), cm->collections().size());
+#endif
+}
+
void tst_QOrganizerManager::addExceptions()
{
QFETCH(QString, uri);
@@ -1228,7 +1325,7 @@ void tst_QOrganizerManager::update()
}
}
QVERIFY(foundException);
- exception.setLocation("different location");
+ exception.setDescription("different description");
QVERIFY(cm->saveItem(&exception));
persistentCount = cm->itemsForExport().size();
QCOMPARE(persistentCount, 2); // parent plus one exception
@@ -1237,6 +1334,7 @@ void tst_QOrganizerManager::update()
foreach (const QOrganizerEventOccurrence& curr, items) {
if (curr.startDateTime() == QDateTime(QDate(2010, 10, 21), QTime(8, 0, 0))) {
QVERIFY(!curr.id().isNull());
+ QCOMPARE(curr.description(), QLatin1String("different description"));
} else {
QVERIFY(curr.id().isNull());
}
@@ -1270,7 +1368,7 @@ void tst_QOrganizerManager::remove()
{
QFETCH(QString, uri);
QScopedPointer<QOrganizerManager> cm(QOrganizerManager::fromUri(uri));
-
+
// Use note & todo item depending on backend support
QString type;
if (cm->detailDefinitions(QOrganizerItemType::TypeNote).count())
@@ -1887,8 +1985,11 @@ void tst_QOrganizerManager::compatibleItem()
void tst_QOrganizerManager::recurrenceWithGenerator_data()
{
QTest::addColumn<QString>("uri");
- QTest::addColumn<QDate>("eventDate");
+ QTest::addColumn<QDate>("generatorDate");
QTest::addColumn<QOrganizerRecurrenceRule>("recurrenceRule");
+ QTest::addColumn<QOrganizerRecurrenceRule>("exceptionRule");
+ QTest::addColumn<QSet<QDate> >("recurrenceDates");
+ QTest::addColumn<QSet<QDate> >("exceptionDates");
QTest::addColumn<QDate>("startDate");
QTest::addColumn<QDate>("endDate");
QTest::addColumn<QList<QDate> >("occurrenceDates");
@@ -1902,6 +2003,9 @@ void tst_QOrganizerManager::recurrenceWithGenerator_data()
managers.removeAll("maliciousplugin");
managers.removeAll("skeleton");
+ QOrganizerRecurrenceRule exrule;
+ QSet<QDate> rdates;
+ QSet<QDate> exdates;
foreach(QString mgr, managers) {
QString managerUri = QOrganizerManager::buildUri(mgr, QMap<QString, QString>());
@@ -1910,35 +2014,40 @@ void tst_QOrganizerManager::recurrenceWithGenerator_data()
rrule.setFrequency(QOrganizerRecurrenceRule::Weekly);
rrule.setLimit(QDate(2010, 1, 22));
QTest::newRow(QString("mgr=%1, weekly recurrence").arg(mgr).toLatin1().constData())
- << managerUri << QDate(2010, 1, 1) << rrule
+ << managerUri << QDate(2010, 1, 1)
+ << rrule << exrule << rdates << exdates
<< QDate(2010, 1, 1) << QDate(2010, 1, 20)
// stops at the 15th because the query end date is the 20th
<< (QList<QDate>() << QDate(2010, 1, 1) << QDate(2010, 1, 8) << QDate(2010, 1, 15));
// change the end date of the query to 2010-02-01
QTest::newRow(QString("mgr=%1, weekly recurrence, end date is inclusive").arg(mgr).toLatin1().constData())
- << managerUri << QDate(2010, 1, 1) << rrule
+ << managerUri << QDate(2010, 1, 1)
+ << rrule << exrule << rdates << exdates
<< QDate(2010, 1, 1) << QDate(2010, 2, 1)
<< (QList<QDate>() << QDate(2010, 1, 1) << QDate(2010, 1, 8) << QDate(2010, 1, 15) << QDate(2010, 1, 22));
// Now let's fiddle with the recurrence end date and see what happens
rrule.setLimit(QDate(2010, 1, 23));
QTest::newRow(QString("mgr=%1, weekly recurrence, end date observed (+1)").arg(mgr).toLatin1().constData())
- << managerUri << QDate(2010, 1, 1) << rrule
+ << managerUri << QDate(2010, 1, 1)
+ << rrule << exrule << rdates << exdates
<< QDate(2010, 1, 1) << QDate(2010, 2, 1)
// now stop on the 22nd
<< (QList<QDate>() << QDate(2010, 1, 1) << QDate(2010, 1, 8) << QDate(2010, 1, 15) << QDate(2010, 1, 22));
rrule.setLimit(QDate(2010, 1, 21));
QTest::newRow(QString("mgr=%1, weekly recurrence, end date observed (-1)").arg(mgr).toLatin1().constData())
- << managerUri << QDate(2010, 1, 1) << rrule
+ << managerUri << QDate(2010, 1, 1)
+ << rrule << exrule << rdates << exdates
<< QDate(2010, 1, 1) << QDate(2010, 2, 1)
<< (QList<QDate>() << QDate(2010, 1, 1) << QDate(2010, 1, 8) << QDate(2010, 1, 15));
rrule.setLimit(QDate());
rrule.setLimit(2);
QTest::newRow(QString("mgr=%1, weekly recurrence, count").arg(mgr).toLatin1().constData())
- << managerUri << QDate(2010, 1, 1) << rrule
+ << managerUri << QDate(2010, 1, 1)
+ << rrule << exrule << rdates << exdates
<< QDate(2010, 1, 1) << QDate(2010, 2, 1)
<< (QList<QDate>() << QDate(2010, 1, 1) << QDate(2010, 1, 8));
}
@@ -1948,7 +2057,8 @@ void tst_QOrganizerManager::recurrenceWithGenerator_data()
rrule.setFrequency(QOrganizerRecurrenceRule::Daily);
rrule.setLimit(QDate(2010, 1, 5));
QTest::newRow(QString("mgr=%1, daily").arg(mgr).toLatin1().constData())
- << managerUri << QDate(2010, 1, 1) << rrule
+ << managerUri << QDate(2010, 1, 1)
+ << rrule << exrule << rdates << exdates
<< QDate(2010, 1, 1) << QDate(2015, 1, 1)
<< (QList<QDate>() << QDate(2010, 1, 1) << QDate(2010, 1, 2)
<< QDate(2010, 1, 3) << QDate(2010, 1, 4)
@@ -1956,7 +2066,8 @@ void tst_QOrganizerManager::recurrenceWithGenerator_data()
rrule.setInterval(3);
QTest::newRow(QString("mgr=%1, daily, interval").arg(mgr).toLatin1().constData())
- << managerUri << QDate(2010, 1, 1) << rrule
+ << managerUri << QDate(2010, 1, 1)
+ << rrule << exrule << rdates << exdates
<< QDate(2010, 1, 1) << QDate(2015, 1, 1)
<< (QList<QDate>() << QDate(2010, 1, 1) << QDate(2010, 1, 4));
}
@@ -1968,7 +2079,8 @@ void tst_QOrganizerManager::recurrenceWithGenerator_data()
rrule.setDaysOfWeek(QSet<Qt::DayOfWeek>() << Qt::Friday << Qt::Saturday << Qt::Sunday);
rrule.setLimit(QDate(2010, 1, 27));
QTest::newRow(QString("mgr=%1, weekly, days of week").arg(mgr).toLatin1().constData())
- << managerUri << QDate(2010, 1, 1) << rrule
+ << managerUri << QDate(2010, 1, 1)
+ << rrule << exrule << rdates << exdates
<< QDate(2010, 1, 1) << QDate(2015, 1, 1)
<< (QList<QDate>() << QDate(2010, 1, 1) << QDate(2010, 1, 2) << QDate(2010, 1, 3)
<< QDate(2010, 1, 8) << QDate(2010, 1, 9) << QDate(2010, 1, 10)
@@ -1977,7 +2089,8 @@ void tst_QOrganizerManager::recurrenceWithGenerator_data()
rrule.setInterval(3);
QTest::newRow(QString("mgr=%1, weekly, days of week, interval").arg(mgr).toLatin1().constData())
- << managerUri << QDate(2010, 1, 1) << rrule
+ << managerUri << QDate(2010, 1, 1)
+ << rrule << exrule << rdates << exdates
<< QDate(2010, 1, 1) << QDate(2015, 1, 1)
<< (QList<QDate>() << QDate(2010, 1, 1) << QDate(2010, 1, 2) << QDate(2010, 1, 3)
<< QDate(2010, 1, 22) << QDate(2010, 1, 23) << QDate(2010, 1, 24));
@@ -1989,7 +2102,8 @@ void tst_QOrganizerManager::recurrenceWithGenerator_data()
rrule.setDaysOfMonth(QSet<int>() << 1 << 10);
rrule.setLimit(QDate(2010, 4, 15));
QTest::newRow(QString("mgr=%1, monthly recurrence").arg(mgr).toLatin1().constData())
- << managerUri << QDate(2010, 1, 1) << rrule
+ << managerUri << QDate(2010, 1, 1)
+ << rrule << exrule << rdates << exdates
<< QDate(2010, 1, 1) << QDate(2015, 1, 1)
<< (QList<QDate>() << QDate(2010, 1, 1) << QDate(2010, 1, 10)
<< QDate(2010, 2, 1) << QDate(2010, 2, 10)
@@ -1998,7 +2112,8 @@ void tst_QOrganizerManager::recurrenceWithGenerator_data()
rrule.setInterval(3);
QTest::newRow(QString("mgr=%1, monthly recurrence, interval").arg(mgr).toLatin1().constData())
- << managerUri << QDate(2010, 1, 1) << rrule
+ << managerUri << QDate(2010, 1, 1)
+ << rrule << exrule << rdates << exdates
<< QDate(2010, 1, 1) << QDate(2015, 1, 1)
<< (QList<QDate>() << QDate(2010, 1, 1) << QDate(2010, 1, 10)
<< QDate(2010, 4, 1) << QDate(2010, 4, 10));
@@ -2010,7 +2125,8 @@ void tst_QOrganizerManager::recurrenceWithGenerator_data()
rrule.setDaysOfYear(QSet<int>() << 1 << 32);
rrule.setLimit(QDate(2012, 3, 15));
QTest::newRow(QString("mgr=%1, yearly recurrence").arg(mgr).toLatin1().constData())
- << managerUri << QDate(2010, 1, 1) << rrule
+ << managerUri << QDate(2010, 1, 1)
+ << rrule << exrule << rdates << exdates
<< QDate(2010, 1, 1) << QDate(2015, 1, 1)
<< (QList<QDate>() << QDate(2010, 1, 1) << QDate(2010, 2, 1)
<< QDate(2011, 1, 1) << QDate(2011, 2, 1)
@@ -2019,7 +2135,8 @@ void tst_QOrganizerManager::recurrenceWithGenerator_data()
rrule.setLimit(QDate(2013, 3, 15));
rrule.setInterval(3);
QTest::newRow(QString("mgr=%1, yearly recurrence, interval").arg(mgr).toLatin1().constData())
- << managerUri << QDate(2010, 1, 1) << rrule
+ << managerUri << QDate(2010, 1, 1)
+ << rrule << exrule << rdates << exdates
<< QDate(2010, 1, 1) << QDate(2015, 1, 1)
<< (QList<QDate>() << QDate(2010, 1, 1) << QDate(2010, 2, 1)
<< QDate(2013, 1, 1) << QDate(2013, 2, 1));
@@ -2033,7 +2150,8 @@ void tst_QOrganizerManager::recurrenceWithGenerator_data()
<< QOrganizerRecurrenceRule::March);
rrule.setLimit(QDate(2011, 3, 15));
QTest::newRow(QString("mgr=%1, yearly recurrence, by month").arg(mgr).toLatin1().constData())
- << managerUri << QDate(2010, 1, 1) << rrule
+ << managerUri << QDate(2010, 1, 1)
+ << rrule << exrule << rdates << exdates
<< QDate(2010, 1, 1) << QDate(2015, 1, 1)
<< (QList<QDate>() << QDate(2010, 1, 1) << QDate(2010, 3, 1)
<< QDate(2011, 1, 1) << QDate(2011, 3, 1));
@@ -2047,7 +2165,8 @@ void tst_QOrganizerManager::recurrenceWithGenerator_data()
rrule.setDaysOfWeek(QSet<Qt::DayOfWeek>() << Qt::Thursday);
rrule.setLimit(QDate(2011, 3, 15));
QTest::newRow(QString("mgr=%1, yearly recurrence, by week").arg(mgr).toLatin1().constData())
- << managerUri << QDate(2010, 1, 7) << rrule // this is the first day of week 1
+ << managerUri << QDate(2010, 1, 7) // this is the first day of week 1
+ << rrule << exrule << rdates << exdates
<< QDate(2010, 1, 1) << QDate(2015, 1, 1)
<< (QList<QDate>() << QDate(2010, 1, 7) << QDate(2010, 1, 28)
<< QDate(2011, 1, 6) << QDate(2011, 1, 27));
@@ -2061,7 +2180,8 @@ void tst_QOrganizerManager::recurrenceWithGenerator_data()
rrule.setDaysOfWeek(QSet<Qt::DayOfWeek>() << Qt::Sunday);
rrule.setPositions(QSet<int>() << 1);
QTest::newRow(QString("mgr=%1, yearly recurrence, first Sunday of April").arg(mgr).toLatin1().constData())
- << managerUri << QDate(2010, 4, 4) << rrule // this is the first Sunday of April 2010
+ << managerUri << QDate(2010, 4, 4) // this is the first Sunday of April 2010
+ << rrule << exrule << rdates << exdates
<< QDate(2010, 1, 1) << QDate(2015, 1, 1)
<< (QList<QDate>() << QDate(2010, 4, 4)
<< QDate(2011, 4, 3)
@@ -2078,7 +2198,8 @@ void tst_QOrganizerManager::recurrenceWithGenerator_data()
rrule.setDaysOfWeek(QSet<Qt::DayOfWeek>() << Qt::Sunday);
rrule.setPositions(QSet<int>() << -1);
QTest::newRow(QString("mgr=%1, yearly recurrence, last Sunday of October").arg(mgr).toLatin1().constData())
- << managerUri << QDate(2010, 10, 31) << rrule // this is the last Sunday of October 2010
+ << managerUri << QDate(2010, 10, 31) // this is the last Sunday of October 2010
+ << rrule << exrule << rdates << exdates
<< QDate(2010, 1, 1) << QDate(2015, 1, 1)
<< (QList<QDate>() << QDate(2010, 10, 31)
<< QDate(2011, 10, 30)
@@ -2086,24 +2207,73 @@ void tst_QOrganizerManager::recurrenceWithGenerator_data()
<< QDate(2013, 10, 27)
<< QDate(2014, 10, 26));
}
+
+ {
+ QOrganizerRecurrenceRule rrule; // empty
+ QSet<QDate> rdates;
+ rdates << QDate(2010, 1, 5) << QDate(2010, 1, 8);
+ QTest::newRow(QString("mgr=%1, rdates").arg(mgr).toLatin1().constData())
+ << managerUri << QDate(2010, 1, 1)
+ << rrule << exrule << rdates << exdates
+ << QDate(2010, 1, 1) << QDate(2015, 1, 1)
+ << (QList<QDate>() << QDate(2010, 1, 1)
+ << QDate(2010, 1, 5)
+ << QDate(2010, 1, 8));
+ }
+
+ {
+ QOrganizerRecurrenceRule rrule;
+ rrule.setFrequency(QOrganizerRecurrenceRule::Daily);
+ QSet<QDate> exdates;
+ exdates << QDate(2010, 1, 2) << QDate(2010, 1, 3);
+ QTest::newRow(QString("mgr=%1, exdates").arg(mgr).toLatin1().constData())
+ << managerUri << QDate(2010, 1, 1)
+ << rrule << exrule << rdates << exdates
+ << QDate(2010, 1, 1) << QDate(2010, 1, 5)
+ << (QList<QDate>() << QDate(2010, 1, 1)
+ << QDate(2010, 1, 4)
+ << QDate(2010, 1, 5));
+ }
+
+ {
+ QOrganizerRecurrenceRule rrule;
+ rrule.setFrequency(QOrganizerRecurrenceRule::Daily);
+ QOrganizerRecurrenceRule exrule;
+ exrule.setFrequency(QOrganizerRecurrenceRule::Monthly);
+ exrule.setDaysOfMonth(QSet<int>() << 2 << 3);
+ QTest::newRow(QString("mgr=%1, exrule").arg(mgr).toLatin1().constData())
+ << managerUri << QDate(2010, 1, 1)
+ << rrule << exrule << rdates << exdates
+ << QDate(2010, 1, 1) << QDate(2010, 1, 5)
+ << (QList<QDate>() << QDate(2010, 1, 1)
+ << QDate(2010, 1, 4)
+ << QDate(2010, 1, 5));
+ }
}
}
void tst_QOrganizerManager::recurrenceWithGenerator()
{
QFETCH(QString, uri);
- QFETCH(QDate, eventDate);
+ QFETCH(QDate, generatorDate);
QFETCH(QOrganizerRecurrenceRule, recurrenceRule);
- QScopedPointer<QOrganizerManager> cm(QOrganizerManager::fromUri(uri));
+ QFETCH(QOrganizerRecurrenceRule, exceptionRule);
+ QFETCH(QSet<QDate>, recurrenceDates);
+ QFETCH(QSet<QDate>, exceptionDates);
QFETCH(QDate, startDate);
QFETCH(QDate, endDate);
QFETCH(QList<QDate>, occurrenceDates);
+ QScopedPointer<QOrganizerManager> cm(QOrganizerManager::fromUri(uri));
+
QOrganizerEvent event;
event.setDisplayLabel("event");
- event.setStartDateTime(QDateTime(eventDate, QTime(11, 0, 0)));
- event.setEndDateTime(QDateTime(eventDate, QTime(11, 30, 0)));
+ event.setStartDateTime(QDateTime(generatorDate, QTime(11, 0, 0)));
+ event.setEndDateTime(QDateTime(generatorDate, QTime(11, 30, 0)));
event.setRecurrenceRule(recurrenceRule);
+ event.setExceptionRule(exceptionRule);
+ event.setRecurrenceDates(recurrenceDates);
+ event.setExceptionDates(exceptionDates);
if (cm->saveItem(&event)) {
QList<QOrganizerItem> items = cm->itemOccurrences(event,
@@ -2114,12 +2284,7 @@ void tst_QOrganizerManager::recurrenceWithGenerator()
for (int i = 0; i < items.size(); i++) {
QOrganizerItem item = items.at(i);
QCOMPARE(item.type(), QString(QLatin1String(QOrganizerItemType::TypeEventOccurrence)));
- QDate occurrenceDate;
- if (item.type() == QOrganizerItemType::TypeEventOccurrence) {
- occurrenceDate = item.detail<QOrganizerEventTime>().startDateTime().date();
- } else if (item.type() == QOrganizerItemType::TypeTodoOccurrence) {
- occurrenceDate = item.detail<QOrganizerTodoTime>().startDateTime().date();
- }
+ QDate occurrenceDate = item.detail<QOrganizerEventTime>().startDateTime().date();
//QCOMPARE(occurrenceDate, occurrenceDates.at(i));
actualDates << occurrenceDate;
}
@@ -2136,6 +2301,61 @@ void tst_QOrganizerManager::recurrenceWithGenerator()
}
}
+void tst_QOrganizerManager::todoRecurrenceWithGenerator_data()
+{
+ recurrenceWithGenerator_data();
+}
+
+// This is just a copy of recurrenceWithGenerator, but for todos, not events
+void tst_QOrganizerManager::todoRecurrenceWithGenerator()
+{
+ QFETCH(QString, uri);
+ QFETCH(QDate, generatorDate);
+ QFETCH(QOrganizerRecurrenceRule, recurrenceRule);
+ QFETCH(QOrganizerRecurrenceRule, exceptionRule);
+ QFETCH(QSet<QDate>, recurrenceDates);
+ QFETCH(QSet<QDate>, exceptionDates);
+ QFETCH(QDate, startDate);
+ QFETCH(QDate, endDate);
+ QFETCH(QList<QDate>, occurrenceDates);
+
+ QScopedPointer<QOrganizerManager> cm(QOrganizerManager::fromUri(uri));
+
+ QOrganizerTodo todo;
+ todo.setDisplayLabel("todo");
+ todo.setStartDateTime(QDateTime(generatorDate, QTime(11, 0, 0)));
+ todo.setDueDateTime(QDateTime(generatorDate, QTime(11, 30, 0)));
+ todo.setRecurrenceRule(recurrenceRule);
+ todo.setExceptionRule(exceptionRule);
+ todo.setRecurrenceDates(recurrenceDates);
+ todo.setExceptionDates(exceptionDates);
+
+ if (cm->saveItem(&todo)) {
+ QList<QOrganizerItem> items = cm->itemOccurrences(todo,
+ QDateTime(startDate, QTime(0, 0, 0)),
+ QDateTime(endDate, QTime(23, 59, 59, 999)));
+
+ QList<QDate> actualDates;
+ for (int i = 0; i < items.size(); i++) {
+ QOrganizerItem item = items.at(i);
+ QCOMPARE(item.type(), QString(QLatin1String(QOrganizerItemType::TypeTodoOccurrence)));
+ QDate occurrenceDate = item.detail<QOrganizerTodoTime>().startDateTime().date();
+ //QCOMPARE(occurrenceDate, occurrenceDates.at(i));
+ actualDates << occurrenceDate;
+ }
+
+ if (actualDates != occurrenceDates) {
+ qDebug() << "Actual: " << actualDates;
+ qDebug() << "Expected: " << occurrenceDates;
+ QCOMPARE(actualDates, occurrenceDates);
+ }
+ } else {
+ // Allow backend specific limitations
+ QCOMPARE(cm->error(), QOrganizerManager::NotSupportedError);
+ qWarning() << "The todo not supported by the backend";
+ }
+}
+
void tst_QOrganizerManager::itemValidation()
{
/* Use the memory engine as a reference (validation is not engine specific) */
@@ -2242,9 +2462,10 @@ void tst_QOrganizerManager::signalEmission()
qRegisterMetaType<QOrganizerItemId>("QOrganizerItemId");
qRegisterMetaType<QList<QOrganizerItemId> >("QList<QOrganizerItemId>");
- QSignalSpy spyCA(m1.data(), SIGNAL(itemsAdded(QList<QOrganizerItemId>)));
- QSignalSpy spyCM(m1.data(), SIGNAL(itemsChanged(QList<QOrganizerItemId>)));
- QSignalSpy spyCR(m1.data(), SIGNAL(itemsRemoved(QList<QOrganizerItemId>)));
+ QSignalSpy spyAdded(m1.data(), SIGNAL(itemsAdded(QList<QOrganizerItemId>)));
+ QSignalSpy spyModified(m1.data(), SIGNAL(itemsChanged(QList<QOrganizerItemId>)));
+ QSignalSpy spyRemoved(m1.data(), SIGNAL(itemsRemoved(QList<QOrganizerItemId>)));
+ QSignalSpy spyChanged(m1.data(), SIGNAL(dataChanged()));
QList<QVariant> args;
QList<QOrganizerItemId> arg;
@@ -2263,8 +2484,8 @@ void tst_QOrganizerManager::signalEmission()
QVERIFY(m1->saveItem(&todo));
QOrganizerItemId cid = todo.id();
addSigCount += 1;
- QTRY_COMPARE(spyCA.count(), addSigCount);
- args = spyCA.takeFirst();
+ QTRY_COMPARE(spyAdded.count(), addSigCount);
+ args = spyAdded.takeFirst();
addSigCount -= 1;
arg = args.first().value<QList<QOrganizerItemId> >();
QVERIFY(arg.count() == 1);
@@ -2275,8 +2496,8 @@ void tst_QOrganizerManager::signalEmission()
QVERIFY(todo.saveDetail(&nc));
QVERIFY(m1->saveItem(&todo));
modSigCount += 1;
- QTRY_COMPARE(spyCM.count(), modSigCount);
- args = spyCM.takeFirst();
+ QTRY_COMPARE(spyModified.count(), modSigCount);
+ args = spyModified.takeFirst();
modSigCount -= 1;
arg = args.first().value<QList<QOrganizerItemId> >();
QVERIFY(arg.count() == 1);
@@ -2285,8 +2506,8 @@ void tst_QOrganizerManager::signalEmission()
// verify remove emits signal removed
QVERIFY(m1->removeItem(todo.id()));
remSigCount += 1;
- QTRY_COMPARE(spyCR.count(), remSigCount);
- args = spyCR.takeFirst();
+ QTRY_COMPARE(spyRemoved.count(), remSigCount);
+ args = spyRemoved.takeFirst();
remSigCount -= 1;
arg = args.first().value<QList<QOrganizerItemId> >();
QVERIFY(arg.count() == 1);
@@ -2303,8 +2524,8 @@ void tst_QOrganizerManager::signalEmission()
addSigCount += 1;
QVERIFY(m1->saveItem(&todo3));
addSigCount += 1;
- QTRY_COMPARE(spyCM.count(), modSigCount);
- QTRY_COMPARE(spyCA.count(), addSigCount);
+ QTRY_COMPARE(spyModified.count(), modSigCount);
+ QTRY_COMPARE(spyAdded.count(), addSigCount);
// verify multiple modifies works as advertised
nc2.setLabel("M.");
@@ -2319,21 +2540,21 @@ void tst_QOrganizerManager::signalEmission()
modSigCount += 1;
QVERIFY(m1->saveItem(&todo3));
modSigCount += 1;
- QTRY_COMPARE(spyCM.count(), modSigCount);
+ QTRY_COMPARE(spyModified.count(), modSigCount);
// verify multiple removes works as advertised
m1->removeItem(todo3.id());
remSigCount += 1;
m1->removeItem(todo2.id());
remSigCount += 1;
- QTRY_COMPARE(spyCR.count(), remSigCount);
+ QTRY_COMPARE(spyRemoved.count(), remSigCount);
QVERIFY(!m1->removeItem(todo.id())); // not saved.
/* Now test the batch equivalents */
- spyCA.clear();
- spyCM.clear();
- spyCR.clear();
+ spyAdded.clear();
+ spyModified.clear();
+ spyRemoved.clear();
/* Batch adds - set ids to zero so add succeeds. */
todo.setId(QOrganizerItemId());
@@ -2352,9 +2573,9 @@ void tst_QOrganizerManager::signalEmission()
/* We basically loop, processing events, until we've seen an Add signal for each item */
sigids.clear();
- QTRY_WAIT( while(spyCA.size() > 0) {sigids += spyCA.takeFirst().at(0).value<QList<QOrganizerItemId> >(); }, sigids.contains(todo.id()) && sigids.contains(todo2.id()) && sigids.contains(todo3.id()));
- QTRY_COMPARE(spyCM.count(), 0);
- QTRY_COMPARE(spyCR.count(), 0);
+ QTRY_WAIT( while(spyAdded.size() > 0) {sigids += spyAdded.takeFirst().at(0).value<QList<QOrganizerItemId> >(); }, sigids.contains(todo.id()) && sigids.contains(todo2.id()) && sigids.contains(todo3.id()));
+ QTRY_COMPARE(spyModified.count(), 0);
+ QTRY_COMPARE(spyRemoved.count(), 0);
/* Batch modifies */
QOrganizerItemDisplayLabel modifiedName = todo.detail(QOrganizerItemDisplayLabel::DefinitionName);
@@ -2370,7 +2591,7 @@ void tst_QOrganizerManager::signalEmission()
errorMap = m1->errorMap();
sigids.clear();
- QTRY_WAIT( while(spyCM.size() > 0) {sigids += spyCM.takeFirst().at(0).value<QList<QOrganizerItemId> >(); }, sigids.contains(todo.id()) && sigids.contains(todo2.id()) && sigids.contains(todo3.id()));
+ QTRY_WAIT( while(spyModified.size() > 0) {sigids += spyModified.takeFirst().at(0).value<QList<QOrganizerItemId> >(); }, sigids.contains(todo.id()) && sigids.contains(todo2.id()) && sigids.contains(todo3.id()));
/* Batch removes */
batchRemove << todo.id() << todo2.id() << todo3.id();
@@ -2378,20 +2599,24 @@ void tst_QOrganizerManager::signalEmission()
errorMap = m1->errorMap();
sigids.clear();
- QTRY_WAIT( while(spyCR.size() > 0) {sigids += spyCR.takeFirst().at(0).value<QList<QOrganizerItemId> >(); }, sigids.contains(todo.id()) && sigids.contains(todo2.id()) && sigids.contains(todo3.id()));
+ QTRY_WAIT( while(spyRemoved.size() > 0) {sigids += spyRemoved.takeFirst().at(0).value<QList<QOrganizerItemId> >(); }, sigids.contains(todo.id()) && sigids.contains(todo2.id()) && sigids.contains(todo3.id()));
- QTRY_COMPARE(spyCA.count(), 0);
- QTRY_COMPARE(spyCM.count(), 0);
+ QTRY_COMPARE(spyAdded.count(), 0);
+ QTRY_COMPARE(spyModified.count(), 0);
QScopedPointer<QOrganizerManager> m2(QOrganizerManager::fromUri(uri));
QVERIFY(m1->hasFeature(QOrganizerManager::Anonymous) ==
m2->hasFeature(QOrganizerManager::Anonymous));
/* Now some cross manager testing */
+ spyAdded.clear();
+ spyModified.clear();
+ spyRemoved.clear();
+ spyChanged.clear();
if (!m1->hasFeature(QOrganizerManager::Anonymous)) {
// verify that signals are emitted for modifications made to other managers (same id).
- QSignalSpy spyDC(m1.data(), SIGNAL(dataChanged()));
- spyDC.clear();
+ QSignalSpy spyDataChanged(m1.data(), SIGNAL(dataChanged()));
+ spyDataChanged.clear();
QOrganizerItemDisplayLabel ncs = todo.detail(QOrganizerItemDisplayLabel::DefinitionName);
ncs.setLabel("Test");
QVERIFY(todo.saveDetail(&ncs));
@@ -2404,13 +2629,13 @@ void tst_QOrganizerManager::signalEmission()
QVERIFY(m2->saveItem(&todo));
// we should have one addition and one modification (or at least a data changed signal).
- QTRY_VERIFY(spyDC.count() || (spyCA.count() == 1)); // check that we received the update signals.
- QTRY_VERIFY(spyDC.count() || (spyCM.count() == 1)); // check that we received the update signals.
+ QTRY_VERIFY(spyDataChanged.count() || (spyAdded.count() == 1)); // check that we received the update signals.
+ QTRY_VERIFY(spyDataChanged.count() || (spyModified.count() == 1)); // check that we received the update signals.
todo = m2->item(todo.id()); // reload it.
QVERIFY(m1->item(todo.id()) == todo); // ensure we can read it from m1.
- spyDC.clear();
+ spyDataChanged.clear();
m2->removeItem(todo.id());
- QTRY_VERIFY(spyDC.count() || (spyCR.count() == 1)); // check that we received the remove signal.
+ QTRY_VERIFY(spyDataChanged.count() || (spyRemoved.count() == 1)); // check that we received the remove signal.
}
}
@@ -3069,6 +3294,149 @@ void tst_QOrganizerManager::itemFetch()
QCOMPARE(eventOccurrenceCount, 3);
}
+// This is just a copy of itemFetch(), but for todos
+void tst_QOrganizerManager::todoItemFetch()
+{
+ QFETCH(QString, uri);
+ QScopedPointer<QOrganizerManager> cm(QOrganizerManager::fromUri(uri));
+
+ cm->removeItems(cm->itemIds()); // empty the calendar to prevent the previous test from interfering this one
+
+ QOrganizerTodo todo;
+ todo.setDisplayLabel("todo");
+ todo.setStartDateTime(QDateTime(QDate(2010, 9, 9), QTime(11, 0, 0)));
+ todo.setDueDateTime(QDateTime(QDate(2010, 9, 9), QTime(11, 30, 0)));
+ QVERIFY(cm->saveItem(&todo));
+
+ QOrganizerTodo recTodo;
+ recTodo.setDisplayLabel("daily todo");
+ recTodo.setStartDateTime(QDateTime(QDate(2010, 9, 1), QTime(16, 0, 0)));
+ recTodo.setDueDateTime(QDateTime(QDate(2010, 9, 1), QTime(16, 30, 0)));
+ QOrganizerRecurrenceRule rrule;
+ rrule.setFrequency(QOrganizerRecurrenceRule::Daily);
+ rrule.setLimit(QDate(2010, 9, 10));
+ recTodo.setRecurrenceRule(rrule);
+ QVERIFY(cm->saveItem(&recTodo));
+
+ //fetch all recurrences
+ QList<QOrganizerItem> items = cm->items(QDateTime(QDate(2010, 9, 8)),
+ QDateTime(QDate(2010, 9, 12)));
+ QCOMPARE(items.count(), 4); // should return todo + 3 x occurrencesOfRecTodo
+
+ //fetch only the originating items
+ items = cm->itemsForExport(QDateTime(QDate(2010, 9, 8)), QDateTime(QDate(2010, 9, 12)),
+ QOrganizerItemFilter(), QList<QOrganizerItemSortOrder>(), QOrganizerItemFetchHint());
+ QCOMPARE(items.count(), 2);
+
+ // test semantics of items():
+ // first - save todo with multiple occurrences; call items() -- should get back just occurrences.
+ cm->removeItems(cm->itemIds()); // empty the calendar to prevent the previous test from interfering this one
+ rrule.setLimit(QDate(2010, 9, 3));
+ recTodo.setRecurrenceRule(rrule);
+ recTodo.setId(QOrganizerItemId());
+ cm->saveItem(&recTodo);
+ items = cm->items(QDateTime(), QDateTime());
+ QCOMPARE(items.count(), 3);
+ foreach (const QOrganizerItem& item, items) {
+ QVERIFY(item.type() == QOrganizerItemType::TypeTodoOccurrence);
+ }
+
+ // second - the same situation, but giving a time span that only covers the first day - should get back a single occurrence.
+ items = cm->items(QDateTime(QDate(2010, 9, 1), QTime(15, 0, 0)), QDateTime(QDate(2010, 9, 1), QTime(18, 0, 0)));
+ QCOMPARE(items.count(), 1);
+ foreach (const QOrganizerItem& item, items) {
+ QVERIFY(item.type() == QOrganizerItemType::TypeTodoOccurrence);
+ }
+
+ // third - save event with no recurrence; call items() -- should get back that parent, not an occurrence.
+ cm->removeItems(cm->itemIds()); // empty the calendar to prevent the previous test from interfering this one
+ recTodo.setRecurrenceRules(QSet<QOrganizerRecurrenceRule>()); // clear rrule.
+ recTodo.setId(QOrganizerItemId());
+ cm->saveItem(&recTodo);
+ items = cm->items(QDateTime(), QDateTime());
+ QCOMPARE(items.count(), 1);
+ foreach (const QOrganizerItem& item, items) {
+ QVERIFY(item.type() == QOrganizerItemType::TypeTodo);
+ }
+
+ // fourth - the same situation, but giving a time span. should still get back the parent.
+ items = cm->items(QDateTime(QDate(2010, 9, 1), QTime(15, 0, 0)), QDateTime(QDate(2010, 9, 1), QTime(18, 0, 0)));
+ QCOMPARE(items.count(), 1);
+ foreach (const QOrganizerItem& item, items) {
+ QVERIFY(item.type() == QOrganizerItemType::TypeTodo);
+ }
+
+ // test semantics of itemsForExport():
+ // first - save event with multiple occurrences; call ife() -- get back that parent
+ cm->removeItems(cm->itemIds()); // empty the calendar to prevent the previous test from interfering this one
+ recTodo.setRecurrenceRule(rrule);
+ recTodo.setId(QOrganizerItemId());
+ cm->saveItem(&recTodo);
+ items = cm->itemsForExport();
+ QCOMPARE(items.count(), 1);
+ foreach (const QOrganizerItem& item, items) {
+ QVERIFY(item.type() == QOrganizerItemType::TypeTodo);
+ }
+
+ // second - call items, resave only the first occurrence as an exception,
+ // call ife() -- get back parent + exception
+ items = cm->items();
+ int todoCount = 0;
+ int todoOccurrenceCount = 0;
+ foreach (const QOrganizerItem& item, items) {
+ if (item.type() == QOrganizerItemType::TypeTodoOccurrence) {
+ if (todoOccurrenceCount == 0) {
+ QOrganizerTodoOccurrence exception(item);
+ exception.setDisplayLabel("exception");
+ QVERIFY(cm->saveItem(&exception));
+ }
+ todoOccurrenceCount++;
+ } else if (item.type() == QOrganizerItemType::TypeTodo) {
+ todoCount++;
+ }
+ }
+ QCOMPARE(todoOccurrenceCount, 3);
+ QCOMPARE(todoCount, 0);
+ items = cm->itemsForExport();
+ QCOMPARE(items.count(), 2);
+ todoCount = 0;
+ todoOccurrenceCount = 0;
+ foreach (const QOrganizerItem& item, items) {
+ if (item.type() == QOrganizerItemType::TypeTodo) {
+ todoCount += 1;
+ } else if (item.type() == QOrganizerItemType::TypeTodoOccurrence) {
+ todoOccurrenceCount += 1;
+ }
+ QVERIFY(!item.id().isNull()); // should NEVER be null, since that would be a generated occurrence.
+ }
+ QCOMPARE(todoCount, 1);
+ QCOMPARE(todoOccurrenceCount, 1);
+
+ // third, have all occurrences persisted
+ items = cm->items();
+ foreach (const QOrganizerItem& item, items) {
+ if (item.type() == QOrganizerItemType::TypeTodoOccurrence) {
+ QOrganizerTodoOccurrence exception(item);
+ exception.setDisplayLabel("exception");
+ QVERIFY(cm->saveItem(&exception));
+ }
+ }
+ items = cm->itemsForExport();
+ QCOMPARE(items.size(), 4);
+ todoCount = 0;
+ todoOccurrenceCount = 0;
+ foreach (const QOrganizerItem& item, items) {
+ if (item.type() == QOrganizerItemType::TypeTodo) {
+ todoCount += 1;
+ } else if (item.type() == QOrganizerItemType::TypeTodoOccurrence) {
+ todoOccurrenceCount += 1;
+ }
+ QVERIFY(!item.id().isNull()); // should NEVER be null, since that would be a generated occurrence.
+ }
+ QCOMPARE(todoCount, 1);
+ QCOMPARE(todoOccurrenceCount, 3);
+}
+
void tst_QOrganizerManager::spanOverDays()
{
QFETCH(QString, uri);
@@ -3265,7 +3633,7 @@ void tst_QOrganizerManager::idComparison()
{
QFETCH(QString, uri);
QScopedPointer<QOrganizerManager> cm(QOrganizerManager::fromUri(uri));
-
+
// Can we run this test?
if (!cm->supportedItemTypes().contains(QOrganizerItemType::TypeJournal)) {
QSKIP("Backend not compatible with this test", SkipSingle);
@@ -3340,7 +3708,8 @@ void tst_QOrganizerManager::idComparison()
QVERIFY(bcid1 < bcid2);
QVERIFY(bcid3 < bcid2);
- QVERIFY(e1id < e2id); // this test may be unstable, depending on the backend?
+ if (!uri.contains("mkcal")) //this verification makes no sense for mkcal
+ QVERIFY(e1id < e2id); // this test may be unstable, depending on the backend?
// now we do some tests which might be unstable
QVERIFY(bcid1 < c1id); // collectionIds: the first comparison should be manager uri, and bcid manager uri is early in the alphabet.
@@ -3513,74 +3882,81 @@ void tst_QOrganizerManager::detailOrders()
{
QFETCH(QString, uri);
QScopedPointer<QOrganizerManager> cm(QOrganizerManager::fromUri(uri));
-
+
if (cm->managerName() == "symbian")
QSKIP("symbian manager does not support detail ordering", SkipSingle);
if (cm->managerName() == "maemo5")
QSKIP("maemo5 manager does not support detail ordering", SkipSingle);
-
+
QOrganizerEvent a;
- // comments
- QOrganizerItemComment comment1, comment2, comment3;
-
- comment1.setComment("11111111");
- comment2.setComment("22222222");
- comment3.setComment("33333333");
+ // comments are not supported in mkcal
+ if (cm->managerName() != "mkcal") {
+ // comments
+ QOrganizerItemComment comment1, comment2, comment3;
- a.saveDetail(&comment1);
- a.saveDetail(&comment2);
- a.saveDetail(&comment3);
+ comment1.setComment("11111111");
+ comment2.setComment("22222222");
+ comment3.setComment("33333333");
- QVERIFY(cm->saveItem(&a));
- a = cm->item(a.id());
-
- QList<QOrganizerItemDetail> details = a.details(QOrganizerItemComment::DefinitionName);
- QVERIFY(details.count() == 3);
-
- QVERIFY(a.removeDetail(&comment2));
- QVERIFY(cm->saveItem(&a));
- a = cm->item(a.id());
- details = a.details(QOrganizerItemComment::DefinitionName);
- QVERIFY(details.count() == 2);
-
- a.saveDetail(&comment2);
- QVERIFY(cm->saveItem(&a));
- a = cm->item(a.id());
-
- details = a.details(QOrganizerItemComment::DefinitionName);
- QVERIFY(details.count() == 3);
+ a.saveDetail(&comment1);
+ a.saveDetail(&comment2);
+ a.saveDetail(&comment3);
+
+ QVERIFY(cm->saveItem(&a));
+ a = cm->item(a.id());
+
+ QList<QOrganizerItemDetail> details = a.details(QOrganizerItemComment::DefinitionName);
+ QVERIFY(details.count() == 3);
+
+ QVERIFY(a.removeDetail(&comment2));
+ QVERIFY(cm->saveItem(&a));
+ a = cm->item(a.id());
+ details = a.details(QOrganizerItemComment::DefinitionName);
+ QVERIFY(details.count() == 2);
+
+ a.saveDetail(&comment2);
+ QVERIFY(cm->saveItem(&a));
+ a = cm->item(a.id());
+
+ details = a.details(QOrganizerItemComment::DefinitionName);
+ QVERIFY(details.count() == 3);
+ }
//addresses
+ {
+ QOrganizerItemLocation address1, address2, address3;
- QOrganizerItemLocation address1, address2, address3;
-
- address1.setLabel("Brandl St");
- address3 = address2 = address1;
+ address1.setLabel("Brandl St");
+ address3 = address2 = address1;
- a.saveDetail(&address1);
- a.saveDetail(&address2);
- a.saveDetail(&address3);
+ a.saveDetail(&address1);
+ a.saveDetail(&address2);
+ a.saveDetail(&address3);
- QVERIFY(cm->saveItem(&a));
- a = cm->item(a.id());
-
- details = a.details(QOrganizerItemLocation::DefinitionName);
- QVERIFY(details.count() == 1); // 1 location - they're unique
-
- QVERIFY(a.removeDetail(&address3)); // remove the most recent.
- QVERIFY(cm->saveItem(&a));
- a = cm->item(a.id());
- details = a.details(QOrganizerItemLocation::DefinitionName);
- QVERIFY(details.count() == 0); // unique, remove one means none left.
-
- a.saveDetail(&address2);
- QVERIFY(cm->saveItem(&a));
- a = cm->item(a.id());
-
- details = a.details(QOrganizerItemLocation::DefinitionName);
- QVERIFY(details.count() == 1); // add one back.
+ QVERIFY(cm->saveItem(&a));
+ a = cm->item(a.id());
+
+ QList<QOrganizerItemDetail> details = a.details(QOrganizerItemLocation::DefinitionName);
+ QVERIFY(details.count() == 1); // 1 location - they're unique
+
+ // Detail keys for the moment are not persistent through an item save / fetch
+ address3 = details.at(0);
+
+ QVERIFY(a.removeDetail(&address3)); // remove the most recent.
+ QVERIFY(cm->saveItem(&a));
+ a = cm->item(a.id());
+ details = a.details(QOrganizerItemLocation::DefinitionName);
+ QVERIFY(details.count() == 0); // unique, remove one means none left.
+
+ a.saveDetail(&address2);
+ QVERIFY(cm->saveItem(&a));
+ a = cm->item(a.id());
+
+ details = a.details(QOrganizerItemLocation::DefinitionName);
+ QVERIFY(details.count() == 1); // add one back.
+ }
}
@@ -3620,7 +3996,6 @@ void tst_QOrganizerManager::collections()
QOrganizerEvent i1, i2, i3, i4, i5;
i1.setDisplayLabel("one");
- i1.addComment("item one");
i2.setDisplayLabel("two");
i2.setDescription("this is the second item");
i3.setDisplayLabel("three");
@@ -3695,7 +4070,7 @@ void tst_QOrganizerManager::collections()
i4 = saveList.at(2);
i5 = saveList.at(3);
QList<QOrganizerItem> fetchedItems = oim->items();
- QVERIFY(fetchedItems.count() == (originalItemCount + 4));
+ QCOMPARE(fetchedItems.count(), originalItemCount + 4);
QVERIFY(fetchedItems.contains(i2)); // these three should have been added
QVERIFY(fetchedItems.contains(i3));
QVERIFY(fetchedItems.contains(i4));
@@ -3710,6 +4085,29 @@ void tst_QOrganizerManager::collections()
QVERIFY(fetchedItems.contains(i4));
QVERIFY(fetchedItems.contains(i5));
+ // exceptions must be saved in the same collection as their parent.
+ QOrganizerEvent recurringEvent;
+ recurringEvent.setDescription("A recurring test event parent.");
+ recurringEvent.setLocation("Some Location");
+ recurringEvent.setStartDateTime(QDateTime(QDate(2010,10,5), QTime(10,30)));
+ recurringEvent.setEndDateTime(QDateTime(QDate(2010,10,5), QTime(11,30)));
+ QOrganizerRecurrenceRule rrule;
+ rrule.setFrequency(QOrganizerRecurrenceRule::Weekly);
+ rrule.setLimit(5); // count limited.
+ recurringEvent.setRecurrenceRule(rrule);
+ recurringEvent.setCollectionId(c2.id());
+ QVERIFY(oim->saveItem(&recurringEvent));
+ recurringEvent = oim->item(recurringEvent.id()); // reload it.
+ QVERIFY(recurringEvent.collectionId() == c2.id());
+ QList<QOrganizerItem> occ(oim->itemOccurrences(recurringEvent, QDateTime(), QDateTime()));
+ QVERIFY(occ.size() == 5);
+ QOrganizerEventOccurrence someException = occ.at(2); // there should be five, so this shouldn't segfault.
+ someException.setLocation("Other Location");
+ someException.setCollectionId(c3.id()); // different to parent.
+ QVERIFY(!oim->saveItem(&someException)); // shouldn't work.
+ someException.setCollectionId(c2.id()); // same as parent.
+ QVERIFY(oim->saveItem(&someException)); // should work.
+
// remove a collection, removes its items.
QVERIFY(oim->removeCollection(c2.id()));
fetchedItems = oim->items();
@@ -3717,6 +4115,8 @@ void tst_QOrganizerManager::collections()
QVERIFY(!fetchedItems.contains(i2)); // these three should have been removed
QVERIFY(!fetchedItems.contains(i3));
QVERIFY(!fetchedItems.contains(i4));
+ QVERIFY(!fetchedItems.contains(recurringEvent)); // the parent
+ QVERIFY(!fetchedItems.contains(someException)); // and exceptions too.
QVERIFY(fetchedItems.contains(i5)); // i5 should not have been removed.
// attempt to save an item in a non-existent collection should fail.