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"