mirror of
https://bitbucket.org/smil3y/kde-playground.git
synced 2025-02-23 10:22:50 +00:00
364 lines
12 KiB
C++
364 lines
12 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 "specialcollectionsrequestjob.h"
|
|
|
|
#include "specialcollectionattribute_p.h"
|
|
#include "specialcollections.h"
|
|
#include "specialcollections_p.h"
|
|
#include "specialcollectionshelperjobs_p.h"
|
|
|
|
#include "akonadi/agentmanager.h"
|
|
#include "akonadi/collectioncreatejob.h"
|
|
#include "akonadi/entitydisplayattribute.h"
|
|
|
|
#include <KDebug>
|
|
|
|
#include <QtCore/QVariant>
|
|
|
|
using namespace Akonadi;
|
|
|
|
/**
|
|
@internal
|
|
*/
|
|
class Akonadi::SpecialCollectionsRequestJobPrivate
|
|
{
|
|
public:
|
|
SpecialCollectionsRequestJobPrivate(SpecialCollections *collections, SpecialCollectionsRequestJob *qq);
|
|
|
|
bool isEverythingReady();
|
|
void lockResult(KJob *job); // slot
|
|
void releaseLock(); // slot
|
|
void nextResource();
|
|
void resourceScanResult(KJob *job); // slot
|
|
void createRequestedFolders(ResourceScanJob *job, QHash<QByteArray, bool> &requestedFolders);
|
|
void collectionCreateResult(KJob *job); // slot
|
|
|
|
SpecialCollectionsRequestJob *q;
|
|
SpecialCollections *mSpecialCollections;
|
|
int mPendingCreateJobs;
|
|
|
|
QByteArray mRequestedType;
|
|
AgentInstance mRequestedResource;
|
|
|
|
// Input:
|
|
QHash<QByteArray, bool> mDefaultFolders;
|
|
bool mRequestingDefaultFolders;
|
|
QHash< QString, QHash<QByteArray, bool> > mFoldersForResource;
|
|
QString mDefaultResourceType;
|
|
QVariantMap mDefaultResourceOptions;
|
|
QList<QByteArray> mKnownTypes;
|
|
QMap<QByteArray, QString> mNameForTypeMap;
|
|
QMap<QByteArray, QString> mIconForTypeMap;
|
|
|
|
// Output:
|
|
QStringList mToForget;
|
|
QVector< QPair<Collection, QByteArray> > mToRegister;
|
|
};
|
|
|
|
SpecialCollectionsRequestJobPrivate::SpecialCollectionsRequestJobPrivate(SpecialCollections *collections,
|
|
SpecialCollectionsRequestJob *qq)
|
|
: q(qq)
|
|
, mSpecialCollections(collections)
|
|
, mPendingCreateJobs(0)
|
|
, mRequestingDefaultFolders(false)
|
|
{
|
|
}
|
|
|
|
bool SpecialCollectionsRequestJobPrivate::isEverythingReady()
|
|
{
|
|
// check if all requested folders are known already
|
|
if (mRequestingDefaultFolders) {
|
|
QHashIterator<QByteArray, bool> it(mDefaultFolders);
|
|
while (it.hasNext()) {
|
|
it.next();
|
|
if (it.value() && !mSpecialCollections->hasDefaultCollection(it.key())) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
const QStringList resourceIds = mFoldersForResource.keys();
|
|
QHashIterator<QString, QHash<QByteArray, bool> > resourceIt(mFoldersForResource);
|
|
while (resourceIt.hasNext()) {
|
|
resourceIt.next();
|
|
|
|
const QHash<QByteArray, bool> &requested = resourceIt.value();
|
|
QHashIterator<QByteArray, bool> it(requested);
|
|
while (it.hasNext()) {
|
|
it.next();
|
|
if (it.value() && !mSpecialCollections->hasCollection(it.key(), AgentManager::self()->instance(resourceIt.key()))) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void SpecialCollectionsRequestJobPrivate::lockResult(KJob *job)
|
|
{
|
|
if (job->error()) {
|
|
kWarning() << "Failed to get lock:" << job->errorString();
|
|
q->setError(job->error());
|
|
q->setErrorText(job->errorString());
|
|
q->emitResult();
|
|
return;
|
|
}
|
|
|
|
if (mRequestingDefaultFolders) {
|
|
// If default folders are requested, deal with that first.
|
|
DefaultResourceJob *resjob = new DefaultResourceJob(mSpecialCollections->d->mSettings, q);
|
|
resjob->setDefaultResourceType(mDefaultResourceType);
|
|
resjob->setDefaultResourceOptions(mDefaultResourceOptions);
|
|
resjob->setTypes(mKnownTypes);
|
|
resjob->setNameForTypeMap(mNameForTypeMap);
|
|
resjob->setIconForTypeMap(mIconForTypeMap);
|
|
QObject::connect(resjob, SIGNAL(result(KJob*)), q, SLOT(resourceScanResult(KJob*)));
|
|
} else {
|
|
// If no default folders are requested, go straight to the next step.
|
|
nextResource();
|
|
}
|
|
}
|
|
|
|
void SpecialCollectionsRequestJobPrivate::releaseLock()
|
|
{
|
|
const bool ok = Akonadi::releaseLock();
|
|
if (!ok) {
|
|
kWarning() << "WTF, can't release lock.";
|
|
}
|
|
}
|
|
|
|
void SpecialCollectionsRequestJobPrivate::nextResource()
|
|
{
|
|
if (mFoldersForResource.isEmpty()) {
|
|
kDebug() << "All done! Comitting.";
|
|
|
|
mSpecialCollections->d->beginBatchRegister();
|
|
|
|
// Forget everything we knew before about these resources.
|
|
foreach (const QString &resourceId, mToForget) {
|
|
mSpecialCollections->d->forgetFoldersForResource(resourceId);
|
|
}
|
|
|
|
// Register all the collections that we fetched / created.
|
|
typedef QPair<Collection, QByteArray> RegisterPair;
|
|
foreach (const RegisterPair &pair, mToRegister) {
|
|
const bool ok = mSpecialCollections->registerCollection(pair.second, pair.first);
|
|
Q_ASSERT(ok);
|
|
Q_UNUSED(ok);
|
|
}
|
|
|
|
mSpecialCollections->d->endBatchRegister();
|
|
|
|
// Release the lock once the transaction has been committed.
|
|
QObject::connect(q, SIGNAL(result(KJob*)), q, SLOT(releaseLock()));
|
|
|
|
// We are done!
|
|
q->commit();
|
|
|
|
} else {
|
|
const QString resourceId = mFoldersForResource.keys().first();
|
|
kDebug() << "A resource is done," << mFoldersForResource.count()
|
|
<< "more to do. Now doing resource" << resourceId;
|
|
ResourceScanJob *resjob = new ResourceScanJob(resourceId, mSpecialCollections->d->mSettings, q);
|
|
QObject::connect(resjob, SIGNAL(result(KJob*)), q, SLOT(resourceScanResult(KJob*)));
|
|
}
|
|
}
|
|
|
|
void SpecialCollectionsRequestJobPrivate::resourceScanResult(KJob *job)
|
|
{
|
|
ResourceScanJob *resjob = qobject_cast<ResourceScanJob *>(job);
|
|
Q_ASSERT(resjob);
|
|
|
|
const QString resourceId = resjob->resourceId();
|
|
kDebug() << "resourceId" << resourceId;
|
|
|
|
if (job->error()) {
|
|
kWarning() << "Failed to request resource" << resourceId << ":" << job->errorString();
|
|
return;
|
|
}
|
|
|
|
if (qobject_cast<DefaultResourceJob *>(job)) {
|
|
// This is the default resource.
|
|
if (resourceId != mSpecialCollections->d->defaultResourceId()) {
|
|
kError() << "Resource id's don't match: " << resourceId
|
|
<< mSpecialCollections->d->defaultResourceId();
|
|
Q_ASSERT(false);
|
|
}
|
|
//mToForget.append( mSpecialCollections->defaultResourceId() );
|
|
createRequestedFolders(resjob, mDefaultFolders);
|
|
} else {
|
|
// This is not the default resource.
|
|
QHash<QByteArray, bool> requestedFolders = mFoldersForResource[resourceId];
|
|
mFoldersForResource.remove(resourceId);
|
|
createRequestedFolders(resjob, requestedFolders);
|
|
}
|
|
}
|
|
|
|
void SpecialCollectionsRequestJobPrivate::createRequestedFolders(ResourceScanJob *scanJob,
|
|
QHash<QByteArray, bool> &requestedFolders)
|
|
{
|
|
// Remove from the request list the folders which already exist.
|
|
foreach (const Collection &collection, scanJob->specialCollections()) {
|
|
Q_ASSERT(collection.hasAttribute<SpecialCollectionAttribute>());
|
|
const SpecialCollectionAttribute *attr = collection.attribute<SpecialCollectionAttribute>();
|
|
const QByteArray type = attr->collectionType();
|
|
|
|
if (!type.isEmpty()) {
|
|
mToRegister.append(qMakePair(collection, type));
|
|
requestedFolders.insert(type, false);
|
|
}
|
|
}
|
|
mToForget.append(scanJob->resourceId());
|
|
|
|
// Folders left in the request list must be created.
|
|
Q_ASSERT(mPendingCreateJobs == 0);
|
|
Q_ASSERT(scanJob->rootResourceCollection().isValid());
|
|
|
|
QHashIterator<QByteArray, bool> it(requestedFolders);
|
|
while (it.hasNext()) {
|
|
it.next();
|
|
|
|
if (it.value()) {
|
|
Collection collection;
|
|
collection.setParentCollection(scanJob->rootResourceCollection());
|
|
collection.setName(mNameForTypeMap.value(it.key()));
|
|
|
|
setCollectionAttributes(collection, it.key(), mNameForTypeMap, mIconForTypeMap);
|
|
|
|
CollectionCreateJob *createJob = new CollectionCreateJob(collection, q);
|
|
createJob->setProperty("type", it.key());
|
|
QObject::connect(createJob, SIGNAL(result(KJob*)), q, SLOT(collectionCreateResult(KJob*)));
|
|
|
|
mPendingCreateJobs++;
|
|
}
|
|
}
|
|
|
|
if (mPendingCreateJobs == 0) {
|
|
nextResource();
|
|
}
|
|
}
|
|
|
|
void SpecialCollectionsRequestJobPrivate::collectionCreateResult(KJob *job)
|
|
{
|
|
if (job->error()) {
|
|
kWarning() << "Failed CollectionCreateJob." << job->errorString();
|
|
return;
|
|
}
|
|
|
|
CollectionCreateJob *createJob = qobject_cast<CollectionCreateJob *>(job);
|
|
Q_ASSERT(createJob);
|
|
|
|
const Collection collection = createJob->collection();
|
|
mToRegister.append(qMakePair(collection, createJob->property("type").toByteArray()));
|
|
|
|
Q_ASSERT(mPendingCreateJobs > 0);
|
|
mPendingCreateJobs--;
|
|
kDebug() << "mPendingCreateJobs now" << mPendingCreateJobs;
|
|
|
|
if (mPendingCreateJobs == 0) {
|
|
nextResource();
|
|
}
|
|
}
|
|
|
|
// TODO KDE5: do not inherit from TransactionSequence
|
|
SpecialCollectionsRequestJob::SpecialCollectionsRequestJob(SpecialCollections *collections, QObject *parent)
|
|
: TransactionSequence(parent)
|
|
, d(new SpecialCollectionsRequestJobPrivate(collections, this))
|
|
{
|
|
setProperty("transactionsDisabled", true);
|
|
}
|
|
|
|
SpecialCollectionsRequestJob::~SpecialCollectionsRequestJob()
|
|
{
|
|
delete d;
|
|
}
|
|
|
|
void SpecialCollectionsRequestJob::requestDefaultCollection(const QByteArray &type)
|
|
{
|
|
d->mDefaultFolders[type] = true;
|
|
d->mRequestingDefaultFolders = true;
|
|
d->mRequestedType = type;
|
|
}
|
|
|
|
void SpecialCollectionsRequestJob::requestCollection(const QByteArray &type, const AgentInstance &instance)
|
|
{
|
|
d->mFoldersForResource[instance.identifier()][type] = true;
|
|
d->mRequestedType = type;
|
|
d->mRequestedResource = instance;
|
|
}
|
|
|
|
Akonadi::Collection SpecialCollectionsRequestJob::collection() const
|
|
{
|
|
if (d->mRequestedResource.isValid()) {
|
|
return d->mSpecialCollections->collection(d->mRequestedType, d->mRequestedResource);
|
|
} else {
|
|
return d->mSpecialCollections->defaultCollection(d->mRequestedType);
|
|
}
|
|
}
|
|
|
|
void SpecialCollectionsRequestJob::setDefaultResourceType(const QString &type)
|
|
{
|
|
d->mDefaultResourceType = type;
|
|
}
|
|
|
|
void SpecialCollectionsRequestJob::setDefaultResourceOptions(const QVariantMap &options)
|
|
{
|
|
d->mDefaultResourceOptions = options;
|
|
}
|
|
|
|
void SpecialCollectionsRequestJob::setTypes(const QList<QByteArray> &types)
|
|
{
|
|
d->mKnownTypes = types;
|
|
}
|
|
|
|
void SpecialCollectionsRequestJob::setNameForTypeMap(const QMap<QByteArray, QString> &map)
|
|
{
|
|
d->mNameForTypeMap = map;
|
|
}
|
|
|
|
void SpecialCollectionsRequestJob::setIconForTypeMap(const QMap<QByteArray, QString> &map)
|
|
{
|
|
d->mIconForTypeMap = map;
|
|
}
|
|
|
|
void SpecialCollectionsRequestJob::doStart()
|
|
{
|
|
if (d->isEverythingReady()) {
|
|
emitResult();
|
|
} else {
|
|
GetLockJob *lockJob = new GetLockJob(this);
|
|
connect(lockJob, SIGNAL(result(KJob*)), this, SLOT(lockResult(KJob*)));
|
|
lockJob->start();
|
|
}
|
|
}
|
|
|
|
void SpecialCollectionsRequestJob::slotResult(KJob *job)
|
|
{
|
|
if (job->error()) {
|
|
// If we failed, let others try.
|
|
kWarning() << "Failed SpecialCollectionsRequestJob::slotResult" << job->errorString();
|
|
|
|
d->releaseLock();
|
|
}
|
|
TransactionSequence::slotResult(job);
|
|
}
|
|
|
|
#include "moc_specialcollectionsrequestjob.cpp"
|