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

KDE's Doxygen guidelines are available online.