/* This file is part of libkcal. Copyright (c) 2009 Kevin Krammer This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "resourceakonadi_p.h" #include "concurrentjobs.h" #include "itemsavecontext.h" #include "resourceakonadiconfig.h" #include "storecollectiondialog.h" #include #include #include using namespace KCal; ResourceAkonadi::Private::Private( ResourceAkonadi *parent ) : SharedResourcePrivate( new IdArbiter(), parent ), mParent( parent ), mCalendar( QLatin1String( "UTC" ) ), mLock( new KABC::LockNull( true ) ), mInternalCalendarModification( false ), mAgentModel( 0 ), mAgentFilterModel( 0 ) { } ResourceAkonadi::Private::Private( const KConfigGroup &config, ResourceAkonadi *parent ) : SharedResourcePrivate( config, new IdArbiter(), parent ), mParent( parent ), mCalendar( QLatin1String( "UTC" ) ), mLock( new KABC::LockNull( true ) ), mInternalCalendarModification( false ), mAgentModel( 0 ), mAgentFilterModel( 0 ) { } ResourceAkonadi::Private::~Private() { delete mLock; } bool ResourceAkonadi::Private::doSaveIncidence( Incidence *incidence ) { const ChangeByKResId::const_iterator findIt = mChanges.constFind( incidence->uid() ); if ( findIt == mChanges.constEnd() ) { kWarning( 5800 ) << "No change for incidence (uid=" << incidence->uid() << ", summary=" << incidence->summary() << ")"; return true; } ItemSaveContext saveContext; if ( !prepareItemSaveContext( findIt, saveContext ) ) { const QString message = i18nc( "@info:status", "Processing change set failed" ); savingResult( false, message ); return false; } ConcurrentItemSaveJob itemSaveJob( saveContext ); if ( !itemSaveJob.exec() ) { savingResult( false, itemSaveJob->errorString() ); return false; } mChanges.remove( incidence->uid() ); return true; } QString ResourceAkonadi::Private::subResourceIdentifier( const QString &incidenceUid ) const { return mUidToResourceMap.value( incidenceUid ); } bool ResourceAkonadi::Private::openResource() { kDebug( 5800 ) << (void*) mAgentModel << "state=" << state(); if ( mAgentModel == 0 && state() != Failed ) { mAgentModel = new Akonadi::AgentInstanceModel( this ); mAgentFilterModel = new Akonadi::AgentFilterProxyModel( this ); mAgentFilterModel->addCapabilityFilter( QLatin1String( "Resource" ) ); mAgentFilterModel->addMimeTypeFilter( QLatin1String( "text/calendar" ) ); mAgentFilterModel->setSourceModel( mAgentModel ); } mCalendar.registerObserver( this ); return true; } bool ResourceAkonadi::Private::closeResource() { mCalendar.unregisterObserver( this ); return true; } void ResourceAkonadi::Private::clearResource() { SharedResourcePrivate::clearResource(); // block scope for BoolGuard { BoolGuard internalModification( mInternalCalendarModification, true ); mCalendar.close(); } emit mParent->resourceChanged( mParent ); } const SubResourceBase *ResourceAkonadi::Private::storeSubResourceFromUser( const QString &uid, const QString &mimeType ) { Q_UNUSED( uid ); Q_ASSERT( mStoreCollectionDialog != 0 ); if ( mimeType == Akonadi::IncidenceMimeTypeVisitor::eventMimeType() ) { mStoreCollectionDialog->setLabelText( i18nc( "@label where to store a calendar entry of type Event", "Please select a storage folder for this Event" ) ); } else if ( mimeType == Akonadi::IncidenceMimeTypeVisitor::todoMimeType() ) { mStoreCollectionDialog->setLabelText( i18nc( "@label where to store a calendar entry of type Todo", "Please select a storage folder for this Todo" ) ); } else if ( mimeType == Akonadi::IncidenceMimeTypeVisitor::journalMimeType() ) { mStoreCollectionDialog->setLabelText( i18nc( "@label where to store a calendar entry of type Journal", "Please select a storage folder for this Journal" ) ); } else if ( mimeType == QLatin1String( "text/calendar" ) ) { kWarning( 5800 ) << "Unexpected generic MIME type text/calendar"; mStoreCollectionDialog->setLabelText( i18nc( "@label where to store a calendar entry of unspecified type", "Please select a storage folder for this calendar entry" ) ); } else { kError( 5800 ) << "Unexpected MIME type:" << mimeType; mStoreCollectionDialog->setLabelText( i18nc( "@label", "Please select a storage folder" ) ); } // FIXME should be sub MIME type mStoreCollectionDialog->setMimeType( QLatin1String( "text/calendar" ) ); const SubResourceBase *resource = 0; while ( resource == 0 ) { if ( mStoreCollectionDialog->exec() != QDialog::Accepted ) { return 0; } Akonadi::Collection collection = mStoreCollectionDialog->selectedCollection(); if ( collection.isValid() ) { resource = mModel.subResource( collection.id() ); } } return resource; } Akonadi::Item ResourceAkonadi::Private::createItem( const QString &kresId ) { Akonadi::Item item; Incidence *cachedIncidence = mCalendar.incidence( kresId ); kDebug( 5800 ) << "kresId=" << kresId << "cachedIncidence=" << (void*) cachedIncidence; if ( cachedIncidence != 0 ) { item.setMimeType( mMimeVisitor.mimeType( cachedIncidence ) ); item.setPayload( IncidencePtr( cachedIncidence->clone() ) ); } return item; } Akonadi::Item ResourceAkonadi::Private::updateItem( const Akonadi::Item &item, const QString &kresId, const QString &originalId ) { Akonadi::Item update( item ); Incidence *cachedIncidence = mCalendar.incidence( kresId ); if ( cachedIncidence != 0 ) { IncidencePtr incidencePtr( cachedIncidence->clone() ); incidencePtr->setUid( originalId ); update.setPayload( incidencePtr ); } return update; } StoreConfigIface::CollectionsByMimeType ResourceAkonadi::Private::storeCollectionsFromOldDefault() const { Q_ASSERT( mDefaultStoreCollection.isValid() ); CollectionsByMimeType storeCollections; // FIXME should be sub MIME type // if ( Akonadi::MimeTypeChecker::isWantedCollection( mDefaultStoreCollection, KCal::MimeTypeVisitor::eventMimeType() ) ) { // storeCollections[ KCal::MimeTypeVisitor::eventMimeType() ] = mDefaultStoreCollection; // } // if ( Akonadi::MimeTypeChecker::isWantedCollection( mDefaultStoreCollection, KCal::MimeTypeVisitor::todoMimeType() ) ) { // storeCollections[ KCal::MimeTypeVisitor::todoMimeType() ] = mDefaultStoreCollection; // } // if ( Akonadi::MimeTypeChecker::isWantedCollection( mDefaultStoreCollection, KCal::MimeTypeVisitor::journalMimeType() ) ) { // storeCollections[ KCal::MimeTypeVisitor::journalMimeType() ] = mDefaultStoreCollection; // } storeCollections[ Akonadi::IncidenceMimeTypeVisitor::eventMimeType() ] = mDefaultStoreCollection; storeCollections[ Akonadi::IncidenceMimeTypeVisitor::todoMimeType() ] = mDefaultStoreCollection; storeCollections[ Akonadi::IncidenceMimeTypeVisitor::journalMimeType() ] = mDefaultStoreCollection; return storeCollections; } void ResourceAkonadi::Private::calendarIncidenceAdded( Incidence *incidence ) { Q_UNUSED( incidence ); if ( mInternalCalendarModification ) { return; } // added to the calendar needs to be caught at resource level, e.g // addEvent() method Q_ASSERT( mUidToResourceMap.constFind( incidence->uid() ) != mUidToResourceMap.constEnd() ); } void ResourceAkonadi::Private::calendarIncidenceChanged( Incidence *incidence ) { if ( mInternalCalendarModification ) { return; } kDebug( 5800 ) << "Incidence (uid=" << incidence->uid() << ", summary=" << incidence->summary() << ")"; changeLocalItem( incidence->uid() ); } void ResourceAkonadi::Private::calendarIncidenceDeleted( Incidence *incidence ) { if ( mInternalCalendarModification ) { return; } kDebug( 5800 ) << "Incidence (uid=" << incidence->uid() << ", summary=" << incidence->summary() << ")"; removeLocalItem( incidence->uid() ); } void ResourceAkonadi::Private::subResourceAdded( SubResourceBase *subResourceBase ) { kDebug( 5800 ) << "id=" << subResourceBase->subResourceIdentifier(); SharedResourcePrivate::subResourceAdded( subResourceBase ); SubResource *subResource = qobject_cast( subResourceBase ); connect( subResource, SIGNAL(incidenceAdded(IncidencePtr,QString)), this, SLOT(incidenceAdded(IncidencePtr,QString)) ); connect( subResource, SIGNAL(incidenceChanged(IncidencePtr,QString)), this, SLOT(incidenceChanged(IncidencePtr,QString)) ); connect( subResource, SIGNAL(incidenceRemoved(QString,QString)), this, SLOT(incidenceRemoved(QString,QString)) ); emit mParent->signalSubresourceAdded( mParent, QLatin1String( "calendar" ), subResourceBase->subResourceIdentifier(), subResourceBase->label() ); } void ResourceAkonadi::Private::subResourceRemoved( SubResourceBase *subResourceBase ) { kDebug( 5800 ) << "id=" << subResourceBase->subResourceIdentifier(); SharedResourcePrivate::subResourceRemoved( subResourceBase ); SubResource *subResource = qobject_cast( subResourceBase ); disconnect( subResource, SIGNAL(incidenceAdded(IncidencePtr,QString)), this, SLOT(incidenceAdded(IncidencePtr,QString)) ); disconnect( subResource, SIGNAL(incidenceChanged(IncidencePtr,QString)), this, SLOT(incidenceChanged(IncidencePtr,QString)) ); disconnect( subResource, SIGNAL(incidenceRemoved(QString,QString)), this, SLOT(incidenceRemoved(QString,QString)) ); // block scope for BoolGuard { BoolGuard internalModification( mInternalCalendarModification, true ); QMap::iterator it = mUidToResourceMap.begin(); while ( it != mUidToResourceMap.end() ) { if ( it.value() == subResourceBase->subResourceIdentifier() ) { const QString uid = it.key(); mChanges.remove( uid ); mIdArbiter->removeArbitratedId( uid ); Incidence *cachedIncidence = mCalendar.incidence( uid ); if ( cachedIncidence != 0 ) { mCalendar.deleteIncidence( cachedIncidence ); } it = mUidToResourceMap.erase( it ); } else { ++it; } } } emit mParent->signalSubresourceRemoved( mParent, QLatin1String( "calendar" ), subResourceBase->subResourceIdentifier() ); emit mParent->resourceChanged( mParent ); } void ResourceAkonadi::Private::loadingResult( bool ok, const QString &errorString ) { SharedResourcePrivate::loadingResult( ok, errorString ); if ( ok ) { emit mParent->resourceLoaded( mParent ); } else { mParent->loadError( errorString ); } } void ResourceAkonadi::Private::savingResult( bool ok, const QString &errorString ) { SharedResourcePrivate::savingResult( ok, errorString ); if ( ok ) { emit mParent->resourceSaved( mParent ); } else { mParent->saveError( errorString ); } } void ResourceAkonadi::Private::incidenceAdded( const IncidencePtr &incidencePtr, const QString &subResourceIdentifier ) { kDebug( 5800 ) << "Incidence (uid=" << incidencePtr->uid() << ", summary=" << incidencePtr->summary() << "), subResource=" << subResourceIdentifier; mChanges.remove( incidencePtr->uid() ); // check if we already have it, i.e. if it is the result of us saving it if ( mCalendar.incidence( incidencePtr->uid() ) == 0 ) { Incidence *incidence = incidencePtr->clone(); // block scope for BoolGuard { BoolGuard internalModification( mInternalCalendarModification, true ); mCalendar.addIncidence( incidence ); } mUidToResourceMap.insert( incidence->uid(), subResourceIdentifier ); if ( !isLoading() ) { emit mParent->resourceChanged( mParent ); } } } void ResourceAkonadi::Private::incidenceChanged( const IncidencePtr &incidencePtr, const QString &subResourceIdentifier ) { kDebug( 5800 ) << "Incidence (uid=" << incidencePtr->uid() << ", summary=" << incidencePtr->summary() << "), subResource=" << subResourceIdentifier; mChanges.remove( incidencePtr->uid() ); Incidence *cachedIncidence = mCalendar.incidence( incidencePtr->uid() ); if ( cachedIncidence == 0 ) { kWarning( 5800 ) << "Incidence" << incidencePtr->uid() << "changed but no longer in local list"; return; } // block scope for BoolGuard { BoolGuard internalModification( mInternalCalendarModification, true ); // make sure any observer the resource might have installed gets properly notified cachedIncidence->startUpdates(); bool assignResult = mIncidenceAssigner.assign( cachedIncidence, incidencePtr.get() ); if ( assignResult ) { cachedIncidence->updated(); } cachedIncidence->endUpdates(); if ( !assignResult ) { kWarning( 5800 ) << "Incidence (uid=" << cachedIncidence->uid() << ", summary=" << cachedIncidence->summary() << ") changed type. Replacing it."; mCalendar.deleteIncidence( cachedIncidence ); mCalendar.addIncidence( incidencePtr->clone() ); } } if ( !isLoading() ) { emit mParent->resourceChanged( mParent ); } } void ResourceAkonadi::Private::incidenceRemoved( const QString &uid, const QString &subResourceIdentifier ) { kDebug( 5800 ) << "Incidence (uid=" << uid << "), subResource=" << subResourceIdentifier; mUidToResourceMap.remove( uid ); Incidence *cachedIncidence = mCalendar.incidence( uid ); if ( cachedIncidence == 0 ) { kWarning() << "Incidence (uid=" << uid << ") no longer in local list"; return; } // block scope for BoolGuard { BoolGuard internalModification( mInternalCalendarModification, true ); mCalendar.deleteIncidence( cachedIncidence ); } if ( !isLoading() ) { emit mParent->resourceChanged( mParent ); } } // kate: space-indent on; indent-width 2; replace-tabs on;