File indexing completed on 2024-11-10 04:40:37
0001 /* 0002 SPDX-FileCopyrightText: 2006-2008 Tobias Koenig <tokoe@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "agentmanager.h" 0008 #include "agentmanager_p.h" 0009 0010 #include "agentinstance_p.h" 0011 #include "agenttype_p.h" 0012 #include "collection.h" 0013 #include "servermanager.h" 0014 #include <QDBusConnection> 0015 0016 #include "shared/akranges.h" 0017 0018 #include <QDBusServiceWatcher> 0019 #include <QWidget> 0020 0021 using namespace Akonadi; 0022 using namespace AkRanges; 0023 0024 // @cond PRIVATE 0025 0026 AgentInstance AgentManagerPrivate::createInstance(const AgentType &type) 0027 { 0028 const QString &identifier = mManager->createAgentInstance(type.identifier()); 0029 if (identifier.isEmpty()) { 0030 return AgentInstance(); 0031 } 0032 0033 return fillAgentInstanceLight(identifier); 0034 } 0035 0036 void AgentManagerPrivate::agentTypeAdded(const QString &identifier) 0037 { 0038 // Ignore agent types we already know about, for example because we called 0039 // readAgentTypes before. 0040 if (mTypes.contains(identifier)) { 0041 return; 0042 } 0043 0044 if (mTypes.isEmpty()) { 0045 // The Akonadi ServerManager assumes that the server is up and running as soon 0046 // as it knows about at least one agent type. 0047 // If we Q_EMIT the typeAdded() signal here, it therefore thinks the server is 0048 // running. However, the AgentManager does not know about all agent types yet, 0049 // as the server might still have pending agentTypeAdded() signals, even though 0050 // it internally knows all agent types already. 0051 // This can cause situations where the client gets told by the ServerManager that 0052 // the server is running, yet the client will encounter an error because the 0053 // AgentManager doesn't know all types yet. 0054 // 0055 // Therefore, we read all agent types from the server here so they are known. 0056 readAgentTypes(); 0057 } 0058 0059 const AgentType type = fillAgentType(identifier); 0060 if (type.isValid()) { 0061 mTypes.insert(identifier, type); 0062 0063 Q_EMIT mParent->typeAdded(type); 0064 } 0065 } 0066 0067 void AgentManagerPrivate::agentTypeRemoved(const QString &identifier) 0068 { 0069 if (!mTypes.contains(identifier)) { 0070 return; 0071 } 0072 0073 const AgentType type = mTypes.take(identifier); 0074 Q_EMIT mParent->typeRemoved(type); 0075 } 0076 0077 void AgentManagerPrivate::agentInstanceAdded(const QString &identifier) 0078 { 0079 const AgentInstance instance = fillAgentInstance(identifier); 0080 if (instance.isValid()) { 0081 // It is possible that this function is called when the instance is already 0082 // in our list we filled initially in the constructor. 0083 // This happens when the constructor is called during Akonadi startup, when 0084 // the agent processes are not fully loaded and have no D-Bus interface yet. 0085 // The server-side agent manager then emits the instance added signal when 0086 // the D-Bus interface for the agent comes up. 0087 // In this case, we simply notify that the instance status has changed. 0088 const bool newAgentInstance = !mInstances.contains(identifier); 0089 if (newAgentInstance) { 0090 mInstances.insert(identifier, instance); 0091 Q_EMIT mParent->instanceAdded(instance); 0092 } else { 0093 mInstances.remove(identifier); 0094 mInstances.insert(identifier, instance); 0095 Q_EMIT mParent->instanceStatusChanged(instance); 0096 } 0097 } 0098 } 0099 0100 void AgentManagerPrivate::agentInstanceRemoved(const QString &identifier) 0101 { 0102 if (!mInstances.contains(identifier)) { 0103 return; 0104 } 0105 0106 const AgentInstance instance = mInstances.take(identifier); 0107 Q_EMIT mParent->instanceRemoved(instance); 0108 } 0109 0110 void AgentManagerPrivate::agentInstanceStatusChanged(const QString &identifier, int status, const QString &msg) 0111 { 0112 if (!mInstances.contains(identifier)) { 0113 return; 0114 } 0115 0116 AgentInstance &instance = mInstances[identifier]; 0117 instance.d->mStatus = status; 0118 instance.d->mStatusMessage = msg; 0119 0120 Q_EMIT mParent->instanceStatusChanged(instance); 0121 } 0122 0123 void AgentManagerPrivate::agentInstanceProgressChanged(const QString &identifier, uint progress, const QString &msg) 0124 { 0125 if (!mInstances.contains(identifier)) { 0126 return; 0127 } 0128 0129 AgentInstance &instance = mInstances[identifier]; 0130 instance.d->mProgress = progress; 0131 if (!msg.isEmpty()) { 0132 instance.d->mStatusMessage = msg; 0133 } 0134 0135 Q_EMIT mParent->instanceProgressChanged(instance); 0136 } 0137 0138 void AgentManagerPrivate::agentInstanceWarning(const QString &identifier, const QString &msg) 0139 { 0140 if (!mInstances.contains(identifier)) { 0141 return; 0142 } 0143 0144 AgentInstance &instance = mInstances[identifier]; 0145 Q_EMIT mParent->instanceWarning(instance, msg); 0146 } 0147 0148 void AgentManagerPrivate::agentInstanceError(const QString &identifier, const QString &msg) 0149 { 0150 if (!mInstances.contains(identifier)) { 0151 return; 0152 } 0153 0154 AgentInstance &instance = mInstances[identifier]; 0155 Q_EMIT mParent->instanceError(instance, msg); 0156 } 0157 0158 void AgentManagerPrivate::agentInstanceOnlineChanged(const QString &identifier, bool state) 0159 { 0160 if (!mInstances.contains(identifier)) { 0161 return; 0162 } 0163 0164 AgentInstance &instance = mInstances[identifier]; 0165 instance.d->mIsOnline = state; 0166 Q_EMIT mParent->instanceOnline(instance, state); 0167 } 0168 0169 void AgentManagerPrivate::agentInstanceNameChanged(const QString &identifier, const QString &name) 0170 { 0171 if (!mInstances.contains(identifier)) { 0172 return; 0173 } 0174 0175 AgentInstance &instance = mInstances[identifier]; 0176 instance.d->mName = name; 0177 0178 Q_EMIT mParent->instanceNameChanged(instance); 0179 } 0180 0181 void AgentManagerPrivate::readAgentTypes() 0182 { 0183 const QDBusReply<QStringList> types = mManager->agentTypes(); 0184 if (types.isValid()) { 0185 const QStringList lst = types.value(); 0186 for (const QString &type : lst) { 0187 const AgentType agentType = fillAgentType(type); 0188 if (agentType.isValid()) { 0189 mTypes.insert(type, agentType); 0190 Q_EMIT mParent->typeAdded(agentType); 0191 } 0192 } 0193 } 0194 } 0195 0196 void AgentManagerPrivate::readAgentInstances() 0197 { 0198 const QDBusReply<QStringList> instances = mManager->agentInstances(); 0199 if (instances.isValid()) { 0200 const QStringList lst = instances.value(); 0201 for (const QString &instance : lst) { 0202 const AgentInstance agentInstance = fillAgentInstance(instance); 0203 if (agentInstance.isValid()) { 0204 mInstances.insert(instance, agentInstance); 0205 Q_EMIT mParent->instanceAdded(agentInstance); 0206 } 0207 } 0208 } 0209 } 0210 0211 AgentType AgentManagerPrivate::fillAgentType(const QString &identifier) const 0212 { 0213 AgentType type; 0214 type.d->mIdentifier = identifier; 0215 type.d->mName = mManager->agentName(identifier); 0216 type.d->mDescription = mManager->agentComment(identifier); 0217 type.d->mIconName = mManager->agentIcon(identifier); 0218 type.d->mMimeTypes = mManager->agentMimeTypes(identifier); 0219 type.d->mCapabilities = mManager->agentCapabilities(identifier); 0220 type.d->mCustomProperties = mManager->agentCustomProperties(identifier); 0221 0222 return type; 0223 } 0224 0225 void AgentManagerPrivate::setName(const AgentInstance &instance, const QString &name) 0226 { 0227 mManager->setAgentInstanceName(instance.identifier(), name); 0228 } 0229 0230 void AgentManagerPrivate::setOnline(const AgentInstance &instance, bool state) 0231 { 0232 mManager->setAgentInstanceOnline(instance.identifier(), state); 0233 } 0234 0235 void AgentManagerPrivate::configure(const AgentInstance &instance, QWidget *parent) 0236 { 0237 qlonglong winId = 0; 0238 if (parent) { 0239 winId = static_cast<qlonglong>(parent->window()->winId()); 0240 } 0241 0242 mManager->agentInstanceConfigure(instance.identifier(), winId); 0243 } 0244 0245 void AgentManagerPrivate::synchronize(const AgentInstance &instance) 0246 { 0247 mManager->agentInstanceSynchronize(instance.identifier()); 0248 } 0249 0250 void AgentManagerPrivate::synchronizeCollectionTree(const AgentInstance &instance) 0251 { 0252 mManager->agentInstanceSynchronizeCollectionTree(instance.identifier()); 0253 } 0254 0255 void AgentManagerPrivate::synchronizeTags(const AgentInstance &instance) 0256 { 0257 mManager->agentInstanceSynchronizeTags(instance.identifier()); 0258 } 0259 0260 void AgentManagerPrivate::synchronizeRelations(const AgentInstance &instance) 0261 { 0262 mManager->agentInstanceSynchronizeRelations(instance.identifier()); 0263 } 0264 0265 AgentInstance AgentManagerPrivate::fillAgentInstance(const QString &identifier) const 0266 { 0267 AgentInstance instance; 0268 0269 const QString agentTypeIdentifier = mManager->agentInstanceType(identifier); 0270 if (!mTypes.contains(agentTypeIdentifier)) { 0271 return instance; 0272 } 0273 0274 instance.d->mType = mTypes.value(agentTypeIdentifier); 0275 instance.d->mIdentifier = identifier; 0276 instance.d->mName = mManager->agentInstanceName(identifier); 0277 instance.d->mStatus = mManager->agentInstanceStatus(identifier); 0278 instance.d->mStatusMessage = mManager->agentInstanceStatusMessage(identifier); 0279 instance.d->mProgress = mManager->agentInstanceProgress(identifier); 0280 instance.d->mIsOnline = mManager->agentInstanceOnline(identifier); 0281 0282 return instance; 0283 } 0284 0285 AgentInstance AgentManagerPrivate::fillAgentInstanceLight(const QString &identifier) const 0286 { 0287 AgentInstance instance; 0288 0289 const QString agentTypeIdentifier = mManager->agentInstanceType(identifier); 0290 Q_ASSERT_X(mTypes.contains(agentTypeIdentifier), "fillAgentInstanceLight", "Requests non-existing agent type"); 0291 0292 instance.d->mType = mTypes.value(agentTypeIdentifier); 0293 instance.d->mIdentifier = identifier; 0294 0295 return instance; 0296 } 0297 0298 void AgentManagerPrivate::createDBusInterface() 0299 { 0300 mTypes.clear(); 0301 mInstances.clear(); 0302 0303 using AgentManagerIface = org::freedesktop::Akonadi::AgentManager; 0304 mManager = std::make_unique<AgentManagerIface>(ServerManager::serviceName(ServerManager::Control), 0305 QStringLiteral("/AgentManager"), 0306 QDBusConnection::sessionBus(), 0307 mParent); 0308 0309 connect(mManager.get(), &AgentManagerIface::agentTypeAdded, this, &AgentManagerPrivate::agentTypeAdded); 0310 connect(mManager.get(), &AgentManagerIface::agentTypeRemoved, this, &AgentManagerPrivate::agentTypeRemoved); 0311 connect(mManager.get(), &AgentManagerIface::agentInstanceAdded, this, &AgentManagerPrivate::agentInstanceAdded); 0312 connect(mManager.get(), &AgentManagerIface::agentInstanceRemoved, this, &AgentManagerPrivate::agentInstanceRemoved); 0313 connect(mManager.get(), &AgentManagerIface::agentInstanceStatusChanged, this, &AgentManagerPrivate::agentInstanceStatusChanged); 0314 connect(mManager.get(), &AgentManagerIface::agentInstanceProgressChanged, this, &AgentManagerPrivate::agentInstanceProgressChanged); 0315 connect(mManager.get(), &AgentManagerIface::agentInstanceNameChanged, this, &AgentManagerPrivate::agentInstanceNameChanged); 0316 connect(mManager.get(), &AgentManagerIface::agentInstanceWarning, this, &AgentManagerPrivate::agentInstanceWarning); 0317 connect(mManager.get(), &AgentManagerIface::agentInstanceError, this, &AgentManagerPrivate::agentInstanceError); 0318 connect(mManager.get(), &AgentManagerIface::agentInstanceOnlineChanged, this, &AgentManagerPrivate::agentInstanceOnlineChanged); 0319 0320 if (mManager->isValid()) { 0321 readAgentTypes(); 0322 readAgentInstances(); 0323 } 0324 } 0325 0326 AgentManager *AgentManagerPrivate::mSelf = nullptr; 0327 0328 AgentManager::AgentManager() 0329 : QObject(nullptr) 0330 , d(new AgentManagerPrivate(this)) 0331 { 0332 // needed for queued connections on our signals 0333 qRegisterMetaType<Akonadi::AgentType>(); 0334 qRegisterMetaType<Akonadi::AgentInstance>(); 0335 0336 d->createDBusInterface(); 0337 0338 d->mServiceWatcher = std::make_unique<QDBusServiceWatcher>(ServerManager::serviceName(ServerManager::Control), 0339 QDBusConnection::sessionBus(), 0340 QDBusServiceWatcher::WatchForRegistration); 0341 connect(d->mServiceWatcher.get(), &QDBusServiceWatcher::serviceRegistered, this, [this]() { 0342 if (d->mTypes.isEmpty()) { // just to be safe 0343 d->readAgentTypes(); 0344 } 0345 if (d->mInstances.isEmpty()) { 0346 d->readAgentInstances(); 0347 } 0348 }); 0349 } 0350 0351 /// @endcond 0352 0353 AgentManager::~AgentManager() = default; 0354 0355 AgentManager *AgentManager::self() 0356 { 0357 if (!AgentManagerPrivate::mSelf) { 0358 AgentManagerPrivate::mSelf = new AgentManager(); 0359 } 0360 0361 return AgentManagerPrivate::mSelf; 0362 } 0363 0364 AgentType::List AgentManager::types() const 0365 { 0366 // Maybe the Control process is up and ready but we haven't been to the event loop yet so 0367 // QDBusServiceWatcher hasn't notified us yet. 0368 // In that case make sure to do it here, to avoid going into Broken state. 0369 if (d->mTypes.isEmpty()) { 0370 d->readAgentTypes(); 0371 } 0372 return d->mTypes | Views::values | Actions::toQVector; 0373 } 0374 0375 AgentType AgentManager::type(const QString &identifier) const 0376 { 0377 return d->mTypes.value(identifier); 0378 } 0379 0380 AgentInstance::List AgentManager::instances() const 0381 { 0382 return d->mInstances | Views::values | Actions::toQVector; 0383 } 0384 0385 AgentInstance AgentManager::instance(const QString &identifier) const 0386 { 0387 return d->mInstances.value(identifier); 0388 } 0389 0390 void AgentManager::removeInstance(const AgentInstance &instance) 0391 { 0392 d->mManager->removeAgentInstance(instance.identifier()); 0393 } 0394 0395 void AgentManager::synchronizeCollection(const Collection &collection) 0396 { 0397 synchronizeCollection(collection, false); 0398 } 0399 0400 void AgentManager::synchronizeCollection(const Collection &collection, bool recursive) 0401 { 0402 const QString resId = collection.resource(); 0403 Q_ASSERT(!resId.isEmpty()); 0404 d->mManager->agentInstanceSynchronizeCollection(resId, collection.id(), recursive); 0405 } 0406 0407 #include "moc_agentmanager.cpp" 0408 0409 #include "moc_agentmanager_p.cpp"