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

KDE's Doxygen guidelines are available online.