File indexing completed on 2024-11-10 04:40:30

0001 /*
0002     SPDX-FileCopyrightText: 2006-2007 Volker Krause <vkrause@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "itemfetchjob.h"
0008 
0009 #include "attributefactory.h"
0010 #include "collection.h"
0011 #include "itemfetchscope.h"
0012 #include "job_p.h"
0013 #include "private/protocol_p.h"
0014 #include "protocolhelper_p.h"
0015 #include "session_p.h"
0016 #include "tagfetchscope.h"
0017 
0018 #include <QTimer>
0019 
0020 using namespace Akonadi;
0021 
0022 class Akonadi::ItemFetchJobPrivate : public JobPrivate
0023 {
0024 public:
0025     explicit ItemFetchJobPrivate(ItemFetchJob *parent)
0026         : JobPrivate(parent)
0027         , mCollection(Collection::root())
0028     {
0029         mEmitTimer.setSingleShot(true);
0030         mEmitTimer.setInterval(std::chrono::milliseconds{100});
0031     }
0032 
0033     ~ItemFetchJobPrivate() override
0034     {
0035         delete mValuePool;
0036     }
0037 
0038     void init()
0039     {
0040         QObject::connect(&mEmitTimer, &QTimer::timeout, q_ptr, [this]() {
0041             timeout();
0042         });
0043     }
0044     void aboutToFinish() override
0045     {
0046         timeout();
0047     }
0048 
0049     void timeout()
0050     {
0051         Q_Q(ItemFetchJob);
0052 
0053         mEmitTimer.stop(); // in case we are called by result()
0054         if (!mPendingItems.isEmpty()) {
0055             if (!q->error()) {
0056                 Q_EMIT q->itemsReceived(mPendingItems);
0057             }
0058             mPendingItems.clear();
0059         }
0060     }
0061 
0062     QString jobDebuggingString() const override
0063     {
0064         if (mRequestedItems.isEmpty()) {
0065             QString str = QStringLiteral("All items from collection %1").arg(mCollection.id());
0066             if (mFetchScope.fetchChangedSince().isValid()) {
0067                 str += QStringLiteral(" changed since %1").arg(mFetchScope.fetchChangedSince().toString());
0068             }
0069             return str;
0070 
0071         } else {
0072             try {
0073                 QString itemStr = QStringLiteral("items id: ");
0074                 bool firstItem = true;
0075                 for (const Akonadi::Item &item : std::as_const(mRequestedItems)) {
0076                     if (firstItem) {
0077                         firstItem = false;
0078                     } else {
0079                         itemStr += QStringLiteral(", ");
0080                     }
0081                     itemStr += QString::number(item.id());
0082                     const Akonadi::Collection parentCollection = item.parentCollection();
0083                     if (parentCollection.isValid()) {
0084                         itemStr += QStringLiteral(" from collection %1").arg(parentCollection.id());
0085                     }
0086                 }
0087                 return itemStr;
0088                 // return QString(); //QString::fromLatin1(ProtocolHelper::entitySetToScope(mRequestedItems));
0089             } catch (const Exception &e) {
0090                 return QString::fromUtf8(e.what());
0091             }
0092         }
0093     }
0094 
0095     Q_DECLARE_PUBLIC(ItemFetchJob)
0096 
0097     Collection mCollection;
0098     Tag mCurrentTag;
0099     Item::List mRequestedItems;
0100     Item::List mResultItems;
0101     ItemFetchScope mFetchScope;
0102     Item::List mPendingItems; // items pending for emitting itemsReceived()
0103     QTimer mEmitTimer;
0104     ProtocolHelperValuePool *mValuePool = nullptr;
0105     ItemFetchJob::DeliveryOptions mDeliveryOptions = ItemFetchJob::Default;
0106     int mCount = 0;
0107     Protocol::FetchLimit mItemsLimit;
0108 };
0109 
0110 ItemFetchJob::ItemFetchJob(const Collection &collection, QObject *parent)
0111     : Job(new ItemFetchJobPrivate(this), parent)
0112 {
0113     Q_D(ItemFetchJob);
0114     d->init();
0115 
0116     d->mCollection = collection;
0117     d->mValuePool = new ProtocolHelperValuePool; // only worth it for lots of results
0118 }
0119 
0120 ItemFetchJob::ItemFetchJob(const Item &item, QObject *parent)
0121     : Job(new ItemFetchJobPrivate(this), parent)
0122 {
0123     Q_D(ItemFetchJob);
0124     d->init();
0125 
0126     d->mRequestedItems.append(item);
0127 }
0128 
0129 ItemFetchJob::ItemFetchJob(const Item::List &items, QObject *parent)
0130     : Job(new ItemFetchJobPrivate(this), parent)
0131 {
0132     Q_D(ItemFetchJob);
0133     d->init();
0134 
0135     d->mRequestedItems = items;
0136 }
0137 
0138 ItemFetchJob::ItemFetchJob(const QList<Item::Id> &items, QObject *parent)
0139     : Job(new ItemFetchJobPrivate(this), parent)
0140 {
0141     Q_D(ItemFetchJob);
0142     d->init();
0143 
0144     d->mRequestedItems.reserve(items.size());
0145     for (auto id : items) {
0146         d->mRequestedItems.append(Item(id));
0147     }
0148 }
0149 ItemFetchJob::ItemFetchJob(const Tag &tag, QObject *parent)
0150     : Job(new ItemFetchJobPrivate(this), parent)
0151 {
0152     Q_D(ItemFetchJob);
0153     d->init();
0154 
0155     d->mCurrentTag = tag;
0156     d->mValuePool = new ProtocolHelperValuePool;
0157 }
0158 
0159 ItemFetchJob::~ItemFetchJob() = default;
0160 
0161 void ItemFetchJob::doStart()
0162 {
0163     Q_D(ItemFetchJob);
0164 
0165     try {
0166         d->sendCommand(Protocol::FetchItemsCommandPtr::create(d->mRequestedItems.isEmpty() ? Scope() : ProtocolHelper::entitySetToScope(d->mRequestedItems),
0167                                                               ProtocolHelper::commandContextToProtocol(d->mCollection, d->mCurrentTag, d->mRequestedItems),
0168                                                               ProtocolHelper::itemFetchScopeToProtocol(d->mFetchScope),
0169                                                               ProtocolHelper::tagFetchScopeToProtocol(d->mFetchScope.tagFetchScope()),
0170                                                               d->mItemsLimit));
0171     } catch (const Akonadi::Exception &e) {
0172         setError(Job::Unknown);
0173         setErrorText(QString::fromUtf8(e.what()));
0174         emitResult();
0175         return;
0176     }
0177 }
0178 
0179 bool ItemFetchJob::doHandleResponse(qint64 tag, const Protocol::CommandPtr &response)
0180 {
0181     Q_D(ItemFetchJob);
0182 
0183     if (!response->isResponse() || response->type() != Protocol::Command::FetchItems) {
0184         return Job::doHandleResponse(tag, response);
0185     }
0186 
0187     const auto &resp = Protocol::cmdCast<Protocol::FetchItemsResponse>(response);
0188     // Invalid ID marks the last part of the response
0189     if (resp.id() < 0) {
0190         return true;
0191     }
0192 
0193     const Item item = ProtocolHelper::parseItemFetchResult(resp, nullptr, d->mValuePool);
0194     if (!item.isValid()) {
0195         return false;
0196     }
0197 
0198     d->mCount++;
0199 
0200     if (d->mDeliveryOptions & ItemGetter) {
0201         d->mResultItems.append(item);
0202     }
0203 
0204     if (d->mDeliveryOptions & EmitItemsInBatches) {
0205         d->mPendingItems.append(item);
0206         if (!d->mEmitTimer.isActive()) {
0207             d->mEmitTimer.start();
0208         }
0209     } else if (d->mDeliveryOptions & EmitItemsIndividually) {
0210         Q_EMIT itemsReceived(Item::List() << item);
0211     }
0212 
0213     return false;
0214 }
0215 
0216 Item::List ItemFetchJob::items() const
0217 {
0218     Q_D(const ItemFetchJob);
0219 
0220     return d->mResultItems;
0221 }
0222 
0223 void ItemFetchJob::clearItems()
0224 {
0225     Q_D(ItemFetchJob);
0226 
0227     d->mResultItems.clear();
0228 }
0229 
0230 void ItemFetchJob::setFetchScope(const ItemFetchScope &fetchScope)
0231 {
0232     Q_D(ItemFetchJob);
0233 
0234     d->mFetchScope = fetchScope;
0235 }
0236 
0237 ItemFetchScope &ItemFetchJob::fetchScope()
0238 {
0239     Q_D(ItemFetchJob);
0240 
0241     return d->mFetchScope;
0242 }
0243 
0244 void ItemFetchJob::setCollection(const Akonadi::Collection &collection)
0245 {
0246     Q_D(ItemFetchJob);
0247 
0248     d->mCollection = collection;
0249 }
0250 
0251 void ItemFetchJob::setDeliveryOption(DeliveryOptions options)
0252 {
0253     Q_D(ItemFetchJob);
0254 
0255     d->mDeliveryOptions = options;
0256 }
0257 
0258 ItemFetchJob::DeliveryOptions ItemFetchJob::deliveryOptions() const
0259 {
0260     Q_D(const ItemFetchJob);
0261 
0262     return d->mDeliveryOptions;
0263 }
0264 
0265 int ItemFetchJob::count() const
0266 {
0267     Q_D(const ItemFetchJob);
0268 
0269     return d->mCount;
0270 }
0271 
0272 void ItemFetchJob::setLimit(int limit, int start, Qt::SortOrder order)
0273 {
0274     Q_D(ItemFetchJob);
0275     d->mItemsLimit.setLimit(limit);
0276     d->mItemsLimit.setLimitOffset(start);
0277     d->mItemsLimit.setSortOrder(order);
0278 }
0279 #include "moc_itemfetchjob.cpp"