File indexing completed on 2024-12-15 04:54:36

0001 /*
0002  * SPDX-FileCopyrightText: 2016 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.net>
0003  *
0004  * SPDX-License-Identifier: GPL-2.0-or-later
0005  *
0006  */
0007 
0008 #include "searchcollectionindexingwarning.h"
0009 #include "messagelist_debug.h"
0010 
0011 #include <Akonadi/CachePolicy>
0012 #include <Akonadi/CollectionFetchJob>
0013 #include <Akonadi/CollectionFetchScope>
0014 #include <Akonadi/CollectionStatistics>
0015 #include <Akonadi/EntityHiddenAttribute>
0016 #include <Akonadi/PersistentSearchAttribute>
0017 
0018 #include <PimCommon/PimUtil>
0019 
0020 #include <KLocalizedString>
0021 
0022 #include <PIM/indexeditems.h>
0023 
0024 using namespace MessageList::Core;
0025 
0026 SearchCollectionIndexingWarning::SearchCollectionIndexingWarning(QWidget *parent)
0027     : KMessageWidget(parent)
0028     , mIndexedItems(new Akonadi::Search::PIM::IndexedItems(this))
0029 {
0030     setVisible(false);
0031     setWordWrap(true);
0032     setText(
0033         i18n("Some of the search folders in this query are still being indexed "
0034              "or are excluded from indexing completely. The results below may be incomplete."));
0035     setCloseButtonVisible(true);
0036     setMessageType(Information);
0037 }
0038 
0039 SearchCollectionIndexingWarning::~SearchCollectionIndexingWarning() = default;
0040 
0041 Akonadi::CollectionFetchJob *SearchCollectionIndexingWarning::fetchCollections(const Akonadi::Collection::List &cols, bool recursive)
0042 {
0043     const Akonadi::CollectionFetchJob::Type type = recursive ? Akonadi::CollectionFetchJob::Recursive : Akonadi::CollectionFetchJob::Base;
0044     auto fetch = new Akonadi::CollectionFetchJob(cols, type, this);
0045     fetch->fetchScope().setAncestorRetrieval(Akonadi::CollectionFetchScope::None);
0046     fetch->fetchScope().setContentMimeTypes(QStringList() << Akonadi::Collection::mimeType() << QStringLiteral("message/rfc822"));
0047     fetch->fetchScope().setIncludeStatistics(true);
0048     return fetch;
0049 }
0050 
0051 void SearchCollectionIndexingWarning::setCollection(const Akonadi::Collection &collection)
0052 {
0053     if (collection == mCollection) {
0054         return;
0055     }
0056 
0057     animatedHide();
0058 
0059     mCollection = collection;
0060     mCollections.clear();
0061 
0062     // Not a search collection?
0063     if (!collection.hasAttribute<Akonadi::PersistentSearchAttribute>()) {
0064         return;
0065     }
0066 
0067     const auto attr = collection.attribute<Akonadi::PersistentSearchAttribute>();
0068     Akonadi::Collection::List cols;
0069     const QList<qint64> queryCols = attr->queryCollections();
0070     cols.reserve(queryCols.count());
0071     for (qint64 col : queryCols) {
0072         cols.push_back(Akonadi::Collection(col));
0073     }
0074     if (cols.isEmpty()) {
0075         return;
0076     }
0077 
0078     // First retrieve the top-level collections
0079     Akonadi::CollectionFetchJob *fetch = fetchCollections(cols, false);
0080     fetch->setProperty("recursiveQuery", attr->isRecursive());
0081     connect(fetch, &Akonadi::CollectionFetchJob::finished, this, &SearchCollectionIndexingWarning::queryRootCollectionFetchFinished);
0082 }
0083 
0084 void SearchCollectionIndexingWarning::queryRootCollectionFetchFinished(KJob *job)
0085 {
0086     if (job->error()) {
0087         qCWarning(MESSAGELIST_LOG) << job->errorString();
0088         return;
0089     }
0090 
0091     // Store the root collections
0092     mCollections = qobject_cast<Akonadi::CollectionFetchJob *>(job)->collections();
0093 
0094     if (job->property("recursiveQuery").toBool()) {
0095         // Fetch all descendants, if necessary
0096         Akonadi::CollectionFetchJob *fetch = fetchCollections(mCollections, true);
0097         connect(fetch, &Akonadi::CollectionFetchJob::finished, this, &SearchCollectionIndexingWarning::queryCollectionFetchFinished);
0098     } else {
0099         queryIndexerStatus();
0100     }
0101 }
0102 
0103 void SearchCollectionIndexingWarning::queryCollectionFetchFinished(KJob *job)
0104 {
0105     if (job->error()) {
0106         qCWarning(MESSAGELIST_LOG) << job->errorString();
0107         return;
0108     }
0109 
0110     mCollections += qobject_cast<Akonadi::CollectionFetchJob *>(job)->collections();
0111     queryIndexerStatus();
0112 }
0113 
0114 void SearchCollectionIndexingWarning::queryIndexerStatus()
0115 {
0116     bool allFullyIndexed = true;
0117     for (const Akonadi::Collection &col : std::as_const(mCollections)) {
0118         if (col.hasAttribute<Akonadi::EntityHiddenAttribute>()) {
0119             continue;
0120         }
0121         if (PimCommon::Util::isImapResource(col.resource()) && !col.cachePolicy().localParts().contains(QLatin1StringView("RFC822"))) {
0122             continue;
0123         }
0124         const qlonglong result = mIndexedItems->indexedItems(col.id());
0125 
0126         qCDebug(MESSAGELIST_LOG) << "Collection:" << col.displayName() << "(" << col.id() << "), count:" << col.statistics().count() << ", index:" << result;
0127         if (col.statistics().count() != result) {
0128             allFullyIndexed = false;
0129             break;
0130         }
0131     }
0132     if (!allFullyIndexed) {
0133         animatedShow();
0134     }
0135 }
0136 
0137 #include "moc_searchcollectionindexingwarning.cpp"