File indexing completed on 2024-11-10 04:40:30
0001 /* 0002 SPDX-FileCopyrightText: 2009 Tobias Koenig <tokoe@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "itemsearchjob.h" 0008 0009 #include "itemfetchscope.h" 0010 #include "job_p.h" 0011 #include "private/protocol_p.h" 0012 #include "protocolhelper_p.h" 0013 #include "searchquery.h" 0014 #include "tagfetchscope.h" 0015 0016 #include <QCoreApplication> 0017 #include <QThreadStorage> 0018 #include <QTimer> 0019 0020 using namespace Akonadi; 0021 0022 class Akonadi::ItemSearchJobPrivate : public JobPrivate 0023 { 0024 public: 0025 ItemSearchJobPrivate(ItemSearchJob *parent, const SearchQuery &query) 0026 : JobPrivate(parent) 0027 , mQuery(query) 0028 { 0029 mEmitTimer.setSingleShot(true); 0030 mEmitTimer.setInterval(std::chrono::milliseconds{100}); 0031 } 0032 0033 void init() 0034 { 0035 QObject::connect(&mEmitTimer, &QTimer::timeout, q_ptr, [this]() { 0036 timeout(); 0037 }); 0038 } 0039 0040 void aboutToFinish() override 0041 { 0042 timeout(); 0043 } 0044 0045 void timeout() 0046 { 0047 Q_Q(Akonadi::ItemSearchJob); 0048 0049 mEmitTimer.stop(); // in case we are called by result() 0050 if (!mPendingItems.isEmpty()) { 0051 if (!q->error()) { 0052 Q_EMIT q->itemsReceived(mPendingItems); 0053 } 0054 mPendingItems.clear(); 0055 } 0056 } 0057 QString jobDebuggingString() const override 0058 { 0059 QStringList flags; 0060 if (mRecursive) { 0061 flags.append(QStringLiteral("recursive")); 0062 } 0063 if (mRemote) { 0064 flags.append(QStringLiteral("remote")); 0065 } 0066 if (mCollections.isEmpty()) { 0067 flags.append(QStringLiteral("all collections")); 0068 } else { 0069 flags.append(QStringLiteral("%1 collections").arg(mCollections.count())); 0070 } 0071 return QStringLiteral("%1,json=%2").arg(flags.join(QLatin1Char(',')), QString::fromUtf8(mQuery.toJSON())); 0072 } 0073 0074 Q_DECLARE_PUBLIC(ItemSearchJob) 0075 0076 SearchQuery mQuery; 0077 Collection::List mCollections; 0078 QStringList mMimeTypes; 0079 bool mRecursive = false; 0080 bool mRemote = false; 0081 ItemFetchScope mItemFetchScope; 0082 TagFetchScope mTagFetchScope; 0083 0084 Item::List mItems; 0085 Item::List mPendingItems; // items pending for emitting itemsReceived() 0086 0087 QTimer mEmitTimer; 0088 }; 0089 0090 QThreadStorage<Session *> instances; 0091 0092 static void cleanupDefaultSearchSession() 0093 { 0094 instances.setLocalData(nullptr); 0095 } 0096 0097 static Session *defaultSearchSession() 0098 { 0099 if (!instances.hasLocalData()) { 0100 const QByteArray sessionName = Session::defaultSession()->sessionId() + "-SearchSession"; 0101 instances.setLocalData(new Session(sessionName)); 0102 qAddPostRoutine(cleanupDefaultSearchSession); 0103 } 0104 return instances.localData(); 0105 } 0106 0107 static QObject *sessionForJob(QObject *parent) 0108 { 0109 if (qobject_cast<Job *>(parent) || qobject_cast<Session *>(parent)) { 0110 return parent; 0111 } 0112 return defaultSearchSession(); 0113 } 0114 0115 ItemSearchJob::ItemSearchJob(QObject *parent) 0116 : Job(new ItemSearchJobPrivate(this, SearchQuery()), sessionForJob(parent)) 0117 { 0118 Q_D(ItemSearchJob); 0119 d->init(); 0120 } 0121 0122 ItemSearchJob::ItemSearchJob(const SearchQuery &query, QObject *parent) 0123 : Job(new ItemSearchJobPrivate(this, query), sessionForJob(parent)) 0124 { 0125 Q_D(ItemSearchJob); 0126 d->init(); 0127 } 0128 0129 ItemSearchJob::~ItemSearchJob() = default; 0130 0131 void ItemSearchJob::setQuery(const SearchQuery &query) 0132 { 0133 Q_D(ItemSearchJob); 0134 0135 d->mQuery = query; 0136 } 0137 0138 void ItemSearchJob::setFetchScope(const ItemFetchScope &fetchScope) 0139 { 0140 Q_D(ItemSearchJob); 0141 0142 d->mItemFetchScope = fetchScope; 0143 } 0144 0145 ItemFetchScope &ItemSearchJob::fetchScope() 0146 { 0147 Q_D(ItemSearchJob); 0148 0149 return d->mItemFetchScope; 0150 } 0151 0152 void ItemSearchJob::setTagFetchScope(const TagFetchScope &fetchScope) 0153 { 0154 Q_D(ItemSearchJob); 0155 0156 d->mTagFetchScope = fetchScope; 0157 } 0158 0159 TagFetchScope &ItemSearchJob::tagFetchScope() 0160 { 0161 Q_D(ItemSearchJob); 0162 0163 return d->mTagFetchScope; 0164 } 0165 0166 void ItemSearchJob::setSearchCollections(const Collection::List &collections) 0167 { 0168 Q_D(ItemSearchJob); 0169 0170 d->mCollections = collections; 0171 } 0172 0173 Collection::List ItemSearchJob::searchCollections() const 0174 { 0175 return d_func()->mCollections; 0176 } 0177 0178 void ItemSearchJob::setMimeTypes(const QStringList &mimeTypes) 0179 { 0180 Q_D(ItemSearchJob); 0181 0182 d->mMimeTypes = mimeTypes; 0183 } 0184 0185 QStringList ItemSearchJob::mimeTypes() const 0186 { 0187 return d_func()->mMimeTypes; 0188 } 0189 0190 void ItemSearchJob::setRecursive(bool recursive) 0191 { 0192 Q_D(ItemSearchJob); 0193 0194 d->mRecursive = recursive; 0195 } 0196 0197 bool ItemSearchJob::isRecursive() const 0198 { 0199 return d_func()->mRecursive; 0200 } 0201 0202 void ItemSearchJob::setRemoteSearchEnabled(bool enabled) 0203 { 0204 Q_D(ItemSearchJob); 0205 0206 d->mRemote = enabled; 0207 } 0208 0209 bool ItemSearchJob::isRemoteSearchEnabled() const 0210 { 0211 return d_func()->mRemote; 0212 } 0213 0214 void ItemSearchJob::doStart() 0215 { 0216 Q_D(ItemSearchJob); 0217 0218 auto cmd = Protocol::SearchCommandPtr::create(); 0219 cmd->setMimeTypes(d->mMimeTypes); 0220 if (!d->mCollections.isEmpty()) { 0221 QList<qint64> ids; 0222 ids.reserve(d->mCollections.size()); 0223 for (const Collection &col : std::as_const(d->mCollections)) { 0224 ids << col.id(); 0225 } 0226 cmd->setCollections(ids); 0227 } 0228 cmd->setRecursive(d->mRecursive); 0229 cmd->setRemote(d->mRemote); 0230 cmd->setQuery(QString::fromUtf8(d->mQuery.toJSON())); 0231 cmd->setItemFetchScope(ProtocolHelper::itemFetchScopeToProtocol(d->mItemFetchScope)); 0232 cmd->setTagFetchScope(ProtocolHelper::tagFetchScopeToProtocol(d->mTagFetchScope)); 0233 0234 d->sendCommand(cmd); 0235 } 0236 0237 bool ItemSearchJob::doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) 0238 { 0239 Q_D(ItemSearchJob); 0240 0241 if (response->isResponse() && response->type() == Protocol::Command::FetchItems) { 0242 const Item item = ProtocolHelper::parseItemFetchResult(Protocol::cmdCast<Protocol::FetchItemsResponse>(response)); 0243 if (!item.isValid()) { 0244 return false; 0245 } 0246 d->mItems.append(item); 0247 d->mPendingItems.append(item); 0248 if (!d->mEmitTimer.isActive()) { 0249 d->mEmitTimer.start(); 0250 } 0251 0252 return false; 0253 } 0254 0255 if (response->isResponse() && response->type() == Protocol::Command::Search) { 0256 return true; 0257 } 0258 0259 return Job::doHandleResponse(tag, response); 0260 } 0261 0262 Item::List ItemSearchJob::items() const 0263 { 0264 Q_D(const ItemSearchJob); 0265 0266 return d->mItems; 0267 } 0268 0269 #include "moc_itemsearchjob.cpp"