Akonadi

itemfetchjob.cpp
1 /*
2  SPDX-FileCopyrightText: 2006-2007 Volker Krause <[email protected]>
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 
20 using namespace Akonadi;
21 
22 class Akonadi::ItemFetchJobPrivate : public JobPrivate
23 {
24 public:
25  explicit ItemFetchJobPrivate(ItemFetchJob *parent)
26  : JobPrivate(parent)
27  {
28  mCollection = Collection::root();
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 {
72  try {
73  QString itemStr = QStringLiteral("items id: ");
74  bool firstItem = true;
75  for (const Akonadi::Item &item : std::as_const(mRequestedItems)) {
76  if (firstItem) {
77  firstItem = false;
78  } else {
79  itemStr += QStringLiteral(", ");
80  }
81  itemStr += QString::number(item.id());
82  const Akonadi::Collection parentCollection = item.parentCollection();
83  if (parentCollection.isValid()) {
84  itemStr += QStringLiteral(" from collection %1").arg(parentCollection.id());
85  }
86  }
87  return itemStr;
88  // return QString(); //QString::fromLatin1(ProtocolHelper::entitySetToScope(mRequestedItems));
89  } catch (const Exception &e) {
90  return QString::fromUtf8(e.what());
91  }
92  }
93  }
94 
95  Q_DECLARE_PUBLIC(ItemFetchJob)
96 
97  Collection mCollection;
98  Tag mCurrentTag;
99  Item::List mRequestedItems;
100  Item::List mResultItems;
101  ItemFetchScope mFetchScope;
102  Item::List mPendingItems; // items pending for emitting itemsReceived()
103  QTimer mEmitTimer;
104  ProtocolHelperValuePool *mValuePool = nullptr;
105  ItemFetchJob::DeliveryOptions mDeliveryOptions = ItemFetchJob::Default;
106  int mCount = 0;
107  Protocol::FetchLimit mItemsLimit;
108 };
109 
110 ItemFetchJob::ItemFetchJob(const Collection &collection, QObject *parent)
111  : Job(new ItemFetchJobPrivate(this), parent)
112 {
113  Q_D(ItemFetchJob);
114  d->init();
115 
116  d->mCollection = collection;
117  d->mValuePool = new ProtocolHelperValuePool; // only worth it for lots of results
118 }
119 
121  : Job(new ItemFetchJobPrivate(this), parent)
122 {
123  Q_D(ItemFetchJob);
124  d->init();
125 
126  d->mRequestedItems.append(item);
127 }
128 
130  : Job(new ItemFetchJobPrivate(this), parent)
131 {
132  Q_D(ItemFetchJob);
133  d->init();
134 
135  d->mRequestedItems = items;
136 }
137 
139  : Job(new ItemFetchJobPrivate(this), parent)
140 {
141  Q_D(ItemFetchJob);
142  d->init();
143 
144  d->mRequestedItems.reserve(items.size());
145  for (auto id : items) {
146  d->mRequestedItems.append(Item(id));
147  }
148 }
149 
151  : Job(new ItemFetchJobPrivate(this), parent)
152 {
153  Q_D(ItemFetchJob);
154  d->init();
155 
156  d->mRequestedItems.reserve(items.size());
157  for (auto id : items) {
158  d->mRequestedItems.append(Item(id));
159  }
160 }
161 
163  : Job(new ItemFetchJobPrivate(this), parent)
164 {
165  Q_D(ItemFetchJob);
166  d->init();
167 
168  d->mCurrentTag = tag;
169  d->mValuePool = new ProtocolHelperValuePool;
170 }
171 
172 ItemFetchJob::~ItemFetchJob() = default;
173 
175 {
176  Q_D(ItemFetchJob);
177 
178  try {
179  d->sendCommand(Protocol::FetchItemsCommandPtr::create(d->mRequestedItems.isEmpty() ? Scope() : ProtocolHelper::entitySetToScope(d->mRequestedItems),
180  ProtocolHelper::commandContextToProtocol(d->mCollection, d->mCurrentTag, d->mRequestedItems),
181  ProtocolHelper::itemFetchScopeToProtocol(d->mFetchScope),
182  ProtocolHelper::tagFetchScopeToProtocol(d->mFetchScope.tagFetchScope()),
183  d->mItemsLimit));
184  } catch (const Akonadi::Exception &e) {
187  emitResult();
188  return;
189  }
190 }
191 
192 bool ItemFetchJob::doHandleResponse(qint64 tag, const Protocol::CommandPtr &response)
193 {
194  Q_D(ItemFetchJob);
195 
196  if (!response->isResponse() || response->type() != Protocol::Command::FetchItems) {
197  return Job::doHandleResponse(tag, response);
198  }
199 
200  const auto &resp = Protocol::cmdCast<Protocol::FetchItemsResponse>(response);
201  // Invalid ID marks the last part of the response
202  if (resp.id() < 0) {
203  return true;
204  }
205 
206  const Item item = ProtocolHelper::parseItemFetchResult(resp, nullptr, d->mValuePool);
207  if (!item.isValid()) {
208  return false;
209  }
210 
211  d->mCount++;
212 
213  if (d->mDeliveryOptions & ItemGetter) {
214  d->mResultItems.append(item);
215  }
216 
217  if (d->mDeliveryOptions & EmitItemsInBatches) {
218  d->mPendingItems.append(item);
219  if (!d->mEmitTimer.isActive()) {
220  d->mEmitTimer.start();
221  }
222  } else if (d->mDeliveryOptions & EmitItemsIndividually) {
223  Q_EMIT itemsReceived(Item::List() << item);
224  }
225 
226  return false;
227 }
228 
230 {
231  Q_D(const ItemFetchJob);
232 
233  return d->mResultItems;
234 }
235 
237 {
238  Q_D(ItemFetchJob);
239 
240  d->mResultItems.clear();
241 }
242 
244 {
245  Q_D(ItemFetchJob);
246 
247  d->mFetchScope = fetchScope;
248 }
249 
251 {
252  Q_D(ItemFetchJob);
253 
254  return d->mFetchScope;
255 }
256 
258 {
259  Q_D(ItemFetchJob);
260 
261  d->mCollection = collection;
262 }
263 
265 {
266  Q_D(ItemFetchJob);
267 
268  d->mDeliveryOptions = options;
269 }
270 
272 {
273  Q_D(const ItemFetchJob);
274 
275  return d->mDeliveryOptions;
276 }
277 
279 {
280  Q_D(const ItemFetchJob);
281 
282  return d->mCount;
283 }
284 
285 void ItemFetchJob::setLimit(int limit, int start, Qt::SortOrder order)
286 {
287  Q_D(ItemFetchJob);
288  d->mItemsLimit.setLimit(limit);
289  d->mItemsLimit.setLimitOffset(start);
290  d->mItemsLimit.setSortOrder(order);
291 }
292 #include "moc_itemfetchjob.cpp"
~ItemFetchJob() override
Destroys the item fetch job.
void itemsReceived(const Akonadi::Item::List &items)
This signal is emitted whenever new items have been fetched completely.
bool isValid() const
Returns whether the item is valid.
Definition: item.cpp:88
void emitResult()
items available through items()
Definition: itemfetchjob.h:202
Unknown error.
Definition: job.h:102
Represents a collection of PIM items.
Definition: collection.h:61
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
void setError(int errorCode)
ItemFetchJob(const Collection &collection, QObject *parent=nullptr)
Creates a new item fetch job that retrieves all items inside the given collection.
void setDeliveryOption(DeliveryOptions options)
Sets the mechanisms by which the items should be fetched.
Base class for all actions in the Akonadi storage.
Definition: job.h:80
void start() override
Jobs are started automatically once entering the event loop again, no need to explicitly call this...
Definition: job.cpp:313
void doStart() override
This method must be reimplemented in the concrete jobs.
int size() const const
Item::List items() const
Returns the fetched items.
emitted via signal upon reception
Definition: itemfetchjob.h:203
ItemFetchScope & fetchScope()
Returns the item fetch scope.
void timeout()
void setErrorText(const QString &errorText)
QString number(int n, int base)
QString fromUtf8(const char *str, int size)
void setLimit(int limit, int start, Qt::SortOrder order=Qt::DescendingOrder)
Sets the limit of fetched items.
DeliveryOptions deliveryOptions() const
Returns the delivery options.
static Collection root()
Returns the root collection.
Definition: collection.cpp:287
Collection parentCollection() const
Returns the parent collection of this object.
Definition: collection.cpp:195
void setFetchScope(const ItemFetchScope &fetchScope)
Sets the item fetch scope.
Specifies which parts of an item should be fetched from the Akonadi storage.
QCA_EXPORT void init()
const char * what() const noexcept override
Returns the error message associated with this exception.
Definition: exception.cpp:65
SortOrder
Helper integration between Akonadi and Qt.
Base class for exceptions used by the Akonadi library.
Definition: exceptionbase.h:29
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
Job that fetches items from the Akonadi storage.
Definition: itemfetchjob.h:69
emitted via signal in bulk (collected and emitted delayed via timer)
Definition: itemfetchjob.h:204
An Akonadi Tag.
Definition: tag.h:25
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...
int count() const
Returns the total number of retrieved items.
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
int size() const const
void clearItems()
Save memory by clearing the fetched items.
void setCollection(const Collection &collection)
Specifies the collection the item is in.
Q_EMITQ_EMIT
Represents a PIM item stored in Akonadi storage.
Definition: item.h:100
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Mon Dec 6 2021 23:07:31 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.