Akonadi

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

KDE's Doxygen guidelines are available online.