Akonadi

agentbase.cpp
1/*
2 SPDX-FileCopyrightText: 2006 Till Adam <adam@kde.org>
3 SPDX-FileCopyrightText: 2007 Volker Krause <vkrause@kde.org>
4 SPDX-FileCopyrightText: 2007 Bruno Virlet <bruno.virlet@gmail.com>
5 SPDX-FileCopyrightText: 2008 Kevin Krammer <kevin.krammer@gmx.at>
6
7 SPDX-License-Identifier: LGPL-2.0-or-later
8*/
9
10#include "agentbase.h"
11#include "agentbase_p.h"
12
13#include "agentconfigurationdialog.h"
14#include "agentmanager.h"
15#include "akonadifull-version.h"
16#include "changerecorder.h"
17#include "controladaptor.h"
18#include "itemfetchjob.h"
19#include "monitor_p.h"
20#include "private/standarddirs_p.h"
21#include "servermanager_p.h"
22#include "session.h"
23#include "session_p.h"
24#include "statusadaptor.h"
25
26#include "akonadiagentbase_debug.h"
27
28#include <KLocalizedString>
29
30#include <KAboutData>
31
32#include <QCommandLineParser>
33#include <QNetworkInformation>
34#include <QPointer>
35#include <QSettings>
36#include <QTimer>
37
38#include <QStandardPaths>
39#include <signal.h>
40#include <stdlib.h>
41#include <strstream>
42#if defined __GLIBC__
43#include <malloc.h> // for dumping memory information
44#endif
45
46#ifdef Q_OS_WIN
47#include <Windows.h>
48#endif
49
50#include <chrono>
51#include <thread>
52
53using namespace Akonadi;
54using namespace std::chrono_literals;
55static AgentBase *sAgentBase = nullptr;
56
60
64
65void AgentBase::Observer::itemAdded(const Item &item, const Collection &collection)
66{
67 Q_UNUSED(item)
68 Q_UNUSED(collection)
69 if (sAgentBase) {
70 sAgentBase->d_ptr->changeProcessed();
71 }
72}
73
74void AgentBase::Observer::itemChanged(const Item &item, const QSet<QByteArray> &partIdentifiers)
75{
76 Q_UNUSED(item)
77 Q_UNUSED(partIdentifiers)
78 if (sAgentBase) {
79 sAgentBase->d_ptr->changeProcessed();
80 }
81}
82
84{
85 Q_UNUSED(item)
86 if (sAgentBase) {
87 sAgentBase->d_ptr->changeProcessed();
88 }
89}
90
92{
93 Q_UNUSED(collection)
94 Q_UNUSED(parent)
95 if (sAgentBase) {
96 sAgentBase->d_ptr->changeProcessed();
97 }
98}
99
101{
102 Q_UNUSED(collection)
103 if (sAgentBase) {
104 sAgentBase->d_ptr->changeProcessed();
105 }
106}
107
109{
110 Q_UNUSED(collection)
111 if (sAgentBase) {
112 sAgentBase->d_ptr->changeProcessed();
113 }
114}
115
117{
118 Q_UNUSED(item)
119 Q_UNUSED(source)
120 Q_UNUSED(dest)
121 if (sAgentBase) {
122 sAgentBase->d_ptr->changeProcessed();
123 }
124}
125
127{
128 Q_UNUSED(item)
129 Q_UNUSED(collection)
130 if (sAgentBase) {
131 // not implementation, let's disconnect the signal to enable optimizations in Monitor
132 QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::itemLinked, sAgentBase->d_ptr.get(), &AgentBasePrivate::itemLinked);
133 sAgentBase->d_ptr->changeProcessed();
134 }
135}
136
138{
139 Q_UNUSED(item)
140 Q_UNUSED(collection)
141 if (sAgentBase) {
142 // not implementation, let's disconnect the signal to enable optimizations in Monitor
143 QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::itemUnlinked, sAgentBase->d_ptr.get(), &AgentBasePrivate::itemUnlinked);
144 sAgentBase->d_ptr->changeProcessed();
145 }
146}
147
149{
150 Q_UNUSED(collection)
151 Q_UNUSED(source)
152 Q_UNUSED(dest)
153 if (sAgentBase) {
154 sAgentBase->d_ptr->changeProcessed();
155 }
156}
157
159{
160 Q_UNUSED(changedAttributes)
161 collectionChanged(collection);
162}
163
165{
166 Q_UNUSED(items)
167 Q_UNUSED(addedFlags)
168 Q_UNUSED(removedFlags)
169
170 if (sAgentBase) {
171 // not implementation, let's disconnect the signal to enable optimizations in Monitor
172 QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::itemsFlagsChanged, sAgentBase->d_ptr.get(), &AgentBasePrivate::itemsFlagsChanged);
173 sAgentBase->d_ptr->changeProcessed();
174 }
175}
176
177void AgentBase::ObserverV3::itemsMoved(const Akonadi::Item::List &items, const Collection &sourceCollection, const Collection &destinationCollection)
178{
179 Q_UNUSED(items)
180 Q_UNUSED(sourceCollection)
181 Q_UNUSED(destinationCollection)
182
183 if (sAgentBase) {
184 // not implementation, let's disconnect the signal to enable optimizations in Monitor
185 QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::itemsMoved, sAgentBase->d_ptr.get(), &AgentBasePrivate::itemsMoved);
186 sAgentBase->d_ptr->changeProcessed();
187 }
188}
189
191{
192 Q_UNUSED(items)
193
194 if (sAgentBase) {
195 // not implementation, let's disconnect the signal to enable optimizations in Monitor
196 QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::itemsRemoved, sAgentBase->d_ptr.get(), &AgentBasePrivate::itemsRemoved);
197 sAgentBase->d_ptr->changeProcessed();
198 }
199}
200
202{
203 Q_UNUSED(items)
204 Q_UNUSED(collection)
205
206 if (sAgentBase) {
207 // not implementation, let's disconnect the signal to enable optimizations in Monitor
208 QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::itemsLinked, sAgentBase->d_ptr.get(), &AgentBasePrivate::itemsLinked);
209 sAgentBase->d_ptr->changeProcessed();
210 }
211}
212
214{
215 Q_UNUSED(items)
216 Q_UNUSED(collection)
217
218 if (sAgentBase) {
219 // not implementation, let's disconnect the signal to enable optimizations in Monitor
220 QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::itemsUnlinked, sAgentBase->d_ptr.get(), &AgentBasePrivate::itemsUnlinked);
221 sAgentBase->d_ptr->changeProcessed();
223}
224
225AgentBase::TagObserver::TagObserver() = default;
226
227AgentBase::TagObserver::~TagObserver() = default;
228
229void AgentBase::TagObserver::tagAdded(const Akonadi::Tag &tag)
230{
231 Q_UNUSED(tag)
232 if (sAgentBase) {
233 QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::tagAdded, sAgentBase->d_ptr.get(), &AgentBasePrivate::tagAdded);
234 sAgentBase->d_ptr->changeProcessed();
235 }
236}
237
238void AgentBase::TagObserver::tagChanged(const Akonadi::Tag &tag)
239{
240 Q_UNUSED(tag)
241 if (sAgentBase) {
242 QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::tagChanged, sAgentBase->d_ptr.get(), &AgentBasePrivate::tagChanged);
243 sAgentBase->d_ptr->changeProcessed();
244 }
245}
246
247void AgentBase::TagObserver::tagRemoved(const Akonadi::Tag &tag)
248{
249 Q_UNUSED(tag)
250 if (sAgentBase) {
251 QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::tagRemoved, sAgentBase->d_ptr.get(), &AgentBasePrivate::tagRemoved);
252 sAgentBase->d_ptr->changeProcessed();
253 }
254}
255
256void AgentBase::TagObserver::itemsTagsChanged(const Akonadi::Item::List &items, const QSet<Akonadi::Tag> &addedTags, const QSet<Akonadi::Tag> &removedTags)
257{
258 Q_UNUSED(items)
259 Q_UNUSED(addedTags)
260 Q_UNUSED(removedTags)
261
262 if (sAgentBase) {
263 QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::itemsTagsChanged, sAgentBase->d_ptr.get(), &AgentBasePrivate::itemsTagsChanged);
264 sAgentBase->d_ptr->changeProcessed();
265 }
266}
267/// @cond PRIVATE
268
269AgentBasePrivate::AgentBasePrivate(AgentBase *parent)
270 : q_ptr(parent)
271 , mStatusCode(AgentBase::Idle)
272 , mProgress(0)
273 , mNeedsNetwork(false)
274 , mOnline(false)
275 , mDesiredOnlineState(false)
276 , mPendingQuit(false)
277 , mSettings(nullptr)
278 , mChangeRecorder(nullptr)
279 , mTracer(nullptr)
280 , mObserver(nullptr)
281 , mPowerInterface(nullptr)
282 , mTemporaryOfflineTimer(nullptr)
283 , mEventLoopLocker(nullptr)
284{
285 Internal::setClientType(Internal::Agent);
286}
287
288AgentBasePrivate::~AgentBasePrivate()
289{
290 mChangeRecorder->setConfig(nullptr);
291 delete mSettings;
292}
293
294void AgentBasePrivate::init()
295{
296 Q_Q(AgentBase);
297 /**
298 * Create a default session for this process.
299 */
300 SessionPrivate::createDefaultSession(mId.toLatin1());
301
302 mTracer =
303 new org::freedesktop::Akonadi::Tracer(ServerManager::serviceName(ServerManager::Server), QStringLiteral("/tracing"), QDBusConnection::sessionBus(), q);
304
305 new Akonadi__ControlAdaptor(q);
306 new Akonadi__StatusAdaptor(q);
307 if (!QDBusConnection::sessionBus().registerObject(QStringLiteral("/"), q, QDBusConnection::ExportAdaptors)) {
308 Q_EMIT q->error(i18n("Unable to register object at dbus: %1", QDBusConnection::sessionBus().lastError().message()));
309 }
310
312
313 mChangeRecorder = new ChangeRecorder(q);
314 mChangeRecorder->setObjectName(QLatin1StringView("AgentBaseChangeRecorder"));
315 mChangeRecorder->ignoreSession(Session::defaultSession());
316 mChangeRecorder->itemFetchScope().setCacheOnly(true);
317 mChangeRecorder->setConfig(mSettings);
318
319 mDesiredOnlineState = mSettings->value(QStringLiteral("Agent/DesiredOnlineState"), true).toBool();
320 mOnline = mDesiredOnlineState;
321
322 // reinitialize the status message now that online state is available
323 mStatusMessage = defaultReadyMessage();
324
325 mName = mSettings->value(QStringLiteral("Agent/Name")).toString();
326 if (mName.isEmpty()) {
327 mName = mSettings->value(QStringLiteral("Resource/Name")).toString();
328 if (!mName.isEmpty()) {
329 mSettings->remove(QStringLiteral("Resource/Name"));
330 mSettings->setValue(QStringLiteral("Agent/Name"), mName);
331 }
332 }
333
334 connect(mChangeRecorder, &Monitor::itemAdded, this, &AgentBasePrivate::itemAdded);
335 connect(mChangeRecorder, &Monitor::itemChanged, this, &AgentBasePrivate::itemChanged);
336 connect(mChangeRecorder, &Monitor::collectionAdded, this, &AgentBasePrivate::collectionAdded);
337 connect(mChangeRecorder,
338 qOverload<const Collection &>(&ChangeRecorder::collectionChanged),
339 this,
340 qOverload<const Collection &>(&AgentBasePrivate::collectionChanged));
341 connect(mChangeRecorder,
343 this,
344 qOverload<const Collection &, const QSet<QByteArray> &>(&AgentBasePrivate::collectionChanged));
345 connect(mChangeRecorder, &Monitor::collectionMoved, this, &AgentBasePrivate::collectionMoved);
346 connect(mChangeRecorder, &Monitor::collectionRemoved, this, &AgentBasePrivate::collectionRemoved);
347 connect(mChangeRecorder, &Monitor::collectionSubscribed, this, &AgentBasePrivate::collectionSubscribed);
348 connect(mChangeRecorder, &Monitor::collectionUnsubscribed, this, &AgentBasePrivate::collectionUnsubscribed);
349
350 connect(q, qOverload<int, const QString &>(&AgentBase::status), this, &AgentBasePrivate::slotStatus);
351 connect(q, &AgentBase::percent, this, &AgentBasePrivate::slotPercent);
352 connect(q, &AgentBase::warning, this, &AgentBasePrivate::slotWarning);
353 connect(q, &AgentBase::error, this, &AgentBasePrivate::slotError);
354
355 mPowerInterface = new QDBusInterface(QStringLiteral("org.kde.Solid.PowerManagement"),
356 QStringLiteral("/org/kde/Solid/PowerManagement/Actions/SuspendSession"),
357 QStringLiteral("org.kde.Solid.PowerManagement.Actions.SuspendSession"),
359 this);
360 if (mPowerInterface->isValid()) {
361 connect(mPowerInterface, SIGNAL(resumingFromSuspend()), this, SLOT(slotResumedFromSuspend())); // clazy:exclude=old-style-connect
362 } else {
363 delete mPowerInterface;
364 mPowerInterface = nullptr;
365 }
366
367 // Use reference counting to allow agents to finish internal jobs when the
368 // agent is stopped.
369 mEventLoopLocker = new QEventLoopLocker();
370
371 mResourceTypeName = AgentManager::self()->instance(mId).type().name();
372 setProgramName();
373
374 QTimer::singleShot(0s, q, [this] {
375 delayedInit();
376 });
377}
378
379void AgentBasePrivate::delayedInit()
380{
381 Q_Q(AgentBase);
382
383 const QString serviceId = ServerManager::agentServiceName(ServerManager::Agent, mId);
384 if (!QDBusConnection::sessionBus().registerService(serviceId)) {
385 qCCritical(AKONADIAGENTBASE_LOG) << "Unable to register service" << serviceId << "at dbus:" << QDBusConnection::sessionBus().lastError().message();
386 }
387 q->setOnlineInternal(mDesiredOnlineState);
388
390}
391
392void AgentBasePrivate::setProgramName()
393{
394 // ugly, really ugly, if you find another solution, change it and blame me for this code (Andras)
395 QString programName = mResourceTypeName;
396 if (!mName.isEmpty()) {
397 programName = i18nc("Name and type of Akonadi resource", "%1 of type %2", mName, mResourceTypeName);
398 }
399
401}
402
403void AgentBasePrivate::itemAdded(const Akonadi::Item &item, const Akonadi::Collection &collection)
404{
405 if (mObserver) {
406 mObserver->itemAdded(item, collection);
407 } else {
409 }
410}
411
412void AgentBasePrivate::itemChanged(const Akonadi::Item &item, const QSet<QByteArray> &partIdentifiers)
413{
414 if (mObserver) {
415 mObserver->itemChanged(item, partIdentifiers);
416 } else {
418 }
419}
420
421void AgentBasePrivate::itemMoved(const Akonadi::Item &item, const Akonadi::Collection &source, const Akonadi::Collection &dest)
422{
423 auto observer2 = dynamic_cast<AgentBase::ObserverV2 *>(mObserver);
424 if (mObserver) {
425 // inter-resource moves, requires we know which resources the source and destination are in though
426 if (!source.resource().isEmpty() && !dest.resource().isEmpty()) {
427 if (source.resource() != dest.resource()) {
428 if (source.resource() == q_ptr->identifier()) { // moved away from us
429 Akonadi::Item i(item);
430 i.setParentCollection(source);
431 mObserver->itemRemoved(i);
432 } else if (dest.resource() == q_ptr->identifier()) { // moved to us
433 mObserver->itemAdded(item, dest);
434 } else if (observer2) {
435 observer2->itemMoved(item, source, dest);
436 } else {
437 // not for us, not sure if we should get here at all
439 }
440 return;
441 }
442 }
443 // intra-resource move
444 if (observer2) {
445 observer2->itemMoved(item, source, dest);
446 } else {
447 // ### we cannot just call itemRemoved here as this will already trigger changeProcessed()
448 // so, just itemAdded() is good enough as no resource can have implemented intra-resource moves anyway
449 // without using ObserverV2
450 mObserver->itemAdded(item, dest);
451 // mObserver->itemRemoved( item );
452 }
453 }
454}
455
456void AgentBasePrivate::itemRemoved(const Akonadi::Item &item)
457{
458 if (mObserver) {
459 mObserver->itemRemoved(item);
460 } else {
462 }
463}
464
465void AgentBasePrivate::itemLinked(const Akonadi::Item &item, const Akonadi::Collection &collection)
466{
467 auto observer2 = dynamic_cast<AgentBase::ObserverV2 *>(mObserver);
468 if (observer2) {
469 observer2->itemLinked(item, collection);
470 } else {
472 }
473}
474
475void AgentBasePrivate::itemUnlinked(const Akonadi::Item &item, const Akonadi::Collection &collection)
476{
477 auto observer2 = dynamic_cast<AgentBase::ObserverV2 *>(mObserver);
478 if (observer2) {
479 observer2->itemUnlinked(item, collection);
480 } else {
482 }
483}
484
485void AgentBasePrivate::itemsFlagsChanged(const Akonadi::Item::List &items, const QSet<QByteArray> &addedFlags, const QSet<QByteArray> &removedFlags)
486{
487 auto observer3 = dynamic_cast<AgentBase::ObserverV3 *>(mObserver);
488 if (observer3) {
489 observer3->itemsFlagsChanged(items, addedFlags, removedFlags);
490 } else {
491 Q_ASSERT_X(false, Q_FUNC_INFO, "Batch slots must never be called when ObserverV3 is not available");
492 }
493}
494
495void AgentBasePrivate::itemsMoved(const Akonadi::Item::List &items, const Akonadi::Collection &source, const Akonadi::Collection &destination)
496{
497 auto observer3 = dynamic_cast<AgentBase::ObserverV3 *>(mObserver);
498 if (observer3) {
499 observer3->itemsMoved(items, source, destination);
500 } else {
501 Q_ASSERT_X(false, Q_FUNC_INFO, "Batch slots must never be called when ObserverV3 is not available");
502 }
503}
504
505void AgentBasePrivate::itemsRemoved(const Akonadi::Item::List &items)
506{
507 auto observer3 = dynamic_cast<AgentBase::ObserverV3 *>(mObserver);
508 if (observer3) {
509 observer3->itemsRemoved(items);
510 } else {
511 Q_ASSERT_X(false, Q_FUNC_INFO, "Batch slots must never be called when ObserverV3 is not available");
512 }
513}
514
515void AgentBasePrivate::itemsLinked(const Akonadi::Item::List &items, const Akonadi::Collection &collection)
516{
517 if (!mObserver) {
519 return;
520 }
521
522 auto observer3 = dynamic_cast<AgentBase::ObserverV3 *>(mObserver);
523 if (observer3) {
524 observer3->itemsLinked(items, collection);
525 } else {
526 Q_ASSERT_X(false, Q_FUNC_INFO, "Batch slots must never be called when ObserverV3 is not available");
527 }
528}
529
530void AgentBasePrivate::itemsUnlinked(const Akonadi::Item::List &items, const Akonadi::Collection &collection)
531{
532 if (!mObserver) {
534 return;
535 }
536
537 auto observer3 = dynamic_cast<AgentBase::ObserverV3 *>(mObserver);
538 if (observer3) {
539 observer3->itemsUnlinked(items, collection);
540 } else {
541 Q_ASSERT_X(false, Q_FUNC_INFO, "Batch slots must never be called when ObserverV3 is not available");
542 }
543}
544
545void AgentBasePrivate::tagAdded(const Akonadi::Tag &tag)
546{
547 if (auto tagObserver = dynamic_cast<AgentBase::TagObserver *>(mObserver); tagObserver) {
548 tagObserver->tagAdded(tag);
549 } else {
551 }
552}
553
554void AgentBasePrivate::tagChanged(const Akonadi::Tag &tag)
555{
556 if (auto tagObserver = dynamic_cast<AgentBase::TagObserver *>(mObserver); tagObserver) {
557 tagObserver->tagChanged(tag);
558 } else {
560 }
561}
562
563void AgentBasePrivate::tagRemoved(const Akonadi::Tag &tag)
564{
565 if (auto tagObserver = dynamic_cast<AgentBase::TagObserver *>(mObserver); tagObserver) {
566 tagObserver->tagRemoved(tag);
567 } else {
569 }
570}
571
572void AgentBasePrivate::itemsTagsChanged(const Akonadi::Item::List &items, const QSet<Akonadi::Tag> &addedTags, const QSet<Akonadi::Tag> &removedTags)
573{
574 if (auto tagObserver = dynamic_cast<AgentBase::TagObserver *>(mObserver); tagObserver) {
575 tagObserver->itemsTagsChanged(items, addedTags, removedTags);
576 } else {
578 }
579}
580
581void AgentBasePrivate::collectionAdded(const Akonadi::Collection &collection, const Akonadi::Collection &parent)
582{
583 if (mObserver) {
584 mObserver->collectionAdded(collection, parent);
585 } else {
587 }
588}
589
590void AgentBasePrivate::collectionChanged(const Akonadi::Collection &collection)
591{
592 auto observer2 = dynamic_cast<AgentBase::ObserverV2 *>(mObserver);
593 if (mObserver && observer2 == nullptr) { // For ObserverV2 we use the variant with the part identifiers
594 mObserver->collectionChanged(collection);
595 } else if (!mObserver) {
597 }
598}
599
600void AgentBasePrivate::collectionChanged(const Akonadi::Collection &collection, const QSet<QByteArray> &changedAttributes)
601{
602 auto observer2 = dynamic_cast<AgentBase::ObserverV2 *>(mObserver);
603 if (observer2) {
604 observer2->collectionChanged(collection, changedAttributes);
605 } else {
607 }
608}
609
610void AgentBasePrivate::collectionMoved(const Akonadi::Collection &collection, const Akonadi::Collection &source, const Akonadi::Collection &dest)
611{
612 auto observer2 = dynamic_cast<AgentBase::ObserverV2 *>(mObserver);
613 if (observer2) {
614 observer2->collectionMoved(collection, source, dest);
615 } else if (mObserver) {
616 // ### we cannot just call collectionRemoved here as this will already trigger changeProcessed()
617 // so, just collectionAdded() is good enough as no resource can have implemented intra-resource moves anyway
618 // without using ObserverV2
619 mObserver->collectionAdded(collection, dest);
620 } else {
622 }
623}
624
625void AgentBasePrivate::collectionRemoved(const Akonadi::Collection &collection)
626{
627 if (mObserver) {
628 mObserver->collectionRemoved(collection);
629 } else {
631 }
632}
633
634void AgentBasePrivate::collectionSubscribed(const Akonadi::Collection &collection, const Akonadi::Collection &parent)
635{
636 Q_UNUSED(collection)
637 Q_UNUSED(parent)
639}
640
641void AgentBasePrivate::collectionUnsubscribed(const Akonadi::Collection &collection)
642{
643 Q_UNUSED(collection)
645}
646
647void AgentBasePrivate::changeProcessed()
648{
649 mChangeRecorder->changeProcessed();
650 QTimer::singleShot(0s, mChangeRecorder, &ChangeRecorder::replayNext);
651}
652
653void AgentBasePrivate::slotStatus(int status, const QString &message)
654{
655 mStatusMessage = message;
656 mStatusCode = 0;
657
658 switch (status) {
659 case AgentBase::Idle:
660 if (mStatusMessage.isEmpty()) {
661 mStatusMessage = defaultReadyMessage();
662 }
663
664 mStatusCode = 0;
665 break;
667 if (mStatusMessage.isEmpty()) {
668 mStatusMessage = defaultSyncingMessage();
669 }
670
671 mStatusCode = 1;
672 break;
674 if (mStatusMessage.isEmpty()) {
675 mStatusMessage = defaultErrorMessage();
676 }
677
678 mStatusCode = 2;
679 break;
680
682 if (mStatusMessage.isEmpty()) {
683 mStatusMessage = defaultUnconfiguredMessage();
684 }
685
686 mStatusCode = 3;
687 break;
688
689 default:
690 Q_ASSERT(!"Unknown status passed");
691 break;
692 }
693}
694
695void AgentBasePrivate::slotPercent(int progress)
696{
697 mProgress = progress;
698}
699
700void AgentBasePrivate::slotWarning(const QString &message)
701{
702 mTracer->warning(QStringLiteral("AgentBase(%1)").arg(mId), message);
703}
704
705void AgentBasePrivate::slotError(const QString &message)
706{
707 mTracer->error(QStringLiteral("AgentBase(%1)").arg(mId), message);
708}
709
710void AgentBasePrivate::slotNetworkStatusChange(bool isOnline)
711{
712 Q_UNUSED(isOnline)
713 Q_Q(AgentBase);
714 q->setOnlineInternal(mDesiredOnlineState);
715}
716
717void AgentBasePrivate::slotResumedFromSuspend()
718{
719 if (mNeedsNetwork) {
720 slotNetworkStatusChange(QNetworkInformation::instance()->reachability() != QNetworkInformation::Reachability::Online);
721 }
722}
723
724void AgentBasePrivate::slotTemporaryOfflineTimeout()
725{
726 Q_Q(AgentBase);
727 q->setOnlineInternal(true);
728}
729
730QString AgentBasePrivate::dumpNotificationListToString() const
731{
732 return mChangeRecorder->dumpNotificationListToString();
733}
734
735void AgentBasePrivate::dumpMemoryInfo() const
736{
737 // Send it to stdout, so we can debug user problems.
738 // since you have to explicitly call this
739 // it won't flood users with release builds.
740 QTextStream stream(stdout);
741 stream << dumpMemoryInfoToString();
742}
743
744QString AgentBasePrivate::dumpMemoryInfoToString() const
745{
746 // man mallinfo for more info
747 QString str;
748#if defined __GLIBC__
749 struct mallinfo mi;
750 mi = mallinfo();
751 QTextStream stream(&str);
752 stream << "Total non-mmapped bytes (arena): " << mi.arena << '\n'
753 << "# of free chunks (ordblks): " << mi.ordblks << '\n'
754 << "# of free fastbin blocks (smblks>: " << mi.smblks << '\n'
755 << "# of mapped regions (hblks): " << mi.hblks << '\n'
756 << "Bytes in mapped regions (hblkhd): " << mi.hblkhd << '\n'
757 << "Max. total allocated space (usmblks): " << mi.usmblks << '\n'
758 << "Free bytes held in fastbins (fsmblks):" << mi.fsmblks << '\n'
759 << "Total allocated space (uordblks): " << mi.uordblks << '\n'
760 << "Total free space (fordblks): " << mi.fordblks << '\n'
761 << "Topmost releasable block (keepcost): " << mi.keepcost << '\n';
762#else
763 str = QLatin1StringView("mallinfo() not supported");
764#endif
765 return str;
766}
767
769 : d_ptr(new AgentBasePrivate(this))
770{
771 sAgentBase = this;
772 d_ptr->mId = id;
773 d_ptr->init();
774}
775
776AgentBase::AgentBase(AgentBasePrivate *d, const QString &id)
777 : d_ptr(d)
778{
779 sAgentBase = this;
780 d_ptr->mId = id;
781 d_ptr->init();
782}
783
784AgentBase::~AgentBase() = default;
785
786void AgentBase::debugAgent(int argc, char **argv)
787{
788 Q_UNUSED(argc)
789#ifdef Q_OS_WIN
790 if (qEnvironmentVariableIsSet("AKONADI_DEBUG_WAIT")) {
791 if (QByteArray(argv[0]).endsWith(QByteArray(qgetenv("AKONADI_DEBUG_WAIT") + QByteArrayLiteral(".exe")))) {
792 while (!IsDebuggerPresent()) {
793 std::this_thread::sleep_for(std::chrono::milliseconds(100));
794 }
795 DebugBreak();
796 }
797 }
798#else
799 Q_UNUSED(argv)
800#endif
801}
802
803QString AgentBase::parseArguments(int argc, char **argv)
804{
805 Q_UNUSED(argc)
806
807 QCommandLineOption identifierOption(QStringLiteral("identifier"), i18nc("@info:shell", "Agent identifier"), QStringLiteral("argument"));
808 QCommandLineParser parser;
809 parser.addOption(identifierOption);
810 parser.addHelpOption();
811 parser.addVersionOption();
812 parser.process(*qApp);
813 parser.setApplicationDescription(i18n("Akonadi Agent"));
814
815 if (!parser.isSet(identifierOption)) {
816 qCDebug(AKONADIAGENTBASE_LOG) << "Identifier argument missing";
817 exit(1);
818 }
819
820 const QString identifier = parser.value(identifierOption);
821 if (identifier.isEmpty()) {
822 qCDebug(AKONADIAGENTBASE_LOG) << "Identifier argument is empty";
823 exit(1);
824 }
825
827 QCoreApplication::setApplicationVersion(QStringLiteral(AKONADI_FULL_VERSION));
828
829 const QFileInfo fi(QString::fromLocal8Bit(argv[0]));
830 // strip off full path and possible .exe suffix
831 const QString catalog = fi.baseName();
832
833 auto translator = new QTranslator(qApp);
834 translator->load(catalog);
836
837 return identifier;
838}
839
840/// @endcond
841
843{
844 KLocalizedString::setApplicationDomain(QByteArrayLiteral("libakonadi6"));
845 KAboutData::setApplicationData(r.aboutData());
846 return qApp->exec();
847}
848
850{
851 Q_D(const AgentBase);
852
853 return d->mStatusCode;
854}
855
857{
858 Q_D(const AgentBase);
859
860 return d->mStatusMessage;
861}
862
864{
865 Q_D(const AgentBase);
866
867 return d->mProgress;
868}
869
871{
872 Q_D(const AgentBase);
873
874 return d->mProgressMessage;
875}
876
878{
879 Q_D(const AgentBase);
880
881 return d->mOnline;
882}
883
884void AgentBase::setNeedsNetwork(bool needsNetwork)
885{
886 Q_D(AgentBase);
887 if (d->mNeedsNetwork == needsNetwork) {
888 return;
889 }
890
891 d->mNeedsNetwork = needsNetwork;
892 QNetworkInformation::loadBackendByFeatures(QNetworkInformation::Feature::Reachability);
894 d->slotNetworkStatusChange(reachability == QNetworkInformation::Reachability::Online);
895 });
896}
897
898void AgentBase::setOnline(bool state)
899{
900 Q_D(AgentBase);
901
902 if (d->mPendingQuit) {
903 return;
904 }
905
906 d->mDesiredOnlineState = state;
907 if (!d->mSettings) {
909 d->mSettings->setValue(QStringLiteral("Agent/Name"), agentName());
910 }
911 d->mSettings->setValue(QStringLiteral("Agent/DesiredOnlineState"), state);
912 setOnlineInternal(state);
913}
914
915void AgentBase::setTemporaryOffline(int makeOnlineInSeconds)
916{
917 Q_D(AgentBase);
918
919 // if not currently online, avoid bringing it online after the timeout
920 if (!d->mOnline) {
921 return;
922 }
923
924 setOnlineInternal(false);
925
926 if (!d->mTemporaryOfflineTimer) {
927 d->mTemporaryOfflineTimer = new QTimer(d);
928 d->mTemporaryOfflineTimer->setSingleShot(true);
929 connect(d->mTemporaryOfflineTimer, &QTimer::timeout, d, &AgentBasePrivate::slotTemporaryOfflineTimeout);
930 }
931 d->mTemporaryOfflineTimer->setInterval(std::chrono::seconds{makeOnlineInSeconds});
932 d->mTemporaryOfflineTimer->start();
933}
934
935void AgentBase::setOnlineInternal(bool state)
936{
937 Q_D(AgentBase);
938 if (state && d->mNeedsNetwork) {
939 if (QNetworkInformation::instance()->reachability() != QNetworkInformation::Reachability::Online) {
940 // Don't go online if the resource needs network but there is none
941 state = false;
942 }
943 }
944 d->mOnline = state;
945
946 if (d->mTemporaryOfflineTimer) {
947 d->mTemporaryOfflineTimer->stop();
948 }
949
950 const QString newMessage = d->defaultReadyMessage();
951 if (d->mStatusMessage != newMessage && d->mStatusCode != AgentBase::Broken) {
952 Q_EMIT status(d->mStatusCode, newMessage);
953 }
954
955 doSetOnline(state);
956 Q_EMIT onlineChanged(state);
957}
958
959void AgentBase::doSetOnline(bool online)
960{
961 Q_UNUSED(online)
962}
963
964KAboutData AgentBase::aboutData() const
965{
966 // akonadi_google_resource_1 -> org.kde.akonadi_google_resource
967 const QString desktopEntry = QLatin1StringView("org.kde.") + qApp->applicationName().remove(QRegularExpression(QStringLiteral("_[0-9]+$")));
968
969 KAboutData data(qApp->applicationName(), agentName(), qApp->applicationVersion());
970 data.setDesktopFileName(desktopEntry);
971 return data;
972}
973
974void AgentBase::configure(WId windowId)
975{
976 Q_UNUSED(windowId)
977
978 // Fallback if the agent implements the new plugin-based configuration,
979 // but someone calls the deprecated configure() method
980 auto instance = Akonadi::AgentManager::self()->instance(identifier());
981 QPointer<AgentConfigurationDialog> dialog = new AgentConfigurationDialog(instance, nullptr);
982 if (dialog->exec()) {
984 } else {
986 }
987 delete dialog;
988}
989
990#ifdef Q_OS_WIN // krazy:exclude=cpp
991void AgentBase::configure(qlonglong windowId)
992{
993 configure(static_cast<WId>(windowId));
994}
995#endif
996
998{
999 const bool registered = QDBusConnection::sessionBus().interface()->isServiceRegistered(QStringLiteral("org.freedesktop.akonaditray"));
1000 if (!registered) {
1001 return 0;
1002 }
1003
1004 QDBusInterface dbus(QStringLiteral("org.freedesktop.akonaditray"), QStringLiteral("/Actions"), QStringLiteral("org.freedesktop.Akonadi.Tray"));
1005 const QDBusMessage reply = dbus.call(QStringLiteral("getWinId"));
1006
1007 if (reply.type() == QDBusMessage::ErrorMessage) {
1008 return 0;
1009 }
1010
1011 const WId winid = static_cast<WId>(reply.arguments().at(0).toLongLong());
1012
1013 return winid;
1014}
1015
1016void AgentBase::quit()
1017{
1018 Q_D(AgentBase);
1019 aboutToQuit();
1020
1021 if (d->mSettings) {
1022 d->mChangeRecorder->setConfig(nullptr);
1023 d->mSettings->sync();
1024 delete d->mSettings;
1025 d->mSettings = nullptr;
1026 }
1027
1028 delete d->mEventLoopLocker;
1029 d->mEventLoopLocker = nullptr;
1030}
1031
1033{
1034 Q_D(AgentBase);
1035 d->mPendingQuit = true;
1036}
1037
1039{
1040 Q_D(AgentBase);
1041 // prevent the monitor from picking up deletion signals for our own data if we are a resource
1042 // and thus avoid that we kill our own data as last act before our own death
1043 d->mChangeRecorder->blockSignals(true);
1044
1045 aboutToQuit();
1046
1047 const QString fileName = d->mSettings->fileName();
1048
1049 /*
1050 * First destroy the settings object...
1051 */
1052 d->mChangeRecorder->setConfig(nullptr);
1053 delete d->mSettings;
1054 d->mSettings = nullptr;
1055
1056 /*
1057 * ... then remove the file from hd.
1058 */
1059 if (!QFile::remove(fileName)) {
1060 qCWarning(AKONADIAGENTBASE_LOG) << "Impossible to remove " << fileName;
1061 }
1062
1063 /*
1064 * ... and remove the changes file from hd.
1065 */
1066 const QString changeDataFileName = fileName + QStringLiteral("_changes.dat");
1067 if (!QFile::remove(changeDataFileName)) {
1068 qCWarning(AKONADIAGENTBASE_LOG) << "Impossible to remove " << changeDataFileName;
1069 }
1070
1071 /*
1072 * ... and also remove the agent configuration file if there is one.
1073 */
1075 if (!QFile::remove(configFile)) {
1076 qCWarning(AKONADIAGENTBASE_LOG) << "Impossible to remove config file " << configFile;
1077 }
1078
1079 delete d->mEventLoopLocker;
1080 d->mEventLoopLocker = nullptr;
1081}
1082
1084{
1085 Q_D(AgentBase);
1086
1087 // TODO in theory we should re-connect change recorder signals here that we disconnected previously
1088 d->mObserver = observer;
1089
1090 const bool hasObserverV3 = (dynamic_cast<AgentBase::ObserverV3 *>(d->mObserver) != nullptr);
1091 const bool hasTagObserver = (dynamic_cast<AgentBase::TagObserver *>(d->mObserver) != nullptr);
1092
1093 disconnect(d->mChangeRecorder, &Monitor::tagAdded, d, &AgentBasePrivate::tagAdded);
1094 disconnect(d->mChangeRecorder, &Monitor::tagChanged, d, &AgentBasePrivate::tagChanged);
1095 disconnect(d->mChangeRecorder, &Monitor::tagRemoved, d, &AgentBasePrivate::tagRemoved);
1096 disconnect(d->mChangeRecorder, &Monitor::itemsTagsChanged, d, &AgentBasePrivate::itemsTagsChanged);
1097 disconnect(d->mChangeRecorder, &Monitor::itemsFlagsChanged, d, &AgentBasePrivate::itemsFlagsChanged);
1098 disconnect(d->mChangeRecorder, &Monitor::itemsMoved, d, &AgentBasePrivate::itemsMoved);
1099 disconnect(d->mChangeRecorder, &Monitor::itemsRemoved, d, &AgentBasePrivate::itemsRemoved);
1100 disconnect(d->mChangeRecorder, &Monitor::itemsLinked, d, &AgentBasePrivate::itemsLinked);
1101 disconnect(d->mChangeRecorder, &Monitor::itemsUnlinked, d, &AgentBasePrivate::itemsUnlinked);
1102 disconnect(d->mChangeRecorder, &Monitor::itemMoved, d, &AgentBasePrivate::itemMoved);
1103 disconnect(d->mChangeRecorder, &Monitor::itemRemoved, d, &AgentBasePrivate::itemRemoved);
1104 disconnect(d->mChangeRecorder, &Monitor::itemLinked, d, &AgentBasePrivate::itemLinked);
1105 disconnect(d->mChangeRecorder, &Monitor::itemUnlinked, d, &AgentBasePrivate::itemUnlinked);
1106
1107 if (hasTagObserver) {
1108 connect(d->mChangeRecorder, &Monitor::tagAdded, d, &AgentBasePrivate::tagAdded);
1109 connect(d->mChangeRecorder, &Monitor::tagChanged, d, &AgentBasePrivate::tagChanged);
1110 connect(d->mChangeRecorder, &Monitor::tagRemoved, d, &AgentBasePrivate::tagRemoved);
1111 connect(d->mChangeRecorder, &Monitor::itemsTagsChanged, d, &AgentBasePrivate::itemsTagsChanged);
1112
1113 // If the agent has a TagObserver, we assume it wants to receive everything tag-related.
1114 d->mChangeRecorder->itemFetchScope().setFetchTags(true);
1115 d->mChangeRecorder->tagFetchScope().setFetchAllAttributes(true);
1116 d->mChangeRecorder->tagFetchScope().setFetchRemoteId(true);
1117 }
1118
1119 if (hasObserverV3) {
1120 connect(d->mChangeRecorder, &Monitor::itemsFlagsChanged, d, &AgentBasePrivate::itemsFlagsChanged);
1121 connect(d->mChangeRecorder, &Monitor::itemsMoved, d, &AgentBasePrivate::itemsMoved);
1122 connect(d->mChangeRecorder, &Monitor::itemsRemoved, d, &AgentBasePrivate::itemsRemoved);
1123 connect(d->mChangeRecorder, &Monitor::itemsLinked, d, &AgentBasePrivate::itemsLinked);
1124 connect(d->mChangeRecorder, &Monitor::itemsUnlinked, d, &AgentBasePrivate::itemsUnlinked);
1125 } else {
1126 // V2 - don't connect these if we have V3
1127 connect(d->mChangeRecorder, &Monitor::itemMoved, d, &AgentBasePrivate::itemMoved);
1128 connect(d->mChangeRecorder, &Monitor::itemRemoved, d, &AgentBasePrivate::itemRemoved);
1129 connect(d->mChangeRecorder, &Monitor::itemLinked, d, &AgentBasePrivate::itemLinked);
1130 connect(d->mChangeRecorder, &Monitor::itemUnlinked, d, &AgentBasePrivate::itemUnlinked);
1131 }
1132}
1133
1135{
1136 return d_ptr->mId;
1137}
1138
1140{
1141 Q_D(AgentBase);
1142 if (name == d->mName) {
1143 return;
1144 }
1145
1146 // TODO: rename collection
1147 d->mName = name;
1148
1149 if (d->mName.isEmpty() || d->mName == d->mId) {
1150 d->mSettings->remove(QStringLiteral("Resource/Name"));
1151 d->mSettings->remove(QStringLiteral("Agent/Name"));
1152 } else {
1153 d->mSettings->setValue(QStringLiteral("Agent/Name"), d->mName);
1154 }
1155
1156 d->mSettings->sync();
1157
1158 d->setProgramName();
1159
1160 Q_EMIT agentNameChanged(d->mName);
1161}
1162
1164{
1165 Q_D(const AgentBase);
1166 if (d->mName.isEmpty()) {
1167 return d->mId;
1168 } else {
1169 return d->mName;
1170 }
1171}
1172
1174{
1175 Q_D(AgentBase);
1176 d->changeProcessed();
1177}
1178
1180{
1181 return d_ptr->mChangeRecorder;
1182}
1183
1184KSharedConfigPtr AgentBase::config()
1185{
1187}
1188
1189void AgentBase::abort()
1190{
1192}
1193
1194void AgentBase::reconfigure()
1195{
1197}
1198
1199#include "moc_agentbase.cpp"
1200#include "moc_agentbase_p.cpp"
BC extension of Observer with support for monitoring item and collection moves.
Definition agentbase.h:238
virtual void itemUnlinked(const Akonadi::Item &item, const Akonadi::Collection &collection)
Reimplement to handle item unlinking.
virtual void itemMoved(const Akonadi::Item &item, const Akonadi::Collection &collectionSource, const Akonadi::Collection &collectionDestination)
Reimplement to handle item moves.
virtual void collectionChanged(const Akonadi::Collection &collection, const QSet< QByteArray > &changedAttributes)
Reimplement to handle changes to existing collections.
virtual void collectionMoved(const Akonadi::Collection &collection, const Akonadi::Collection &collectionSource, const Akonadi::Collection &collectionDestination)
Reimplement to handle collection moves.
virtual void itemLinked(const Akonadi::Item &item, const Akonadi::Collection &collection)
Reimplement to handle item linking.
BC extension of ObserverV2 with support for batch operations.
Definition agentbase.h:302
virtual void itemsFlagsChanged(const Akonadi::Item::List &items, const QSet< QByteArray > &addedFlags, const QSet< QByteArray > &removedFlags)
Reimplement to handle changes in flags of existing items.
virtual void itemsLinked(const Akonadi::Item::List &items, const Akonadi::Collection &collection)
Reimplement to handle batch notifications about items linking.
virtual void itemsRemoved(const Akonadi::Item::List &items)
Reimplement to handle batch notification about items deletion.
virtual void itemsUnlinked(const Akonadi::Item::List &items, const Akonadi::Collection &collection)
Reimplement to handle batch notifications about items unlinking.
virtual void itemsMoved(const Akonadi::Item::List &items, const Akonadi::Collection &sourceCollection, const Akonadi::Collection &destinationCollection)
Reimplement to handle batch notification about items move.
The interface for reacting on monitored or replayed changes.
Definition agentbase.h:179
virtual ~Observer()
Destroys the observer instance.
Definition agentbase.cpp:61
virtual void collectionAdded(const Akonadi::Collection &collection, const Akonadi::Collection &parent)
Reimplement to handle adding of new collections.
Definition agentbase.cpp:91
virtual void collectionChanged(const Akonadi::Collection &collection)
Reimplement to handle changes to existing collections.
virtual void collectionRemoved(const Akonadi::Collection &collection)
Reimplement to handle deletion of collections.
Observer()
Creates an observer instance.
Definition agentbase.cpp:57
virtual void itemAdded(const Akonadi::Item &item, const Akonadi::Collection &collection)
Reimplement to handle adding of new items.
Definition agentbase.cpp:65
virtual void itemChanged(const Akonadi::Item &item, const QSet< QByteArray > &partIdentifiers)
Reimplement to handle changes to existing items.
Definition agentbase.cpp:74
virtual void itemRemoved(const Akonadi::Item &item)
Reimplement to handle deletion of items.
Definition agentbase.cpp:83
The base class for all Akonadi agents and resources.
Definition agentbase.h:73
void warning(const QString &message)
This signal shall be used to report warnings.
void changeProcessed()
Marks the current change as processes and replays the next change if change recording is enabled (noo...
virtual void doSetOnline(bool online)
This method is called whenever the online status has changed.
void configurationDialogAccepted()
This signal is emitted whenever the user has accepted the configuration dialog.
void setTemporaryOffline(int makeOnlineInSeconds=300)
Sets the agent offline but will make it online again after a given time.
void setNeedsNetwork(bool needsNetwork)
Sets whether the agent needs network or not.
virtual int status() const
This method returns the current status code of the agent.
void onlineChanged(bool online)
Emitted when the online state changed.
KSharedConfigPtr config()
Returns the config object for this Agent.
virtual void cleanup()
This method is called when the agent is removed from the system, so it can do some cleanup stuff.
void reloadConfiguration()
Emitted if another application has changed the agent's configuration remotely and called AgentInstanc...
virtual QString statusMessage() const
This method returns an i18n'ed description of the current status code.
virtual QString progressMessage() const
This method returns an i18n'ed description of the current progress.
WId winIdForDialogs() const
This method returns the windows id, which should be used for dialogs.
void setAgentName(const QString &name)
This method is used to set the name of the agent.
~AgentBase() override
Destroys the agent base.
ChangeRecorder * changeRecorder() const
Returns the Akonadi::ChangeRecorder object used for monitoring.
virtual void aboutToQuit()
This method is called whenever the agent application is about to quit.
virtual void configure(WId windowId)
This method is called whenever the agent shall show its configuration dialog to the user.
QString agentName() const
Returns the name of the agent.
@ Running
The agent is working on something.
Definition agentbase.h:398
@ NotConfigured
The agent is lacking required configuration.
Definition agentbase.h:400
@ Broken
The agent encountered an error state.
Definition agentbase.h:399
@ Idle
The agent does currently nothing.
Definition agentbase.h:397
void percent(int progress)
This signal should be emitted whenever the progress of an action in the agent (e.g.
void abortRequested()
Emitted when another application has remotely asked the agent to abort its current operation.
bool isOnline() const
Returns whether the agent is currently online.
QString identifier() const
Returns the instance identifier of this agent.
virtual int progress() const
This method returns the current progress of the agent in percentage.
static int init(int argc, char **argv)
Use this method in the main function of your agent application to initialize your agent subclass.
Definition agentbase.h:428
void agentNameChanged(const QString &name)
This signal is emitted whenever the name of the agent has changed.
void setOnline(bool state)
Sets whether the agent shall be online or not.
void error(const QString &message)
This signal shall be used to report errors.
void configurationDialogRejected()
This signal is emitted whenever the user has rejected the configuration dialog.
AgentBase(const QString &id)
Creates an agent base.
void registerObserver(Observer *observer)
Registers the given observer for reacting on monitored or recorded changes.
AgentType type() const
Returns the agent type of this instance.
static AgentManager * self()
Returns the global instance of the agent manager.
AgentInstance instance(const QString &identifier) const
Returns the agent instance with the given identifier or an invalid agent instance if the identifier d...
QString name() const
Returns the i18n'ed name of the agent type.
Records and replays change notification.
void replayNext()
Replay the next change notification and erase the previous one from the record.
Represents a collection of PIM items.
Definition collection.h:62
Represents a PIM item stored in Akonadi storage.
Definition item.h:100
void itemsTagsChanged(const Akonadi::Item::List &items, const QSet< Akonadi::Tag > &addedTags, const QSet< Akonadi::Tag > &removedTags)
This signal is emitted if tags of monitored items have changed.
void itemChanged(const Akonadi::Item &item, const QSet< QByteArray > &partIdentifiers)
This signal is emitted if a monitored item has changed, e.g.
void collectionMoved(const Akonadi::Collection &collection, const Akonadi::Collection &source, const Akonadi::Collection &destination)
This signals is emitted if a monitored collection has been moved.
void collectionUnsubscribed(const Akonadi::Collection &collection)
This signal is emitted if a user unsubscribes from a collection.
void itemLinked(const Akonadi::Item &item, const Akonadi::Collection &collection)
This signal is emitted if a reference to an item is added to a virtual collection.
void itemRemoved(const Akonadi::Item &item)
This signal is emitted if.
void tagRemoved(const Akonadi::Tag &tag)
This signal is emitted if a monitored tag is removed from the server storage.
void tagChanged(const Akonadi::Tag &tag)
This signal is emitted if a monitored tag is changed on the server.
void collectionSubscribed(const Akonadi::Collection &collection, const Akonadi::Collection &parent)
This signal is emitted if a collection has been subscribed to by the user.
void tagAdded(const Akonadi::Tag &tag)
This signal is emitted if a tag has been added to Akonadi storage.
void itemsFlagsChanged(const Akonadi::Item::List &items, const QSet< QByteArray > &addedFlags, const QSet< QByteArray > &removedFlags)
This signal is emitted if flags of monitored items have changed.
void collectionRemoved(const Akonadi::Collection &collection)
This signal is emitted if a monitored collection has been removed from the Akonadi storage.
void itemsRemoved(const Akonadi::Item::List &items)
This signal is emitted if monitored items have been removed from Akonadi storage of items have been r...
void itemAdded(const Akonadi::Item &item, const Akonadi::Collection &collection)
This signal is emitted if an item has been added to a monitored collection in the Akonadi storage.
void itemsUnlinked(const Akonadi::Item::List &items, const Akonadi::Collection &collection)
This signal is emitted if a reference to items is removed from a virtual collection.
void collectionAdded(const Akonadi::Collection &collection, const Akonadi::Collection &parent)
This signal is emitted if a new collection has been added to a monitored collection in the Akonadi st...
void itemMoved(const Akonadi::Item &item, const Akonadi::Collection &collectionSource, const Akonadi::Collection &collectionDestination)
This signal is emitted if a monitored item has been moved between two collections.
void itemsLinked(const Akonadi::Item::List &items, const Akonadi::Collection &collection)
This signal is emitted if a reference to multiple items is added to a virtual collection.
void collectionChanged(const Akonadi::Collection &collection)
This signal is emitted if a monitored collection has been changed (properties or content).
void itemsMoved(const Akonadi::Item::List &items, const Akonadi::Collection &collectionSource, const Akonadi::Collection &collectionDestination)
This is signal is emitted when multiple monitored items have been moved between two collections.
void itemUnlinked(const Akonadi::Item &item, const Akonadi::Collection &collection)
This signal is emitted if a reference to an item is removed from a virtual collection.
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...
static QString addNamespace(const QString &string)
Adds the multi-instance namespace to string if required (with '_' as separator).
static QString agentConfigFilePath(const QString &identifier)
Returns absolute path to configuration file of an agent identified by given identifier.
static QString serviceName(ServiceType serviceType)
Returns the namespaced D-Bus service name for serviceType.
static Session * defaultSession()
Returns the default session for this thread.
An Akonadi Tag.
Definition tag.h:26
static void setApplicationData(const KAboutData &aboutData)
static void setApplicationDomain(const QByteArray &domain)
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
Helper integration between Akonadi and Qt.
QCommandLineOption addHelpOption()
bool addOption(const QCommandLineOption &option)
QCommandLineOption addVersionOption()
bool isSet(const QCommandLineOption &option) const const
void process(const QCoreApplication &app)
void setApplicationDescription(const QString &description)
QString value(const QCommandLineOption &option) const const
void setApplicationName(const QString &application)
void setApplicationVersion(const QString &version)
bool installTranslator(QTranslator *translationFile)
QDBusMessage call(QDBus::CallMode mode, const QString &method, Args &&... args)
QDBusConnectionInterface * interface() const const
QDBusError lastError() const const
bool registerObject(const QString &path, QObject *object, RegisterOptions options)
QDBusConnection sessionBus()
QDBusReply< bool > isServiceRegistered(const QString &serviceName) const const
const QDBusMessage & message() const const
QString message() const const
QList< QVariant > arguments() const const
MessageType type() const const
bool remove()
void setApplicationDisplayName(const QString &name)
const_reference at(qsizetype i) const const
QNetworkInformation * instance()
bool loadBackendByFeatures(Features features)
void reachabilityChanged(Reachability newReachability)
Q_EMITQ_EMIT
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool disconnect(const QMetaObject::Connection &connection)
QObject * parent() const const
QString writableLocation(StandardLocation type)
QString fromLocal8Bit(QByteArrayView str)
bool isEmpty() const const
void timeout()
Q_D(Todo)
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.