Akonadi

specialcollections.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 "specialcollections.h"
8#include "akonadicore_debug.h"
9#include "specialcollectionattribute.h"
10#include "specialcollections_p.h"
11
12#include "agentinstance.h"
13#include "agentmanager.h"
14#include "collectionfetchjob.h"
15#include "collectionfetchscope.h"
16#include "collectionmodifyjob.h"
17#include "monitor.h"
18
19#include <KCoreConfigSkeleton>
20
21#include <QHash>
22
23using namespace Akonadi;
24
25SpecialCollectionsPrivate::SpecialCollectionsPrivate(KCoreConfigSkeleton *settings, SpecialCollections *qq)
26 : q(qq)
27 , mSettings(settings)
28 , mBatchMode(false)
29{
30 mMonitor = new Monitor(q);
31 mMonitor->setObjectName(QLatin1StringView("SpecialCollectionsMonitor"));
32 mMonitor->fetchCollectionStatistics(true);
33
34 /// In order to know if items are added or deleted
35 /// from one of our specialcollection folders,
36 /// we have to watch all mail item add/move/delete notifications
37 /// and check for the parent to see if it is one we care about
38 QObject::connect(mMonitor, &Monitor::collectionRemoved, q, [this](const Akonadi::Collection &col) {
39 collectionRemoved(col);
40 });
42 collectionStatisticsChanged(id, statistics);
43 });
44}
45
46SpecialCollectionsPrivate::~SpecialCollectionsPrivate()
47{
48}
49
50QString SpecialCollectionsPrivate::defaultResourceId() const
51{
52 if (mDefaultResourceId.isEmpty()) {
53 mSettings->load();
54 const KConfigSkeletonItem *item = mSettings->findItem(QStringLiteral("DefaultResourceId"));
55 Q_ASSERT(item);
56
57 mDefaultResourceId = item->property().toString();
58 }
59 return mDefaultResourceId;
60}
61
62void SpecialCollectionsPrivate::emitChanged(const QString &resourceId)
63{
64 if (mBatchMode) {
65 mToEmitChangedFor.insert(resourceId);
66 } else {
67 qCDebug(AKONADICORE_LOG) << "Emitting changed for" << resourceId;
68 const AgentInstance agentInstance = AgentManager::self()->instance(resourceId);
69 Q_EMIT q->collectionsChanged(agentInstance);
70 // first compare with local value then with config value (which also updates the local value)
71 if (resourceId == mDefaultResourceId || resourceId == defaultResourceId()) {
72 qCDebug(AKONADICORE_LOG) << "Emitting defaultFoldersChanged.";
73 Q_EMIT q->defaultCollectionsChanged();
74 }
75 }
76}
77
78void SpecialCollectionsPrivate::collectionRemoved(const Collection &collection)
79{
80 qCDebug(AKONADICORE_LOG) << "Collection" << collection.id() << "resource" << collection.resource();
81 if (mFoldersForResource.contains(collection.resource())) {
82 // Retrieve the list of special folders for the resource the collection belongs to
83 QHash<QByteArray, Collection> &folders = mFoldersForResource[collection.resource()];
84 {
86 while (it.hasNext()) {
87 it.next();
88 if (it.value() == collection) {
89 // The collection to be removed is a special folder
90 it.remove();
91 emitChanged(collection.resource());
92 }
93 }
94 }
95
96 if (folders.isEmpty()) {
97 // This resource has no more folders, so remove it completely.
98 mFoldersForResource.remove(collection.resource());
99 }
100 }
101}
102
103void SpecialCollectionsPrivate::collectionStatisticsChanged(Akonadi::Collection::Id collectionId, const Akonadi::CollectionStatistics &statistics)
104{
105 // need to get the name of the collection in order to be able to check if we are storing it,
106 // but we have the id from the monitor, so fetch the name.
108 fetchJob->fetchScope().setAncestorRetrieval(Akonadi::CollectionFetchScope::None);
109 fetchJob->setProperty("statistics", QVariant::fromValue(statistics));
110
111 q->connect(fetchJob, &CollectionFetchJob::result, q, [this](KJob *job) {
112 collectionFetchJobFinished(job);
113 });
114}
115
116void SpecialCollectionsPrivate::collectionFetchJobFinished(KJob *job)
117{
118 if (job->error()) {
119 qCWarning(AKONADICORE_LOG) << "Error fetching collection to get name from id for statistics updating in specialcollections!";
120 return;
121 }
122
123 const Akonadi::CollectionFetchJob *fetchJob = qobject_cast<Akonadi::CollectionFetchJob *>(job);
124
125 Q_ASSERT(!fetchJob->collections().empty());
126 const Akonadi::Collection collection = fetchJob->collections().at(0);
127 const auto statistics = fetchJob->property("statistics").value<Akonadi::CollectionStatistics>();
128
129 mFoldersForResource[collection.resource()][collection.name().toUtf8()].setStatistics(statistics);
130}
131
132void SpecialCollectionsPrivate::beginBatchRegister()
133{
134 Q_ASSERT(!mBatchMode);
135 mBatchMode = true;
136 Q_ASSERT(mToEmitChangedFor.isEmpty());
137}
138
139void SpecialCollectionsPrivate::endBatchRegister()
140{
141 Q_ASSERT(mBatchMode);
142 mBatchMode = false;
143
144 for (const QString &resourceId : std::as_const(mToEmitChangedFor)) {
145 emitChanged(resourceId);
146 }
147
148 mToEmitChangedFor.clear();
149}
150
151void SpecialCollectionsPrivate::forgetFoldersForResource(const QString &resourceId)
152{
153 if (mFoldersForResource.contains(resourceId)) {
154 const auto folders = mFoldersForResource[resourceId];
155 for (const auto &collection : folders) {
156 mMonitor->setCollectionMonitored(collection, false);
157 }
158
159 mFoldersForResource.remove(resourceId);
160 emitChanged(resourceId);
161 }
162}
163
164AgentInstance SpecialCollectionsPrivate::defaultResource() const
165{
166 const QString identifier = defaultResourceId();
167 return AgentManager::self()->instance(identifier);
168}
169
171 : QObject(parent)
172 , d(new SpecialCollectionsPrivate(settings, this))
173{
174}
175
177
178bool SpecialCollections::hasCollection(const QByteArray &type, const AgentInstance &instance) const
179{
180 return d->mFoldersForResource.value(instance.identifier()).contains(type);
181}
182
184{
185 return d->mFoldersForResource.value(instance.identifier()).value(type);
186}
187
189{
191 Collection attributeCollection(collection);
192 auto attribute = attributeCollection.attribute<SpecialCollectionAttribute>(Collection::AddIfMissing);
193 attribute->setCollectionType(type);
194 new CollectionModifyJob(attributeCollection);
195 }
196}
197
199{
201 Collection attributeCollection(collection);
202 attributeCollection.removeAttribute<SpecialCollectionAttribute>();
203 new CollectionModifyJob(attributeCollection);
204 }
205}
206
208{
209 if (!collection.isValid()) {
210 qCWarning(AKONADICORE_LOG) << "Invalid collection.";
211 return false;
212 }
213
214 const QString &resourceId = collection.resource();
215 if (resourceId.isEmpty()) {
216 qCWarning(AKONADICORE_LOG) << "Collection has empty resourceId.";
217 return false;
218 }
219
221
222 d->mMonitor->setCollectionMonitored(collection, false);
223 // Remove from list of collection
224 d->collectionRemoved(collection);
225 return true;
226}
227
229{
230 if (!collection.isValid()) {
231 qCWarning(AKONADICORE_LOG) << "Invalid collection.";
232 return false;
233 }
234
235 const QString &resourceId = collection.resource();
236 if (resourceId.isEmpty()) {
237 qCWarning(AKONADICORE_LOG) << "Collection has empty resourceId.";
238 return false;
239 }
240
242
243 const Collection oldCollection = d->mFoldersForResource.value(resourceId).value(type);
244 if (oldCollection != collection) {
245 if (oldCollection.isValid()) {
246 d->mMonitor->setCollectionMonitored(oldCollection, false);
247 }
248 d->mMonitor->setCollectionMonitored(collection, true);
249 d->mFoldersForResource[resourceId].insert(type, collection);
250 d->emitChanged(resourceId);
251 }
252
253 return true;
254}
255
257{
258 return hasCollection(type, d->defaultResource());
259}
260
262{
263 return collection(type, d->defaultResource());
264}
265
266#include "moc_specialcollections.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.
Job that fetches collections from the Akonadi storage.
@ Base
Only fetch the base collection.
Collection::List collections() const
Returns the list of fetched collection.
@ None
No ancestor retrieval at all (the default)
Job that modifies a collection in the Akonadi storage.
Provides statistics information of a Collection.
Represents a collection of PIM items.
Definition collection.h:62
qint64 Id
Describes the unique id type.
Definition collection.h:79
bool hasAttribute(const QByteArray &name) const
Returns true if the collection has an attribute of the given type name, false otherwise.
@ AddIfMissing
Creates the attribute if it is missing.
Definition collection.h:281
void removeAttribute(const QByteArray &name)
Removes and deletes the attribute of the given type name.
Attribute * attribute(const QByteArray &name)
Returns the attribute of the given type name if available, 0 otherwise.
Monitors an item or collection for changes.
Definition monitor.h:71
void collectionRemoved(const Akonadi::Collection &collection)
This signal is emitted if a monitored collection has been removed from the Akonadi storage.
void collectionStatisticsChanged(Akonadi::Collection::Id id, const Akonadi::CollectionStatistics &statistics)
This signal is emitted if the statistics information of a monitored collection has changed.
An Attribute that stores the special collection type of a collection.
void setCollectionType(const QByteArray &type)
Sets the special collections type of the collection.
QByteArray collectionType() const
Returns the special collections type of the collection.
An interface to special collections.
static void setSpecialCollectionType(const QByteArray &type, const Akonadi::Collection &collection)
Sets the special collection attribute which marks collection as being a special collection of type ty...
SpecialCollections(KCoreConfigSkeleton *config, QObject *parent=nullptr)
Creates a new special collections object.
~SpecialCollections() override
Destroys the special collections object.
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.
Akonadi::Collection collection(const QByteArray &type, const AgentInstance &instance) const
Returns the special collection of the given type in the given agent instance, or an invalid collectio...
static void unsetSpecialCollection(const Akonadi::Collection &collection)
unsets the special collection attribute which marks collection as being a special collection.
bool unregisterCollection(const Collection &collection)
Unregisters the given collection as a special collection.
bool registerCollection(const QByteArray &type, const Akonadi::Collection &collection)
Registers the given collection as a special collection with the given type.
Akonadi::Collection defaultCollection(const QByteArray &type) const
Returns the special collection of given type in the default resource, or an invalid collection if suc...
virtual QVariant property() const=0
int error() const
Helper integration between Akonadi and Qt.
QAction * statistics(const QObject *recvr, const char *slot, QObject *parent)
bool isEmpty() const const
bool remove(const Key &key)
const_reference at(qsizetype i) const const
bool empty() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QVariant property(const char *name) const const
bool isEmpty() const const
QByteArray toUtf8() const const
QVariant fromValue(T &&value)
QString toString() const const
T value() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 4 2024 16:31:58 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.