kde-playground/kdepim-runtime/migration/kmail/emptyresourcecleaner.cpp
2015-04-14 22:08:21 +00:00

229 lines
7.3 KiB
C++

/* This file is part of the KDE project
Copyright (C) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net
Author: Kevin Krammer, krake@kdab.com
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 "emptyresourcecleaner.h"
#include <akonadi/agentinstance.h>
#include <akonadi/agentmanager.h>
#include <akonadi/collection.h>
#include <akonadi/collectiondeletejob.h>
#include <akonadi/collectionfetchjob.h>
#include <akonadi/collectionfetchscope.h>
#include <akonadi/collectionstatistics.h>
#include <akonadi/itemfetchjob.h>
#include <KDebug>
#include <QHash>
#include <QVariant>
using namespace Akonadi;
typedef QHash<Collection::Id, Collection> CollectionHash;
class EmptyResourceCleaner::Private
{
EmptyResourceCleaner *const q;
public:
Private( EmptyResourceCleaner *parent, const AgentInstance &resource )
: q( parent ), mResource( resource ), mOptions( CheckOnly )
{
}
void deleteCollections();
void deleteResource();
void cleaupFinished();
public:
AgentInstance mResource;
CleaningOptions mOptions;
Collection::List mAllCollections;
CollectionHash mDeletableCollections;
CollectionHash mDeletedCollections;
public: // slots
void collectionFetchResult( KJob *job );
void collectionDeleteResult( KJob *job );
};
void EmptyResourceCleaner::Private::deleteCollections()
{
CollectionHash::iterator it = mDeletableCollections.begin();
while ( it != mDeletableCollections.end() ) {
const Collection collection = it.value();
const Collection parent = collection.parentCollection();
if ( mDeletedCollections.contains( parent.id() ) ) {
mDeletedCollections.insert( collection.id(), collection );
it = mDeletableCollections.erase( it );
} else {
kDebug( KDE_DEFAULT_DEBUG_AREA ) << "Removing collection: id=" << collection.id()
<< "remoteId=" << collection.remoteId();
CollectionDeleteJob *deleteJob = new CollectionDeleteJob( collection );
deleteJob->setProperty( "collection", QVariant::fromValue<Collection>( collection ) );
connect( deleteJob, SIGNAL(result(KJob*)), q, SLOT(collectionDeleteResult(KJob*)) );
return;
}
}
Q_ASSERT( mDeletableCollections.isEmpty() );
if ( mOptions.testFlag( DeleteEmptyResource ) &&
mDeletedCollections.count() == mAllCollections.count() ) {
deleteResource();
} else {
emit q->cleanupFinished( mResource );
}
}
void EmptyResourceCleaner::Private::deleteResource()
{
kDebug( KDE_DEFAULT_DEBUG_AREA ) << "Removing resource" << mResource.identifier();
AgentManager::self()->removeInstance( mResource );
emit q->cleanupFinished( mResource );
}
void EmptyResourceCleaner::Private::collectionFetchResult( KJob *job )
{
if ( job->error() != 0 ) {
kError() << job->errorString();
emit q->cleanupFinished( mResource );
return;
}
CollectionFetchJob *fetchJob = qobject_cast<CollectionFetchJob*>( job );
Q_ASSERT( fetchJob != 0 );
mAllCollections = fetchJob->collections();
CollectionHash nonEmptyCollections;
Q_FOREACH ( const Collection &collection, mAllCollections ) {
qint64 itemCount = collection.statistics().count();
// TODO should be async as well
if ( itemCount == -1 ) {
ItemFetchJob *itemFetch = new ItemFetchJob( collection );
if ( itemFetch->exec() ) {
itemCount = itemFetch->items().count();
}
}
kDebug( KDE_DEFAULT_DEBUG_AREA ) << "collection" << collection.name()
<< "has" << itemCount
<< "items";
if ( itemCount == 0 ) {
mDeletableCollections.insert( collection.id(), collection );
} else {
nonEmptyCollections.insert( collection.id(), collection );
}
}
kDebug( KDE_DEFAULT_DEBUG_AREA ) << mDeletableCollections.count()
<< "potenially deletable collections"
<< nonEmptyCollections.count() << "not empty";
Q_FOREACH ( const Collection &collection, nonEmptyCollections ) {
Collection parent = collection.parentCollection();
while ( parent.isValid() && parent != Collection::root() ) {
mDeletableCollections.remove( parent.id() );
parent = parent.parentCollection();
}
}
kDebug( KDE_DEFAULT_DEBUG_AREA ) << mDeletableCollections.count() << "of"
<< mAllCollections.count() << "are empty";
if ( mOptions.testFlag( DeleteEmptyCollections ) ) {
deleteCollections();
} else if ( mOptions.testFlag( DeleteEmptyResource ) &&
mDeletableCollections.count() == mAllCollections.count() ) {
deleteResource();
} else {
emit q->cleanupFinished( mResource );
}
}
void EmptyResourceCleaner::Private::collectionDeleteResult( KJob *job )
{
if ( job->error() != 0 ) {
kError() << job->errorString();
emit q->cleanupFinished( mResource );
return;
}
CollectionDeleteJob *deleteJob = qobject_cast<CollectionDeleteJob*>( job );
Q_ASSERT( deleteJob != 0 );
const Collection collection = deleteJob->property( "collection" ).value<Collection>();
mDeletableCollections.remove( collection.id() );
mDeletedCollections.insert( collection.id(), collection );
deleteCollections();
}
EmptyResourceCleaner::EmptyResourceCleaner( const AgentInstance &resource, QObject *parent )
: QObject( parent ), d( new Private( this, resource ) )
{
kDebug( KDE_DEFAULT_DEBUG_AREA ) << "Creating cleaner for resource"
<< d->mResource.identifier();
connect( this, SIGNAL(cleanupFinished(Akonadi::AgentInstance)), SLOT(deleteLater()) );
CollectionFetchScope scope;
scope.setResource( d->mResource.identifier() );
scope.setAncestorRetrieval( CollectionFetchScope::All );
scope.setIncludeStatistics( true );
CollectionFetchJob *fetchJob = new CollectionFetchJob( Collection::root(), CollectionFetchJob::Recursive );
fetchJob->setFetchScope( scope );
connect( fetchJob, SIGNAL(result(KJob*)), SLOT(collectionFetchResult(KJob*)) );
}
EmptyResourceCleaner::~EmptyResourceCleaner()
{
delete d;
}
void EmptyResourceCleaner::setCleaningOptions( CleaningOptions options )
{
d->mOptions = options;
}
EmptyResourceCleaner::CleaningOptions EmptyResourceCleaner::cleaningOptions() const
{
return d->mOptions;
}
Collection::List EmptyResourceCleaner::deletableCollections() const
{
return d->mDeletableCollections.values();
}
bool EmptyResourceCleaner::isResourceDeletable() const
{
return ( d->mDeletedCollections.count() + d->mDeletableCollections.count() )
== d->mAllCollections.count();
}
#include "moc_emptyresourcecleaner.cpp"
// kate: space-indent on; indent-width 2; replace-tabs on;