kde-playground/kdepimlibs/akonadi/specialcollections.cpp
2015-04-14 21:49:29 +00:00

282 lines
9.7 KiB
C++

/*
Copyright (c) 2009 Constantin Berzan <exit3219@gmail.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 "specialcollections.h"
#include "specialcollections_p.h"
#include "specialcollectionattribute_p.h"
#include "akonadi/agentinstance.h"
#include "akonadi/agentmanager.h"
#include "akonadi/collectionmodifyjob.h"
#include "akonadi/collectionfetchjob.h"
#include "akonadi/monitor.h"
#include <KDebug>
#include <kcoreconfigskeleton.h>
#include <QtCore/QHash>
#include <QtCore/QObject>
#include <QtCore/QSet>
#include <akonadi/collectionfetchscope.h>
using namespace Akonadi;
SpecialCollectionsPrivate::SpecialCollectionsPrivate(KCoreConfigSkeleton *settings, SpecialCollections *qq)
: q(qq)
, mSettings(settings)
, mBatchMode(false)
{
mMonitor = new Monitor(q);
mMonitor->fetchCollectionStatistics(true);
/// In order to know if items are added or deleted
/// from one of our specialcollection folders,
/// we have to watch all mail item add/move/delete notifications
/// and check for the parent to see if it is one we care about
QObject::connect(mMonitor, SIGNAL(collectionRemoved(Akonadi::Collection)),
q, SLOT(collectionRemoved(Akonadi::Collection)));
QObject::connect(mMonitor, SIGNAL(collectionStatisticsChanged(Akonadi::Collection::Id,Akonadi::CollectionStatistics)),
q, SLOT(collectionStatisticsChanged(Akonadi::Collection::Id,Akonadi::CollectionStatistics)));
}
SpecialCollectionsPrivate::~SpecialCollectionsPrivate()
{
}
QString SpecialCollectionsPrivate::defaultResourceId() const
{
if (mDefaultResourceId.isEmpty()) {
mSettings->readConfig();
const KConfigSkeletonItem *item = mSettings->findItem(QLatin1String("DefaultResourceId"));
Q_ASSERT(item);
mDefaultResourceId = item->property().toString();
}
return mDefaultResourceId;
}
void SpecialCollectionsPrivate::emitChanged(const QString &resourceId)
{
if (mBatchMode) {
mToEmitChangedFor.insert(resourceId);
} else {
kDebug() << "Emitting changed for" << resourceId;
const AgentInstance agentInstance = AgentManager::self()->instance(resourceId);
emit q->collectionsChanged(agentInstance);
// first compare with local value then with config value (which also updates the local value)
if (resourceId == mDefaultResourceId || resourceId == defaultResourceId()) {
kDebug() << "Emitting defaultFoldersChanged.";
emit q->defaultCollectionsChanged();
}
}
}
void SpecialCollectionsPrivate::collectionRemoved(const Collection &collection)
{
kDebug() << "Collection" << collection.id() << "resource" << collection.resource();
if (mFoldersForResource.contains(collection.resource())) {
// Retrieve the list of special folders for the resource the collection belongs to
QHash<QByteArray, Collection> &folders = mFoldersForResource[collection.resource()];
{
QMutableHashIterator<QByteArray, Collection> it(folders);
while (it.hasNext()) {
it.next();
if (it.value() == collection) {
// The collection to be removed is a special folder
it.remove();
emitChanged(collection.resource());
}
}
}
if (folders.isEmpty()) {
// This resource has no more folders, so remove it completely.
mFoldersForResource.remove(collection.resource());
}
}
}
void SpecialCollectionsPrivate::collectionStatisticsChanged(Akonadi::Collection::Id collectionId, const Akonadi::CollectionStatistics &statistics)
{
// need to get the name of the collection in order to be able to check if we are storing it,
// but we have the id from the monitor, so fetch the name.
Akonadi::CollectionFetchJob *fetchJob = new Akonadi::CollectionFetchJob(Collection(collectionId), Akonadi::CollectionFetchJob::Base);
fetchJob->fetchScope().setAncestorRetrieval(Akonadi::CollectionFetchScope::None);
fetchJob->setProperty("statistics", QVariant::fromValue(statistics));
q->connect(fetchJob, SIGNAL(result(KJob*)), q, SLOT(collectionFetchJobFinished(KJob*)));
}
void SpecialCollectionsPrivate::collectionFetchJobFinished(KJob *job)
{
if (job->error()) {
kWarning() << "Error fetching collection to get name from id for statistics updating in specialcollections!";
return;
}
const Akonadi::CollectionFetchJob *fetchJob = qobject_cast<Akonadi::CollectionFetchJob *>(job);
Q_ASSERT(fetchJob->collections().size() > 0);
const Akonadi::Collection collection = fetchJob->collections().first();
const Akonadi::CollectionStatistics statistics = fetchJob->property("statistics").value<Akonadi::CollectionStatistics>();
mFoldersForResource[collection.resource()][collection.name().toUtf8()].setStatistics(statistics);
}
void SpecialCollectionsPrivate::beginBatchRegister()
{
Q_ASSERT(!mBatchMode);
mBatchMode = true;
Q_ASSERT(mToEmitChangedFor.isEmpty());
}
void SpecialCollectionsPrivate::endBatchRegister()
{
Q_ASSERT(mBatchMode);
mBatchMode = false;
foreach (const QString &resourceId, mToEmitChangedFor) {
emitChanged(resourceId);
}
mToEmitChangedFor.clear();
}
void SpecialCollectionsPrivate::forgetFoldersForResource(const QString &resourceId)
{
if (mFoldersForResource.contains(resourceId)) {
const Collection::List folders = mFoldersForResource[resourceId].values();
foreach (const Collection &collection, folders) {
mMonitor->setCollectionMonitored(collection, false);
}
mFoldersForResource.remove(resourceId);
emitChanged(resourceId);
}
}
AgentInstance SpecialCollectionsPrivate::defaultResource() const
{
const QString identifier = defaultResourceId();
return AgentManager::self()->instance(identifier);
}
SpecialCollections::SpecialCollections(KCoreConfigSkeleton *settings, QObject *parent)
: QObject(parent)
, d(new SpecialCollectionsPrivate(settings, this))
{
}
SpecialCollections::~SpecialCollections()
{
delete d;
}
bool SpecialCollections::hasCollection(const QByteArray &type, const AgentInstance &instance) const
{
return d->mFoldersForResource.value(instance.identifier()).contains(type);
}
Akonadi::Collection SpecialCollections::collection(const QByteArray &type, const AgentInstance &instance) const
{
return d->mFoldersForResource.value(instance.identifier()).value(type);
}
void SpecialCollections::setSpecialCollectionType(const QByteArray &type, const Akonadi::Collection &collection)
{
if (!collection.hasAttribute<SpecialCollectionAttribute>() || collection.attribute<SpecialCollectionAttribute>()->collectionType() != type) {
Collection attributeCollection(collection);
SpecialCollectionAttribute *attribute = attributeCollection.attribute<SpecialCollectionAttribute>(Collection::AddIfMissing);
attribute->setCollectionType(type);
new CollectionModifyJob(attributeCollection);
}
}
void SpecialCollections::unsetSpecialCollection(const Akonadi::Collection &collection)
{
if (collection.hasAttribute<SpecialCollectionAttribute>()) {
Collection attributeCollection(collection);
attributeCollection.removeAttribute<SpecialCollectionAttribute>();
new CollectionModifyJob(attributeCollection);
}
}
bool SpecialCollections::unregisterCollection(const Collection &collection)
{
if (!collection.isValid()) {
kWarning() << "Invalid collection.";
return false;
}
const QString &resourceId = collection.resource();
if (resourceId.isEmpty()) {
kWarning() << "Collection has empty resourceId.";
return false;
}
unsetSpecialCollection(collection);
d->mMonitor->setCollectionMonitored(collection, false);
//Remove from list of collection
d->collectionRemoved(collection);
return true;
}
bool SpecialCollections::registerCollection(const QByteArray &type, const Collection &collection)
{
if (!collection.isValid()) {
kWarning() << "Invalid collection.";
return false;
}
const QString &resourceId = collection.resource();
if (resourceId.isEmpty()) {
kWarning() << "Collection has empty resourceId.";
return false;
}
setSpecialCollectionType(type, collection);
const Collection oldCollection = d->mFoldersForResource.value(resourceId).value(type);
if (oldCollection != collection) {
if (oldCollection.isValid()) {
d->mMonitor->setCollectionMonitored(oldCollection, false);
}
d->mMonitor->setCollectionMonitored(collection, true);
d->mFoldersForResource[resourceId].insert(type, collection);
d->emitChanged(resourceId);
}
return true;
}
bool SpecialCollections::hasDefaultCollection(const QByteArray &type) const
{
return hasCollection(type, d->defaultResource());
}
Akonadi::Collection SpecialCollections::defaultCollection(const QByteArray &type) const
{
return collection(type, d->defaultResource());
}
#include "moc_specialcollections.cpp"