File indexing completed on 2024-05-12 15:51:16
0001 // SPDX-FileCopyrightText: 2015 Dan Leinir Turthra Jensen <admin@leinir.dk> 0002 // SPDX-License-Identifier: LGPL-2.1-only or LGPL-3.0-only or LicenseRef-KDE-Accepted-LGPL 0003 0004 #include "baloocontentlister.h" 0005 0006 #include <Baloo/File> 0007 #include <Baloo/IndexerConfig> 0008 #include <KFileMetaData/PropertyInfo> 0009 #include <KFileMetaData/UserMetaData> 0010 0011 #include <QDateTime> 0012 #include <QDebug> 0013 #include <QFileInfo> 0014 #include <QList> 0015 #include <QMimeDatabase> 0016 #include <QProcess> 0017 #include <QThreadPool> 0018 0019 #include "contentquery.h" 0020 0021 class BalooContentLister::Private 0022 { 0023 public: 0024 Private(BalooContentLister *qq) 0025 : q(qq) 0026 { 0027 } 0028 0029 BalooContentLister *q = nullptr; 0030 0031 Baloo::QueryRunnable *createQuery(ContentQuery *contentQuery, const QString &location = QString{}); 0032 0033 QStringList locations; 0034 QString searchString; 0035 QList<Baloo::QueryRunnable *> queries; 0036 QList<QString> queryLocations; 0037 0038 QMimeDatabase mimeDatabase; 0039 }; 0040 0041 BalooContentLister::BalooContentLister(QObject *parent) 0042 : ContentListerBase(parent) 0043 , d(std::make_unique<Private>(this)) 0044 { 0045 } 0046 0047 BalooContentLister::~BalooContentLister() 0048 { 0049 QThreadPool::globalInstance()->waitForDone(); 0050 } 0051 0052 bool BalooContentLister::balooEnabled() const 0053 { 0054 // Baloo is not intended to be used outside of Plasma sessions 0055 // and so we can bypass all the testing if we are not actually 0056 // in a full KDE session. 0057 bool result{qEnvironmentVariableIsSet("KDE_FULL_SESSION")}; 0058 0059 if (result) { 0060 Baloo::IndexerConfig config; 0061 result = config.fileIndexingEnabled(); 0062 0063 if (result) { 0064 // It would be terribly nice with a bit of baloo engine exporting, so 0065 // we can ask the database about whether or not it is accessible... 0066 // But, this is a catch-all check anyway, so we get a complete "everything's broken" 0067 // result if anything is broken... guess it will do :) 0068 QProcess statuscheck; 0069 statuscheck.start(QStringLiteral("balooctl"), QStringList() << QStringLiteral("status")); 0070 statuscheck.waitForFinished(); 0071 if (statuscheck.exitStatus() == QProcess::CrashExit || statuscheck.exitCode() != 0) { 0072 result = false; 0073 } 0074 } 0075 } 0076 0077 return result; 0078 } 0079 0080 void BalooContentLister::startSearch(const QList<ContentQuery *> &queries) 0081 { 0082 for (const auto &query : queries) { 0083 const auto locations = query->locations(); 0084 for (const auto &location : locations) { 0085 d->queries.append(d->createQuery(query, location)); 0086 } 0087 0088 if (query->locations().isEmpty()) { 0089 d->queries.append(d->createQuery(query)); 0090 } 0091 } 0092 0093 if (!d->queries.empty()) { 0094 qWarning() << "starting query" << d->queries.first(); 0095 QThreadPool::globalInstance()->start(d->queries.first()); 0096 } 0097 } 0098 0099 void BalooContentLister::queryCompleted(Baloo::QueryRunnable *query) 0100 { 0101 d->queries.removeAll(query); 0102 if (d->queries.empty()) { 0103 Q_EMIT searchCompleted(); 0104 } else { 0105 qWarning() << "starting query" << d->queries.first(); 0106 QThreadPool::globalInstance()->start(d->queries.first()); 0107 } 0108 } 0109 0110 void BalooContentLister::queryResult(const ContentQuery *query, const QString &location, const QString &file) 0111 { 0112 Q_UNUSED(location) 0113 if (knownFiles.contains(file)) { 0114 return; 0115 } 0116 0117 // Like the one above, this is also not nice: apparently Baloo can return results to 0118 // files that no longer exist on the file system. So we have to check manually whether 0119 // the results provided are actually sensible results... 0120 if (!QFileInfo::exists(file)) { 0121 return; 0122 } 0123 0124 // It would be nice if Baloo could do mime type filtering on its own... 0125 if (!query->mimeTypes().isEmpty()) { 0126 const auto &mimeType = d->mimeDatabase.mimeTypeForFile(file).name(); 0127 if (!query->mimeTypes().contains(mimeType)) 0128 return; 0129 } 0130 0131 auto metadata = metaDataForFile(file); 0132 0133 Baloo::File balooFile(file); 0134 balooFile.load(); 0135 auto properties = balooFile.properties(); 0136 auto it = properties.constBegin(); 0137 for (; it != properties.constEnd(); it++) { 0138 KFileMetaData::PropertyInfo propInfo(it.key()); 0139 metadata[propInfo.name()] = it.value(); 0140 } 0141 0142 knownFiles << file; 0143 Q_EMIT fileFound(file, metadata); 0144 } 0145 0146 Baloo::QueryRunnable *BalooContentLister::Private::createQuery(ContentQuery *contentQuery, const QString &location) 0147 { 0148 auto balooQuery = Baloo::Query{}; 0149 0150 switch (contentQuery->type()) { 0151 case ContentQuery::Audio: 0152 balooQuery.setType(QStringLiteral("Audio")); 0153 break; 0154 case ContentQuery::Documents: 0155 case ContentQuery::Epub: 0156 balooQuery.setType(QStringLiteral("Document")); 0157 break; 0158 case ContentQuery::Images: 0159 balooQuery.setType(QStringLiteral("Image")); 0160 break; 0161 case ContentQuery::Video: 0162 balooQuery.setType(QStringLiteral("Video")); 0163 break; 0164 break; 0165 default: 0166 break; 0167 } 0168 0169 balooQuery.setSearchString(QStringLiteral("epub")); 0170 0171 auto runnable = new Baloo::QueryRunnable{balooQuery}; 0172 connect(runnable, &Baloo::QueryRunnable::queryResult, q, [this, contentQuery, location](QRunnable *, const QString &file) { 0173 q->queryResult(contentQuery, location, file); 0174 }); 0175 connect(runnable, &Baloo::QueryRunnable::finished, q, &BalooContentLister::queryCompleted); 0176 0177 return runnable; 0178 } 0179 0180 #include "moc_baloocontentlister.cpp"