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::configure(const AgentInstance &instance, QWidget *parent)
236{
237 qlonglong winId = 0;
238 if (parent) {
239 winId = static_cast<qlonglong>(parent->window()->winId());
240 }
241
242 mManager->agentInstanceConfigure(instance.identifier(), winId);
243}
244
245void AgentManagerPrivate::synchronize(const AgentInstance &instance)
246{
247 mManager->agentInstanceSynchronize(instance.identifier());
248}
249
250void AgentManagerPrivate::synchronizeCollectionTree(const AgentInstance &instance)
251{
252 mManager->agentInstanceSynchronizeCollectionTree(instance.identifier());
253}
254
255void AgentManagerPrivate::synchronizeTags(const AgentInstance &instance)
256{
257 mManager->agentInstanceSynchronizeTags(instance.identifier());
258}
259
260AgentInstance AgentManagerPrivate::fillAgentInstance(const QString &identifier) const
261{
262 AgentInstance instance;
263
264 const QString agentTypeIdentifier = mManager->agentInstanceType(identifier);
265 if (!mTypes.contains(agentTypeIdentifier)) {
266 return instance;
267 }
268
269 instance.d->mType = mTypes.value(agentTypeIdentifier);
270 instance.d->mIdentifier = identifier;
271 instance.d->mName = mManager->agentInstanceName(identifier);
272 instance.d->mStatus = mManager->agentInstanceStatus(identifier);
273 instance.d->mStatusMessage = mManager->agentInstanceStatusMessage(identifier);
274 instance.d->mProgress = mManager->agentInstanceProgress(identifier);
275 instance.d->mIsOnline = mManager->agentInstanceOnline(identifier);
276
277 return instance;
278}
279
280AgentInstance AgentManagerPrivate::fillAgentInstanceLight(const QString &identifier) const
281{
282 AgentInstance instance;
283
284 const QString agentTypeIdentifier = mManager->agentInstanceType(identifier);
285 Q_ASSERT_X(mTypes.contains(agentTypeIdentifier), "fillAgentInstanceLight", "Requests non-existing agent type");
286
287 instance.d->mType = mTypes.value(agentTypeIdentifier);
288 instance.d->mIdentifier = identifier;
289
290 return instance;
291}
292
293void AgentManagerPrivate::createDBusInterface()
294{
295 mTypes.clear();
296 mInstances.clear();
297
298 using AgentManagerIface = org::freedesktop::Akonadi::AgentManager;
299 mManager = std::make_unique<AgentManagerIface>(ServerManager::serviceName(ServerManager::Control),
300 QStringLiteral("/AgentManager"),
302 mParent);
303
304 connect(mManager.get(), &AgentManagerIface::agentTypeAdded, this, &AgentManagerPrivate::agentTypeAdded);
305 connect(mManager.get(), &AgentManagerIface::agentTypeRemoved, this, &AgentManagerPrivate::agentTypeRemoved);
306 connect(mManager.get(), &AgentManagerIface::agentInstanceAdded, this, &AgentManagerPrivate::agentInstanceAdded);
307 connect(mManager.get(), &AgentManagerIface::agentInstanceRemoved, this, &AgentManagerPrivate::agentInstanceRemoved);
308 connect(mManager.get(), &AgentManagerIface::agentInstanceStatusChanged, this, &AgentManagerPrivate::agentInstanceStatusChanged);
309 connect(mManager.get(), &AgentManagerIface::agentInstanceProgressChanged, this, &AgentManagerPrivate::agentInstanceProgressChanged);
310 connect(mManager.get(), &AgentManagerIface::agentInstanceNameChanged, this, &AgentManagerPrivate::agentInstanceNameChanged);
311 connect(mManager.get(), &AgentManagerIface::agentInstanceWarning, this, &AgentManagerPrivate::agentInstanceWarning);
312 connect(mManager.get(), &AgentManagerIface::agentInstanceError, this, &AgentManagerPrivate::agentInstanceError);
313 connect(mManager.get(), &AgentManagerIface::agentInstanceOnlineChanged, this, &AgentManagerPrivate::agentInstanceOnlineChanged);
314
315 if (mManager->isValid()) {
316 readAgentTypes();
317 readAgentInstances();
318 }
319}
320
321AgentManager *AgentManagerPrivate::mSelf = nullptr;
322
324 : QObject(nullptr)
325 , d(new AgentManagerPrivate(this))
326{
327 // needed for queued connections on our signals
328 qRegisterMetaType<Akonadi::AgentType>();
329 qRegisterMetaType<Akonadi::AgentInstance>();
330
331 d->createDBusInterface();
332
333 d->mServiceWatcher = std::make_unique<QDBusServiceWatcher>(ServerManager::serviceName(ServerManager::Control),
336 connect(d->mServiceWatcher.get(), &QDBusServiceWatcher::serviceRegistered, this, [this]() {
337 if (d->mTypes.isEmpty()) { // just to be safe
338 d->readAgentTypes();
339 }
340 if (d->mInstances.isEmpty()) {
341 d->readAgentInstances();
342 }
343 });
344}
345
346/// @endcond
347
349
350AgentManager *AgentManager::self()
351{
352 if (!AgentManagerPrivate::mSelf) {
353 AgentManagerPrivate::mSelf = new AgentManager();
354 }
355
356 return AgentManagerPrivate::mSelf;
357}
358
359AgentType::List AgentManager::types() const
360{
361 // Maybe the Control process is up and ready but we haven't been to the event loop yet so
362 // QDBusServiceWatcher hasn't notified us yet.
363 // In that case make sure to do it here, to avoid going into Broken state.
364 if (d->mTypes.isEmpty()) {
365 d->readAgentTypes();
366 }
367 return d->mTypes | Views::values | Actions::toQVector;
368}
369
370AgentType AgentManager::type(const QString &identifier) const
371{
372 return d->mTypes.value(identifier);
373}
374
375AgentInstance::List AgentManager::instances() const
376{
377 return d->mInstances | Views::values | Actions::toQVector;
378}
379
380AgentInstance AgentManager::instance(const QString &identifier) const
381{
382 return d->mInstances.value(identifier);
383}
384
385void AgentManager::removeInstance(const AgentInstance &instance)
386{
387 d->mManager->removeAgentInstance(instance.identifier());
388}
389
390void AgentManager::synchronizeCollection(const Collection &collection)
391{
392 synchronizeCollection(collection, false);
393}
394
395void AgentManager::synchronizeCollection(const Collection &collection, bool recursive)
396{
397 const QString resId = collection.resource();
398 Q_ASSERT(!resId.isEmpty());
399 d->mManager->agentInstanceSynchronizeCollection(resId, collection.id(), recursive);
400}
401
402#include "moc_agentmanager.cpp"
403
404#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.
QString name(GameStandardAction id)
VehicleSection::Type type(QStringView coachNumber, QStringView coachClassification)
QDBusConnection sessionBus()
bool isValid() const const
void serviceRegistered(const QString &serviceName)
bool isEmpty() const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
WId winId() const const
QWidget * window() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Jul 26 2024 11:52:52 by doxygen 1.11.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.