Akonadi

itemfetchjob.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 "itemfetchjob.h"
8
9#include "attributefactory.h"
10#include "collection.h"
11#include "itemfetchscope.h"
12#include "job_p.h"
13#include "private/protocol_p.h"
14#include "protocolhelper_p.h"
15#include "session_p.h"
16#include "tagfetchscope.h"
17
18#include <QTimer>
19
20using namespace Akonadi;
21
22class Akonadi::ItemFetchJobPrivate : public JobPrivate
23{
24public:
25 explicit ItemFetchJobPrivate(ItemFetchJob *parent)
26 : JobPrivate(parent)
27 , mCollection(Collection::root())
28 {
29 mEmitTimer.setSingleShot(true);
30 mEmitTimer.setInterval(std::chrono::milliseconds{100});
31 }
32
33 ~ItemFetchJobPrivate() override
34 {
35 delete mValuePool;
36 }
37
38 void init()
39 {
40 QObject::connect(&mEmitTimer, &QTimer::timeout, q_ptr, [this]() {
41 timeout();
42 });
43 }
44 void aboutToFinish() override
45 {
46 timeout();
47 }
48
49 void timeout()
50 {
51 Q_Q(ItemFetchJob);
52
53 mEmitTimer.stop(); // in case we are called by result()
54 if (!mPendingItems.isEmpty()) {
55 if (!q->error()) {
56 Q_EMIT q->itemsReceived(mPendingItems);
57 }
58 mPendingItems.clear();
59 }
60 }
61
62 QString jobDebuggingString() const override
63 {
64 if (mRequestedItems.isEmpty()) {
65 QString str = QStringLiteral("All items from collection %1").arg(mCollection.id());
66 if (mFetchScope.fetchChangedSince().isValid()) {
67 str += QStringLiteral(" changed since %1").arg(mFetchScope.fetchChangedSince().toString());
68 }
69 return str;
70
71 } else if (mRequestedItems.size() > 10) {
72 return QStringLiteral("%1 items from collection %2").arg(mRequestedItems.size()).arg(mCollection.id());
73
74 } else {
75 try {
76 QString itemStr = QStringLiteral("items id: ");
77 bool firstItem = true;
78 for (const Akonadi::Item &item : std::as_const(mRequestedItems)) {
79 if (firstItem) {
80 firstItem = false;
81 } else {
82 itemStr += QStringLiteral(", ");
83 }
84 itemStr += QString::number(item.id());
85 const Akonadi::Collection parentCollection = item.parentCollection();
86 if (parentCollection.isValid()) {
87 itemStr += QStringLiteral(" from collection %1").arg(parentCollection.id());
88 }
89 }
90 return itemStr;
91
92 } catch (const Exception &e) {
93 return QString::fromUtf8(e.what());
94 }
95 }
96 }
97
98 Q_DECLARE_PUBLIC(ItemFetchJob)
99
100 Collection mCollection;
101 Tag mCurrentTag;
102 Item::List mRequestedItems;
103 Item::List mResultItems;
104 ItemFetchScope mFetchScope;
105 Item::List mPendingItems; // items pending for emitting itemsReceived()
106 QTimer mEmitTimer;
107 ProtocolHelperValuePool *mValuePool = nullptr;
108 ItemFetchJob::DeliveryOptions mDeliveryOptions = ItemFetchJob::Default;
109 int mChunkStart = 0; // index into mRequestedItems
110 int mCount = 0;
111 Protocol::FetchLimit mItemsLimit;
112};
113
115 : Job(new ItemFetchJobPrivate(this), parent)
116{
118 d->init();
119
120 d->mCollection = collection;
121 d->mValuePool = new ProtocolHelperValuePool; // only worth it for lots of results
122}
123
125 : Job(new ItemFetchJobPrivate(this), parent)
126{
128 d->init();
129
130 d->mRequestedItems.append(item);
131}
132
134 : Job(new ItemFetchJobPrivate(this), parent)
135{
137 d->init();
138
139 d->mRequestedItems = items;
140}
141
143 : Job(new ItemFetchJobPrivate(this), parent)
144{
146 d->init();
147
148 d->mRequestedItems.reserve(items.size());
149 for (auto id : items) {
150 d->mRequestedItems.append(Item(id));
151 }
152}
154 : Job(new ItemFetchJobPrivate(this), parent)
155{
157 d->init();
158
159 d->mCurrentTag = tag;
160 d->mValuePool = new ProtocolHelperValuePool;
161}
162
164
166{
168
169 constexpr int maximumParametersSize = 1000;
170 const auto items = d->mRequestedItems.mid(d->mChunkStart, maximumParametersSize);
171 d->mChunkStart += maximumParametersSize;
172
173 try {
174 d->sendCommand(Protocol::FetchItemsCommandPtr::create(items.isEmpty() ? Scope() : ProtocolHelper::entitySetToScope(items),
175 ProtocolHelper::commandContextToProtocol(d->mCollection, d->mCurrentTag, items),
176 ProtocolHelper::itemFetchScopeToProtocol(d->mFetchScope),
177 ProtocolHelper::tagFetchScopeToProtocol(d->mFetchScope.tagFetchScope()),
178 d->mItemsLimit));
179 } catch (const Akonadi::Exception &e) {
182 emitResult();
183 return;
184 }
185}
186
187bool ItemFetchJob::doHandleResponse(qint64 tag, const Protocol::CommandPtr &response)
188{
190
191 if (!response->isResponse() || response->type() != Protocol::Command::FetchItems) {
192 return Job::doHandleResponse(tag, response);
193 }
194
195 const auto &resp = Protocol::cmdCast<Protocol::FetchItemsResponse>(response);
196 // Invalid ID marks the last part of the response
197 if (resp.id() < 0) {
198 // Do we have more chunks to fetch?
199 if (d->mChunkStart < d->mRequestedItems.size()) {
200 doStart();
201 return false;
202 }
203
204 // all done
205 return true;
206 }
207
208 const Item item = ProtocolHelper::parseItemFetchResult(resp, nullptr, d->mValuePool);
209 if (!item.isValid()) {
210 return false;
211 }
212
213 d->mCount++;
214
215 if (d->mDeliveryOptions & ItemGetter) {
216 d->mResultItems.append(item);
217 }
218
219 if (d->mDeliveryOptions & EmitItemsInBatches) {
220 d->mPendingItems.append(item);
221 if (!d->mEmitTimer.isActive()) {
222 d->mEmitTimer.start();
223 }
224 } else if (d->mDeliveryOptions & EmitItemsIndividually) {
226 }
227
228 return false;
229}
230
232{
233 Q_D(const ItemFetchJob);
234
235 return d->mResultItems;
236}
237
239{
241
242 d->mResultItems.clear();
243}
244
246{
248
249 d->mFetchScope = fetchScope;
250}
251
253{
255
256 return d->mFetchScope;
257}
258
260{
262
263 d->mCollection = collection;
264}
265
266void ItemFetchJob::setDeliveryOption(DeliveryOptions options)
267{
269
270 d->mDeliveryOptions = options;
271}
272
273ItemFetchJob::DeliveryOptions ItemFetchJob::deliveryOptions() const
274{
275 Q_D(const ItemFetchJob);
276
277 return d->mDeliveryOptions;
278}
279
281{
282 Q_D(const ItemFetchJob);
283
284 return d->mCount;
285}
286
287void ItemFetchJob::setLimit(int limit, int start, Qt::SortOrder order)
288{
290 d->mItemsLimit.setLimit(limit);
291 d->mItemsLimit.setLimitOffset(start);
292 d->mItemsLimit.setSortOrder(order);
293}
294#include "moc_itemfetchjob.cpp"
Represents a collection of PIM items.
Definition collection.h:62
Base class for exceptions used by the Akonadi library.
const char * what() const noexcept override
Returns the error message associated with this exception.
Definition exception.cpp:65
int count() const
Returns the total number of retrieved items.
bool doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) override
This method should be reimplemented in the concrete jobs in case you want to handle incoming data.
void itemsReceived(const Akonadi::Item::List &items)
This signal is emitted whenever new items have been fetched completely.
void setDeliveryOption(DeliveryOptions options)
Sets the mechanisms by which the items should be fetched.
ItemFetchJob(const Collection &collection, QObject *parent=nullptr)
Creates a new item fetch job that retrieves all items inside the given collection.
void setFetchScope(const ItemFetchScope &fetchScope)
Sets the item fetch scope.
void setLimit(int limit, int start, Qt::SortOrder order=Qt::DescendingOrder)
Sets the limit of fetched items.
DeliveryOptions deliveryOptions() const
Returns the delivery options.
void setCollection(const Collection &collection)
Specifies the collection the item is in.
void doStart() override
This method must be reimplemented in the concrete jobs.
@ EmitItemsInBatches
emitted via signal in bulk (collected and emitted delayed via timer)
@ ItemGetter
items available through items()
@ EmitItemsIndividually
emitted via signal upon reception
ItemFetchScope & fetchScope()
Returns the item fetch scope.
void clearItems()
Save memory by clearing the fetched items.
~ItemFetchJob() override
Destroys the item fetch job.
Item::List items() const
Returns the fetched items.
Specifies which parts of an item should be fetched from the Akonadi storage.
Represents a PIM item stored in Akonadi storage.
Definition item.h:100
bool isValid() const
Returns whether the item is valid.
Definition item.cpp:88
QList< Item > List
Describes a list of items.
Definition item.h:110
virtual bool doHandleResponse(qint64 tag, const Protocol::CommandPtr &response)
This method should be reimplemented in the concrete jobs in case you want to handle incoming data.
Definition job.cpp:381
Job(QObject *parent=nullptr)
Creates a new job.
Definition job.cpp:290
@ Unknown
Unknown error.
Definition job.h:102
void start() override
Jobs are started automatically once entering the event loop again, no need to explicitly call this.
Definition job.cpp:313
An Akonadi Tag.
Definition tag.h:26
void setErrorText(const QString &errorText)
void emitResult()
void setError(int errorCode)
Helper integration between Akonadi and Qt.
Q_EMITQ_EMIT
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QObject * parent() const const
QString arg(Args &&... args) const const
QString fromUtf8(QByteArrayView str)
QString number(double n, char format, int precision)
SortOrder
void timeout()
Q_D(Todo)
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri Jan 24 2025 11:49:57 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.