Akonadi

specialcollectionsrequestjob.cpp
1/*
2 SPDX-FileCopyrightText: 2009 Constantin Berzan <exit3219@gmail.com>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#include "specialcollectionsrequestjob.h"
8
9#include "specialcollectionattribute.h"
10#include "specialcollections_p.h"
11#include "specialcollectionshelperjobs_p.h"
12
13#include "agentmanager.h"
14#include "collectioncreatejob.h"
15
16#include "akonadicore_debug.h"
17
18using namespace Akonadi;
19
20/**
21 @internal
22*/
23class Akonadi::SpecialCollectionsRequestJobPrivate
24{
25public:
26 SpecialCollectionsRequestJobPrivate(SpecialCollections *collections, SpecialCollectionsRequestJob *qq);
27
28 bool isEverythingReady() const;
29 void lockResult(KJob *job); // slot
30 void releaseLock(); // slot
31 void nextResource();
32 void resourceScanResult(KJob *job); // slot
33 void createRequestedFolders(ResourceScanJob *job, QHash<QByteArray, bool> &requestedFolders);
34 void collectionCreateResult(KJob *job); // slot
35
37 SpecialCollections *mSpecialCollections = nullptr;
38 int mPendingCreateJobs = 0;
39
40 QByteArray mRequestedType;
41 AgentInstance mRequestedResource;
42
43 // Input:
44 QHash<QByteArray, bool> mDefaultFolders;
45 bool mRequestingDefaultFolders = false;
46 QHash<QString, QHash<QByteArray, bool>> mFoldersForResource;
47 QString mDefaultResourceType;
48 QVariantMap mDefaultResourceOptions;
49 QList<QByteArray> mKnownTypes;
50 QMap<QByteArray, QString> mNameForTypeMap;
51 QMap<QByteArray, QString> mIconForTypeMap;
52
53 // Output:
54 QStringList mToForget;
56};
57
58SpecialCollectionsRequestJobPrivate::SpecialCollectionsRequestJobPrivate(SpecialCollections *collections, SpecialCollectionsRequestJob *qq)
59 : q(qq)
60 , mSpecialCollections(collections)
61{
62}
63
64bool SpecialCollectionsRequestJobPrivate::isEverythingReady() const
65{
66 // check if all requested folders are known already
67 if (mRequestingDefaultFolders) {
68 for (auto it = mDefaultFolders.cbegin(), end = mDefaultFolders.cend(); it != end; ++it) {
69 if (it.value() && !mSpecialCollections->hasDefaultCollection(it.key())) {
70 return false;
71 }
72 }
73 }
74
75 for (auto resourceIt = mFoldersForResource.cbegin(), end = mFoldersForResource.cend(); resourceIt != end; ++resourceIt) {
76 const QHash<QByteArray, bool> &requested = resourceIt.value();
77 for (auto it = requested.cbegin(), end = requested.cend(); it != end; ++it) {
78 if (it.value() && !mSpecialCollections->hasCollection(it.key(), AgentManager::self()->instance(resourceIt.key()))) {
79 return false;
80 }
81 }
82 }
83
84 return true;
85}
86
87void SpecialCollectionsRequestJobPrivate::lockResult(KJob *job)
88{
89 if (job->error()) {
90 qCWarning(AKONADICORE_LOG) << "Failed to get lock:" << job->errorString();
91 q->setError(job->error());
92 q->setErrorText(job->errorString());
93 q->emitResult();
94 return;
95 }
96
97 if (mRequestingDefaultFolders) {
98 // If default folders are requested, deal with that first.
99 auto resjob = new DefaultResourceJob(mSpecialCollections->d->mSettings, q);
100 resjob->setDefaultResourceType(mDefaultResourceType);
101 resjob->setDefaultResourceOptions(mDefaultResourceOptions);
102 resjob->setTypes(mKnownTypes);
103 resjob->setNameForTypeMap(mNameForTypeMap);
104 resjob->setIconForTypeMap(mIconForTypeMap);
105 QObject::connect(resjob, &KJob::result, q, [this](KJob *job) {
106 resourceScanResult(job);
107 });
108 } else {
109 // If no default folders are requested, go straight to the next step.
110 nextResource();
111 }
112}
113
114void SpecialCollectionsRequestJobPrivate::releaseLock()
115{
116 const bool ok = Akonadi::releaseLock();
117 if (!ok) {
118 qCWarning(AKONADICORE_LOG) << "WTF, can't release lock.";
119 }
120}
121
122void SpecialCollectionsRequestJobPrivate::nextResource()
123{
124 if (mFoldersForResource.isEmpty()) {
125 qCDebug(AKONADICORE_LOG) << "All done! Committing.";
126
127 mSpecialCollections->d->beginBatchRegister();
128
129 // Forget everything we knew before about these resources.
130 for (const QString &resourceId : std::as_const(mToForget)) {
131 mSpecialCollections->d->forgetFoldersForResource(resourceId);
132 }
133
134 // Register all the collections that we fetched / created.
135 using RegisterPair = QPair<Collection, QByteArray>;
136 for (const RegisterPair &pair : std::as_const(mToRegister)) {
137 const bool ok = mSpecialCollections->registerCollection(pair.second, pair.first);
138 Q_ASSERT(ok);
139 Q_UNUSED(ok)
140 }
141
142 mSpecialCollections->d->endBatchRegister();
143
144 // Release the lock once the transaction has been committed.
145 QObject::connect(q, &KJob::result, q, [this]() {
146 releaseLock();
147 });
148
149 // We are done!
150 q->commit();
151
152 } else {
153 const QString resourceId = mFoldersForResource.cbegin().key();
154 qCDebug(AKONADICORE_LOG) << "A resource is done," << mFoldersForResource.count() << "more to do. Now doing resource" << resourceId;
155 auto resjob = new ResourceScanJob(resourceId, mSpecialCollections->d->mSettings, q);
156 QObject::connect(resjob, &KJob::result, q, [this](KJob *job) {
157 resourceScanResult(job);
158 });
159 }
160}
161
162void SpecialCollectionsRequestJobPrivate::resourceScanResult(KJob *job)
163{
164 auto resjob = qobject_cast<ResourceScanJob *>(job);
165 Q_ASSERT(resjob);
166
167 const QString resourceId = resjob->resourceId();
168 qCDebug(AKONADICORE_LOG) << "resourceId" << resourceId;
169
170 if (job->error()) {
171 qCWarning(AKONADICORE_LOG) << "Failed to request resource" << resourceId << ":" << job->errorString();
172 return;
173 }
174
175 if (qobject_cast<DefaultResourceJob *>(job)) {
176 // This is the default resource.
177 if (resourceId != mSpecialCollections->d->defaultResourceId()) {
178 qCWarning(AKONADICORE_LOG) << "Resource id's don't match: " << resourceId << mSpecialCollections->d->defaultResourceId();
179 Q_ASSERT(false);
180 }
181 // mToForget.append( mSpecialCollections->defaultResourceId() );
182 createRequestedFolders(resjob, mDefaultFolders);
183 } else {
184 // This is not the default resource.
185 QHash<QByteArray, bool> requestedFolders = mFoldersForResource[resourceId];
186 mFoldersForResource.remove(resourceId);
187 createRequestedFolders(resjob, requestedFolders);
188 }
189}
190
191void SpecialCollectionsRequestJobPrivate::createRequestedFolders(ResourceScanJob *scanJob, QHash<QByteArray, bool> &requestedFolders)
192{
193 // Remove from the request list the folders which already exist.
194 const Akonadi::Collection::List lstSpecialCols = scanJob->specialCollections();
195 for (const Collection &collection : lstSpecialCols) {
196 Q_ASSERT(collection.hasAttribute<SpecialCollectionAttribute>());
197 const auto attr = collection.attribute<SpecialCollectionAttribute>();
198 const QByteArray type = attr->collectionType();
199
200 if (!type.isEmpty()) {
201 mToRegister.append(qMakePair(collection, type));
202 requestedFolders.insert(type, false);
203 }
204 }
205 mToForget.append(scanJob->resourceId());
206
207 // Folders left in the request list must be created.
208 Q_ASSERT(mPendingCreateJobs == 0);
209 Q_ASSERT(scanJob->rootResourceCollection().isValid());
210
211 QHashIterator<QByteArray, bool> it(requestedFolders);
212 while (it.hasNext()) {
213 it.next();
214
215 if (it.value()) {
216 Collection collection;
217 collection.setParentCollection(scanJob->rootResourceCollection());
218 collection.setName(mNameForTypeMap.value(it.key()));
219
220 setCollectionAttributes(collection, it.key(), mNameForTypeMap, mIconForTypeMap);
221
222 auto createJob = new CollectionCreateJob(collection, q);
223 createJob->setProperty("type", it.key());
224 QObject::connect(createJob, &KJob::result, q, [this](KJob *job) {
225 collectionCreateResult(job);
226 });
227
228 mPendingCreateJobs++;
229 }
230 }
231
232 if (mPendingCreateJobs == 0) {
233 nextResource();
234 }
235}
236
237void SpecialCollectionsRequestJobPrivate::collectionCreateResult(KJob *job)
238{
239 if (job->error()) {
240 qCWarning(AKONADICORE_LOG) << "Failed CollectionCreateJob." << job->errorString();
241 return;
242 }
243
244 auto createJob = qobject_cast<CollectionCreateJob *>(job);
245 Q_ASSERT(createJob);
246
247 const Collection collection = createJob->collection();
248 mToRegister.append(qMakePair(collection, createJob->property("type").toByteArray()));
249
250 Q_ASSERT(mPendingCreateJobs > 0);
251 mPendingCreateJobs--;
252 qCDebug(AKONADICORE_LOG) << "mPendingCreateJobs now" << mPendingCreateJobs;
253
254 if (mPendingCreateJobs == 0) {
255 nextResource();
256 }
257}
258
259// TODO KDE5: do not inherit from TransactionSequence
261 : TransactionSequence(parent)
262 , d(new SpecialCollectionsRequestJobPrivate(collections, this))
263{
264 setProperty("transactionsDisabled", true);
265}
266
268
270{
271 d->mDefaultFolders[type] = true;
272 d->mRequestingDefaultFolders = true;
273 d->mRequestedType = type;
274}
275
277{
278 d->mFoldersForResource[instance.identifier()][type] = true;
279 d->mRequestedType = type;
280 d->mRequestedResource = instance;
281}
282
284{
285 if (d->mRequestedResource.isValid()) {
286 return d->mSpecialCollections->collection(d->mRequestedType, d->mRequestedResource);
287 } else {
288 return d->mSpecialCollections->defaultCollection(d->mRequestedType);
289 }
290}
291
293{
294 d->mDefaultResourceType = type;
295}
296
298{
299 d->mDefaultResourceOptions = options;
300}
301
303{
304 d->mKnownTypes = types;
305}
306
308{
309 d->mNameForTypeMap = map;
310}
311
313{
314 d->mIconForTypeMap = map;
315}
316
318{
319 if (d->isEverythingReady()) {
320 emitResult();
321 } else {
322 auto lockJob = new GetLockJob(this);
323 connect(lockJob, &GetLockJob::result, this, [this](KJob *job) {
324 d->lockResult(job);
325 });
326 lockJob->start();
327 }
328}
329
330void SpecialCollectionsRequestJob::slotResult(KJob *job)
331{
332 if (job->error()) {
333 // If we failed, let others try.
334 qCWarning(AKONADICORE_LOG) << "Failed SpecialCollectionsRequestJob::slotResult" << job->errorString();
335
336 d->releaseLock();
337 }
338 TransactionSequence::slotResult(job);
339}
340
341#include "moc_specialcollectionsrequestjob.cpp"
Represents one agent instance and takes care of communication with it.
A representation of an agent instance.
QString identifier() const
Returns the unique identifier of the agent instance.
static AgentManager * self()
Returns the global instance of the agent manager.
AgentInstance instance(const QString &identifier) const
Returns the agent instance with the given identifier or an invalid agent instance if the identifier d...
Job that creates a new collection in the Akonadi storage.
Represents a collection of PIM items.
Definition collection.h:62
void setParentCollection(const Collection &parent)
Set the parent collection of this object.
void setName(const QString &name)
Sets the i18n'ed name of the collection.
An Attribute that stores the special collection type of a collection.
A job to request SpecialCollections.
void requestCollection(const QByteArray &type, const AgentInstance &instance)
Requests a special collection of the given type in the given resource instance.
void setIconForTypeMap(const QMap< QByteArray, QString > &map)
Sets the map of special collection types to icon names.
void setTypes(const QList< QByteArray > &types)
Sets the list of well known special collection types.
SpecialCollectionsRequestJob(SpecialCollections *collections, QObject *parent=nullptr)
Creates a new special collections request job.
Collection collection() const
Returns the requested collection.
void setNameForTypeMap(const QMap< QByteArray, QString > &map)
Sets the map of special collection types to display names.
~SpecialCollectionsRequestJob() override
Destroys the special collections request job.
void setDefaultResourceOptions(const QVariantMap &options)
Sets the configuration options that shall be applied to the new resource that is created if the reque...
void doStart() override
This method must be reimplemented in the concrete jobs.
void requestDefaultCollection(const QByteArray &type)
Requests a special collection of the given type in the default resource.
void setDefaultResourceType(const QString &type)
Sets the type of the resource that shall be created if the requested special collection does not exis...
An interface to special collections.
bool hasCollection(const QByteArray &type, const AgentInstance &instance) const
Returns whether the given agent instance has a special collection of the given type.
bool hasDefaultCollection(const QByteArray &type) const
Returns whether the default resource has a special collection of the given type.
bool registerCollection(const QByteArray &type, const Akonadi::Collection &collection)
Registers the given collection as a special collection with the given type.
Base class for jobs that need to run a sequence of sub-jobs in a transaction.
void commit()
Commits the transaction as soon as all pending sub-jobs finished successfully.
void setErrorText(const QString &errorText)
virtual QString errorString() const
void emitResult()
int error() const
void result(KJob *job)
void setError(int errorCode)
Helper integration between Akonadi and Qt.
VehicleSection::Type type(QStringView coachNumber, QStringView coachClassification)
const QList< QKeySequence > & end()
A glue between Qt and the standard library.
const_iterator cbegin() const const
const_iterator cend() const const
qsizetype count() const const
iterator insert(const Key &key, const T &value)
bool isEmpty() const const
bool remove(const Key &key)
T value(const Key &key) const const
void append(QList< T > &&value)
T value(const Key &key, const T &defaultValue) const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
T qobject_cast(QObject *object)
bool setProperty(const char *name, QVariant &&value)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:13:38 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.