Akonadi

specialcollectionshelperjobs.cpp
1 /*
2  SPDX-FileCopyrightText: 2009 Constantin Berzan <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6 
7 #include "specialcollectionshelperjobs_p.h"
8 
9 #include "servermanager.h"
10 #include "specialcollectionattribute.h"
11 #include "specialcollections.h"
12 #include <QDBusConnection>
13 
14 #include "agentinstance.h"
15 #include "agentinstancecreatejob.h"
16 #include "agentmanager.h"
17 #include "collectionfetchjob.h"
18 #include "collectionfetchscope.h"
19 #include "collectionmodifyjob.h"
20 #include "entitydisplayattribute.h"
21 #include "resourcesynchronizationjob.h"
22 
23 #include "akonadicore_debug.h"
24 
25 #include <KCoreConfigSkeleton>
26 #include <KLocalizedString>
27 
28 #include <QDBusConnectionInterface>
29 #include <QDBusInterface>
30 #include <QDBusServiceWatcher>
31 #include <QMetaMethod>
32 #include <QTime>
33 #include <QTimer>
34 
35 #define LOCK_WAIT_TIMEOUT_SECONDS 30
36 
37 using namespace Akonadi;
38 
39 // convenient methods to get/set the default resource id
40 static void setDefaultResourceId(KCoreConfigSkeleton *settings, const QString &value)
41 {
42  KConfigSkeletonItem *item = settings->findItem(QStringLiteral("DefaultResourceId"));
43  Q_ASSERT(item);
44  item->setProperty(value);
45 }
46 
47 static QString defaultResourceId(KCoreConfigSkeleton *settings)
48 {
49  const KConfigSkeletonItem *item = settings->findItem(QStringLiteral("DefaultResourceId"));
50  Q_ASSERT(item);
51  return item->property().toString();
52 }
53 
54 static QString dbusServiceName()
55 {
56  const QString service = QStringLiteral("org.kde.pim.SpecialCollections");
58  return service + ServerManager::instanceIdentifier();
59  }
60  return service;
61 }
62 
63 static QVariant::Type argumentType(const QMetaObject *mo, const QString &method)
64 {
65  QMetaMethod m;
66  for (int i = 0; i < mo->methodCount(); ++i) {
67  const QString signature = QString::fromLatin1(mo->method(i).methodSignature());
68  if (signature.startsWith(method)) {
69  m = mo->method(i);
70  }
71  }
72 
73  if (m.methodSignature().isEmpty()) {
74  return QVariant::Invalid;
75  }
76 
77  const QList<QByteArray> argTypes = m.parameterTypes();
78  if (argTypes.count() != 1) {
79  return QVariant::Invalid;
80  }
81 
82  return QVariant::nameToType(argTypes.first().constData());
83 }
84 
85 // ===================== ResourceScanJob ============================
86 
87 /**
88  @internal
89 */
90 class Akonadi::ResourceScanJobPrivate
91 {
92 public:
93  ResourceScanJobPrivate(KCoreConfigSkeleton *settings, ResourceScanJob *qq);
94 
95  void fetchResult(KJob *job); // slot
96 
97  ResourceScanJob *const q;
98 
99  // Input:
100  QString mResourceId;
101  KCoreConfigSkeleton *mSettings = nullptr;
102 
103  // Output:
104  Collection mRootCollection;
105  Collection::List mSpecialCollections;
106 };
107 
108 ResourceScanJobPrivate::ResourceScanJobPrivate(KCoreConfigSkeleton *settings, ResourceScanJob *qq)
109  : q(qq)
110  , mSettings(settings)
111 {
112 }
113 
114 void ResourceScanJobPrivate::fetchResult(KJob *job)
115 {
116  if (job->error()) {
117  qCWarning(AKONADICORE_LOG) << job->errorText();
118  return;
119  }
120 
121  auto fetchJob = qobject_cast<CollectionFetchJob *>(job);
122  Q_ASSERT(fetchJob);
123 
124  Q_ASSERT(!mRootCollection.isValid());
125  Q_ASSERT(mSpecialCollections.isEmpty());
126  const Akonadi::Collection::List lstCols = fetchJob->collections();
127  for (const Collection &collection : lstCols) {
128  if (collection.parentCollection() == Collection::root()) {
129  if (mRootCollection.isValid()) {
130  qCWarning(AKONADICORE_LOG) << "Resource has more than one root collection. I don't know what to do.";
131  } else {
132  mRootCollection = collection;
133  }
134  }
135 
136  if (collection.hasAttribute<SpecialCollectionAttribute>()) {
137  mSpecialCollections.append(collection);
138  }
139  }
140 
141  qCDebug(AKONADICORE_LOG) << "Fetched root collection" << mRootCollection.id() << "and" << mSpecialCollections.count() << "local folders"
142  << "(total" << fetchJob->collections().count() << "collections).";
143 
144  if (!mRootCollection.isValid()) {
145  q->setError(ResourceScanJob::Unknown);
146  q->setErrorText(i18n("Could not fetch root collection of resource %1.", mResourceId));
147  q->emitResult();
148  return;
149  }
150 
151  // We are done!
152  q->emitResult();
153 }
154 
155 ResourceScanJob::ResourceScanJob(const QString &resourceId, KCoreConfigSkeleton *settings, QObject *parent)
156  : Job(parent)
157  , d(new ResourceScanJobPrivate(settings, this))
158 {
159  setResourceId(resourceId);
160 }
161 
162 ResourceScanJob::~ResourceScanJob() = default;
163 
164 QString ResourceScanJob::resourceId() const
165 {
166  return d->mResourceId;
167 }
168 
169 void ResourceScanJob::setResourceId(const QString &resourceId)
170 {
171  d->mResourceId = resourceId;
172 }
173 
174 Akonadi::Collection ResourceScanJob::rootResourceCollection() const
175 {
176  return d->mRootCollection;
177 }
178 
179 Akonadi::Collection::List ResourceScanJob::specialCollections() const
180 {
181  return d->mSpecialCollections;
182 }
183 
184 void ResourceScanJob::doStart()
185 {
186  if (d->mResourceId.isEmpty()) {
187  if (!qobject_cast<DefaultResourceJob *>(this)) {
188  qCCritical(AKONADICORE_LOG) << "No resource ID given.";
189  setError(Job::Unknown);
190  setErrorText(i18n("No resource ID given."));
191  }
192  emitResult();
193  return;
194  }
195 
197  fetchJob->fetchScope().setResource(d->mResourceId);
198  fetchJob->fetchScope().setIncludeStatistics(true);
199  fetchJob->fetchScope().setListFilter(CollectionFetchScope::Display);
200  connect(fetchJob, &CollectionFetchJob::result, this, [this](KJob *job) {
201  d->fetchResult(job);
202  });
203 }
204 
205 // ===================== DefaultResourceJob ============================
206 
207 /**
208  @internal
209 */
210 class Akonadi::DefaultResourceJobPrivate
211 {
212 public:
213  DefaultResourceJobPrivate(KCoreConfigSkeleton *settings, DefaultResourceJob *qq);
214 
215  void tryFetchResource();
216  void resourceCreateResult(KJob *job); // slot
217  void resourceSyncResult(KJob *job); // slot
218  void collectionFetchResult(KJob *job); // slot
219  void collectionModifyResult(KJob *job); // slot
220 
221  DefaultResourceJob *const q;
222  KCoreConfigSkeleton *mSettings = nullptr;
223  QVariantMap mDefaultResourceOptions;
224  QList<QByteArray> mKnownTypes;
225  QMap<QByteArray, QString> mNameForTypeMap;
226  QMap<QByteArray, QString> mIconForTypeMap;
227  QString mDefaultResourceType;
228  int mPendingModifyJobs = 0;
229  bool mResourceWasPreexisting = true;
230 };
231 
232 DefaultResourceJobPrivate::DefaultResourceJobPrivate(KCoreConfigSkeleton *settings, DefaultResourceJob *qq)
233  : q(qq)
234  , mSettings(settings)
235  , mPendingModifyJobs(0)
236  , mResourceWasPreexisting(true /* for safety, so as not to accidentally delete data */)
237 {
238 }
239 
240 void DefaultResourceJobPrivate::tryFetchResource()
241 {
242  // Get the resourceId from config. Another instance might have changed it in the meantime.
243  mSettings->load();
244 
245  const QString resourceId = defaultResourceId(mSettings);
246 
247  qCDebug(AKONADICORE_LOG) << "Read defaultResourceId" << resourceId << "from config.";
248 
249  const AgentInstance resource = AgentManager::self()->instance(resourceId);
250  if (resource.isValid()) {
251  // The resource exists; scan it.
252  mResourceWasPreexisting = true;
253  qCDebug(AKONADICORE_LOG) << "Found resource" << resourceId;
254  q->setResourceId(resourceId);
255 
257  fetchJob->fetchScope().setResource(resourceId);
258  fetchJob->fetchScope().setIncludeStatistics(true);
259  q->connect(fetchJob, &CollectionFetchJob::result, q, [this](KJob *job) {
260  collectionFetchResult(job);
261  });
262  } else {
263  // Try harder: maybe the default resource has been removed and another one added
264  // without updating the config file, in this case search for a resource
265  // of the same type and the default name
266  const AgentInstance::List resources = AgentManager::self()->instances();
267  for (const AgentInstance &resourceInstance : resources) {
268  if (resourceInstance.type().identifier() == mDefaultResourceType) {
269  if (resourceInstance.name() == mDefaultResourceOptions.value(QStringLiteral("Name")).toString()) {
270  // found a matching one...
271  setDefaultResourceId(mSettings, resourceInstance.identifier());
272  mSettings->save();
273  mResourceWasPreexisting = true;
274  qCDebug(AKONADICORE_LOG) << "Found resource" << resourceInstance.identifier();
275  q->setResourceId(resourceInstance.identifier());
276  q->ResourceScanJob::doStart();
277  return;
278  }
279  }
280  }
281 
282  // Create the resource.
283  mResourceWasPreexisting = false;
284  qCDebug(AKONADICORE_LOG) << "Creating maildir resource.";
285  const AgentType type = AgentManager::self()->type(mDefaultResourceType);
286  auto job = new AgentInstanceCreateJob(type, q);
287  QObject::connect(job, &AgentInstanceCreateJob::result, q, [this](KJob *job) {
288  resourceCreateResult(job);
289  });
290  job->start(); // non-Akonadi::Job
291  }
292 }
293 
294 void DefaultResourceJobPrivate::resourceCreateResult(KJob *job)
295 {
296  if (job->error()) {
297  qCWarning(AKONADICORE_LOG) << job->errorText();
298  // fail( i18n( "Failed to create the default resource (%1).", job->errorString() ) );
299  q->setError(job->error());
300  q->setErrorText(job->errorText());
301  q->emitResult();
302  return;
303  }
304 
305  AgentInstance agent;
306 
307  // Get the resource instance.
308  {
309  auto createJob = qobject_cast<AgentInstanceCreateJob *>(job);
310  Q_ASSERT(createJob);
311  agent = createJob->instance();
312  setDefaultResourceId(mSettings, agent.identifier());
313  qCDebug(AKONADICORE_LOG) << "Created maildir resource with id" << defaultResourceId(mSettings);
314  }
315 
316  const QString defaultId = defaultResourceId(mSettings);
317 
318  // Configure the resource.
319  {
320  agent.setName(mDefaultResourceOptions.value(QStringLiteral("Name")).toString());
321 
322  const auto service = ServerManager::agentServiceName(ServerManager::Resource, defaultId);
323  QDBusInterface conf(service, QStringLiteral("/Settings"), QString());
324 
325  if (!conf.isValid()) {
326  q->setError(-1);
327  q->setErrorText(i18n("Invalid resource identifier '%1'", defaultId));
328  q->emitResult();
329  return;
330  }
331 
332  QMap<QString, QVariant>::const_iterator it = mDefaultResourceOptions.cbegin();
333  const QMap<QString, QVariant>::const_iterator itEnd = mDefaultResourceOptions.cend();
334  for (; it != itEnd; ++it) {
335  if (it.key() == QLatin1String("Name")) {
336  continue;
337  }
338 
339  const QString methodName = QStringLiteral("set%1").arg(it.key());
340  const QVariant::Type argType = argumentType(conf.metaObject(), methodName);
341  if (argType == QVariant::Invalid) {
342  q->setError(Job::Unknown);
343  q->setErrorText(i18n("Failed to configure default resource via D-Bus."));
344  q->emitResult();
345  return;
346  }
347 
348  QDBusReply<void> reply = conf.call(methodName, it.value());
349  if (!reply.isValid()) {
350  q->setError(Job::Unknown);
351  q->setErrorText(i18n("Failed to configure default resource via D-Bus."));
352  q->emitResult();
353  return;
354  }
355  }
356 
357  conf.call(QStringLiteral("save"));
358 
359  agent.reconfigure();
360  }
361 
362  // Sync the resource.
363  {
364  auto syncJob = new ResourceSynchronizationJob(agent, q);
365  QObject::connect(syncJob, &ResourceSynchronizationJob::result, q, [this](KJob *job) {
366  resourceSyncResult(job);
367  });
368  syncJob->start(); // non-Akonadi
369  }
370 }
371 
372 void DefaultResourceJobPrivate::resourceSyncResult(KJob *job)
373 {
374  if (job->error()) {
375  qCWarning(AKONADICORE_LOG) << job->errorText();
376  // fail( i18n( "ResourceSynchronizationJob failed (%1).", job->errorString() ) );
377  return;
378  }
379 
380  // Fetch the collections of the resource.
381  qCDebug(AKONADICORE_LOG) << "Fetching maildir collections.";
383  fetchJob->fetchScope().setResource(defaultResourceId(mSettings));
384  QObject::connect(fetchJob, &CollectionFetchJob::result, q, [this](KJob *job) {
385  collectionFetchResult(job);
386  });
387 }
388 
389 void DefaultResourceJobPrivate::collectionFetchResult(KJob *job)
390 {
391  if (job->error()) {
392  qCWarning(AKONADICORE_LOG) << job->errorText();
393  // fail( i18n( "Failed to fetch the root maildir collection (%1).", job->errorString() ) );
394  return;
395  }
396 
397  auto fetchJob = qobject_cast<CollectionFetchJob *>(job);
398  Q_ASSERT(fetchJob);
399 
400  const Collection::List collections = fetchJob->collections();
401  qCDebug(AKONADICORE_LOG) << "Fetched" << collections.count() << "collections.";
402 
403  // Find the root maildir collection.
404  Collection::List toRecover;
405  Collection resourceCollection;
406  for (const Collection &collection : collections) {
407  if (collection.parentCollection() == Collection::root()) {
408  resourceCollection = collection;
409  toRecover.append(collection);
410  break;
411  }
412  }
413 
414  if (!resourceCollection.isValid()) {
415  q->setError(Job::Unknown);
416  q->setErrorText(i18n("Failed to fetch the resource collection."));
417  q->emitResult();
418  return;
419  }
420 
421  // Find all children of the resource collection.
422  for (const Collection &collection : std::as_const(collections)) {
423  if (collection.parentCollection() == resourceCollection) {
424  toRecover.append(collection);
425  }
426  }
427 
428  QHash<QString, QByteArray> typeForName;
429  for (const QByteArray &type : std::as_const(mKnownTypes)) {
430  const QString displayName = mNameForTypeMap.value(type);
431  typeForName[displayName] = type;
432  }
433 
434  // These collections have been created by the maildir resource, when it
435  // found the folders on disk. So give them the necessary attributes now.
436  Q_ASSERT(mPendingModifyJobs == 0);
437  for (Collection collection : std::as_const(toRecover)) {
438  if (collection.hasAttribute<SpecialCollectionAttribute>()) {
439  continue;
440  }
441 
442  // Find the type for the collection.
443  const QString name = collection.displayName();
444  const QByteArray type = typeForName.value(name);
445 
446  if (!type.isEmpty()) {
447  qCDebug(AKONADICORE_LOG) << "Recovering collection" << name;
448  setCollectionAttributes(collection, type, mNameForTypeMap, mIconForTypeMap);
449 
450  auto modifyJob = new CollectionModifyJob(collection, q);
451  QObject::connect(modifyJob, &CollectionModifyJob::result, q, [this](KJob *job) {
452  collectionModifyResult(job);
453  });
454  mPendingModifyJobs++;
455  } else {
456  qCDebug(AKONADICORE_LOG) << "Searching for names: " << typeForName.keys();
457  qCDebug(AKONADICORE_LOG) << "Unknown collection name" << name << "-- not recovering.";
458  }
459  }
460 
461  if (mPendingModifyJobs == 0) {
462  // Scan the resource.
463  q->setResourceId(defaultResourceId(mSettings));
464  q->ResourceScanJob::doStart();
465  }
466 }
467 
468 void DefaultResourceJobPrivate::collectionModifyResult(KJob *job)
469 {
470  if (job->error()) {
471  qCWarning(AKONADICORE_LOG) << job->errorText();
472  // fail( i18n( "Failed to modify the root maildir collection (%1).", job->errorString() ) );
473  return;
474  }
475 
476  Q_ASSERT(mPendingModifyJobs > 0);
477  mPendingModifyJobs--;
478  qCDebug(AKONADICORE_LOG) << "pendingModifyJobs now" << mPendingModifyJobs;
479  if (mPendingModifyJobs == 0) {
480  // Write the updated config.
481  qCDebug(AKONADICORE_LOG) << "Writing defaultResourceId" << defaultResourceId(mSettings) << "to config.";
482  mSettings->save();
483 
484  // Scan the resource.
485  q->setResourceId(defaultResourceId(mSettings));
486  q->ResourceScanJob::doStart();
487  }
488 }
489 
490 DefaultResourceJob::DefaultResourceJob(KCoreConfigSkeleton *settings, QObject *parent)
491  : ResourceScanJob(QString(), settings, parent)
492  , d(new DefaultResourceJobPrivate(settings, this))
493 {
494 }
495 
496 DefaultResourceJob::~DefaultResourceJob() = default;
497 
498 void DefaultResourceJob::setDefaultResourceType(const QString &type)
499 {
500  d->mDefaultResourceType = type;
501 }
502 
503 void DefaultResourceJob::setDefaultResourceOptions(const QVariantMap &options)
504 {
505  d->mDefaultResourceOptions = options;
506 }
507 
508 void DefaultResourceJob::setTypes(const QList<QByteArray> &types)
509 {
510  d->mKnownTypes = types;
511 }
512 
513 void DefaultResourceJob::setNameForTypeMap(const QMap<QByteArray, QString> &map)
514 {
515  d->mNameForTypeMap = map;
516 }
517 
518 void DefaultResourceJob::setIconForTypeMap(const QMap<QByteArray, QString> &map)
519 {
520  d->mIconForTypeMap = map;
521 }
522 
523 void DefaultResourceJob::doStart()
524 {
525  d->tryFetchResource();
526 }
527 
528 void DefaultResourceJob::slotResult(KJob *job)
529 {
530  if (job->error()) {
531  qCWarning(AKONADICORE_LOG) << job->errorText();
532  // Do some cleanup.
533  if (!d->mResourceWasPreexisting) {
534  // We only removed the resource instance if we have created it.
535  // Otherwise we might lose the user's data.
536  const AgentInstance resource = AgentManager::self()->instance(defaultResourceId(d->mSettings));
537  qCDebug(AKONADICORE_LOG) << "Removing resource" << resource.identifier();
538  AgentManager::self()->removeInstance(resource);
539  }
540  }
541 
542  Job::slotResult(job);
543 }
544 
545 // ===================== GetLockJob ============================
546 
547 class Akonadi::GetLockJobPrivate
548 {
549 public:
550  explicit GetLockJobPrivate(GetLockJob *qq);
551 
552  void doStart(); // slot
553  void timeout(); // slot
554 
555  GetLockJob *const q;
556  QTimer *mSafetyTimer = nullptr;
557 };
558 
559 GetLockJobPrivate::GetLockJobPrivate(GetLockJob *qq)
560  : q(qq)
561  , mSafetyTimer(nullptr)
562 {
563 }
564 
565 void GetLockJobPrivate::doStart()
566 {
567  // Just doing registerService() and checking its return value is not sufficient,
568  // since we may *already* own the name, and then registerService() returns true.
569 
571  const bool alreadyLocked = bus.interface()->isServiceRegistered(dbusServiceName());
572  const bool gotIt = bus.registerService(dbusServiceName());
573 
574  if (gotIt && !alreadyLocked) {
575  // qCDebug(AKONADICORE_LOG) << "Got lock immediately.";
576  q->emitResult();
577  } else {
580  if (QDBusConnection::sessionBus().registerService(dbusServiceName())) {
581  mSafetyTimer->stop();
582  q->emitResult();
583  }
584  });
585 
586  mSafetyTimer = new QTimer(q);
587  mSafetyTimer->setSingleShot(true);
588  mSafetyTimer->setInterval(LOCK_WAIT_TIMEOUT_SECONDS * 1000);
589  mSafetyTimer->start();
590  QObject::connect(mSafetyTimer, &QTimer::timeout, q, [this]() {
591  timeout();
592  });
593  }
594 }
595 
596 void GetLockJobPrivate::timeout()
597 {
598  qCWarning(AKONADICORE_LOG) << "Timeout trying to get lock. Check who has acquired the name" << dbusServiceName() << "on DBus, using qdbus or qdbusviewer.";
599  q->setError(Job::Unknown);
600  q->setErrorText(i18n("Timeout trying to get lock."));
601  q->emitResult();
602 }
603 
604 GetLockJob::GetLockJob(QObject *parent)
605  : KJob(parent)
606  , d(new GetLockJobPrivate(this))
607 {
608 }
609 
610 GetLockJob::~GetLockJob() = default;
611 
612 void GetLockJob::start()
613 {
614  QTimer::singleShot(0, this, [this]() {
615  d->doStart();
616  });
617 }
618 
619 void Akonadi::setCollectionAttributes(Akonadi::Collection &collection,
620  const QByteArray &type,
621  const QMap<QByteArray, QString> &nameForType,
622  const QMap<QByteArray, QString> &iconForType)
623 {
624  {
625  auto attr = new EntityDisplayAttribute;
626  attr->setIconName(iconForType.value(type));
627  attr->setDisplayName(nameForType.value(type));
628  collection.addAttribute(attr);
629  }
630 
631  {
632  auto attr = new SpecialCollectionAttribute;
633  attr->setCollectionType(type);
634  collection.addAttribute(attr);
635  }
636 }
637 
638 bool Akonadi::releaseLock()
639 {
640  return QDBusConnection::sessionBus().unregisterService(dbusServiceName());
641 }
642 
643 #include "moc_specialcollectionshelperjobs_p.cpp"
int methodCount() const const
T & first()
QString identifier() const
Returns the unique identifier of the agent instance.
const T value(const Key &key) const const
virtual QVariant property() const=0
Job that modifies a collection in the Akonadi storage.
@ Unknown
Unknown error.
Definition: job.h:102
virtual Q_SCRIPTABLE void start()=0
void result(KJob *job)
A representation of an agent type.
const T value(const Key &key, const T &defaultValue) const const
virtual void setProperty(const QVariant &p)=0
int count(const T &value) const const
bool isValid() const const
QList< Key > keys() const const
void append(const T &value)
Q_SCRIPTABLE Q_NOREPLY void start()
QVariant::Type nameToType(const char *name)
Represents a collection of PIM items.
Definition: collection.h:61
@ Display
Only retrieve collections for display, taking the local preference and enabled into account.
QDBusReply< bool > isServiceRegistered(const QString &serviceName) const const
QVector< AgentInstance > List
Describes a list of agent instances.
KConfigSkeletonItem * findItem(const QString &name) const
Attribute that stores the properties that are used to display an entity.
void serviceUnregistered(const QString &serviceName)
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QMap::const_iterator cbegin() const const
static QString agentServiceName(ServiceAgentType agentType, const QString &identifier)
Returns the namespaced D-Bus service name for an agent of type agentType with agent identifier identi...
Job that fetches collections from the Akonadi storage.
QStringList types(Mode mode=Writing)
QByteArray methodSignature() 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...
void removeInstance(const AgentInstance &instance)
Removes the given agent instance.
Job that synchronizes a resource.
void addAttribute(Attribute *attribute)
Adds an attribute to the collection.
Definition: collection.cpp:151
QString i18n(const char *text, const TYPE &arg...)
QDBusConnection sessionBus()
bool registerService(const QString &serviceName)
void reconfigure() const
Tell the agent that its configuration has been changed remotely via D-Bus.
bool unregisterService(const QString &serviceName)
char * toString(const T &value)
void setName(const QString &name)
Sets the user visible name of the agent instance.
QMap::const_iterator cend() const const
void setCollectionType(const QByteArray &type)
Sets the special collections type of the collection.
void timeout()
QString errorText() const
QMetaMethod method(int index) const const
An Attribute that stores the special collection type of a collection.
Base class for all actions in the Akonadi storage.
Definition: job.h:80
static Collection root()
Returns the root collection.
Definition: collection.cpp:287
const Key key(const T &value, const Key &defaultKey) const const
QDBusConnectionInterface * interface() const const
static QString instanceIdentifier()
Returns the identifier of the Akonadi instance we are connected to.
AKONADI_CALENDAR_EXPORT QString displayName(Akonadi::ETMCalendar *calendar, const Akonadi::Collection &collection)
AgentType type(const QString &identifier) const
Returns the agent type with the given identifier or an invalid agent type if the identifier does not ...
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const const
VehicleSection::Type type(QStringView coachNumber, QStringView coachClassification)
void setIconName(const QString &name)
Sets the icon name for the default icon.
bool isEmpty() const const
const char * constData() const const
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
QString fromLatin1(const char *str, int size)
QString name(StandardShortcut id)
static AgentManager * self()
Returns the global instance of the agent manager.
int count(const T &value) const const
AgentInstance::List instances() const
Returns the list of all available agent instances.
static bool hasInstanceIdentifier()
Returns true if we are connected to a non-default Akonadi server instance.
@ Recursive
List all sub-collections.
int error() const
bool isValid() const
Returns whether the agent instance object is valid.
QFuture< void > map(Sequence &sequence, MapFunctor function)
QList< QByteArray > parameterTypes() const const
A representation of an agent instance.
Job for creating new agent instances.
QString toString() const const
Helper integration between Akonadi and Qt.
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Sat Jul 2 2022 06:41:49 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.