Akonadi

specialcollections.cpp
1 /*
2  Copyright (c) 2009 Constantin Berzan <[email protected]>
3 
4  This library is free software; you can redistribute it and/or modify it
5  under the terms of the GNU Library General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or (at your
7  option) any later version.
8 
9  This library is distributed in the hope that it will be useful, but WITHOUT
10  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12  License for more details.
13 
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB. If not, write to the
16  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  02110-1301, USA.
18 */
19 
20 #include "specialcollections.h"
21 #include "akonadicore_debug.h"
22 #include "specialcollections_p.h"
23 #include "specialcollectionattribute.h"
24 
25 #include "agentinstance.h"
26 #include "agentmanager.h"
27 #include "collectionmodifyjob.h"
28 #include "collectionfetchjob.h"
29 #include "monitor.h"
30 #include "collectionfetchscope.h"
31 
32 #include <KCoreConfigSkeleton>
33 
34 #include <QHash>
35 #include <QObject>
36 
37 using namespace Akonadi;
38 
39 SpecialCollectionsPrivate::SpecialCollectionsPrivate(KCoreConfigSkeleton *settings, SpecialCollections *qq)
40  : q(qq)
41  , mSettings(settings)
42  , mBatchMode(false)
43 {
44  mMonitor = new Monitor(q);
45  mMonitor->setObjectName(QStringLiteral("SpecialCollectionsMonitor"));
46  mMonitor->fetchCollectionStatistics(true);
47 
53  q, [this](const Akonadi::Collection &col) { collectionRemoved(col); });
55  q, [this](Akonadi::Collection::Id id, const Akonadi::CollectionStatistics &statistics)
56  { collectionStatisticsChanged(id, statistics); });
57 }
58 
59 SpecialCollectionsPrivate::~SpecialCollectionsPrivate()
60 {
61 }
62 
63 QString SpecialCollectionsPrivate::defaultResourceId() const
64 {
65  if (mDefaultResourceId.isEmpty()) {
66  mSettings->load();
67  const KConfigSkeletonItem *item = mSettings->findItem(QStringLiteral("DefaultResourceId"));
68  Q_ASSERT(item);
69 
70  mDefaultResourceId = item->property().toString();
71  }
72  return mDefaultResourceId;
73 }
74 
75 void SpecialCollectionsPrivate::emitChanged(const QString &resourceId)
76 {
77  if (mBatchMode) {
78  mToEmitChangedFor.insert(resourceId);
79  } else {
80  qCDebug(AKONADICORE_LOG) << "Emitting changed for" << resourceId;
81  const AgentInstance agentInstance = AgentManager::self()->instance(resourceId);
82  Q_EMIT q->collectionsChanged(agentInstance);
83  // first compare with local value then with config value (which also updates the local value)
84  if (resourceId == mDefaultResourceId || resourceId == defaultResourceId()) {
85  qCDebug(AKONADICORE_LOG) << "Emitting defaultFoldersChanged.";
86  Q_EMIT q->defaultCollectionsChanged();
87  }
88  }
89 }
90 
91 void SpecialCollectionsPrivate::collectionRemoved(const Collection &collection)
92 {
93  qCDebug(AKONADICORE_LOG) << "Collection" << collection.id() << "resource" << collection.resource();
94  if (mFoldersForResource.contains(collection.resource())) {
95 
96  // Retrieve the list of special folders for the resource the collection belongs to
97  QHash<QByteArray, Collection> &folders = mFoldersForResource[collection.resource()];
98  {
100  while (it.hasNext()) {
101  it.next();
102  if (it.value() == collection) {
103  // The collection to be removed is a special folder
104  it.remove();
105  emitChanged(collection.resource());
106  }
107  }
108  }
109 
110  if (folders.isEmpty()) {
111  // This resource has no more folders, so remove it completely.
112  mFoldersForResource.remove(collection.resource());
113  }
114  }
115 }
116 
117 void SpecialCollectionsPrivate::collectionStatisticsChanged(Akonadi::Collection::Id collectionId, const Akonadi::CollectionStatistics &statistics)
118 {
119  // need to get the name of the collection in order to be able to check if we are storing it,
120  // but we have the id from the monitor, so fetch the name.
123  fetchJob->setProperty("statistics", QVariant::fromValue(statistics));
124 
125  q->connect(fetchJob, &CollectionFetchJob::result, q, [this](KJob *job) { collectionFetchJobFinished(job); });
126 }
127 
128 void SpecialCollectionsPrivate::collectionFetchJobFinished(KJob *job)
129 {
130  if (job->error()) {
131  qCWarning(AKONADICORE_LOG) << "Error fetching collection to get name from id for statistics updating in specialcollections!";
132  return;
133  }
134 
135  const Akonadi::CollectionFetchJob *fetchJob = qobject_cast<Akonadi::CollectionFetchJob *>(job);
136 
137  Q_ASSERT(fetchJob->collections().size() > 0);
138  const Akonadi::Collection collection = fetchJob->collections().at(0);
139  const Akonadi::CollectionStatistics statistics = fetchJob->property("statistics").value<Akonadi::CollectionStatistics>();
140 
141  mFoldersForResource[collection.resource()][collection.name().toUtf8()].setStatistics(statistics);
142 }
143 
144 void SpecialCollectionsPrivate::beginBatchRegister()
145 {
146  Q_ASSERT(!mBatchMode);
147  mBatchMode = true;
148  Q_ASSERT(mToEmitChangedFor.isEmpty());
149 }
150 
151 void SpecialCollectionsPrivate::endBatchRegister()
152 {
153  Q_ASSERT(mBatchMode);
154  mBatchMode = false;
155 
156  for (const QString &resourceId : qAsConst(mToEmitChangedFor)) {
157  emitChanged(resourceId);
158  }
159 
160  mToEmitChangedFor.clear();
161 }
162 
163 void SpecialCollectionsPrivate::forgetFoldersForResource(const QString &resourceId)
164 {
165  if (mFoldersForResource.contains(resourceId)) {
166  const auto folders = mFoldersForResource[resourceId];
167  for (const auto &collection : folders) {
168  mMonitor->setCollectionMonitored(collection, false);
169  }
170 
171  mFoldersForResource.remove(resourceId);
172  emitChanged(resourceId);
173  }
174 }
175 
176 AgentInstance SpecialCollectionsPrivate::defaultResource() const
177 {
178  const QString identifier = defaultResourceId();
179  return AgentManager::self()->instance(identifier);
180 }
181 
183  : QObject(parent)
184  , d(new SpecialCollectionsPrivate(settings, this))
185 {
186 }
187 
189 {
190  delete d;
191 }
192 
193 bool SpecialCollections::hasCollection(const QByteArray &type, const AgentInstance &instance) const
194 {
195  return d->mFoldersForResource.value(instance.identifier()).contains(type);
196 }
197 
199 {
200  return d->mFoldersForResource.value(instance.identifier()).value(type);
201 }
202 
204 {
205  if (!collection.hasAttribute<SpecialCollectionAttribute>() || collection.attribute<SpecialCollectionAttribute>()->collectionType() != type) {
206  Collection attributeCollection(collection);
208  attribute->setCollectionType(type);
209  new CollectionModifyJob(attributeCollection);
210  }
211 }
212 
214 {
215  if (collection.hasAttribute<SpecialCollectionAttribute>()) {
216  Collection attributeCollection(collection);
217  attributeCollection.removeAttribute<SpecialCollectionAttribute>();
218  new CollectionModifyJob(attributeCollection);
219  }
220 }
221 
223 {
224  if (!collection.isValid()) {
225  qCWarning(AKONADICORE_LOG) << "Invalid collection.";
226  return false;
227  }
228 
229  const QString &resourceId = collection.resource();
230  if (resourceId.isEmpty()) {
231  qCWarning(AKONADICORE_LOG) << "Collection has empty resourceId.";
232  return false;
233  }
234 
235  unsetSpecialCollection(collection);
236 
237  d->mMonitor->setCollectionMonitored(collection, false);
238  //Remove from list of collection
239  d->collectionRemoved(collection);
240  return true;
241 }
242 
244 {
245  if (!collection.isValid()) {
246  qCWarning(AKONADICORE_LOG) << "Invalid collection.";
247  return false;
248  }
249 
250  const QString &resourceId = collection.resource();
251  if (resourceId.isEmpty()) {
252  qCWarning(AKONADICORE_LOG) << "Collection has empty resourceId.";
253  return false;
254  }
255 
256  setSpecialCollectionType(type, collection);
257 
258  const Collection oldCollection = d->mFoldersForResource.value(resourceId).value(type);
259  if (oldCollection != collection) {
260  if (oldCollection.isValid()) {
261  d->mMonitor->setCollectionMonitored(oldCollection, false);
262  }
263  d->mMonitor->setCollectionMonitored(collection, true);
264  d->mFoldersForResource[resourceId].insert(type, collection);
265  d->emitChanged(resourceId);
266  }
267 
268  return true;
269 }
270 
272 {
273  return hasCollection(type, d->defaultResource());
274 }
275 
277 {
278  return collection(type, d->defaultResource());
279 }
280 
281 #include "moc_specialcollections.cpp"
Job that modifies a collection in the Akonadi storage.
bool registerCollection(const QByteArray &type, const Akonadi::Collection &collection)
Registers the given collection as a special collection with the given type.
An interface to special collections.
void setAncestorRetrieval(AncestorRetrieval ancestorDepth)
Sets how many levels of ancestor collections should be included in the retrieval. ...
Collection::List collections() const
Returns the list of fetched collection.
bool hasCollection(const QByteArray &type, const AgentInstance &instance) const
Returns whether the given agent instance has a special collection of the given type.
bool isValid() const
Returns whether the collection is valid.
Definition: collection.cpp:137
Provides statistics information of a Collection.
bool hasDefaultCollection(const QByteArray &type) const
Returns whether the default resource has a special collection of the given type.
CollectionFetchScope & fetchScope()
Returns the collection fetch scope.
Represents a collection of PIM items.
Definition: collection.h:76
qint64 Id
Describes the unique id type.
Definition: collection.h:82
Job that fetches collections from the Akonadi storage.
An Attribute that stores the special collection type of a collection.
T value() const const
Creates the attribute if it is missing.
Definition: collection.h:283
QString identifier() const
Returns the unique identifier of the agent instance.
SpecialCollections(KCoreConfigSkeleton *config, QObject *parent=nullptr)
Creates a new special collections object.
Only fetch the base collection.
Akonadi::Collection defaultCollection(const QByteArray &type) const
Returns the special collection of given type in the default resource, or an invalid collection if suc...
QString & insert(int position, QChar ch)
QVariant property(const char *name) const const
AgentInstance instance(const QString &identifier) const
Returns the agent instance with the given identifier or an invalid agent instance if the identifier d...
bool isEmpty() const const
QString resource() const
Returns the identifier of the resource owning the collection.
Definition: collection.cpp:318
void collectionRemoved(const Akonadi::Collection &collection)
This signal is emitted if a monitored collection has been removed from the Akonadi storage...
~SpecialCollections()
Destroys the special collections object.
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...
int remove(const Key &key)
Attribute * attribute(const QByteArray &name)
Returns the attribute of the given type name if available, 0 otherwise.
Definition: collection.cpp:192
QVariant fromValue(const T &value)
bool hasAttribute(const QByteArray &name) const
Returns true if the collection has an attribute of the given type name, false otherwise.
Definition: collection.cpp:177
void collectionStatisticsChanged(Akonadi::Collection::Id id, const Akonadi::CollectionStatistics &statistics)
This signal is emitted if the statistics information of a monitored collection has changed...
Monitors an item or collection for changes.
Definition: monitor.h:84
const T & at(int i) const const
Id id() const
Returns the unique identifier of the collection.
Definition: collection.cpp:112
void setCollectionType(const QByteArray &type)
Sets the special collections type of the collection.
bool isEmpty() const const
Helper integration between Akonadi and Qt.
QByteArray collectionType() const
Returns the special collections type of the collection.
static AgentManager * self()
Returns the global instance of the agent manager.
bool setProperty(const char *name, const QVariant &value)
A representation of an agent instance.
static void unsetSpecialCollection(const Akonadi::Collection &collection)
unsets the special collection attribute which marks collection as being a special collection...
void result(KJob *job)
bool unregisterCollection(const Collection &collection)
Unregisters the given collection as a special collection.
No ancestor retrieval at all (the default)
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
int size() const const
virtual QVariant property() const =0
QString toString() const const
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...
void removeAttribute(const QByteArray &name)
Removes and deletes the attribute of the given type name.
Definition: collection.cpp:172
int error() const
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Wed May 27 2020 22:43:40 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.