Akonadi

core/agentmanager.cpp
1/*
2 SPDX-FileCopyrightText: 2006-2008 Tobias Koenig <tokoe@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#include "agentmanager.h"
8#include "agentmanager_p.h"
9
10#include "agentinstance_p.h"
11#include "agenttype_p.h"
12#include "collection.h"
13#include "servermanager.h"
14#include <QDBusConnection>
15
16#include "shared/akranges.h"
17
18#include <QDBusServiceWatcher>
19
20using namespace Akonadi;
21using namespace AkRanges;
22
23// @cond PRIVATE
24
25AgentInstance AgentManagerPrivate::createInstance(const AgentType &type)
26{
27 const QString &identifier = mManager->createAgentInstance(type.identifier());
28 if (identifier.isEmpty()) {
29 return AgentInstance();
30 }
31
32 return fillAgentInstanceLight(identifier);
33}
34
35void AgentManagerPrivate::agentTypeAdded(const QString &identifier)
36{
37 // Ignore agent types we already know about, for example because we called
38 // readAgentTypes before.
39 if (mTypes.contains(identifier)) {
40 return;
41 }
42
43 if (mTypes.isEmpty()) {
44 // The Akonadi ServerManager assumes that the server is up and running as soon
45 // as it knows about at least one agent type.
46 // If we Q_EMIT the typeAdded() signal here, it therefore thinks the server is
47 // running. However, the AgentManager does not know about all agent types yet,
48 // as the server might still have pending agentTypeAdded() signals, even though
49 // it internally knows all agent types already.
50 // This can cause situations where the client gets told by the ServerManager that
51 // the server is running, yet the client will encounter an error because the
52 // AgentManager doesn't know all types yet.
53 //
54 // Therefore, we read all agent types from the server here so they are known.
55 readAgentTypes();
56 }
57
58 const AgentType type = fillAgentType(identifier);
59 if (type.isValid()) {
60 mTypes.insert(identifier, type);
61
62 Q_EMIT mParent->typeAdded(type);
63 }
64}
65
66void AgentManagerPrivate::agentTypeRemoved(const QString &identifier)
67{
68 if (!mTypes.contains(identifier)) {
69 return;
70 }
71
72 const AgentType type = mTypes.take(identifier);
73 Q_EMIT mParent->typeRemoved(type);
74}
75
76void AgentManagerPrivate::agentInstanceAdded(const QString &identifier)
77{
78 const AgentInstance instance = fillAgentInstance(identifier);
79 if (instance.isValid()) {
80 // It is possible that this function is called when the instance is already
81 // in our list we filled initially in the constructor.
82 // This happens when the constructor is called during Akonadi startup, when
83 // the agent processes are not fully loaded and have no D-Bus interface yet.
84 // The server-side agent manager then emits the instance added signal when
85 // the D-Bus interface for the agent comes up.
86 // In this case, we simply notify that the instance status has changed.
87 const bool newAgentInstance = !mInstances.contains(identifier);
88 if (newAgentInstance) {
89 mInstances.insert(identifier, instance);
90 Q_EMIT mParent->instanceAdded(instance);
91 } else {
92 mInstances.remove(identifier);
93 mInstances.insert(identifier, instance);
94 Q_EMIT mParent->instanceStatusChanged(instance);
95 }
96 }
97}
98
99void AgentManagerPrivate::agentInstanceRemoved(const QString &identifier)
100{
101 if (!mInstances.contains(identifier)) {
102 return;
103 }
104
105 const AgentInstance instance = mInstances.take(identifier);
106 Q_EMIT mParent->instanceRemoved(instance);
107}
108
109void AgentManagerPrivate::agentInstanceStatusChanged(const QString &identifier, int status, const QString &msg)
110{
111 if (!mInstances.contains(identifier)) {
112 return;
113 }
114
115 AgentInstance &instance = mInstances[identifier];
116 instance.d->mStatus = status;
117 instance.d->mStatusMessage = msg;
118
119 Q_EMIT mParent->instanceStatusChanged(instance);
120}
121
122void AgentManagerPrivate::agentInstanceProgressChanged(const QString &identifier, uint progress, const QString &msg)
123{
124 if (!mInstances.contains(identifier)) {
125 return;
126 }
127
128 AgentInstance &instance = mInstances[identifier];
129 instance.d->mProgress = progress;
130 if (!msg.isEmpty()) {
131 instance.d->mStatusMessage = msg;
132 }
133
134 Q_EMIT mParent->instanceProgressChanged(instance);
135}
136
137void AgentManagerPrivate::agentInstanceWarning(const QString &identifier, const QString &msg)
138{
139 if (!mInstances.contains(identifier)) {
140 return;
141 }
142
143 AgentInstance &instance = mInstances[identifier];
144 Q_EMIT mParent->instanceWarning(instance, msg);
145}
146
147void AgentManagerPrivate::agentInstanceError(const QString &identifier, const QString &msg)
148{
149 if (!mInstances.contains(identifier)) {
150 return;
151 }
152
153 AgentInstance &instance = mInstances[identifier];
154 Q_EMIT mParent->instanceError(instance, msg);
155}
156
157void AgentManagerPrivate::agentInstanceOnlineChanged(const QString &identifier, bool state)
158{
159 if (!mInstances.contains(identifier)) {
160 return;
161 }
162
163 AgentInstance &instance = mInstances[identifier];
164 instance.d->mIsOnline = state;
165 Q_EMIT mParent->instanceOnline(instance, state);
166}
167
168void AgentManagerPrivate::agentInstanceNameChanged(const QString &identifier, const QString &name)
169{
170 if (!mInstances.contains(identifier)) {
171 return;
172 }
173
174 AgentInstance &instance = mInstances[identifier];
175 instance.d->mName = name;
176
177 Q_EMIT mParent->instanceNameChanged(instance);
178}
179
180void AgentManagerPrivate::readAgentTypes()
181{
182 const QDBusReply<QStringList> types = mManager->agentTypes();
183 if (types.isValid()) {
184 const QStringList lst = types.value();
185 for (const QString &type : lst) {
186 const AgentType agentType = fillAgentType(type);
187 if (agentType.isValid()) {
188 mTypes.insert(type, agentType);
189 Q_EMIT mParent->typeAdded(agentType);
190 }
191 }
192 }
193}
194
195void AgentManagerPrivate::readAgentInstances()
196{
197 const QDBusReply<QStringList> instances = mManager->agentInstances();
198 if (instances.isValid()) {
199 const QStringList lst = instances.value();
200 for (const QString &instance : lst) {
201 const AgentInstance agentInstance = fillAgentInstance(instance);
202 if (agentInstance.isValid()) {
203 mInstances.insert(instance, agentInstance);
204 Q_EMIT mParent->instanceAdded(agentInstance);
205 }
206 }
207 }
208}
209
210AgentType AgentManagerPrivate::fillAgentType(const QString &identifier) const
211{
212 AgentType type;
213 type.d->mIdentifier = identifier;
214 type.d->mName = mManager->agentName(identifier);
215 type.d->mDescription = mManager->agentComment(identifier);
216 type.d->mIconName = mManager->agentIcon(identifier);
217 type.d->mMimeTypes = mManager->agentMimeTypes(identifier);
218 type.d->mCapabilities = mManager->agentCapabilities(identifier);
219 type.d->mCustomProperties = mManager->agentCustomProperties(identifier);
220
221 return type;
222}
223
224void AgentManagerPrivate::setName(const AgentInstance &instance, const QString &name)
225{
226 mManager->setAgentInstanceName(instance.identifier(), name);
227}
228
229void AgentManagerPrivate::setOnline(const AgentInstance &instance, bool state)
230{
231 mManager->setAgentInstanceOnline(instance.identifier(), state);
232}
233
234void AgentManagerPrivate::setActivities(const AgentInstance &instance, const QStringList &activities)
235{
236 mManager->setAgentInstanceActivities(instance.identifier(), activities);
237}
238
239void AgentManagerPrivate::setActivitiesEnabled(const AgentInstance &instance, bool enabled)
240{
241 mManager->setAgentInstanceActivitiesEnabled(instance.identifier(), enabled);
242}
243
244void AgentManagerPrivate::configure(const AgentInstance &instance, qlonglong winId)
245{
246 mManager->agentInstanceConfigure(instance.identifier(), winId);
247}
248
249void AgentManagerPrivate::synchronize(const AgentInstance &instance)
250{
251 mManager->agentInstanceSynchronize(instance.identifier());
252}
253
254void AgentManagerPrivate::synchronizeCollectionTree(const AgentInstance &instance)
255{
256 mManager->agentInstanceSynchronizeCollectionTree(instance.identifier());
257}
258
259void AgentManagerPrivate::synchronizeTags(const AgentInstance &instance)
260{
261 mManager->agentInstanceSynchronizeTags(instance.identifier());
262}
263
264AgentInstance AgentManagerPrivate::fillAgentInstance(const QString &identifier) const
265{
266 AgentInstance instance;
267
268 const QString agentTypeIdentifier = mManager->agentInstanceType(identifier);
269 if (!mTypes.contains(agentTypeIdentifier)) {
270 return instance;
271 }
272
273 instance.d->mType = mTypes.value(agentTypeIdentifier);
274 instance.d->mIdentifier = identifier;
275 instance.d->mName = mManager->agentInstanceName(identifier);
276 instance.d->mStatus = mManager->agentInstanceStatus(identifier);
277 instance.d->mStatusMessage = mManager->agentInstanceStatusMessage(identifier);
278 instance.d->mProgress = mManager->agentInstanceProgress(identifier);
279 instance.d->mIsOnline = mManager->agentInstanceOnline(identifier);
280 // FIXME need to reactivate it
281 // FIXME activities instance.d->mActivities = mManager->agentInstanceActivities(identifier);
282 // FIXME activities instance.d->mActivitiesEnabled = mManager->agentInstanceActivitiesEnabled(identifier);
283
284 return instance;
285}
286
287AgentInstance AgentManagerPrivate::fillAgentInstanceLight(const QString &identifier) const
288{
289 AgentInstance instance;
290
291 const QString agentTypeIdentifier = mManager->agentInstanceType(identifier);
292 Q_ASSERT_X(mTypes.contains(agentTypeIdentifier), "fillAgentInstanceLight", "Requests non-existing agent type");
293
294 instance.d->mType = mTypes.value(agentTypeIdentifier);
295 instance.d->mIdentifier = identifier;
296
297 return instance;
298}
299
300void AgentManagerPrivate::createDBusInterface()
301{
302 mTypes.clear();
303 mInstances.clear();
304
305 using AgentManagerIface = org::freedesktop::Akonadi::AgentManager;
306 mManager = std::make_unique<AgentManagerIface>(ServerManager::serviceName(ServerManager::Control),
307 QStringLiteral("/AgentManager"),
309 mParent);
310
311 connect(mManager.get(), &AgentManagerIface::agentTypeAdded, this, &AgentManagerPrivate::agentTypeAdded);
312 connect(mManager.get(), &AgentManagerIface::agentTypeRemoved, this, &AgentManagerPrivate::agentTypeRemoved);
313 connect(mManager.get(), &AgentManagerIface::agentInstanceAdded, this, &AgentManagerPrivate::agentInstanceAdded);
314 connect(mManager.get(), &AgentManagerIface::agentInstanceRemoved, this, &AgentManagerPrivate::agentInstanceRemoved);
315 connect(mManager.get(), &AgentManagerIface::agentInstanceStatusChanged, this, &AgentManagerPrivate::agentInstanceStatusChanged);
316 connect(mManager.get(), &AgentManagerIface::agentInstanceProgressChanged, this, &AgentManagerPrivate::agentInstanceProgressChanged);
317 connect(mManager.get(), &AgentManagerIface::agentInstanceNameChanged, this, &AgentManagerPrivate::agentInstanceNameChanged);
318 connect(mManager.get(), &AgentManagerIface::agentInstanceWarning, this, &AgentManagerPrivate::agentInstanceWarning);
319 connect(mManager.get(), &AgentManagerIface::agentInstanceError, this, &AgentManagerPrivate::agentInstanceError);
320 connect(mManager.get(), &AgentManagerIface::agentInstanceOnlineChanged, this, &AgentManagerPrivate::agentInstanceOnlineChanged);
321
322 if (mManager->isValid()) {
323 readAgentTypes();
324 readAgentInstances();
325 }
326}
327
328AgentManager *AgentManagerPrivate::mSelf = nullptr;
329
331 : QObject(nullptr)
332 , d(new AgentManagerPrivate(this))
333{
334 // needed for queued connections on our signals
335 qRegisterMetaType<Akonadi::AgentType>();
336 qRegisterMetaType<Akonadi::AgentInstance>();
337
338 d->createDBusInterface();
339
340 d->mServiceWatcher = std::make_unique<QDBusServiceWatcher>(ServerManager::serviceName(ServerManager::Control),
343 connect(d->mServiceWatcher.get(), &QDBusServiceWatcher::serviceRegistered, this, [this]() {
344 if (d->mTypes.isEmpty()) { // just to be safe
345 d->readAgentTypes();
346 }
347 if (d->mInstances.isEmpty()) {
348 d->readAgentInstances();
349 }
350 });
351}
352
353/// @endcond
354
356
358{
359 if (!AgentManagerPrivate::mSelf) {
360 AgentManagerPrivate::mSelf = new AgentManager();
361 }
362
363 return AgentManagerPrivate::mSelf;
364}
365
367{
368 // Maybe the Control process is up and ready but we haven't been to the event loop yet so
369 // QDBusServiceWatcher hasn't notified us yet.
370 // In that case make sure to do it here, to avoid going into Broken state.
371 if (d->mTypes.isEmpty()) {
372 d->readAgentTypes();
373 }
374 return d->mTypes | Views::values | Actions::toQVector;
375}
376
377AgentType AgentManager::type(const QString &identifier) const
378{
379 return d->mTypes.value(identifier);
380}
381
383{
384 return d->mInstances | Views::values | Actions::toQVector;
385}
386
387AgentInstance AgentManager::instance(const QString &identifier) const
388{
389 return d->mInstances.value(identifier);
390}
391
392void AgentManager::removeInstance(const AgentInstance &instance)
393{
394 d->mManager->removeAgentInstance(instance.identifier());
395}
396
398{
399 synchronizeCollection(collection, false);
400}
401
402void AgentManager::synchronizeCollection(const Collection &collection, bool recursive)
403{
404 const QString resId = collection.resource();
405 Q_ASSERT(!resId.isEmpty());
406 d->mManager->agentInstanceSynchronizeCollection(resId, collection.id(), recursive);
407}
408
409#include "moc_agentmanager.cpp"
410
411#include "moc_agentmanager_p.cpp"
Represents one agent instance and takes care of communication with it.
QString identifier() const
Set/get the unique identifier of this AgentInstance.
The agent manager has knowledge about all available agents (it scans for .desktop files in the agent ...
AgentManager(bool verbose, QObject *parent=nullptr)
Creates a new agent manager.
~AgentManager() override
Destroys the agent manager.
QList< AgentInstance > List
Describes a list of agent instances.
Provides an interface to retrieve agent types and manage agent instances.
AgentType::List types() const
Returns the list of all available agent types.
AgentType type(const QString &identifier) const
Returns the agent type with the given identifier or an invalid agent type if the identifier does not ...
static AgentManager * self()
Returns the global instance of the agent manager.
void removeInstance(const AgentInstance &instance)
Removes the given agent instance.
AgentInstance instance(const QString &identifier) const
Returns the agent instance with the given identifier or an invalid agent instance if the identifier d...
void synchronizeCollection(const Collection &collection)
Trigger a synchronization of the given collection by its owning resource agent.
AgentInstance::List instances() const
Returns the list of all available agent instances.
A representation of an agent type.
QList< AgentType > List
Describes a list of agent types.
Represents a collection of PIM items.
Definition collection.h:62
static QString serviceName(ServiceType serviceType)
Returns the namespaced D-Bus service name for serviceType.
Q_SCRIPTABLE CaptureState status()
Helper integration between Akonadi and Qt.
QString name(const QVariant &location)
VehicleSection::Type type(QStringView coachNumber, QStringView coachClassification)
QDBusConnection sessionBus()
bool isValid() const const
void serviceRegistered(const QString &serviceName)
T value(qsizetype i) const const
bool isEmpty() const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri Mar 28 2025 11:53:20 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.