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

KDE's Doxygen guidelines are available online.