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 <KAboutData>
29#include <KCrash>
30#include <KIconTheme>
31#include <KLocalizedString>
32#include <KStyleManager>
33
34#include <QCommandLineParser>
35#include <QNetworkInformation>
36#include <QPointer>
37#include <QSettings>
38#include <QTimer>
39
40#include <QStandardPaths>
41#include <signal.h>
42#include <stdlib.h>
43#include <strstream>
44#if defined __GLIBC__
45#include <malloc.h> // for dumping memory information
46#endif
47
48#ifdef Q_OS_WIN
49#include <Windows.h>
50#endif
51
52#include <chrono>
53#include <thread>
54
55using namespace Akonadi;
56using namespace std::chrono_literals;
57static AgentBase *sAgentBase = nullptr;
58
62
66
67void AgentBase::Observer::itemAdded(const Item &item, const Collection &collection)
68{
69 Q_UNUSED(item)
70 Q_UNUSED(collection)
71 if (sAgentBase) {
72 sAgentBase->d_ptr->changeProcessed();
73 }
74}
75
76void AgentBase::Observer::itemChanged(const Item &item, const QSet<QByteArray> &partIdentifiers)
77{
78 Q_UNUSED(item)
79 Q_UNUSED(partIdentifiers)
80 if (sAgentBase) {
81 sAgentBase->d_ptr->changeProcessed();
82 }
83}
84
86{
87 Q_UNUSED(item)
88 if (sAgentBase) {
89 sAgentBase->d_ptr->changeProcessed();
90 }
91}
92
94{
95 Q_UNUSED(collection)
96 Q_UNUSED(parent)
97 if (sAgentBase) {
98 sAgentBase->d_ptr->changeProcessed();
99 }
100}
101
103{
104 Q_UNUSED(collection)
105 if (sAgentBase) {
106 sAgentBase->d_ptr->changeProcessed();
107 }
108}
109
111{
112 Q_UNUSED(collection)
113 if (sAgentBase) {
114 sAgentBase->d_ptr->changeProcessed();
115 }
116}
117
119{
120 Q_UNUSED(item)
121 Q_UNUSED(source)
122 Q_UNUSED(dest)
123 if (sAgentBase) {
124 sAgentBase->d_ptr->changeProcessed();
125 }
126}
127
129{
130 Q_UNUSED(item)
131 Q_UNUSED(collection)
132 if (sAgentBase) {
133 // not implementation, let's disconnect the signal to enable optimizations in Monitor
134 QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::itemLinked, sAgentBase->d_ptr.get(), &AgentBasePrivate::itemLinked);
135 sAgentBase->d_ptr->changeProcessed();
136 }
137}
138
140{
141 Q_UNUSED(item)
142 Q_UNUSED(collection)
143 if (sAgentBase) {
144 // not implementation, let's disconnect the signal to enable optimizations in Monitor
145 QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::itemUnlinked, sAgentBase->d_ptr.get(), &AgentBasePrivate::itemUnlinked);
146 sAgentBase->d_ptr->changeProcessed();
147 }
148}
149
151{
152 Q_UNUSED(collection)
153 Q_UNUSED(source)
154 Q_UNUSED(dest)
155 if (sAgentBase) {
156 sAgentBase->d_ptr->changeProcessed();
157 }
158}
159
161{
162 Q_UNUSED(changedAttributes)
163 collectionChanged(collection);
164}
165
167{
168 Q_UNUSED(items)
169 Q_UNUSED(addedFlags)
170 Q_UNUSED(removedFlags)
171
172 if (sAgentBase) {
173 // not implementation, let's disconnect the signal to enable optimizations in Monitor
174 QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::itemsFlagsChanged, sAgentBase->d_ptr.get(), &AgentBasePrivate::itemsFlagsChanged);
175 sAgentBase->d_ptr->changeProcessed();
176 }
177}
178
179void AgentBase::ObserverV3::itemsMoved(const Akonadi::Item::List &items, const Collection &sourceCollection, const Collection &destinationCollection)
180{
181 Q_UNUSED(items)
182 Q_UNUSED(sourceCollection)
183 Q_UNUSED(destinationCollection)
184
185 if (sAgentBase) {
186 // not implementation, let's disconnect the signal to enable optimizations in Monitor
187 QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::itemsMoved, sAgentBase->d_ptr.get(), &AgentBasePrivate::itemsMoved);
188 sAgentBase->d_ptr->changeProcessed();
189 }
190}
191
193{
194 Q_UNUSED(items)
195
196 if (sAgentBase) {
197 // not implementation, let's disconnect the signal to enable optimizations in Monitor
198 QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::itemsRemoved, sAgentBase->d_ptr.get(), &AgentBasePrivate::itemsRemoved);
199 sAgentBase->d_ptr->changeProcessed();
200 }
201}
202
204{
205 Q_UNUSED(items)
206 Q_UNUSED(collection)
207
208 if (sAgentBase) {
209 // not implementation, let's disconnect the signal to enable optimizations in Monitor
210 QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::itemsLinked, sAgentBase->d_ptr.get(), &AgentBasePrivate::itemsLinked);
211 sAgentBase->d_ptr->changeProcessed();
212 }
213}
214
216{
217 Q_UNUSED(items)
218 Q_UNUSED(collection)
219
220 if (sAgentBase) {
221 // not implementation, let's disconnect the signal to enable optimizations in Monitor
222 QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::itemsUnlinked, sAgentBase->d_ptr.get(), &AgentBasePrivate::itemsUnlinked);
223 sAgentBase->d_ptr->changeProcessed();
224 }
225}
226
227AgentBase::TagObserver::TagObserver() = default;
228
229AgentBase::TagObserver::~TagObserver() = default;
230
231void AgentBase::TagObserver::tagAdded(const Akonadi::Tag &tag)
232{
233 Q_UNUSED(tag)
234 if (sAgentBase) {
235 QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::tagAdded, sAgentBase->d_ptr.get(), &AgentBasePrivate::tagAdded);
236 sAgentBase->d_ptr->changeProcessed();
237 }
238}
239
240void AgentBase::TagObserver::tagChanged(const Akonadi::Tag &tag)
241{
242 Q_UNUSED(tag)
243 if (sAgentBase) {
244 QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::tagChanged, sAgentBase->d_ptr.get(), &AgentBasePrivate::tagChanged);
245 sAgentBase->d_ptr->changeProcessed();
246 }
247}
248
249void AgentBase::TagObserver::tagRemoved(const Akonadi::Tag &tag)
250{
251 Q_UNUSED(tag)
252 if (sAgentBase) {
253 QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::tagRemoved, sAgentBase->d_ptr.get(), &AgentBasePrivate::tagRemoved);
254 sAgentBase->d_ptr->changeProcessed();
255 }
256}
257
258void AgentBase::TagObserver::itemsTagsChanged(const Akonadi::Item::List &items, const QSet<Akonadi::Tag> &addedTags, const QSet<Akonadi::Tag> &removedTags)
259{
260 Q_UNUSED(items)
261 Q_UNUSED(addedTags)
262 Q_UNUSED(removedTags)
263
264 if (sAgentBase) {
265 QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::itemsTagsChanged, sAgentBase->d_ptr.get(), &AgentBasePrivate::itemsTagsChanged);
266 sAgentBase->d_ptr->changeProcessed();
267 }
268}
269/// @cond PRIVATE
270
271AgentBasePrivate::AgentBasePrivate(AgentBase *parent)
272 : q_ptr(parent)
273 , mStatusCode(AgentBase::Idle)
274 , mProgress(0)
275 , mNeedsNetwork(false)
276 , mOnline(false)
277 , mDesiredOnlineState(false)
278 , mPendingQuit(false)
279 , mSettings(nullptr)
280 , mChangeRecorder(nullptr)
281 , mTracer(nullptr)
282 , mObserver(nullptr)
283 , mPowerInterface(nullptr)
284 , mTemporaryOfflineTimer(nullptr)
285 , mEventLoopLocker(nullptr)
286{
287 Internal::setClientType(Internal::Agent);
288}
289
290AgentBasePrivate::~AgentBasePrivate()
291{
292 mChangeRecorder->setConfig(nullptr);
293 delete mSettings;
294}
295
296void AgentBasePrivate::init()
297{
298 Q_Q(AgentBase);
299 /**
300 * Create a default session for this process.
301 */
302 SessionPrivate::createDefaultSession(mId.toLatin1());
303
304 mTracer =
305 new org::freedesktop::Akonadi::Tracer(ServerManager::serviceName(ServerManager::Server), QStringLiteral("/tracing"), QDBusConnection::sessionBus(), q);
306
307 new Akonadi__ControlAdaptor(q);
308 new Akonadi__StatusAdaptor(q);
309 if (!QDBusConnection::sessionBus().registerObject(QStringLiteral("/"), q, QDBusConnection::ExportAdaptors)) {
310 Q_EMIT q->error(i18n("Unable to register object at dbus: %1", QDBusConnection::sessionBus().lastError().message()));
311 }
312
314
315 mChangeRecorder = new ChangeRecorder(q);
316 mChangeRecorder->setObjectName(QLatin1StringView("AgentBaseChangeRecorder"));
317 mChangeRecorder->ignoreSession(Session::defaultSession());
318 mChangeRecorder->itemFetchScope().setCacheOnly(true);
319 mChangeRecorder->setConfig(mSettings);
320
321 mDesiredOnlineState = mSettings->value(QLatin1StringView("Agent/DesiredOnlineState"), true).toBool();
322 mOnline = mDesiredOnlineState;
323
324 // reinitialize the status message now that online state is available
325 mStatusMessage = defaultReadyMessage();
326
327 mName = mSettings->value(QLatin1StringView("Agent/Name")).toString();
328 if (mName.isEmpty()) {
329 mName = mSettings->value(QLatin1StringView("Resource/Name")).toString();
330 if (!mName.isEmpty()) {
331 mSettings->remove(QLatin1StringView("Resource/Name"));
332 mSettings->setValue(QLatin1StringView("Agent/Name"), mName);
333 }
334 }
335
336 mActivities = mSettings->value(QLatin1StringView("Agent/Activities")).toStringList();
337 mActivitiesEnabled = mSettings->value(QLatin1StringView("Agent/ActivitiesEnabled"), false).toBool();
338 connect(mChangeRecorder, &Monitor::itemAdded, this, &AgentBasePrivate::itemAdded);
339 connect(mChangeRecorder, &Monitor::itemChanged, this, &AgentBasePrivate::itemChanged);
340 connect(mChangeRecorder, &Monitor::collectionAdded, this, &AgentBasePrivate::collectionAdded);
341 connect(mChangeRecorder,
342 qOverload<const Collection &>(&ChangeRecorder::collectionChanged),
343 this,
344 qOverload<const Collection &>(&AgentBasePrivate::collectionChanged));
345 connect(mChangeRecorder,
347 this,
348 qOverload<const Collection &, const QSet<QByteArray> &>(&AgentBasePrivate::collectionChanged));
349 connect(mChangeRecorder, &Monitor::collectionMoved, this, &AgentBasePrivate::collectionMoved);
350 connect(mChangeRecorder, &Monitor::collectionRemoved, this, &AgentBasePrivate::collectionRemoved);
351 connect(mChangeRecorder, &Monitor::collectionSubscribed, this, &AgentBasePrivate::collectionSubscribed);
352 connect(mChangeRecorder, &Monitor::collectionUnsubscribed, this, &AgentBasePrivate::collectionUnsubscribed);
353
354 connect(q, qOverload<int, const QString &>(&AgentBase::status), this, &AgentBasePrivate::slotStatus);
355 connect(q, &AgentBase::percent, this, &AgentBasePrivate::slotPercent);
356 connect(q, &AgentBase::warning, this, &AgentBasePrivate::slotWarning);
357 connect(q, &AgentBase::error, this, &AgentBasePrivate::slotError);
358
359 mPowerInterface = new QDBusInterface(QStringLiteral("org.kde.Solid.PowerManagement"),
360 QStringLiteral("/org/kde/Solid/PowerManagement/Actions/SuspendSession"),
361 QStringLiteral("org.kde.Solid.PowerManagement.Actions.SuspendSession"),
363 this);
364 if (mPowerInterface->isValid()) {
365 connect(mPowerInterface, SIGNAL(resumingFromSuspend()), this, SLOT(slotResumedFromSuspend())); // clazy:exclude=old-style-connect
366 } else {
367 delete mPowerInterface;
368 mPowerInterface = nullptr;
369 }
370
371 // Use reference counting to allow agents to finish internal jobs when the
372 // agent is stopped.
373 mEventLoopLocker = new QEventLoopLocker();
374
375 mResourceTypeName = AgentManager::self()->instance(mId).type().name();
376 setProgramName();
377
378 QTimer::singleShot(0s, q, [this] {
379 delayedInit();
380 });
381}
382
383void AgentBasePrivate::delayedInit()
384{
385 Q_Q(AgentBase);
386
387 const QString serviceId = ServerManager::agentServiceName(ServerManager::Agent, mId);
388 if (!QDBusConnection::sessionBus().registerService(serviceId)) {
389 qCCritical(AKONADIAGENTBASE_LOG) << "Unable to register service" << serviceId << "at dbus:" << QDBusConnection::sessionBus().lastError().message();
390 }
391 q->setOnlineInternal(mDesiredOnlineState);
392
394}
395
396void AgentBasePrivate::setProgramName()
397{
398 // ugly, really ugly, if you find another solution, change it and blame me for this code (Andras)
399 QString programName = mResourceTypeName;
400 if (!mName.isEmpty()) {
401 programName = i18nc("Name and type of Akonadi resource", "%1 of type %2", mName, mResourceTypeName);
402 }
403
405}
406
407void AgentBasePrivate::itemAdded(const Akonadi::Item &item, const Akonadi::Collection &collection)
408{
409 if (mObserver) {
410 mObserver->itemAdded(item, collection);
411 } else {
413 }
414}
415
416void AgentBasePrivate::itemChanged(const Akonadi::Item &item, const QSet<QByteArray> &partIdentifiers)
417{
418 if (mObserver) {
419 mObserver->itemChanged(item, partIdentifiers);
420 } else {
422 }
423}
424
425void AgentBasePrivate::itemMoved(const Akonadi::Item &item, const Akonadi::Collection &source, const Akonadi::Collection &dest)
426{
427 auto observer2 = dynamic_cast<AgentBase::ObserverV2 *>(mObserver);
428 if (mObserver) {
429 // inter-resource moves, requires we know which resources the source and destination are in though
430 if (!source.resource().isEmpty() && !dest.resource().isEmpty()) {
431 if (source.resource() != dest.resource()) {
432 if (source.resource() == q_ptr->identifier()) { // moved away from us
433 Akonadi::Item i(item);
434 i.setParentCollection(source);
435 mObserver->itemRemoved(i);
436 } else if (dest.resource() == q_ptr->identifier()) { // moved to us
437 mObserver->itemAdded(item, dest);
438 } else if (observer2) {
439 observer2->itemMoved(item, source, dest);
440 } else {
441 // not for us, not sure if we should get here at all
443 }
444 return;
445 }
446 }
447 // intra-resource move
448 if (observer2) {
449 observer2->itemMoved(item, source, dest);
450 } else {
451 // ### we cannot just call itemRemoved here as this will already trigger changeProcessed()
452 // so, just itemAdded() is good enough as no resource can have implemented intra-resource moves anyway
453 // without using ObserverV2
454 mObserver->itemAdded(item, dest);
455 // mObserver->itemRemoved( item );
456 }
457 }
458}
459
460void AgentBasePrivate::itemRemoved(const Akonadi::Item &item)
461{
462 if (mObserver) {
463 mObserver->itemRemoved(item);
464 } else {
466 }
467}
468
469void AgentBasePrivate::itemLinked(const Akonadi::Item &item, const Akonadi::Collection &collection)
470{
471 auto observer2 = dynamic_cast<AgentBase::ObserverV2 *>(mObserver);
472 if (observer2) {
473 observer2->itemLinked(item, collection);
474 } else {
476 }
477}
478
479void AgentBasePrivate::itemUnlinked(const Akonadi::Item &item, const Akonadi::Collection &collection)
480{
481 auto observer2 = dynamic_cast<AgentBase::ObserverV2 *>(mObserver);
482 if (observer2) {
483 observer2->itemUnlinked(item, collection);
484 } else {
486 }
487}
488
489void AgentBasePrivate::itemsFlagsChanged(const Akonadi::Item::List &items, const QSet<QByteArray> &addedFlags, const QSet<QByteArray> &removedFlags)
490{
491 auto observer3 = dynamic_cast<AgentBase::ObserverV3 *>(mObserver);
492 if (observer3) {
493 observer3->itemsFlagsChanged(items, addedFlags, removedFlags);
494 } else {
495 Q_ASSERT_X(false, Q_FUNC_INFO, "Batch slots must never be called when ObserverV3 is not available");
496 }
497}
498
499void AgentBasePrivate::itemsMoved(const Akonadi::Item::List &items, const Akonadi::Collection &source, const Akonadi::Collection &destination)
500{
501 auto observer3 = dynamic_cast<AgentBase::ObserverV3 *>(mObserver);
502 if (observer3) {
503 observer3->itemsMoved(items, source, destination);
504 } else {
505 Q_ASSERT_X(false, Q_FUNC_INFO, "Batch slots must never be called when ObserverV3 is not available");
506 }
507}
508
509void AgentBasePrivate::itemsRemoved(const Akonadi::Item::List &items)
510{
511 auto observer3 = dynamic_cast<AgentBase::ObserverV3 *>(mObserver);
512 if (observer3) {
513 observer3->itemsRemoved(items);
514 } else {
515 Q_ASSERT_X(false, Q_FUNC_INFO, "Batch slots must never be called when ObserverV3 is not available");
516 }
517}
518
519void AgentBasePrivate::itemsLinked(const Akonadi::Item::List &items, const Akonadi::Collection &collection)
520{
521 if (!mObserver) {
523 return;
524 }
525
526 auto observer3 = dynamic_cast<AgentBase::ObserverV3 *>(mObserver);
527 if (observer3) {
528 observer3->itemsLinked(items, collection);
529 } else {
530 Q_ASSERT_X(false, Q_FUNC_INFO, "Batch slots must never be called when ObserverV3 is not available");
531 }
532}
533
534void AgentBasePrivate::itemsUnlinked(const Akonadi::Item::List &items, const Akonadi::Collection &collection)
535{
536 if (!mObserver) {
538 return;
539 }
540
541 auto observer3 = dynamic_cast<AgentBase::ObserverV3 *>(mObserver);
542 if (observer3) {
543 observer3->itemsUnlinked(items, collection);
544 } else {
545 Q_ASSERT_X(false, Q_FUNC_INFO, "Batch slots must never be called when ObserverV3 is not available");
546 }
547}
548
549void AgentBasePrivate::tagAdded(const Akonadi::Tag &tag)
550{
551 if (auto tagObserver = dynamic_cast<AgentBase::TagObserver *>(mObserver); tagObserver) {
552 tagObserver->tagAdded(tag);
553 } else {
555 }
556}
557
558void AgentBasePrivate::tagChanged(const Akonadi::Tag &tag)
559{
560 if (auto tagObserver = dynamic_cast<AgentBase::TagObserver *>(mObserver); tagObserver) {
561 tagObserver->tagChanged(tag);
562 } else {
564 }
565}
566
567void AgentBasePrivate::tagRemoved(const Akonadi::Tag &tag)
568{
569 if (auto tagObserver = dynamic_cast<AgentBase::TagObserver *>(mObserver); tagObserver) {
570 tagObserver->tagRemoved(tag);
571 } else {
573 }
574}
575
576void AgentBasePrivate::itemsTagsChanged(const Akonadi::Item::List &items, const QSet<Akonadi::Tag> &addedTags, const QSet<Akonadi::Tag> &removedTags)
577{
578 if (auto tagObserver = dynamic_cast<AgentBase::TagObserver *>(mObserver); tagObserver) {
579 tagObserver->itemsTagsChanged(items, addedTags, removedTags);
580 } else {
582 }
583}
584
585void AgentBasePrivate::collectionAdded(const Akonadi::Collection &collection, const Akonadi::Collection &parent)
586{
587 if (mObserver) {
588 mObserver->collectionAdded(collection, parent);
589 } else {
591 }
592}
593
594void AgentBasePrivate::collectionChanged(const Akonadi::Collection &collection)
595{
596 auto observer2 = dynamic_cast<AgentBase::ObserverV2 *>(mObserver);
597 if (mObserver && observer2 == nullptr) { // For ObserverV2 we use the variant with the part identifiers
598 mObserver->collectionChanged(collection);
599 } else if (!mObserver) {
601 }
602}
603
604void AgentBasePrivate::collectionChanged(const Akonadi::Collection &collection, const QSet<QByteArray> &changedAttributes)
605{
606 auto observer2 = dynamic_cast<AgentBase::ObserverV2 *>(mObserver);
607 if (observer2) {
608 observer2->collectionChanged(collection, changedAttributes);
609 } else {
611 }
612}
613
614void AgentBasePrivate::collectionMoved(const Akonadi::Collection &collection, const Akonadi::Collection &source, const Akonadi::Collection &dest)
615{
616 auto observer2 = dynamic_cast<AgentBase::ObserverV2 *>(mObserver);
617 if (observer2) {
618 observer2->collectionMoved(collection, source, dest);
619 } else if (mObserver) {
620 // ### we cannot just call collectionRemoved here as this will already trigger changeProcessed()
621 // so, just collectionAdded() is good enough as no resource can have implemented intra-resource moves anyway
622 // without using ObserverV2
623 mObserver->collectionAdded(collection, dest);
624 } else {
626 }
627}
628
629void AgentBasePrivate::collectionRemoved(const Akonadi::Collection &collection)
630{
631 if (mObserver) {
632 mObserver->collectionRemoved(collection);
633 } else {
635 }
636}
637
638void AgentBasePrivate::collectionSubscribed(const Akonadi::Collection &collection, const Akonadi::Collection &parent)
639{
640 Q_UNUSED(collection)
641 Q_UNUSED(parent)
643}
644
645void AgentBasePrivate::collectionUnsubscribed(const Akonadi::Collection &collection)
646{
647 Q_UNUSED(collection)
649}
650
651void AgentBasePrivate::changeProcessed()
652{
653 mChangeRecorder->changeProcessed();
654 QTimer::singleShot(0s, mChangeRecorder, &ChangeRecorder::replayNext);
655}
656
657void AgentBasePrivate::slotStatus(int status, const QString &message)
658{
659 mStatusMessage = message;
660 mStatusCode = 0;
661
662 switch (status) {
663 case AgentBase::Idle:
664 if (mStatusMessage.isEmpty()) {
665 mStatusMessage = defaultReadyMessage();
666 }
667
668 mStatusCode = 0;
669 break;
671 if (mStatusMessage.isEmpty()) {
672 mStatusMessage = defaultSyncingMessage();
673 }
674
675 mStatusCode = 1;
676 break;
678 if (mStatusMessage.isEmpty()) {
679 mStatusMessage = defaultErrorMessage();
680 }
681
682 mStatusCode = 2;
683 break;
684
686 if (mStatusMessage.isEmpty()) {
687 mStatusMessage = defaultUnconfiguredMessage();
688 }
689
690 mStatusCode = 3;
691 break;
692
693 default:
694 Q_ASSERT(!"Unknown status passed");
695 break;
696 }
697}
698
699void AgentBasePrivate::slotPercent(int progress)
700{
701 mProgress = progress;
702}
703
704void AgentBasePrivate::slotWarning(const QString &message)
705{
706 mTracer->warning(QStringLiteral("AgentBase(%1)").arg(mId), message);
707}
708
709void AgentBasePrivate::slotError(const QString &message)
710{
711 mTracer->error(QStringLiteral("AgentBase(%1)").arg(mId), message);
712}
713
714void AgentBasePrivate::slotNetworkStatusChange(bool isOnline)
715{
716 Q_UNUSED(isOnline)
717 Q_Q(AgentBase);
718 q->setOnlineInternal(mDesiredOnlineState);
719}
720
721void AgentBasePrivate::slotResumedFromSuspend()
722{
723 if (mNeedsNetwork) {
724 slotNetworkStatusChange(QNetworkInformation::instance()->reachability() != QNetworkInformation::Reachability::Online);
725 }
726}
727
728void AgentBasePrivate::slotTemporaryOfflineTimeout()
729{
730 Q_Q(AgentBase);
731 q->setOnlineInternal(true);
732}
733
734QString AgentBasePrivate::dumpNotificationListToString() const
735{
736 return mChangeRecorder->dumpNotificationListToString();
737}
738
739void AgentBasePrivate::dumpMemoryInfo() const
740{
741 // Send it to stdout, so we can debug user problems.
742 // since you have to explicitly call this
743 // it won't flood users with release builds.
744 QTextStream stream(stdout);
745 stream << dumpMemoryInfoToString();
746}
747
748QString AgentBasePrivate::dumpMemoryInfoToString() const
749{
750 // man mallinfo for more info
751 QString str;
752#if defined __GLIBC__
753 struct mallinfo mi;
754 mi = mallinfo();
755 QTextStream stream(&str);
756 stream << "Total non-mmapped bytes (arena): " << mi.arena << '\n'
757 << "# of free chunks (ordblks): " << mi.ordblks << '\n'
758 << "# of free fastbin blocks (smblks>: " << mi.smblks << '\n'
759 << "# of mapped regions (hblks): " << mi.hblks << '\n'
760 << "Bytes in mapped regions (hblkhd): " << mi.hblkhd << '\n'
761 << "Max. total allocated space (usmblks): " << mi.usmblks << '\n'
762 << "Free bytes held in fastbins (fsmblks):" << mi.fsmblks << '\n'
763 << "Total allocated space (uordblks): " << mi.uordblks << '\n'
764 << "Total free space (fordblks): " << mi.fordblks << '\n'
765 << "Topmost releasable block (keepcost): " << mi.keepcost << '\n';
766#else
767 str = QLatin1StringView("mallinfo() not supported");
768#endif
769 return str;
770}
771
773 : d_ptr(new AgentBasePrivate(this))
774{
775 sAgentBase = this;
776 d_ptr->mId = id;
777 d_ptr->init();
778}
779
780AgentBase::AgentBase(AgentBasePrivate *d, const QString &id)
781 : d_ptr(d)
782{
783 sAgentBase = this;
784 d_ptr->mId = id;
785 d_ptr->init();
786}
787
788AgentBase::~AgentBase() = default;
789
790void AgentBase::debugAgent(int argc, char **argv)
791{
792 Q_UNUSED(argc)
793#ifdef Q_OS_WIN
794 if (qEnvironmentVariableIsSet("AKONADI_DEBUG_WAIT")) {
795 if (QByteArray(argv[0]).endsWith(QByteArray(qgetenv("AKONADI_DEBUG_WAIT") + QByteArrayLiteral(".exe")))) {
796 while (!IsDebuggerPresent()) {
797 std::this_thread::sleep_for(std::chrono::milliseconds(100));
798 }
799 DebugBreak();
800 }
801 }
802#else
803 Q_UNUSED(argv)
804#endif
805}
806
807QString AgentBase::parseArguments(int argc, char **argv)
808{
809 Q_UNUSED(argc)
810
811 QCommandLineOption identifierOption(QStringLiteral("identifier"), i18nc("@info:shell", "Agent identifier"), QStringLiteral("argument"));
812 QCommandLineParser parser;
813 parser.addOption(identifierOption);
814 parser.addHelpOption();
815 parser.addVersionOption();
816 parser.process(*qApp);
817 parser.setApplicationDescription(i18n("Akonadi Agent"));
818
819 if (!parser.isSet(identifierOption)) {
820 qCDebug(AKONADIAGENTBASE_LOG) << "Identifier argument missing";
821 exit(1);
822 }
823
824 const QString identifier = parser.value(identifierOption);
825 if (identifier.isEmpty()) {
826 qCDebug(AKONADIAGENTBASE_LOG) << "Identifier argument is empty";
827 exit(1);
828 }
829
831 QCoreApplication::setApplicationVersion(QStringLiteral(AKONADI_FULL_VERSION));
832
833 const QFileInfo fi(QString::fromLocal8Bit(argv[0]));
834 // strip off full path and possible .exe suffix
835 const QString catalog = fi.baseName();
836
837 auto translator = new QTranslator(qApp);
838 translator->load(catalog);
840
841 return identifier;
842}
843
844/// @endcond
845
847{
850 KLocalizedString::setApplicationDomain(QByteArrayLiteral("libakonadi6"));
851 KAboutData::setApplicationData(r.aboutData());
852
854
855 return qApp->exec();
856}
857
859{
860 Q_D(const AgentBase);
861
862 return d->mStatusCode;
863}
864
866{
867 Q_D(const AgentBase);
868
869 return d->mStatusMessage;
870}
871
873{
874 Q_D(const AgentBase);
875
876 return d->mProgress;
877}
878
880{
881 Q_D(const AgentBase);
882
883 return d->mProgressMessage;
884}
885
887{
888 Q_D(const AgentBase);
889
890 return d->mOnline;
891}
892
893void AgentBase::setNeedsNetwork(bool needsNetwork)
894{
895 Q_D(AgentBase);
896 if (d->mNeedsNetwork == needsNetwork) {
897 return;
898 }
899
900 d->mNeedsNetwork = needsNetwork;
901 QNetworkInformation::loadBackendByFeatures(QNetworkInformation::Feature::Reachability);
903 d->slotNetworkStatusChange(reachability == QNetworkInformation::Reachability::Online);
904 });
905}
906
907void AgentBase::setOnline(bool state)
908{
909 Q_D(AgentBase);
910
911 if (d->mPendingQuit) {
912 return;
913 }
914
915 d->mDesiredOnlineState = state;
916 if (!d->mSettings) {
918 d->mSettings->setValue(QLatin1StringView("Agent/Name"), agentName());
919 }
920 d->mSettings->setValue(QLatin1StringView("Agent/DesiredOnlineState"), state);
921 setOnlineInternal(state);
922}
923
924void AgentBase::setTemporaryOffline(int makeOnlineInSeconds)
925{
926 Q_D(AgentBase);
927
928 // if not currently online, avoid bringing it online after the timeout
929 if (!d->mOnline) {
930 return;
931 }
932
933 setOnlineInternal(false);
934
935 if (!d->mTemporaryOfflineTimer) {
936 d->mTemporaryOfflineTimer = new QTimer(d);
937 d->mTemporaryOfflineTimer->setSingleShot(true);
938 connect(d->mTemporaryOfflineTimer, &QTimer::timeout, d, &AgentBasePrivate::slotTemporaryOfflineTimeout);
939 }
940 d->mTemporaryOfflineTimer->setInterval(std::chrono::seconds{makeOnlineInSeconds});
941 d->mTemporaryOfflineTimer->start();
942}
943
944void AgentBase::setOnlineInternal(bool state)
945{
946 Q_D(AgentBase);
947 if (state && d->mNeedsNetwork) {
948 if (QNetworkInformation::instance()->reachability() != QNetworkInformation::Reachability::Online) {
949 // Don't go online if the resource needs network but there is none
950 state = false;
951 }
952 }
953 d->mOnline = state;
954
955 if (d->mTemporaryOfflineTimer) {
956 d->mTemporaryOfflineTimer->stop();
957 }
958
959 const QString newMessage = d->defaultReadyMessage();
960 if (d->mStatusMessage != newMessage && d->mStatusCode != AgentBase::Broken) {
961 Q_EMIT status(d->mStatusCode, newMessage);
962 }
963
964 doSetOnline(state);
965 Q_EMIT onlineChanged(state);
966}
967
968void AgentBase::doSetOnline(bool online)
969{
970 Q_UNUSED(online)
971}
972
973KAboutData AgentBase::aboutData() const
974{
975 // akonadi_google_resource_1 -> org.kde.akonadi_google_resource
976 const QString desktopEntry = QLatin1StringView("org.kde.") + qApp->applicationName().remove(QRegularExpression(QStringLiteral("_[0-9]+$")));
977
978 KAboutData data(qApp->applicationName(), agentName(), qApp->applicationVersion());
979 data.setDesktopFileName(desktopEntry);
980 return data;
981}
982
983void AgentBase::configure(WId windowId)
984{
985 Q_UNUSED(windowId)
986
987 // Fallback if the agent implements the new plugin-based configuration,
988 // but someone calls the deprecated configure() method
989 auto instance = Akonadi::AgentManager::self()->instance(identifier());
990 QPointer<AgentConfigurationDialog> dialog = new AgentConfigurationDialog(instance, nullptr);
991 if (dialog->exec()) {
993 } else {
995 }
996 delete dialog;
997}
998
999#ifdef Q_OS_WIN // krazy:exclude=cpp
1000void AgentBase::configure(qlonglong windowId)
1001{
1002 configure(static_cast<WId>(windowId));
1003}
1004#endif
1005
1007{
1008 const bool registered = QDBusConnection::sessionBus().interface()->isServiceRegistered(QStringLiteral("org.freedesktop.akonaditray"));
1009 if (!registered) {
1010 return 0;
1011 }
1012
1013 QDBusInterface dbus(QStringLiteral("org.freedesktop.akonaditray"), QStringLiteral("/Actions"), QStringLiteral("org.freedesktop.Akonadi.Tray"));
1014 const QDBusMessage reply = dbus.call(QStringLiteral("getWinId"));
1015
1016 if (reply.type() == QDBusMessage::ErrorMessage) {
1017 return 0;
1018 }
1019
1020 const WId winid = static_cast<WId>(reply.arguments().at(0).toLongLong());
1021
1022 return winid;
1023}
1024
1025void AgentBase::quit()
1026{
1027 Q_D(AgentBase);
1028 aboutToQuit();
1029
1030 if (d->mSettings) {
1031 d->mChangeRecorder->setConfig(nullptr);
1032 d->mSettings->sync();
1033 delete d->mSettings;
1034 d->mSettings = nullptr;
1035 }
1036
1037 delete d->mEventLoopLocker;
1038 d->mEventLoopLocker = nullptr;
1039}
1040
1042{
1043 Q_D(AgentBase);
1044 d->mPendingQuit = true;
1045}
1046
1048{
1049 Q_D(AgentBase);
1050 // prevent the monitor from picking up deletion signals for our own data if we are a resource
1051 // and thus avoid that we kill our own data as last act before our own death
1052 d->mChangeRecorder->blockSignals(true);
1053
1054 aboutToQuit();
1055
1056 const QString fileName = d->mSettings->fileName();
1057
1058 /*
1059 * First destroy the settings object...
1060 */
1061 d->mChangeRecorder->setConfig(nullptr);
1062 delete d->mSettings;
1063 d->mSettings = nullptr;
1064
1065 /*
1066 * ... then remove the file from hd.
1067 */
1068 if (!QFile::remove(fileName)) {
1069 qCWarning(AKONADIAGENTBASE_LOG) << "Impossible to remove " << fileName;
1070 }
1071
1072 /*
1073 * ... and remove the changes file from hd.
1074 */
1075 const QString changeDataFileName = fileName + QStringLiteral("_changes.dat");
1076 if (!QFile::remove(changeDataFileName)) {
1077 qCWarning(AKONADIAGENTBASE_LOG) << "Impossible to remove " << changeDataFileName;
1078 }
1079
1080 /*
1081 * ... and also remove the agent configuration file if there is one.
1082 */
1084 if (!QFile::remove(configFile)) {
1085 qCWarning(AKONADIAGENTBASE_LOG) << "Impossible to remove config file " << configFile;
1086 }
1087
1088 delete d->mEventLoopLocker;
1089 d->mEventLoopLocker = nullptr;
1090}
1091
1093{
1094 Q_D(AgentBase);
1095
1096 // TODO in theory we should re-connect change recorder signals here that we disconnected previously
1097 d->mObserver = observer;
1098
1099 const bool hasObserverV3 = (dynamic_cast<AgentBase::ObserverV3 *>(d->mObserver) != nullptr);
1100 const bool hasTagObserver = (dynamic_cast<AgentBase::TagObserver *>(d->mObserver) != nullptr);
1101
1102 disconnect(d->mChangeRecorder, &Monitor::tagAdded, d, &AgentBasePrivate::tagAdded);
1103 disconnect(d->mChangeRecorder, &Monitor::tagChanged, d, &AgentBasePrivate::tagChanged);
1104 disconnect(d->mChangeRecorder, &Monitor::tagRemoved, d, &AgentBasePrivate::tagRemoved);
1105 disconnect(d->mChangeRecorder, &Monitor::itemsTagsChanged, d, &AgentBasePrivate::itemsTagsChanged);
1106 disconnect(d->mChangeRecorder, &Monitor::itemsFlagsChanged, d, &AgentBasePrivate::itemsFlagsChanged);
1107 disconnect(d->mChangeRecorder, &Monitor::itemsMoved, d, &AgentBasePrivate::itemsMoved);
1108 disconnect(d->mChangeRecorder, &Monitor::itemsRemoved, d, &AgentBasePrivate::itemsRemoved);
1109 disconnect(d->mChangeRecorder, &Monitor::itemsLinked, d, &AgentBasePrivate::itemsLinked);
1110 disconnect(d->mChangeRecorder, &Monitor::itemsUnlinked, d, &AgentBasePrivate::itemsUnlinked);
1111 disconnect(d->mChangeRecorder, &Monitor::itemMoved, d, &AgentBasePrivate::itemMoved);
1112 disconnect(d->mChangeRecorder, &Monitor::itemRemoved, d, &AgentBasePrivate::itemRemoved);
1113 disconnect(d->mChangeRecorder, &Monitor::itemLinked, d, &AgentBasePrivate::itemLinked);
1114 disconnect(d->mChangeRecorder, &Monitor::itemUnlinked, d, &AgentBasePrivate::itemUnlinked);
1115
1116 if (hasTagObserver) {
1117 connect(d->mChangeRecorder, &Monitor::tagAdded, d, &AgentBasePrivate::tagAdded);
1118 connect(d->mChangeRecorder, &Monitor::tagChanged, d, &AgentBasePrivate::tagChanged);
1119 connect(d->mChangeRecorder, &Monitor::tagRemoved, d, &AgentBasePrivate::tagRemoved);
1120 connect(d->mChangeRecorder, &Monitor::itemsTagsChanged, d, &AgentBasePrivate::itemsTagsChanged);
1121
1122 // If the agent has a TagObserver, we assume it wants to receive everything tag-related.
1123 d->mChangeRecorder->itemFetchScope().setFetchTags(true);
1124 d->mChangeRecorder->tagFetchScope().setFetchAllAttributes(true);
1125 d->mChangeRecorder->tagFetchScope().setFetchRemoteId(true);
1126 }
1127
1128 if (hasObserverV3) {
1129 connect(d->mChangeRecorder, &Monitor::itemsFlagsChanged, d, &AgentBasePrivate::itemsFlagsChanged);
1130 connect(d->mChangeRecorder, &Monitor::itemsMoved, d, &AgentBasePrivate::itemsMoved);
1131 connect(d->mChangeRecorder, &Monitor::itemsRemoved, d, &AgentBasePrivate::itemsRemoved);
1132 connect(d->mChangeRecorder, &Monitor::itemsLinked, d, &AgentBasePrivate::itemsLinked);
1133 connect(d->mChangeRecorder, &Monitor::itemsUnlinked, d, &AgentBasePrivate::itemsUnlinked);
1134 } else {
1135 // V2 - don't connect these if we have V3
1136 connect(d->mChangeRecorder, &Monitor::itemMoved, d, &AgentBasePrivate::itemMoved);
1137 connect(d->mChangeRecorder, &Monitor::itemRemoved, d, &AgentBasePrivate::itemRemoved);
1138 connect(d->mChangeRecorder, &Monitor::itemLinked, d, &AgentBasePrivate::itemLinked);
1139 connect(d->mChangeRecorder, &Monitor::itemUnlinked, d, &AgentBasePrivate::itemUnlinked);
1140 }
1141}
1142
1144{
1145 return d_ptr->mId;
1146}
1147
1149{
1150 Q_D(AgentBase);
1151 if (name == d->mName) {
1152 return;
1153 }
1154
1155 // TODO: rename collection
1156 d->mName = name;
1157
1158 if (d->mName.isEmpty() || d->mName == d->mId) {
1159 d->mSettings->remove(QLatin1StringView("Resource/Name"));
1160 d->mSettings->remove(QLatin1StringView("Agent/Name"));
1161 } else {
1162 d->mSettings->setValue(QLatin1StringView("Agent/Name"), d->mName);
1163 }
1164
1165 d->mSettings->sync();
1166
1167 d->setProgramName();
1168
1169 Q_EMIT agentNameChanged(d->mName);
1170}
1171
1173{
1174 Q_D(const AgentBase);
1175 if (d->mName.isEmpty()) {
1176 return d->mId;
1177 } else {
1178 return d->mName;
1179 }
1180}
1181
1183{
1184 Q_D(AgentBase);
1185 if (activities == d->mActivities) {
1186 return;
1187 }
1188
1189 d->mActivities = activities;
1190 if (d->mActivities.isEmpty()) {
1191 d->mSettings->remove(QStringLiteral("Agent/Activities"));
1192 } else {
1193 d->mSettings->setValue(QStringLiteral("Agent/Activities"), d->mActivities);
1194 }
1195 Q_EMIT agentActivitiesChanged(d->mActivities);
1196}
1197
1199{
1200 Q_D(const AgentBase);
1201 return d->mActivities;
1202}
1203
1205{
1206 Q_D(const AgentBase);
1207 return d->mActivitiesEnabled;
1208}
1209
1211{
1212 Q_D(AgentBase);
1213 if (enabled == d->mActivitiesEnabled) {
1214 return;
1215 }
1216
1217 d->mActivitiesEnabled = enabled;
1218 d->mSettings->setValue(QStringLiteral("Agent/ActivitiesEnabled"), enabled);
1219 Q_EMIT agentActivitiesEnabledChanged(d->mActivitiesEnabled);
1220}
1221
1223{
1224 Q_D(AgentBase);
1225 d->changeProcessed();
1226}
1227
1229{
1230 return d_ptr->mChangeRecorder;
1231}
1232
1233KSharedConfigPtr AgentBase::config()
1234{
1236}
1237
1238void AgentBase::abort()
1239{
1241}
1242
1243void AgentBase::reconfigure()
1244{
1246}
1247
1248#include "moc_agentbase.cpp"
1249#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:63
virtual void collectionAdded(const Akonadi::Collection &collection, const Akonadi::Collection &parent)
Reimplement to handle adding of new collections.
Definition agentbase.cpp:93
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:59
virtual void itemAdded(const Akonadi::Item &item, const Akonadi::Collection &collection)
Reimplement to handle adding of new items.
Definition agentbase.cpp:67
virtual void itemChanged(const Akonadi::Item &item, const QSet< QByteArray > &partIdentifiers)
Reimplement to handle changes to existing items.
Definition agentbase.cpp:76
virtual void itemRemoved(const Akonadi::Item &item)
Reimplement to handle deletion of items.
Definition agentbase.cpp:85
The base class for all Akonadi agents and resources.
Definition agentbase.h:73
void agentActivitiesEnabledChanged(bool enabled)
This signal is emitted whenever the user has changed enabled activities.
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.
QStringList activities() const
Returns the activities of the agent.
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...
void agentActivitiesChanged(const QStringList &activities)
This signal is emitted whenever the user has changed activities.
void setActivities(const QStringList &activities)
This method is used to set the activities of the agent.
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.
void setActivitiesEnabled(bool enabled)
This method is used to enabled the activities of the agent.
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.
bool activitiesEnabled() const
Returns the activities status of the agent.
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 initTheme()
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.
KCRASH_EXPORT void initialize()
void initStyle()
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)
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 Dec 6 2024 12:00:59 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.