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::itemsMoved(const PimItem::List &items,
91 const Collection &collectionSrc,
92 const Collection &collectionDest,
93 const QByteArray &sourceResource)
94{
95 mAkonadi.searchManager().scheduleSearchUpdate();
96 itemNotification(Protocol::ItemChangeNotification::Move, items, collectionSrc, collectionDest, sourceResource);
97}
98
99void NotificationCollector::itemsRemoved(const PimItem::List &items, const Collection &collection, const QByteArray &resource)
100{
101 itemNotification(Protocol::ItemChangeNotification::Remove, items, collection, Collection(), resource);
102}
103
104void NotificationCollector::itemsLinked(const PimItem::List &items, const Collection &collection)
105{
106 itemNotification(Protocol::ItemChangeNotification::Link, items, collection, Collection(), QByteArray());
107}
108
109void NotificationCollector::itemsUnlinked(const PimItem::List &items, const Collection &collection)
110{
111 itemNotification(Protocol::ItemChangeNotification::Unlink, items, collection, Collection(), QByteArray());
112}
113
114void NotificationCollector::collectionAdded(const Collection &collection, const QByteArray &resource)
115{
116 if (auto cleaner = mAkonadi.cacheCleaner()) {
117 cleaner->collectionAdded(collection.id());
118 }
119 mAkonadi.intervalChecker().collectionAdded(collection.id());
120 collectionNotification(Protocol::CollectionChangeNotification::Add, collection, collection.parentId(), -1, resource);
121}
122
123void NotificationCollector::collectionChanged(const Collection &collection, const QList<QByteArray> &changes, const QByteArray &resource)
124{
125 if (auto cleaner = mAkonadi.cacheCleaner()) {
126 cleaner->collectionChanged(collection.id());
127 }
128 mAkonadi.intervalChecker().collectionChanged(collection.id());
129 if (changes.contains(AKONADI_PARAM_ENABLED)) {
130 mAkonadi.collectionStatistics().invalidateCollection(collection);
131 }
132 collectionNotification(Protocol::CollectionChangeNotification::Modify,
133 collection,
134 collection.parentId(),
135 -1,
136 resource,
137 changes | AkRanges::Actions::toQSet);
138}
139
140void NotificationCollector::collectionMoved(const Collection &collection, const Collection &source, const QByteArray &resource, const QByteArray &destResource)
141{
142 if (auto cleaner = mAkonadi.cacheCleaner()) {
143 cleaner->collectionChanged(collection.id());
144 }
145 mAkonadi.intervalChecker().collectionChanged(collection.id());
146 collectionNotification(Protocol::CollectionChangeNotification::Move,
147 collection,
148 source.id(),
149 collection.parentId(),
150 resource,
152 destResource);
153}
154
155void NotificationCollector::collectionRemoved(const Collection &collection, const QByteArray &resource)
156{
157 if (auto cleaner = mAkonadi.cacheCleaner()) {
158 cleaner->collectionRemoved(collection.id());
159 }
160 mAkonadi.intervalChecker().collectionRemoved(collection.id());
161 mAkonadi.collectionStatistics().invalidateCollection(collection);
162 collectionNotification(Protocol::CollectionChangeNotification::Remove, collection, collection.parentId(), -1, resource);
163}
164
166{
167 if (auto cleaner = mAkonadi.cacheCleaner()) {
168 cleaner->collectionAdded(collection.id());
169 }
170 mAkonadi.intervalChecker().collectionAdded(collection.id());
171 collectionNotification(Protocol::CollectionChangeNotification::Subscribe, collection, collection.parentId(), -1, resource, QSet<QByteArray>());
172}
173
175{
176 if (auto cleaner = mAkonadi.cacheCleaner()) {
177 cleaner->collectionRemoved(collection.id());
178 }
179 mAkonadi.intervalChecker().collectionRemoved(collection.id());
180 mAkonadi.collectionStatistics().invalidateCollection(collection);
181 collectionNotification(Protocol::CollectionChangeNotification::Unsubscribe, collection, collection.parentId(), -1, resource, QSet<QByteArray>());
182}
183
185{
186 tagNotification(Protocol::TagChangeNotification::Add, tag);
187}
188
190{
191 tagNotification(Protocol::TagChangeNotification::Modify, tag);
192}
193
194void NotificationCollector::tagRemoved(const Tag &tag, const QByteArray &resource, const QString &remoteId)
195{
196 tagNotification(Protocol::TagChangeNotification::Remove, tag, resource, remoteId);
197}
198
199void NotificationCollector::clear()
200{
201 mNotifications.clear();
202}
203
205{
206 mConnection = connection;
207}
208
209void NotificationCollector::itemNotification(Protocol::ItemChangeNotification::Operation op,
210 const PimItem &item,
211 const Collection &collection,
212 const Collection &collectionDest,
213 const QByteArray &resource,
214 const QSet<QByteArray> &parts)
215{
216 if (!item.isValid()) {
217 return;
218 }
219 itemNotification(op, PimItem::List{item}, collection, collectionDest, resource, parts);
220}
221
222void NotificationCollector::itemNotification(Protocol::ItemChangeNotification::Operation op,
223 const PimItem::List &items,
224 const Collection &collection,
225 const Collection &collectionDest,
226 const QByteArray &resource,
227 const QSet<QByteArray> &parts,
228 const QSet<QByteArray> &addedFlags,
229 const QSet<QByteArray> &removedFlags,
230 const QSet<qint64> &addedTags,
231 const QSet<qint64> &removedTags)
232{
233 if (items.empty()) {
234 return;
235 }
236
238
239 if ((op == Protocol::ItemChangeNotification::Modify) || (op == Protocol::ItemChangeNotification::ModifyFlags)
240 || (op == Protocol::ItemChangeNotification::ModifyTags)) {
241 vCollections = DataStore::self()->virtualCollections(items);
242 }
243
244 auto msg = Protocol::ItemChangeNotificationPtr::create();
245 if (mConnection) {
246 msg->setSessionId(mConnection->sessionId());
247 }
248 msg->setOperation(op);
249
250 msg->setItemParts(parts);
251 msg->setAddedFlags(addedFlags);
252 msg->setRemovedFlags(removedFlags);
253 msg->setAddedTags(addedTags);
254 msg->setRemovedTags(removedTags);
255
256 if (collectionDest.isValid()) {
257 QByteArray destResourceName;
258 destResourceName = collectionDest.resource().name().toLatin1();
259 msg->setDestinationResource(destResourceName);
260 }
261
262 msg->setParentDestCollection(collectionDest.id());
263
265 ntfItems.reserve(items.size());
266 for (const PimItem &item : items) {
267 Protocol::FetchItemsResponse i;
268 i.setId(item.id());
269 i.setRemoteId(item.remoteId());
270 i.setRemoteRevision(item.remoteRevision());
271 i.setMimeType(item.mimeType().name());
272 ntfItems.push_back(std::move(i));
273 }
274
275 /* Notify all virtual collections the items are linked to. */
277 virtItems.reserve(ntfItems.size());
278 for (const auto &ntfItem : ntfItems) {
279 virtItems.insert(ntfItem.id(), ntfItem);
280 }
281 for (auto iter = vCollections.cbegin(), end = vCollections.constEnd(); iter != end; ++iter) {
282 auto copy = Protocol::ItemChangeNotificationPtr::create(*msg);
284 items.reserve(iter->size());
285 for (const auto &item : std::as_const(*iter)) {
286 items.append(virtItems.value(item.id()));
287 }
288 copy->setItems(items);
289 copy->setParentCollection(iter.key());
290 copy->setResource(resource);
291
292 mAkonadi.collectionStatistics().invalidateCollection(Collection::retrieveById(iter.key()));
293 dispatchNotification(copy);
294 }
295
296 msg->setItems(ntfItems);
297
298 Collection col;
299 if (!collection.isValid()) {
300 msg->setParentCollection(items.first().collection().id());
301 col = items.first().collection();
302 } else {
303 msg->setParentCollection(collection.id());
304 col = collection;
305 }
306
307 QByteArray res = resource;
308 if (res.isEmpty()) {
309 if (col.resourceId() <= 0) {
310 col = Collection::retrieveById(col.id());
311 }
312 res = col.resource().name().toLatin1();
313 }
314 msg->setResource(res);
315
316 // Add and ModifyFlags are handled incrementally
317 // (see itemAdded() and itemsFlagsChanged())
318 if (msg->operation() != Protocol::ItemChangeNotification::Add && msg->operation() != Protocol::ItemChangeNotification::ModifyFlags) {
319 mAkonadi.collectionStatistics().invalidateCollection(col);
320 }
321 dispatchNotification(msg);
322}
323
324void NotificationCollector::collectionNotification(Protocol::CollectionChangeNotification::Operation op,
325 const Collection &collection,
326 Collection::Id source,
327 Collection::Id destination,
328 const QByteArray &resource,
329 const QSet<QByteArray> &changes,
330 const QByteArray &destResource)
331{
332 if (!collection.isValid()) {
333 return;
334 }
335
336 auto msg = Protocol::CollectionChangeNotificationPtr::create();
337 msg->setOperation(op);
338 if (mConnection) {
339 msg->setSessionId(mConnection->sessionId());
340 }
341 msg->setParentCollection(source);
342 msg->setParentDestCollection(destination);
343 msg->setDestinationResource(destResource);
344 msg->setChangedParts(changes);
345
346 auto msgCollection = HandlerHelper::fetchCollectionsResponse(mAkonadi, collection);
347 if (auto mgr = mAkonadi.notificationManager()) {
348 auto fetchScope = mgr->collectionFetchScope();
349 // Make sure we have all the data
350 if (!fetchScope->fetchIdOnly() && msgCollection.name().isEmpty()) {
351 const auto col = Collection::retrieveById(msgCollection.id());
352 const auto mts = col.mimeTypes();
353 QStringList mimeTypes;
354 mimeTypes.reserve(mts.size());
355 for (const auto &mt : mts) {
356 mimeTypes.push_back(mt.name());
357 }
358 msgCollection = HandlerHelper::fetchCollectionsResponse(mAkonadi, col, {}, false, 0, {}, {}, mimeTypes);
359 }
360 // Get up-to-date statistics
361 if (fetchScope->fetchStatistics()) {
362 Collection col;
363 col.setId(msgCollection.id());
364 const auto stats = mAkonadi.collectionStatistics().statistics(col);
365 msgCollection.setStatistics(Protocol::FetchCollectionStatsResponse(stats.count, stats.count - stats.read, stats.size));
366 }
367 // Get attributes
368 const auto requestedAttrs = fetchScope->attributes();
369 auto msgColAttrs = msgCollection.attributes();
370 // TODO: This assumes that we have either none or all attributes in msgCollection
371 if (msgColAttrs.isEmpty() && !requestedAttrs.isEmpty()) {
373 qb.addColumn(CollectionAttribute::typeFullColumnName());
374 qb.addColumn(CollectionAttribute::valueFullColumnName());
375 qb.addValueCondition(CollectionAttribute::collectionIdFullColumnName(), Query::Equals, msgCollection.id());
376 Query::Condition cond(Query::Or);
377 for (const auto &attr : requestedAttrs) {
378 cond.addValueCondition(CollectionAttribute::typeFullColumnName(), Query::Equals, attr);
379 }
380 qb.addCondition(cond);
381 if (!qb.exec()) {
382 qCWarning(AKONADISERVER_LOG) << "NotificationCollector failed to query attributes for Collection" << collection.name() << "(ID"
383 << collection.id() << ")";
384 }
385 const auto attrs = qb.result();
386 for (const auto &attr : attrs) {
387 msgColAttrs.insert(attr.type(), attr.value());
388 }
389 msgCollection.setAttributes(msgColAttrs);
390 }
391 }
392 msg->setCollection(std::move(msgCollection));
393
394 if (!collection.enabled()) {
395 msg->addMetadata("DISABLED");
396 }
397
398 QByteArray res = resource;
399 if (res.isEmpty()) {
400 res = collection.resource().name().toLatin1();
401 }
402 msg->setResource(res);
403
404 dispatchNotification(msg);
405}
406
407void NotificationCollector::tagNotification(Protocol::TagChangeNotification::Operation op, const Tag &tag, const QByteArray &resource, const QString &remoteId)
408{
409 if (!tag.isValid()) {
410 return;
411 }
412
413 auto msg = Protocol::TagChangeNotificationPtr::create();
414 msg->setOperation(op);
415 if (mConnection) {
416 msg->setSessionId(mConnection->sessionId());
417 }
418 msg->setResource(resource);
419 Protocol::FetchTagsResponse msgTag;
420 msgTag.setId(tag.id());
421 msgTag.setRemoteId(remoteId.toUtf8());
422 msgTag.setParentId(tag.parentId());
423 if (auto mgr = mAkonadi.notificationManager()) {
424 auto fetchScope = mgr->tagFetchScope();
425 if (!fetchScope->fetchIdOnly() && msgTag.gid().isEmpty()) {
426 msgTag = HandlerHelper::fetchTagsResponse(Tag::retrieveById(msgTag.id()), fetchScope->toFetchScope(), mConnection);
427 }
428
429 const auto requestedAttrs = fetchScope->attributes();
430 auto msgTagAttrs = msgTag.attributes();
431 if (msgTagAttrs.isEmpty() && !requestedAttrs.isEmpty()) {
433 qb.addColumn(TagAttribute::typeFullColumnName());
434 qb.addColumn(TagAttribute::valueFullColumnName());
435 qb.addValueCondition(TagAttribute::tagIdFullColumnName(), Query::Equals, msgTag.id());
436 Query::Condition cond(Query::Or);
437 for (const auto &attr : requestedAttrs) {
438 cond.addValueCondition(TagAttribute::typeFullColumnName(), Query::Equals, attr);
439 }
440 qb.addCondition(cond);
441 if (!qb.exec()) {
442 qCWarning(AKONADISERVER_LOG) << "NotificationCollection failed to query attributes for Tag" << tag.id();
443 }
444 const auto attrs = qb.result();
445 for (const auto &attr : attrs) {
446 msgTagAttrs.insert(attr.type(), attr.value());
447 }
448 msgTag.setAttributes(msgTagAttrs);
449 }
450 }
451 msg->setTag(std::move(msgTag));
452
453 dispatchNotification(msg);
454}
455
456void NotificationCollector::completeNotification(const Protocol::ChangeNotificationPtr &changeMsg)
457{
458 if (changeMsg->type() == Protocol::Command::ItemChangeNotification) {
459 const auto msg = changeMsg.staticCast<Protocol::ItemChangeNotification>();
460 auto const mgr = mAkonadi.notificationManager();
461 if (mgr && msg->operation() != Protocol::ItemChangeNotification::Remove) {
462 if (mDb->inTransaction()) {
463 qCWarning(AKONADISERVER_LOG) << "NotificationCollector requested FetchHelper from within a transaction."
464 << "Aborting since this would deadlock!";
465 return;
466 }
467 auto fetchScope = mgr->itemFetchScope();
468 // NOTE: Checking and retrieving missing elements for each Item manually
469 // here would require a complex code (and I'm too lazy), so instead we simply
470 // feed the Items to FetchHelper and retrieve them all with the setup from
471 // the aggregated fetch scope. The worst case is that we re-fetch everything
472 // we already have, but that's still better than the pre-ntf-payload situation
473 QList<qint64> ids;
474 const auto items = msg->items();
475 ids.reserve(items.size());
476 bool allHaveRID = true;
477 for (const auto &item : items) {
478 ids.push_back(item.id());
479 allHaveRID &= !item.remoteId().isEmpty();
480 }
481
482 // FetchHelper may trigger ItemRetriever, which needs RemoteID. If we
483 // don't have one (maybe because the Resource has not stored it yet,
484 // we emit a notification without it and leave it up to the Monitor
485 // to retrieve the Item on demand - we should have a RID stored in
486 // Akonadi by then.
487 if (mConnection && (allHaveRID || msg->operation() != Protocol::ItemChangeNotification::Add)) {
488 // Prevent transactions inside FetchHelper to recursively call our slot
489 QScopedValueRollback<bool> ignoreTransactions(mIgnoreTransactions);
490 mIgnoreTransactions = true;
491 CommandContext context;
492 auto itemFetchScope = fetchScope->toFetchScope();
493 auto tagFetchScope = mgr->tagFetchScope()->toFetchScope();
494 itemFetchScope.setFetch(Protocol::ItemFetchScope::CacheOnly);
495 ItemFetchHelper helper(mConnection, context, Scope(ids), itemFetchScope, tagFetchScope, mAkonadi);
496 // The Item was just changed, which means the atime was
497 // updated, no need to do it again a couple milliseconds later.
498 helper.disableATimeUpdates();
500 auto callback = [&fetchedItems](Protocol::FetchItemsResponse &&cmd) {
501 fetchedItems.push_back(std::move(cmd));
502 };
503 if (helper.fetchItems(std::move(callback))) {
504 msg->setItems(fetchedItems);
505 } else {
506 qCWarning(AKONADISERVER_LOG) << "NotificationCollector railed to retrieve Items for notification!";
507 }
508 } else {
510 fetchedItems.reserve(items.size());
511 for (const auto &item : items) {
512 Protocol::FetchItemsResponse resp;
513 resp.setId(item.id());
514 resp.setRevision(item.revision());
515 resp.setMimeType(item.mimeType());
516 resp.setParentId(item.parentId());
517 resp.setGid(item.gid());
518 resp.setSize(item.size());
519 resp.setMTime(item.mTime());
520 resp.setFlags(item.flags());
521 fetchedItems.push_back(std::move(resp));
522 }
523 msg->setItems(fetchedItems);
524 msg->setMustRetrieve(true);
525 }
526 }
527 }
528}
529
530void NotificationCollector::dispatchNotification(const Protocol::ChangeNotificationPtr &msg)
531{
532 if (!mDb || mDb->inTransaction()) {
533 if (msg->type() == Protocol::Command::CollectionChangeNotification) {
534 Protocol::CollectionChangeNotification::appendAndCompress(mNotifications, msg);
535 } else {
536 mNotifications.append(msg);
537 }
538 } else {
539 completeNotification(msg);
540 notify({msg});
541 }
542}
543
545{
546 if (!mNotifications.isEmpty()) {
547 for (auto &ntf : mNotifications) {
548 completeNotification(ntf);
549 }
550 notify(std::move(mNotifications));
551 clear();
552 return true;
553 }
554
555 return false;
556}
557
558void NotificationCollector::notify(Protocol::ChangeNotificationList &&msgs)
559{
560 if (auto mgr = mAkonadi.notificationManager()) {
561 QMetaObject::invokeMethod(mgr, "slotNotify", Qt::QueuedConnection, Q_ARG(Akonadi::Protocol::ChangeNotificationList, msgs));
562 }
563}
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 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 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.
QAction * copy(const QObject *recvr, const char *slot, QObject *parent)
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()
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
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 Fri Dec 13 2024 11:54:59 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.