Akonadi

resourcescheduler.cpp
1 /*
2  Copyright (c) 2007 Volker Krause <[email protected]>
3 
4  This library is free software; you can redistribute it and/or modify it
5  under the terms of the GNU Library General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or (at your
7  option) any later version.
8 
9  This library is distributed in the hope that it will be useful, but WITHOUT
10  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12  License for more details.
13 
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB. If not, write to the
16  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  02110-1301, USA.
18 */
19 
20 #include "resourcescheduler_p.h"
21 
22 #include <QDBusConnection>
23 #include "recursivemover_p.h"
24 
25 #include "akonadiagentbase_debug.h"
26 #include "private/instance_p.h"
27 #include <KLocalizedString>
28 
29 #include <QTimer>
30 #include <QDBusInterface>
31 
32 using namespace Akonadi;
33 
34 qint64 ResourceScheduler::Task::latestSerial = 0;
35 static QDBusAbstractInterface *s_resourcetracker = nullptr;
36 
37 //@cond PRIVATE
38 
39 ResourceScheduler::ResourceScheduler(QObject *parent)
40  : QObject(parent)
41  , mCurrentTasksQueue(-1)
42  , mOnline(false)
43 {
44 }
45 
46 void ResourceScheduler::scheduleFullSync()
47 {
48  Task t;
49  t.type = SyncAll;
50  TaskList &queue = queueForTaskType(t.type);
51  if (queue.contains(t) || mCurrentTask == t) {
52  return;
53  }
54  queue << t;
55  signalTaskToTracker(t, "SyncAll");
56  scheduleNext();
57 }
58 
59 void ResourceScheduler::scheduleCollectionTreeSync()
60 {
61  Task t;
62  t.type = SyncCollectionTree;
63  TaskList &queue = queueForTaskType(t.type);
64  if (queue.contains(t) || mCurrentTask == t) {
65  return;
66  }
67  queue << t;
68  signalTaskToTracker(t, "SyncCollectionTree");
69  scheduleNext();
70 }
71 
72 void ResourceScheduler::scheduleTagSync()
73 {
74  Task t;
75  t.type = SyncTags;
76  TaskList &queue = queueForTaskType(t.type);
77  if (queue.contains(t) || mCurrentTask == t) {
78  return;
79  }
80  queue << t;
81  signalTaskToTracker(t, "SyncTags");
82  scheduleNext();
83 }
84 
85 void ResourceScheduler::scheduleRelationSync()
86 {
87  Task t;
88  t.type = SyncRelations;
89  TaskList &queue = queueForTaskType(t.type);
90  if (queue.contains(t) || mCurrentTask == t) {
91  return;
92  }
93  queue << t;
94  signalTaskToTracker(t, "SyncRelations");
95  scheduleNext();
96 }
97 
98 void ResourceScheduler::scheduleSync(const Collection &col)
99 {
100  Task t;
101  t.type = SyncCollection;
102  t.collection = col;
103  TaskList &queue = queueForTaskType(t.type);
104  if (queue.contains(t) || mCurrentTask == t) {
105  return;
106  }
107  queue << t;
108  signalTaskToTracker(t, "SyncCollection", QString::number(col.id()));
109  scheduleNext();
110 }
111 
112 void ResourceScheduler::scheduleAttributesSync(const Collection &collection)
113 {
114  Task t;
115  t.type = SyncCollectionAttributes;
116  t.collection = collection;
117 
118  TaskList &queue = queueForTaskType(t.type);
119  if (queue.contains(t) || mCurrentTask == t) {
120  return;
121  }
122  queue << t;
123  signalTaskToTracker(t, "SyncCollectionAttributes", QString::number(collection.id()));
124  scheduleNext();
125 }
126 
127 void ResourceScheduler::scheduleItemFetch(const Akonadi::Item &item, const QSet<QByteArray> &parts,
128  const QList<QDBusMessage> &msgs, qint64 parentId)
129 
130 {
131  Task t;
132  t.type = FetchItem;
133  t.items << item;
134  t.itemParts = parts;
135  t.dbusMsgs = msgs;
136  t.argument = parentId;
137 
138  TaskList &queue = queueForTaskType(t.type);
139  queue << t;
140 
141  signalTaskToTracker(t, "FetchItem", QString::number(item.id()));
142  scheduleNext();
143 }
144 
145 void ResourceScheduler::scheduleItemsFetch(const Item::List &items, const QSet<QByteArray> &parts, const QDBusMessage &msg)
146 {
147  Task t;
148  t.type = FetchItems;
149  t.items = items;
150  t.itemParts = parts;
151 
152  // if the current task does already fetch the requested item, break here but
153  // keep the dbus message, so we can send the reply later on
154  if (mCurrentTask == t) {
155  mCurrentTask.dbusMsgs << msg;
156  return;
157  }
158 
159  // If this task is already in the queue, merge with it.
160  TaskList &queue = queueForTaskType(t.type);
161  const int idx = queue.indexOf(t);
162  if (idx != -1) {
163  queue[ idx ].dbusMsgs << msg;
164  return;
165  }
166 
167  t.dbusMsgs << msg;
168  queue << t;
169 
170  QStringList ids;
171  ids.reserve(items.size());
172  for (const auto &item : items) {
173  ids.push_back(QString::number(item.id()));
174  }
175  signalTaskToTracker(t, "FetchItems", ids.join(QLatin1String(", ")));
176  scheduleNext();
177 }
178 
179 void ResourceScheduler::scheduleResourceCollectionDeletion()
180 {
181  Task t;
182  t.type = DeleteResourceCollection;
183  TaskList &queue = queueForTaskType(t.type);
184  if (queue.contains(t) || mCurrentTask == t) {
185  return;
186  }
187  queue << t;
188  signalTaskToTracker(t, "DeleteResourceCollection");
189  scheduleNext();
190 }
191 
192 void ResourceScheduler::scheduleCacheInvalidation(const Collection &collection)
193 {
194  Task t;
195  t.type = InvalideCacheForCollection;
196  t.collection = collection;
197  TaskList &queue = queueForTaskType(t.type);
198  if (queue.contains(t) || mCurrentTask == t) {
199  return;
200  }
201  queue << t;
202  signalTaskToTracker(t, "InvalideCacheForCollection", QString::number(collection.id()));
203  scheduleNext();
204 }
205 
206 void ResourceScheduler::scheduleChangeReplay()
207 {
208  Task t;
209  t.type = ChangeReplay;
210  TaskList &queue = queueForTaskType(t.type);
211  // see ResourceBase::changeProcessed() for why we do not check for mCurrentTask == t here like in the other tasks
212  if (queue.contains(t)) {
213  return;
214  }
215  queue << t;
216  signalTaskToTracker(t, "ChangeReplay");
217  scheduleNext();
218 }
219 
220 void ResourceScheduler::scheduleMoveReplay(const Collection &movedCollection, RecursiveMover *mover)
221 {
222  Task t;
223  t.type = RecursiveMoveReplay;
224  t.collection = movedCollection;
225  t.argument = QVariant::fromValue(mover);
226  TaskList &queue = queueForTaskType(t.type);
227 
228  if (queue.contains(t) || mCurrentTask == t) {
229  return;
230  }
231 
232  queue << t;
233  signalTaskToTracker(t, "RecursiveMoveReplay", QString::number(t.collection.id()));
234  scheduleNext();
235 }
236 
237 void Akonadi::ResourceScheduler::scheduleFullSyncCompletion()
238 {
239  Task t;
240  t.type = SyncAllDone;
241  TaskList &queue = queueForTaskType(t.type);
242  // no compression here, all this does is emitting a D-Bus signal anyway, and compression can trigger races on the receiver side with the signal being lost
243  queue << t;
244  signalTaskToTracker(t, "SyncAllDone");
245  scheduleNext();
246 }
247 
248 void Akonadi::ResourceScheduler::scheduleCollectionTreeSyncCompletion()
249 {
250  Task t;
251  t.type = SyncCollectionTreeDone;
252  TaskList &queue = queueForTaskType(t.type);
253  // no compression here, all this does is emitting a D-Bus signal anyway, and compression can trigger races on the receiver side with the signal being lost
254  queue << t;
255  signalTaskToTracker(t, "SyncCollectionTreeDone");
256  scheduleNext();
257 }
258 
259 void Akonadi::ResourceScheduler::scheduleCustomTask(QObject *receiver, const char *methodName, const QVariant &argument, ResourceBase::SchedulePriority priority)
260 {
261  Task t;
262  t.type = Custom;
263  t.receiver = receiver;
264  t.methodName = methodName;
265  t.argument = argument;
266  QueueType queueType = GenericTaskQueue;
267  if (priority == ResourceBase::AfterChangeReplay) {
268  queueType = AfterChangeReplayQueue;
269  } else if (priority == ResourceBase::Prepend) {
270  queueType = PrependTaskQueue;
271  }
272  TaskList &queue = mTaskList[queueType];
273 
274  if (queue.contains(t)) {
275  return;
276  }
277 
278  switch (priority) {
280  queue.prepend(t);
281  break;
282  default:
283  queue.append(t);
284  break;
285  }
286 
287  signalTaskToTracker(t, "Custom-" + t.methodName);
288  scheduleNext();
289 }
290 
291 void ResourceScheduler::taskDone()
292 {
293  if (isEmpty()) {
294  Q_EMIT status(AgentBase::Idle, i18nc("@info:status Application ready for work", "Ready"));
295  }
296 
297  if (s_resourcetracker) {
298  const QList<QVariant> argumentList = { QString::number(mCurrentTask.serial), QString() };
299  s_resourcetracker->asyncCallWithArgumentList(QStringLiteral("jobEnded"), argumentList);
300  }
301 
302  mCurrentTask = Task();
303  mCurrentTasksQueue = -1;
304  scheduleNext();
305 }
306 
307 void ResourceScheduler::itemFetchDone(const QString &msg)
308 {
309  Q_ASSERT(mCurrentTask.type == FetchItem);
310 
311  TaskList &queue = queueForTaskType(mCurrentTask.type);
312 
313  const qint64 parentId = mCurrentTask.argument.toLongLong();
314  // msg is empty, there was no error
315  if (msg.isEmpty() && !queue.isEmpty()) {
316  Task &nextTask = queue[0];
317  // If the next task is FetchItem too...
318  if (nextTask.type != mCurrentTask.type || nextTask.argument.toLongLong() != parentId) {
319  // If the next task is not FetchItem or the next FetchItem task has
320  // different parentId then this was the last task in the series, so
321  // send the DBus replies.
322  mCurrentTask.sendDBusReplies(msg);
323  }
324  } else {
325  // msg was not empty, there was an error.
326  // remove all subsequent FetchItem tasks with the same parentId
327  auto iter = queue.begin();
328  while (iter != queue.end()) {
329  if (iter->type != mCurrentTask.type || iter->argument.toLongLong() == parentId) {
330  iter = queue.erase(iter);
331  continue;
332  } else {
333  break;
334  }
335  }
336 
337  // ... and send DBus reply with the error message
338  mCurrentTask.sendDBusReplies(msg);
339  }
340 
341  taskDone();
342 }
343 
344 void ResourceScheduler::deferTask()
345 {
346  if (mCurrentTask.type == Invalid) {
347  return;
348  }
349 
350  if (s_resourcetracker) {
351  const QList<QVariant> argumentList = {QString::number(mCurrentTask.serial), QString()};
352  s_resourcetracker->asyncCallWithArgumentList(QStringLiteral("jobEnded"), argumentList);
353  }
354 
355  Task t = mCurrentTask;
356  mCurrentTask = Task();
357 
358  Q_ASSERT(mCurrentTasksQueue >= 0 && mCurrentTasksQueue < NQueueCount);
359  mTaskList[mCurrentTasksQueue].prepend(t);
360  mCurrentTasksQueue = -1;
361 
362  signalTaskToTracker(t, "DeferedTask");
363 
364  scheduleNext();
365 }
366 
367 bool ResourceScheduler::isEmpty()
368 {
369  for (int i = 0; i < NQueueCount; ++i) {
370  if (!mTaskList[i].isEmpty()) {
371  return false;
372  }
373  }
374  return true;
375 }
376 
377 void ResourceScheduler::scheduleNext()
378 {
379  if (mCurrentTask.type != Invalid || isEmpty() || !mOnline) {
380  return;
381  }
382  QTimer::singleShot(0, this, &ResourceScheduler::executeNext);
383 }
384 
385 void ResourceScheduler::executeNext()
386 {
387  if (mCurrentTask.type != Invalid || isEmpty()) {
388  return;
389  }
390 
391  for (int i = 0; i < NQueueCount; ++i) {
392  if (!mTaskList[i].isEmpty()) {
393  mCurrentTask = mTaskList[i].takeFirst();
394  mCurrentTasksQueue = i;
395  break;
396  }
397  }
398 
399  if (s_resourcetracker) {
400  const QList<QVariant> argumentList = { QString::number(mCurrentTask.serial) };
401  s_resourcetracker->asyncCallWithArgumentList(QStringLiteral("jobStarted"), argumentList);
402  }
403 
404  switch (mCurrentTask.type) {
405  case SyncAll:
406  Q_EMIT executeFullSync();
407  break;
408  case SyncCollectionTree:
409  Q_EMIT executeCollectionTreeSync();
410  break;
411  case SyncCollection:
412  Q_EMIT executeCollectionSync(mCurrentTask.collection);
413  break;
414  case SyncCollectionAttributes:
415  Q_EMIT executeCollectionAttributesSync(mCurrentTask.collection);
416  break;
417  case SyncTags:
418  Q_EMIT executeTagSync();
419  break;
420  case FetchItem:
421  Q_EMIT executeItemFetch(mCurrentTask.items.at(0), mCurrentTask.itemParts);
422  break;
423  case FetchItems:
424  Q_EMIT executeItemsFetch(mCurrentTask.items, mCurrentTask.itemParts);
425  break;
426  case DeleteResourceCollection:
427  Q_EMIT executeResourceCollectionDeletion();
428  break;
429  case InvalideCacheForCollection:
430  Q_EMIT executeCacheInvalidation(mCurrentTask.collection);
431  break;
432  case ChangeReplay:
433  Q_EMIT executeChangeReplay();
434  break;
435  case RecursiveMoveReplay:
436  Q_EMIT executeRecursiveMoveReplay(mCurrentTask.argument.value<RecursiveMover *>());
437  break;
438  case SyncAllDone:
439  Q_EMIT fullSyncComplete();
440  break;
441  case SyncCollectionTreeDone:
442  Q_EMIT collectionTreeSyncComplete();
443  break;
444  case SyncRelations:
445  Q_EMIT executeRelationSync();
446  break;
447  case Custom: {
448  const QByteArray methodSig = mCurrentTask.methodName + QByteArray("(QVariant)");
449  const bool hasSlotWithVariant = mCurrentTask.receiver->metaObject()->indexOfMethod(methodSig.constData()) != -1;
450  bool success = false;
451  if (hasSlotWithVariant) {
452  success = QMetaObject::invokeMethod(mCurrentTask.receiver, mCurrentTask.methodName.constData(), Q_ARG(QVariant, mCurrentTask.argument));
453  Q_ASSERT_X(success || !mCurrentTask.argument.isValid(), "ResourceScheduler::executeNext", "Valid argument was provided but the method wasn't found");
454  }
455  if (!success) {
456  success = QMetaObject::invokeMethod(mCurrentTask.receiver, mCurrentTask.methodName.constData());
457  }
458 
459  if (!success) {
460  qCCritical(AKONADIAGENTBASE_LOG) << "Could not invoke slot" << mCurrentTask.methodName << "on" << mCurrentTask.receiver << "with argument" << mCurrentTask.argument;
461  }
462  break;
463  }
464  default: {
465  qCCritical(AKONADIAGENTBASE_LOG) << "Unhandled task type" << mCurrentTask.type;
466  dump();
467  Q_ASSERT(false);
468  }
469  }
470 }
471 
472 ResourceScheduler::Task ResourceScheduler::currentTask() const
473 {
474  return mCurrentTask;
475 }
476 
477 ResourceScheduler::Task &ResourceScheduler::currentTask()
478 {
479  return mCurrentTask;
480 }
481 
482 void ResourceScheduler::setOnline(bool state)
483 {
484  if (mOnline == state) {
485  return;
486  }
487  mOnline = state;
488  if (mOnline) {
489  scheduleNext();
490  } else {
491  if (mCurrentTask.type != Invalid) {
492  // abort running task
493  queueForTaskType(mCurrentTask.type).prepend(mCurrentTask);
494  mCurrentTask = Task();
495  mCurrentTasksQueue = -1;
496  }
497  // abort pending synchronous tasks, might take longer until the resource goes online again
498  TaskList &itemFetchQueue = queueForTaskType(FetchItem);
499  qint64 parentId = -1;
500  Task lastTask;
501  for (QList< Task >::iterator it = itemFetchQueue.begin(); it != itemFetchQueue.end();) {
502  if ((*it).type == FetchItem) {
503  qint64 idx = it->argument.toLongLong();
504  if (parentId == -1) {
505  parentId = idx;
506  }
507  if (idx != parentId) {
508  // Only emit the DBus reply once we reach the last taskwith the
509  // same "idx"
510  lastTask.sendDBusReplies(i18nc("@info", "Job canceled."));
511  parentId = idx;
512  }
513  lastTask = (*it);
514  it = itemFetchQueue.erase(it);
515  if (s_resourcetracker) {
516  const QList<QVariant> argumentList = { QString::number(mCurrentTask.serial), i18nc("@info", "Job canceled.")};
517  s_resourcetracker->asyncCallWithArgumentList(QStringLiteral("jobEnded"), argumentList);
518  }
519  } else {
520  ++it;
521  }
522  }
523  }
524 }
525 
526 void ResourceScheduler::signalTaskToTracker(const Task &task, const QByteArray &taskType, const QString &debugString)
527 {
528  // if there's a job tracer running, tell it about the new job
529  if (!s_resourcetracker) {
530  const QString suffix = Akonadi::Instance::identifier().isEmpty() ? QString() : QLatin1Char('-') + Akonadi::Instance::identifier();
531  if (QDBusConnection::sessionBus().interface()->isServiceRegistered(QStringLiteral("org.kde.akonadiconsole") + suffix)) {
532  s_resourcetracker = new QDBusInterface(QLatin1String("org.kde.akonadiconsole") + suffix,
533  QStringLiteral("/resourcesJobtracker"),
534  QStringLiteral("org.freedesktop.Akonadi.JobTracker"),
535  QDBusConnection::sessionBus(), nullptr);
536  }
537  }
538 
539  if (s_resourcetracker) {
540  const QList<QVariant> argumentList = QList<QVariant>()
541  << static_cast<AgentBase *>(parent())->identifier() // "session" (in our case resource)
542  << QString::number(task.serial) // "job"
543  << QString() // "parent job"
544  << QString::fromLatin1(taskType) // "job type"
545  << debugString // "job debugging string"
546  ;
547  s_resourcetracker->asyncCallWithArgumentList(QStringLiteral("jobCreated"), argumentList);
548  }
549 }
550 
551 void ResourceScheduler::collectionRemoved(const Akonadi::Collection &collection)
552 {
553  if (!collection.isValid()) { // should not happen, but you never know...
554  return;
555  }
556  TaskList &queue = queueForTaskType(SyncCollection);
557  for (QList<Task>::iterator it = queue.begin(); it != queue.end();) {
558  if ((*it).type == SyncCollection && (*it).collection == collection) {
559  it = queue.erase(it);
560  qCDebug(AKONADIAGENTBASE_LOG) << " erasing";
561  } else {
562  ++it;
563  }
564  }
565 }
566 
567 void ResourceScheduler::Task::sendDBusReplies(const QString &errorMsg)
568 {
569  for (const QDBusMessage &msg : qAsConst(dbusMsgs)) {
570  qCDebug(AKONADIAGENTBASE_LOG) << "Sending dbus reply for method" << methodName << "with error" << errorMsg;
571  QDBusMessage reply;
572  if (!errorMsg.isEmpty()) {
573  reply = msg.createErrorReply(QDBusError::Failed, errorMsg);
574  } else if (msg.member() == QLatin1String("requestItemDelivery")) {
575  reply = msg.createReply();
576  } else if (msg.member().isEmpty()) {
577  continue; // unittest calls scheduleItemFetch with empty QDBusMessage
578  } else {
579  qCCritical(AKONADIAGENTBASE_LOG) << "ResourceScheduler: got unexpected method name :" << msg.member();
580  }
582  }
583 }
584 
585 ResourceScheduler::QueueType ResourceScheduler::queueTypeForTaskType(TaskType type)
586 {
587  switch (type) {
588  case ChangeReplay:
589  case RecursiveMoveReplay:
590  return ChangeReplayQueue;
591  case FetchItem:
592  case FetchItems:
593  case SyncCollectionAttributes:
594  return UserActionQueue;
595  default:
596  return GenericTaskQueue;
597  }
598 }
599 
600 ResourceScheduler::TaskList &ResourceScheduler::queueForTaskType(TaskType type)
601 {
602  const QueueType qt = queueTypeForTaskType(type);
603  return mTaskList[qt];
604 }
605 
606 void ResourceScheduler::dump()
607 {
608  qCDebug(AKONADIAGENTBASE_LOG) << dumpToString();
609 }
610 
611 QString ResourceScheduler::dumpToString() const
612 {
613  QString ret;
614  QTextStream str(&ret);
615  str << "ResourceScheduler: " << (mOnline ? "Online" : "Offline") << '\n';
616  str << " current task: " << mCurrentTask << '\n';
617  for (int i = 0; i < NQueueCount; ++i) {
618  const TaskList &queue = mTaskList[i];
619  if (queue.isEmpty()) {
620  str << " queue " << i << " is empty" << '\n';
621  } else {
622  str << " queue " << i << " " << queue.size() << " tasks:\n";
623  const QList<Task>::const_iterator queueEnd(queue.constEnd());
624  for (QList<Task>::const_iterator it = queue.constBegin(); it != queueEnd; ++it) {
625  str << " " << (*it) << '\n';
626  }
627  }
628  }
629  str.flush();
630  return ret;
631 }
632 
633 void ResourceScheduler::clear()
634 {
635  qCDebug(AKONADIAGENTBASE_LOG) << "Clearing ResourceScheduler queues:";
636  for (int i = 0; i < NQueueCount; ++i) {
637  TaskList &queue = mTaskList[i];
638  queue.clear();
639  }
640  mCurrentTask = Task();
641  mCurrentTasksQueue = -1;
642 }
643 
644 void Akonadi::ResourceScheduler::cancelQueues()
645 {
646  for (int i = 0; i < NQueueCount; ++i) {
647  TaskList &queue = mTaskList[i];
648  if (s_resourcetracker) {
649  for (const Task &t : queue) {
650  QList<QVariant> argumentList{QString::number(t.serial), QString()};
651  s_resourcetracker->asyncCallWithArgumentList(QStringLiteral("jobEnded"), argumentList);
652  }
653  }
654  queue.clear();
655  }
656 }
657 
658 static const char s_taskTypes[][27] = {
659  "Invalid (no task)",
660  "SyncAll",
661  "SyncCollectionTree",
662  "SyncCollection",
663  "SyncCollectionAttributes",
664  "SyncTags",
665  "FetchItem",
666  "FetchItems",
667  "ChangeReplay",
668  "RecursiveMoveReplay",
669  "DeleteResourceCollection",
670  "InvalideCacheForCollection",
671  "SyncAllDone",
672  "SyncCollectionTreeDone",
673  "SyncRelations",
674  "Custom"
675 };
676 
677 QTextStream &Akonadi::operator<<(QTextStream &d, const ResourceScheduler::Task &task)
678 {
679  d << task.serial << " " << s_taskTypes[task.type] << " ";
680  if (task.type != ResourceScheduler::Invalid) {
681  if (task.collection.isValid()) {
682  d << "collection " << task.collection.id() << " ";
683  }
684  if (!task.items.isEmpty()) {
685  QStringList ids;
686  ids.reserve(task.items.size());
687  for (const auto &item : qAsConst(task.items)) {
688  ids.push_back(QString::number(item.id()));
689  }
690  d << "items " << ids.join(QLatin1String(", ")) << " ";
691  }
692  if (!task.methodName.isEmpty()) {
693  d << task.methodName << " " << task.argument.toString();
694  }
695  }
696  return d;
697 }
698 
699 QDebug Akonadi::operator<<(QDebug d, const ResourceScheduler::Task &task)
700 {
701  QString s;
702  QTextStream str(&s);
703  str << task;
704  d << s;
705  return d;
706 }
707 
708 //@endcond
709 
710 #include "moc_resourcescheduler_p.cpp"
NETWORKMANAGERQT_EXPORT NetworkManager::Status status()
bool isValid() const
Returns whether the collection is valid.
Definition: collection.cpp:137
void push_back(const T &value)
void reserve(int alloc)
Represents a collection of PIM items.
Definition: collection.h:76
QDBusConnection sessionBus()
QString join(const QString &separator) const const
void clear()
SchedulePriority
Describes the scheduling priority of a task that has been queued for execution.
Definition: resourcebase.h:782
QString number(int n, int base)
QString i18nc(const char *context, const char *text, const TYPE &arg...)
bool send(const QDBusMessage &message) const const
bool isEmpty() const const
The task is scheduled after the last ChangeReplay task in the queue.
Definition: resourcebase.h:784
const char * constData() const const
QVariant fromValue(const T &value)
bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType type, QGenericReturnArgument ret, QGenericArgument val0, QGenericArgument val1, QGenericArgument val2, QGenericArgument val3, QGenericArgument val4, QGenericArgument val5, QGenericArgument val6, QGenericArgument val7, QGenericArgument val8, QGenericArgument val9)
Id id() const
Returns the unique identifier of the collection.
Definition: collection.cpp:112
QDBusPendingCall asyncCallWithArgumentList(const QString &method, const QList< QVariant > &args)
Helper integration between Akonadi and Qt.
QString fromLatin1(const char *str, int size)
The task will be executed as soon as the current task has finished.
Definition: resourcebase.h:783
QObject * parent() const const
The agent does currently nothing.
Definition: agentbase.h:436
Q_EMITQ_EMIT
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Fri Jun 5 2020 23:08:56 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.