Akonadi

notificationcollector.cpp
1/*
2 SPDX-FileCopyrightText: 2006-2007 Volker Krause <vkrause@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#include "notificationcollector.h"
8#include "aggregatedfetchscope.h"
9#include "akonadi.h"
10#include "cachecleaner.h"
11#include "connection.h"
12#include "handler/itemfetchhelper.h"
13#include "handlerhelper.h"
14#include "intervalcheck.h"
15#include "notificationmanager.h"
16#include "search/searchmanager.h"
17#include "selectquerybuilder.h"
18#include "shared/akranges.h"
19#include "storage/collectionstatistics.h"
20#include "storage/datastore.h"
21#include "storage/entity.h"
22
23#include "akonadiserver_debug.h"
24
25#include <QScopedValueRollback>
26
27using namespace Akonadi;
28using namespace Akonadi::Server;
29
31 : mDb(db)
32 , mAkonadi(akonadi)
33{
35 if (!mIgnoreTransactions) {
37 }
38 });
40 if (!mIgnoreTransactions) {
41 clear();
42 }
43 });
44}
45
46void NotificationCollector::itemAdded(const PimItem &item, bool seen, const Collection &collection, const QByteArray &resource)
47{
48 mAkonadi.searchManager().scheduleSearchUpdate();
49 mAkonadi.collectionStatistics().itemAdded(collection, item.size(), seen);
50 itemNotification(Protocol::ItemChangeNotification::Add, item, collection, Collection(), resource);
51}
52
53void NotificationCollector::itemChanged(const PimItem &item, const QSet<QByteArray> &changedParts, const Collection &collection, const QByteArray &resource)
54{
55 mAkonadi.searchManager().scheduleSearchUpdate();
56 itemNotification(Protocol::ItemChangeNotification::Modify, item, collection, Collection(), resource, changedParts);
57}
58
59void NotificationCollector::itemsFlagsChanged(const PimItem::List &items,
60 const QSet<QByteArray> &addedFlags,
61 const QSet<QByteArray> &removedFlags,
62 const Collection &collection,
63 const QByteArray &resource)
64{
65 int seenCount = (addedFlags.contains(AKONADI_FLAG_SEEN) || addedFlags.contains(AKONADI_FLAG_IGNORED) ? items.count() : 0);
66 seenCount -= (removedFlags.contains(AKONADI_FLAG_SEEN) || removedFlags.contains(AKONADI_FLAG_IGNORED) ? items.count() : 0);
67
68 mAkonadi.collectionStatistics().itemsSeenChanged(collection, seenCount);
69 itemNotification(Protocol::ItemChangeNotification::ModifyFlags, items, collection, Collection(), resource, QSet<QByteArray>(), addedFlags, removedFlags);
70}
71
72void NotificationCollector::itemsTagsChanged(const PimItem::List &items,
73 const QSet<qint64> &addedTags,
74 const QSet<qint64> &removedTags,
75 const Collection &collection,
76 const QByteArray &resource)
77{
78 itemNotification(Protocol::ItemChangeNotification::ModifyTags,
79 items,
80 collection,
81 Collection(),
82 resource,
86 addedTags,
87 removedTags);
88}
89
90void NotificationCollector::itemsRelationsChanged(const PimItem::List &items,
91 const Relation::List &addedRelations,
92 const Relation::List &removedRelations,
93 const Collection &collection,
94 const QByteArray &resource)
95{
96 itemNotification(Protocol::ItemChangeNotification::ModifyRelations,
97 items,
98 collection,
99 Collection(),
100 resource,
104 QSet<qint64>(),
105 QSet<qint64>(),
106 addedRelations,
107 removedRelations);
108}
109
110void NotificationCollector::itemsMoved(const PimItem::List &items,
111 const Collection &collectionSrc,
112 const Collection &collectionDest,
113 const QByteArray &sourceResource)
114{
115 mAkonadi.searchManager().scheduleSearchUpdate();
116 itemNotification(Protocol::ItemChangeNotification::Move, items, collectionSrc, collectionDest, sourceResource);
117}
118
119void NotificationCollector::itemsRemoved(const PimItem::List &items, const Collection &collection, const QByteArray &resource)
120{
121 itemNotification(Protocol::ItemChangeNotification::Remove, items, collection, Collection(), resource);
122}
123
124void NotificationCollector::itemsLinked(const PimItem::List &items, const Collection &collection)
125{
126 itemNotification(Protocol::ItemChangeNotification::Link, items, collection, Collection(), QByteArray());
127}
128
129void NotificationCollector::itemsUnlinked(const PimItem::List &items, const Collection &collection)
130{
131 itemNotification(Protocol::ItemChangeNotification::Unlink, items, collection, Collection(), QByteArray());
132}
133
134void NotificationCollector::collectionAdded(const Collection &collection, const QByteArray &resource)
135{
136 if (auto cleaner = mAkonadi.cacheCleaner()) {
137 cleaner->collectionAdded(collection.id());
138 }
139 mAkonadi.intervalChecker().collectionAdded(collection.id());
140 collectionNotification(Protocol::CollectionChangeNotification::Add, collection, collection.parentId(), -1, resource);
141}
142
143void NotificationCollector::collectionChanged(const Collection &collection, const QList<QByteArray> &changes, const QByteArray &resource)
144{
145 if (auto cleaner = mAkonadi.cacheCleaner()) {
146 cleaner->collectionChanged(collection.id());
147 }
148 mAkonadi.intervalChecker().collectionChanged(collection.id());
149 if (changes.contains(AKONADI_PARAM_ENABLED)) {
150 mAkonadi.collectionStatistics().invalidateCollection(collection);
151 }
152 collectionNotification(Protocol::CollectionChangeNotification::Modify,
153 collection,
154 collection.parentId(),
155 -1,
156 resource,
157 changes | AkRanges::Actions::toQSet);
158}
159
160void NotificationCollector::collectionMoved(const Collection &collection, const Collection &source, const QByteArray &resource, const QByteArray &destResource)
161{
162 if (auto cleaner = mAkonadi.cacheCleaner()) {
163 cleaner->collectionChanged(collection.id());
164 }
165 mAkonadi.intervalChecker().collectionChanged(collection.id());
166 collectionNotification(Protocol::CollectionChangeNotification::Move,
167 collection,
168 source.id(),
169 collection.parentId(),
170 resource,
172 destResource);
173}
174
175void NotificationCollector::collectionRemoved(const Collection &collection, const QByteArray &resource)
176{
177 if (auto cleaner = mAkonadi.cacheCleaner()) {
178 cleaner->collectionRemoved(collection.id());
179 }
180 mAkonadi.intervalChecker().collectionRemoved(collection.id());
181 mAkonadi.collectionStatistics().invalidateCollection(collection);
182 collectionNotification(Protocol::CollectionChangeNotification::Remove, collection, collection.parentId(), -1, resource);
183}
184
186{
187 if (auto cleaner = mAkonadi.cacheCleaner()) {
188 cleaner->collectionAdded(collection.id());
189 }
190 mAkonadi.intervalChecker().collectionAdded(collection.id());
191 collectionNotification(Protocol::CollectionChangeNotification::Subscribe, collection, collection.parentId(), -1, resource, QSet<QByteArray>());
192}
193
195{
196 if (auto cleaner = mAkonadi.cacheCleaner()) {
197 cleaner->collectionRemoved(collection.id());
198 }
199 mAkonadi.intervalChecker().collectionRemoved(collection.id());
200 mAkonadi.collectionStatistics().invalidateCollection(collection);
201 collectionNotification(Protocol::CollectionChangeNotification::Unsubscribe, collection, collection.parentId(), -1, resource, QSet<QByteArray>());
202}
203
205{
206 tagNotification(Protocol::TagChangeNotification::Add, tag);
207}
208
210{
211 tagNotification(Protocol::TagChangeNotification::Modify, tag);
212}
213
214void NotificationCollector::tagRemoved(const Tag &tag, const QByteArray &resource, const QString &remoteId)
215{
216 tagNotification(Protocol::TagChangeNotification::Remove, tag, resource, remoteId);
217}
218
220{
221 relationNotification(Protocol::RelationChangeNotification::Add, relation);
222}
223
225{
226 relationNotification(Protocol::RelationChangeNotification::Remove, relation);
227}
228
229void NotificationCollector::clear()
230{
231 mNotifications.clear();
232}
233
235{
236 mConnection = connection;
237}
238
239void NotificationCollector::itemNotification(Protocol::ItemChangeNotification::Operation op,
240 const PimItem &item,
241 const Collection &collection,
242 const Collection &collectionDest,
243 const QByteArray &resource,
244 const QSet<QByteArray> &parts)
245{
246 if (!item.isValid()) {
247 return;
248 }
249 itemNotification(op, PimItem::List{item}, collection, collectionDest, resource, parts);
250}
251
252void NotificationCollector::itemNotification(Protocol::ItemChangeNotification::Operation op,
253 const PimItem::List &items,
254 const Collection &collection,
255 const Collection &collectionDest,
256 const QByteArray &resource,
257 const QSet<QByteArray> &parts,
258 const QSet<QByteArray> &addedFlags,
259 const QSet<QByteArray> &removedFlags,
260 const QSet<qint64> &addedTags,
261 const QSet<qint64> &removedTags,
262 const Relation::List &addedRelations,
263 const Relation::List &removedRelations)
264{
265 if (items.empty()) {
266 return;
267 }
268
270
271 if ((op == Protocol::ItemChangeNotification::Modify) || (op == Protocol::ItemChangeNotification::ModifyFlags)
272 || (op == Protocol::ItemChangeNotification::ModifyTags) || (op == Protocol::ItemChangeNotification::ModifyRelations)) {
273 vCollections = DataStore::self()->virtualCollections(items);
274 }
275
276 auto msg = Protocol::ItemChangeNotificationPtr::create();
277 if (mConnection) {
278 msg->setSessionId(mConnection->sessionId());
279 }
280 msg->setOperation(op);
281
282 msg->setItemParts(parts);
283 msg->setAddedFlags(addedFlags);
284 msg->setRemovedFlags(removedFlags);
285 msg->setAddedTags(addedTags);
286 msg->setRemovedTags(removedTags);
287 if (!addedRelations.isEmpty()) {
289 rels.reserve(addedRelations.size());
290 for (const Relation &rel : addedRelations) {
291 rels.insert(Protocol::ItemChangeNotification::Relation(rel.leftId(), rel.rightId(), rel.relationType().name()));
292 }
293 msg->setAddedRelations(rels);
294 }
295 if (!removedRelations.isEmpty()) {
297 rels.reserve(removedRelations.size());
298 for (const Relation &rel : removedRelations) {
299 rels.insert(Protocol::ItemChangeNotification::Relation(rel.leftId(), rel.rightId(), rel.relationType().name()));
300 }
301 msg->setRemovedRelations(rels);
302 }
303
304 if (collectionDest.isValid()) {
305 QByteArray destResourceName;
306 destResourceName = collectionDest.resource().name().toLatin1();
307 msg->setDestinationResource(destResourceName);
308 }
309
310 msg->setParentDestCollection(collectionDest.id());
311
313 ntfItems.reserve(items.size());
314 for (const PimItem &item : items) {
315 Protocol::FetchItemsResponse i;
316 i.setId(item.id());
317 i.setRemoteId(item.remoteId());
318 i.setRemoteRevision(item.remoteRevision());
319 i.setMimeType(item.mimeType().name());
320 ntfItems.push_back(std::move(i));
321 }
322
323 /* Notify all virtual collections the items are linked to. */
325 virtItems.reserve(ntfItems.size());
326 for (const auto &ntfItem : ntfItems) {
327 virtItems.insert(ntfItem.id(), ntfItem);
328 }
329 for (auto iter = vCollections.cbegin(), end = vCollections.constEnd(); iter != end; ++iter) {
330 auto copy = Protocol::ItemChangeNotificationPtr::create(*msg);
332 items.reserve(iter->size());
333 for (const auto &item : std::as_const(*iter)) {
334 items.append(virtItems.value(item.id()));
335 }
336 copy->setItems(items);
337 copy->setParentCollection(iter.key());
338 copy->setResource(resource);
339
340 mAkonadi.collectionStatistics().invalidateCollection(Collection::retrieveById(iter.key()));
341 dispatchNotification(copy);
342 }
343
344 msg->setItems(ntfItems);
345
346 Collection col;
347 if (!collection.isValid()) {
348 msg->setParentCollection(items.first().collection().id());
349 col = items.first().collection();
350 } else {
351 msg->setParentCollection(collection.id());
352 col = collection;
353 }
354
355 QByteArray res = resource;
356 if (res.isEmpty()) {
357 if (col.resourceId() <= 0) {
358 col = Collection::retrieveById(col.id());
359 }
360 res = col.resource().name().toLatin1();
361 }
362 msg->setResource(res);
363
364 // Add and ModifyFlags are handled incrementally
365 // (see itemAdded() and itemsFlagsChanged())
366 if (msg->operation() != Protocol::ItemChangeNotification::Add && msg->operation() != Protocol::ItemChangeNotification::ModifyFlags) {
367 mAkonadi.collectionStatistics().invalidateCollection(col);
368 }
369 dispatchNotification(msg);
370}
371
372void NotificationCollector::collectionNotification(Protocol::CollectionChangeNotification::Operation op,
373 const Collection &collection,
374 Collection::Id source,
375 Collection::Id destination,
376 const QByteArray &resource,
377 const QSet<QByteArray> &changes,
378 const QByteArray &destResource)
379{
380 if (!collection.isValid()) {
381 return;
382 }
383
384 auto msg = Protocol::CollectionChangeNotificationPtr::create();
385 msg->setOperation(op);
386 if (mConnection) {
387 msg->setSessionId(mConnection->sessionId());
388 }
389 msg->setParentCollection(source);
390 msg->setParentDestCollection(destination);
391 msg->setDestinationResource(destResource);
392 msg->setChangedParts(changes);
393
394 auto msgCollection = HandlerHelper::fetchCollectionsResponse(mAkonadi, collection);
395 if (auto mgr = mAkonadi.notificationManager()) {
396 auto fetchScope = mgr->collectionFetchScope();
397 // Make sure we have all the data
398 if (!fetchScope->fetchIdOnly() && msgCollection.name().isEmpty()) {
399 const auto col = Collection::retrieveById(msgCollection.id());
400 const auto mts = col.mimeTypes();
401 QStringList mimeTypes;
402 mimeTypes.reserve(mts.size());
403 for (const auto &mt : mts) {
404 mimeTypes.push_back(mt.name());
405 }
406 msgCollection = HandlerHelper::fetchCollectionsResponse(mAkonadi, col, {}, false, 0, {}, {}, mimeTypes);
407 }
408 // Get up-to-date statistics
409 if (fetchScope->fetchStatistics()) {
410 Collection col;
411 col.setId(msgCollection.id());
412 const auto stats = mAkonadi.collectionStatistics().statistics(col);
413 msgCollection.setStatistics(Protocol::FetchCollectionStatsResponse(stats.count, stats.count - stats.read, stats.size));
414 }
415 // Get attributes
416 const auto requestedAttrs = fetchScope->attributes();
417 auto msgColAttrs = msgCollection.attributes();
418 // TODO: This assumes that we have either none or all attributes in msgCollection
419 if (msgColAttrs.isEmpty() && !requestedAttrs.isEmpty()) {
421 qb.addColumn(CollectionAttribute::typeFullColumnName());
422 qb.addColumn(CollectionAttribute::valueFullColumnName());
423 qb.addValueCondition(CollectionAttribute::collectionIdFullColumnName(), Query::Equals, msgCollection.id());
424 Query::Condition cond(Query::Or);
425 for (const auto &attr : requestedAttrs) {
426 cond.addValueCondition(CollectionAttribute::typeFullColumnName(), Query::Equals, attr);
427 }
428 qb.addCondition(cond);
429 if (!qb.exec()) {
430 qCWarning(AKONADISERVER_LOG) << "NotificationCollector failed to query attributes for Collection" << collection.name() << "(ID"
431 << collection.id() << ")";
432 }
433 const auto attrs = qb.result();
434 for (const auto &attr : attrs) {
435 msgColAttrs.insert(attr.type(), attr.value());
436 }
437 msgCollection.setAttributes(msgColAttrs);
438 }
439 }
440 msg->setCollection(std::move(msgCollection));
441
442 if (!collection.enabled()) {
443 msg->addMetadata("DISABLED");
444 }
445
446 QByteArray res = resource;
447 if (res.isEmpty()) {
448 res = collection.resource().name().toLatin1();
449 }
450 msg->setResource(res);
451
452 dispatchNotification(msg);
453}
454
455void NotificationCollector::tagNotification(Protocol::TagChangeNotification::Operation op, const Tag &tag, const QByteArray &resource, const QString &remoteId)
456{
457 if (!tag.isValid()) {
458 return;
459 }
460
461 auto msg = Protocol::TagChangeNotificationPtr::create();
462 msg->setOperation(op);
463 if (mConnection) {
464 msg->setSessionId(mConnection->sessionId());
465 }
466 msg->setResource(resource);
467 Protocol::FetchTagsResponse msgTag;
468 msgTag.setId(tag.id());
469 msgTag.setRemoteId(remoteId.toUtf8());
470 msgTag.setParentId(tag.parentId());
471 if (auto mgr = mAkonadi.notificationManager()) {
472 auto fetchScope = mgr->tagFetchScope();
473 if (!fetchScope->fetchIdOnly() && msgTag.gid().isEmpty()) {
474 msgTag = HandlerHelper::fetchTagsResponse(Tag::retrieveById(msgTag.id()), fetchScope->toFetchScope(), mConnection);
475 }
476
477 const auto requestedAttrs = fetchScope->attributes();
478 auto msgTagAttrs = msgTag.attributes();
479 if (msgTagAttrs.isEmpty() && !requestedAttrs.isEmpty()) {
481 qb.addColumn(TagAttribute::typeFullColumnName());
482 qb.addColumn(TagAttribute::valueFullColumnName());
483 qb.addValueCondition(TagAttribute::tagIdFullColumnName(), Query::Equals, msgTag.id());
484 Query::Condition cond(Query::Or);
485 for (const auto &attr : requestedAttrs) {
486 cond.addValueCondition(TagAttribute::typeFullColumnName(), Query::Equals, attr);
487 }
488 qb.addCondition(cond);
489 if (!qb.exec()) {
490 qCWarning(AKONADISERVER_LOG) << "NotificationCollection failed to query attributes for Tag" << tag.id();
491 }
492 const auto attrs = qb.result();
493 for (const auto &attr : attrs) {
494 msgTagAttrs.insert(attr.type(), attr.value());
495 }
496 msgTag.setAttributes(msgTagAttrs);
497 }
498 }
499 msg->setTag(std::move(msgTag));
500
501 dispatchNotification(msg);
502}
503
504void NotificationCollector::relationNotification(Protocol::RelationChangeNotification::Operation op, const Relation &relation)
505{
506 auto msg = Protocol::RelationChangeNotificationPtr::create();
507 msg->setOperation(op);
508 if (mConnection) {
509 msg->setSessionId(mConnection->sessionId());
510 }
511 msg->setRelation(HandlerHelper::fetchRelationsResponse(relation));
512
513 dispatchNotification(msg);
514}
515
516void NotificationCollector::completeNotification(const Protocol::ChangeNotificationPtr &changeMsg)
517{
518 if (changeMsg->type() == Protocol::Command::ItemChangeNotification) {
519 const auto msg = changeMsg.staticCast<Protocol::ItemChangeNotification>();
520 auto const mgr = mAkonadi.notificationManager();
521 if (mgr && msg->operation() != Protocol::ItemChangeNotification::Remove) {
522 if (mDb->inTransaction()) {
523 qCWarning(AKONADISERVER_LOG) << "NotificationCollector requested FetchHelper from within a transaction."
524 << "Aborting since this would deadlock!";
525 return;
526 }
527 auto fetchScope = mgr->itemFetchScope();
528 // NOTE: Checking and retrieving missing elements for each Item manually
529 // here would require a complex code (and I'm too lazy), so instead we simply
530 // feed the Items to FetchHelper and retrieve them all with the setup from
531 // the aggregated fetch scope. The worst case is that we re-fetch everything
532 // we already have, but that's still better than the pre-ntf-payload situation
533 QList<qint64> ids;
534 const auto items = msg->items();
535 ids.reserve(items.size());
536 bool allHaveRID = true;
537 for (const auto &item : items) {
538 ids.push_back(item.id());
539 allHaveRID &= !item.remoteId().isEmpty();
540 }
541
542 // FetchHelper may trigger ItemRetriever, which needs RemoteID. If we
543 // don't have one (maybe because the Resource has not stored it yet,
544 // we emit a notification without it and leave it up to the Monitor
545 // to retrieve the Item on demand - we should have a RID stored in
546 // Akonadi by then.
547 if (mConnection && (allHaveRID || msg->operation() != Protocol::ItemChangeNotification::Add)) {
548 // Prevent transactions inside FetchHelper to recursively call our slot
549 QScopedValueRollback<bool> ignoreTransactions(mIgnoreTransactions);
550 mIgnoreTransactions = true;
551 CommandContext context;
552 auto itemFetchScope = fetchScope->toFetchScope();
553 auto tagFetchScope = mgr->tagFetchScope()->toFetchScope();
554 itemFetchScope.setFetch(Protocol::ItemFetchScope::CacheOnly);
555 ItemFetchHelper helper(mConnection, context, Scope(ids), itemFetchScope, tagFetchScope, mAkonadi);
556 // The Item was just changed, which means the atime was
557 // updated, no need to do it again a couple milliseconds later.
558 helper.disableATimeUpdates();
560 auto callback = [&fetchedItems](Protocol::FetchItemsResponse &&cmd) {
561 fetchedItems.push_back(std::move(cmd));
562 };
563 if (helper.fetchItems(std::move(callback))) {
564 msg->setItems(fetchedItems);
565 } else {
566 qCWarning(AKONADISERVER_LOG) << "NotificationCollector railed to retrieve Items for notification!";
567 }
568 } else {
570 fetchedItems.reserve(items.size());
571 for (const auto &item : items) {
572 Protocol::FetchItemsResponse resp;
573 resp.setId(item.id());
574 resp.setRevision(item.revision());
575 resp.setMimeType(item.mimeType());
576 resp.setParentId(item.parentId());
577 resp.setGid(item.gid());
578 resp.setSize(item.size());
579 resp.setMTime(item.mTime());
580 resp.setFlags(item.flags());
581 fetchedItems.push_back(std::move(resp));
582 }
583 msg->setItems(fetchedItems);
584 msg->setMustRetrieve(true);
585 }
586 }
587 }
588}
589
590void NotificationCollector::dispatchNotification(const Protocol::ChangeNotificationPtr &msg)
591{
592 if (!mDb || mDb->inTransaction()) {
593 if (msg->type() == Protocol::Command::CollectionChangeNotification) {
594 Protocol::CollectionChangeNotification::appendAndCompress(mNotifications, msg);
595 } else {
596 mNotifications.append(msg);
597 }
598 } else {
599 completeNotification(msg);
600 notify({msg});
601 }
602}
603
605{
606 if (!mNotifications.isEmpty()) {
607 for (auto &ntf : mNotifications) {
608 completeNotification(ntf);
609 }
610 notify(std::move(mNotifications));
611 clear();
612 return true;
613 }
614
615 return false;
616}
617
618void NotificationCollector::notify(Protocol::ChangeNotificationList &&msgs)
619{
620 if (auto mgr = mAkonadi.notificationManager()) {
621 QMetaObject::invokeMethod(mgr, "slotNotify", Qt::QueuedConnection, Q_ARG(Akonadi::Protocol::ChangeNotificationList, msgs));
622 }
623}
Represents a collection of PIM items.
Definition collection.h:62
qint64 Id
Describes the unique id type.
Definition collection.h:79
void setParentCollection(const Collection &parent)
Set the parent collection of this object.
void setId(Id identifier)
Sets the unique identifier of the collection.
An Akonadi Relation.
Definition relation.h:41
An Connection represents one connection of a client to the server.
Definition connection.h:39
This class handles all the database access.
Definition datastore.h:95
QList< Collection > virtualCollections(const PimItem &item)
Returns all virtual collections the item is linked to.
bool inTransaction() const
Returns true if there is a transaction in progress.
static DataStore * self()
Per thread singleton.
void transactionRolledBack()
Emitted if a transaction has been aborted.
void transactionCommitted()
Emitted if a transaction has been successfully committed.
static Protocol::FetchCollectionsResponse fetchCollectionsResponse(AkonadiServer &akonadi, const Collection &col)
Returns the protocol representation of the given collection.
void collectionRemoved(const Collection &collection, const QByteArray &resource=QByteArray())
Notify about a removed collection.
void itemsMoved(const PimItem::List &items, const Collection &collectionSrc=Collection(), const Collection &collectionDest=Collection(), const QByteArray &sourceResource=QByteArray())
Notify about moved items Provide as many parameters as you have at hand currently,...
void itemsRelationsChanged(const PimItem::List &items, const Relation::List &addedRelations, const Relation::List &removedRelations, const Collection &collection=Collection(), const QByteArray &resource=QByteArray())
Notify about changed items relations.
void tagRemoved(const Tag &tag, const QByteArray &resource, const QString &remoteId)
Notify about a removed tag.
void itemsUnlinked(const PimItem::List &items, const Collection &collection)
Notify about unlinked items.
void collectionMoved(const Collection &collection, const Collection &source, const QByteArray &resource=QByteArray(), const QByteArray &destResource=QByteArray())
Notify about a moved collection.
void tagAdded(const Tag &tag)
Notify about an added tag.
void tagChanged(const Tag &tag)
Notify about a changed tag.
bool dispatchNotifications()
Trigger sending of collected notifications.
void itemsTagsChanged(const PimItem::List &items, const QSet< qint64 > &addedTags, const QSet< qint64 > &removedTags, const Collection &collection=Collection(), const QByteArray &resource=QByteArray())
Notify about changed items tags.
NotificationCollector(AkonadiServer &akonadi, DataStore *db)
Create a new notification collector for the given DataStore db.
void collectionChanged(const Collection &collection, const QList< QByteArray > &changes, const QByteArray &resource=QByteArray())
Notify about a changed collection.
void setConnection(Connection *connection)
Sets the connection that is causing the changes.
void itemsLinked(const PimItem::List &items, const Collection &collection)
Notify about linked items.
void relationRemoved(const Relation &relation)
Notify about a removed relation.
void itemsRemoved(const PimItem::List &items, const Collection &collection=Collection(), const QByteArray &resource=QByteArray())
Notify about removed items.
void relationAdded(const Relation &relation)
Notify about an added relation.
void collectionUnsubscribed(const Collection &collection, const QByteArray &resource=QByteArray())
Notify about a collection unsubscription.
void collectionAdded(const Collection &collection, const QByteArray &resource=QByteArray())
Notify about a added collection.
void itemsFlagsChanged(const PimItem::List &items, const QSet< QByteArray > &addedFlags, const QSet< QByteArray > &removedFlags, const Collection &collection=Collection(), const QByteArray &resource=QByteArray())
Notify about changed items flags Provide as many parameters as you have at hand currently,...
void itemChanged(const PimItem &item, const QSet< QByteArray > &changedParts, const Collection &collection=Collection(), const QByteArray &resource=QByteArray())
Notify about a changed item.
void collectionSubscribed(const Collection &collection, const QByteArray &resource=QByteArray())
Notify about a collection subscription.
void itemAdded(const PimItem &item, bool seen, const Collection &collection=Collection(), const QByteArray &resource=QByteArray())
Notify about an added item.
void addValueCondition(const QString &column, Query::CompareOperator op, const QVariant &value, ConditionType type=WhereCondition)
Add a WHERE or HAVING condition which compares a column with a given value.
bool exec()
Executes the query, returns true on success.
void addCondition(const Query::Condition &condition, ConditionType type=WhereCondition)
Add a WHERE condition.
void addColumn(const QString &col)
Adds the given column to a select query.
Represents a WHERE condition tree.
Definition query.h:62
Helper class for creating and executing database SELECT queries.
QList< T > result()
Returns the result of this SELECT query.
An Akonadi Tag.
Definition tag.h:26
Id id() const
Returns the unique identifier of the tag.
Definition tag.cpp:139
Helper integration between Akonadi and Qt.
const QList< QKeySequence > & end()
const QList< QKeySequence > & copy()
A glue between Qt and the standard library.
bool isEmpty() const const
iterator insert(const Key &key, const T &value)
void reserve(qsizetype size)
T value(const Key &key) const const
void append(QList< T > &&value)
bool contains(const AT &value) const const
T & first()
bool isEmpty() const const
void push_back(parameter_type value)
void reserve(qsizetype size)
qsizetype size() const const
const_iterator cbegin() const const
const_iterator constEnd() const const
bool invokeMethod(QObject *context, Functor &&function, FunctorReturnType *ret)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool contains(const QSet< T > &other) const const
iterator insert(const T &value)
void reserve(qsizetype size)
QSharedPointer< X > staticCast() const const
QByteArray toLatin1() const const
QByteArray toUtf8() const const
QueuedConnection
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.