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

KDE's Doxygen guidelines are available online.