File indexing completed on 2024-05-12 15:51:17

0001 // SPDX-FileCopyrightText: 2015 Dan Leinir Turthra Jensen <admin@leinir.dk>
0002 // SPDX-FileCopyrightText: 2022 Carl Schwan <carl@carlschwan.eu>
0003 // SPDX-License-Identifier: LGPL-2.1-only or LGPL-3.0-only or LicenseRef-KDE-Accepted-LGPL
0004 
0005 #include "filesystemcontentlister.h"
0006 
0007 #include <KFileMetaData/UserMetaData>
0008 
0009 #include <QCoreApplication>
0010 #include <QDateTime>
0011 #include <QDirIterator>
0012 #include <QMimeDatabase>
0013 #include <QRunnable>
0014 #include <QThreadPool>
0015 #include <QTimer>
0016 #include <QVariantHash>
0017 
0018 #include "contentquery.h"
0019 
0020 class FileSystemSearcher : public QObject, public QRunnable
0021 {
0022     Q_OBJECT
0023 public:
0024     FileSystemSearcher(ContentQuery *query)
0025         : QObject()
0026     {
0027         m_query = query;
0028     }
0029 
0030     void run() override
0031     {
0032         QMimeDatabase mimeDb;
0033 
0034         auto locations = m_query->locations();
0035         if (locations.isEmpty())
0036             locations.append(QDir::homePath());
0037 
0038         for (const auto &location : locations) {
0039             QDirIterator it(location, QDirIterator::Subdirectories);
0040             while (it.hasNext()) {
0041                 auto filePath = it.next();
0042 
0043                 if (it.fileInfo().isDir())
0044                     continue;
0045 
0046                 if (!m_query->mimeTypes().isEmpty()) {
0047                     QString mimeType = mimeDb.mimeTypeForFile(filePath).name();
0048                     if (!m_query->mimeTypes().contains(mimeType)) {
0049                         continue;
0050                     }
0051                 }
0052 
0053                 auto metadata = ContentListerBase::metaDataForFile(filePath);
0054 
0055                 Q_EMIT fileFound(filePath, metadata);
0056             }
0057         }
0058 
0059         Q_EMIT finished(this);
0060     }
0061 
0062 Q_SIGNALS:
0063     void fileFound(const QString &path, const QVariantMap &metaData);
0064     void finished(FileSystemSearcher *searcher);
0065 
0066 private:
0067     ContentQuery *m_query;
0068 };
0069 
0070 class FilesystemContentLister::Private
0071 {
0072 public:
0073     Private()
0074     {
0075     }
0076 
0077     QList<FileSystemSearcher *> runnables;
0078 };
0079 
0080 FilesystemContentLister::FilesystemContentLister(QObject *parent)
0081     : ContentListerBase(parent)
0082     , d(std::make_unique<Private>())
0083 {
0084 }
0085 
0086 FilesystemContentLister::~FilesystemContentLister()
0087 {
0088     QThreadPool::globalInstance()->waitForDone();
0089 }
0090 
0091 void FilesystemContentLister::startSearch(const QList<ContentQuery *> &queries)
0092 {
0093     for (const auto &query : queries) {
0094         auto runnable = new FileSystemSearcher{query};
0095         connect(runnable, &FileSystemSearcher::fileFound, this, &FilesystemContentLister::fileFound);
0096         connect(runnable, &FileSystemSearcher::finished, this, &FilesystemContentLister::queryFinished);
0097 
0098         d->runnables.append(runnable);
0099     }
0100 
0101     if (!d->runnables.isEmpty()) {
0102         QThreadPool::globalInstance()->start(d->runnables.first());
0103     }
0104 }
0105 
0106 void FilesystemContentLister::queryFinished(QRunnable *runnable)
0107 {
0108     d->runnables.removeAll(static_cast<FileSystemSearcher *>(runnable));
0109 
0110     if (!d->runnables.isEmpty()) {
0111         QThreadPool::globalInstance()->start(d->runnables.first());
0112     } else {
0113         Q_EMIT searchCompleted();
0114     }
0115 }
0116 
0117 #include "filesystemcontentlister.moc"
0118 
0119 #include "moc_filesystemcontentlister.cpp"