kde-playground/kdepim-runtime/kresources/kcal/resourceakonadi_p.cpp

430 lines
14 KiB
C++
Raw Normal View History

2015-04-14 22:08:21 +00:00
/*
This file is part of libkcal.
Copyright (c) 2009 Kevin Krammer <kevin.krammer@gmx.at>
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 <akonadi/agentfilterproxymodel.h>
#include <akonadi/agentinstancemodel.h>
#include <kabc/locknull.h>
using namespace KCal;
ResourceAkonadi::Private::Private( ResourceAkonadi *parent )
: SharedResourcePrivate<SubResource>( 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<SubResource>( 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<SubResource>::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>( 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>( 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<SubResource>::subResourceAdded( subResourceBase );
SubResource *subResource = qobject_cast<SubResource*>( 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<SubResource>::subResourceRemoved( subResourceBase );
SubResource *subResource = qobject_cast<SubResource*>( 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<QString, QString>::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<SubResource>::loadingResult( ok, errorString );
if ( ok ) {
emit mParent->resourceLoaded( mParent );
} else {
mParent->loadError( errorString );
}
}
void ResourceAkonadi::Private::savingResult( bool ok, const QString &errorString )
{
SharedResourcePrivate<SubResource>::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;