File indexing completed on 2024-12-15 04:14:22

0001 /*
0002  * Copyright (C) 2015 Dan Leinir Turthra Jensen <admin@leinir.dk>
0003  *
0004  * This library is free software; you can redistribute it and/or
0005  * modify it under the terms of the GNU Lesser General Public
0006  * License as published by the Free Software Foundation; either
0007  * version 2.1 of the License, or (at your option) version 3, or any
0008  * later version accepted by the membership of KDE e.V. (or its
0009  * successor approved by the membership of KDE e.V.), which shall
0010  * act as a proxy defined in Section 6 of version 3 of the license.
0011  *
0012  * This library is distributed in the hope that it will be useful,
0013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0015  * Lesser General Public License for more details.
0016  *
0017  * You should have received a copy of the GNU Lesser General Public
0018  * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
0019  *
0020  */
0021 
0022 #include "ContentList.h"
0023 #include "FilesystemContentLister.h"
0024 
0025 #ifdef BALOO_FOUND
0026     #include "BalooContentLister.h"
0027 #endif
0028 
0029 #include <QMimeDatabase>
0030 #include <QSet>
0031 #include <QTimer>
0032 #include <QUrl>
0033 
0034 struct ContentEntry {
0035     QString filename;
0036     QUrl filePath;
0037     QVariantMap metadata;
0038 };
0039 
0040 class ContentList::Private {
0041 public:
0042     typedef QQmlListProperty<ContentQuery> QueryListProperty;
0043 
0044     Private()
0045         : actualContentList(nullptr)
0046     {}
0047     QList<ContentEntry*> entries;
0048     ContentListerBase* actualContentList;
0049 
0050     QList<ContentQuery*> queries;
0051     QueryListProperty listProperty;
0052 
0053     QSet<QString> knownFiles;
0054 
0055     bool autoSearch = false;
0056     bool cacheResults = false;
0057     bool completed = false;
0058 
0059     static void appendToList(QueryListProperty* property, ContentQuery* value);
0060     static ContentQuery* listValueAt(QueryListProperty* property, int index);
0061     static void clearList(QueryListProperty* property);
0062     static int countList(QueryListProperty* property);
0063 
0064     static QStringList cachedFiles;
0065 };
0066 
0067 QStringList ContentList::Private::cachedFiles;
0068 
0069 ContentList::ContentList(QObject* parent)
0070     : QAbstractListModel(parent)
0071     , d(new Private)
0072 {
0073 #ifdef BALOO_FOUND
0074     BalooContentLister* baloo = new BalooContentLister(this);
0075     if(baloo->balooEnabled())
0076     {
0077         d->actualContentList = baloo;
0078     }
0079     else
0080     {
0081         baloo->deleteLater();
0082         d->actualContentList = new FilesystemContentLister(this);
0083     }
0084 #else
0085     d->actualContentList = new FilesystemContentLister(this);
0086 #endif
0087     connect(d->actualContentList, &ContentListerBase::fileFound, this, &ContentList::fileFound);
0088     connect(d->actualContentList, &ContentListerBase::searchCompleted, this, &ContentList::searchCompleted);
0089 
0090     d->listProperty = QQmlListProperty<ContentQuery>{this, &d->queries,
0091         &ContentList::Private::appendToList,
0092         &ContentList::Private::countList,
0093         &ContentList::Private::listValueAt,
0094         &ContentList::Private::clearList
0095     };
0096 }
0097 
0098 ContentList::~ContentList()
0099 {
0100     delete d;
0101 }
0102 
0103 QQmlListProperty<ContentQuery> ContentList::queries()
0104 {
0105     return d->listProperty;
0106 }
0107 
0108 bool ContentList::autoSearch() const
0109 {
0110     return d->autoSearch;
0111 }
0112 
0113 bool ContentList::cacheResults() const
0114 {
0115     return d->cacheResults;
0116 }
0117 
0118 QString ContentList::getMimetype(QString filePath)
0119 {
0120     QMimeDatabase db;
0121     QMimeType mime = db.mimeTypeForFile(filePath);
0122     return mime.name();
0123 }
0124 
0125 void ContentList::startSearch()
0126 {
0127     QTimer::singleShot(1, [this]() {
0128         Q_EMIT searchStarted();
0129         d->actualContentList->knownFiles = d->knownFiles;
0130         d->actualContentList->startSearch(d->queries);
0131     });
0132 }
0133 
0134 void ContentList::fileFound(const QString& filePath, const QVariantMap& metaData)
0135 {
0136     if(d->knownFiles.contains(filePath))
0137         return;
0138 
0139     auto fileUrl = QUrl::fromLocalFile(filePath);
0140 
0141     ContentEntry* entry = new ContentEntry();
0142     entry->filename = fileUrl.fileName();
0143     entry->filePath = fileUrl;
0144     entry->metadata = metaData;
0145 
0146     int newRow = d->entries.count();
0147     beginInsertRows(QModelIndex(), newRow, newRow);
0148     d->entries.append(entry);
0149     endInsertRows();
0150 
0151     if(d->cacheResults)
0152         Private::cachedFiles.append(filePath);
0153 }
0154 
0155 void ContentList::setAutoSearch(bool autoSearch)
0156 {
0157     if(autoSearch == d->autoSearch)
0158         return;
0159 
0160     d->autoSearch = autoSearch;
0161     emit autoSearchChanged();
0162 }
0163 
0164 void ContentList::setCacheResults(bool cacheResults)
0165 {
0166     if(cacheResults == d->cacheResults)
0167         return;
0168 
0169     d->cacheResults = cacheResults;
0170 
0171     if(d->cacheResults && d->completed && !Private::cachedFiles.isEmpty())
0172     {
0173         setKnownFiles(Private::cachedFiles);
0174     }
0175 
0176     emit cacheResultsChanged();
0177 }
0178 
0179 void ContentList::setKnownFiles(const QStringList& results)
0180 {
0181     beginResetModel();
0182     d->entries.clear();
0183     d->knownFiles.clear();
0184     for(const auto& result : results)
0185     {
0186         auto entry = new ContentEntry{};
0187         auto url = QUrl::fromLocalFile(result);
0188 
0189         entry->filename = url.fileName();
0190         entry->filePath = url;
0191         entry->metadata = ContentListerBase::metaDataForFile(result);
0192 
0193         d->entries.append(entry);
0194         d->knownFiles.insert(result);
0195     }
0196     endResetModel();
0197 }
0198 
0199 QHash<int, QByteArray> ContentList::roleNames() const
0200 {
0201     return {
0202         { FilenameRole, "filename"},
0203         { FilePathRole, "filePath"},
0204         { MetadataRole, "metadata"}
0205     };
0206 }
0207 
0208 QVariant ContentList::data(const QModelIndex& index, int role) const
0209 {
0210     QVariant result;
0211     if(index.isValid() && index.row() > -1 && index.row() < d->entries.count())
0212     {
0213         const ContentEntry* entry = d->entries[index.row()];
0214         switch(role)
0215         {
0216             case FilenameRole:
0217                 result.setValue(entry->filename);
0218                 break;
0219             case FilePathRole:
0220                 result.setValue(entry->filePath);
0221                 break;
0222             case MetadataRole:
0223                 result.setValue(entry->metadata);
0224                 break;
0225             default:
0226                 break;
0227         }
0228     }
0229     return result;
0230 }
0231 
0232 int ContentList::rowCount(const QModelIndex& parent) const
0233 {
0234     if(parent.isValid())
0235         return 0;
0236     return d->entries.count();
0237 }
0238 
0239 void ContentList::classBegin()
0240 {
0241 }
0242 
0243 void ContentList::componentComplete()
0244 {
0245     d->completed = true;
0246 
0247     if(d->cacheResults && !Private::cachedFiles.isEmpty())
0248         setKnownFiles(Private::cachedFiles);
0249 
0250     if(d->autoSearch)
0251         d->actualContentList->startSearch(d->queries);
0252 }
0253 
0254 bool ContentList::isComplete() const
0255 {
0256     return d->completed;
0257 }
0258 
0259 void ContentList::Private::appendToList(Private::QueryListProperty* property, ContentQuery* value)
0260 {
0261     auto list = static_cast<QList<ContentQuery*>*>(property->data);
0262     auto model = static_cast<ContentList*>(property->object);
0263     list->append(value);
0264     if(model->autoSearch() && model->isComplete())
0265         model->startSearch();
0266 }
0267 
0268 ContentQuery* ContentList::Private::listValueAt(Private::QueryListProperty* property, int index)
0269 {
0270     return static_cast<QList<ContentQuery*>*>(property->data)->at(index);
0271 }
0272 
0273 int ContentList::Private::countList(Private::QueryListProperty* property)
0274 {
0275     return static_cast<QList<ContentQuery*>*>(property->data)->size();
0276 }
0277 
0278 void ContentList::Private::clearList(Private::QueryListProperty* property)
0279 {
0280     auto list = static_cast<QList<ContentQuery*>*>(property->data);
0281     auto model = static_cast<ContentList*>(property->object);
0282     model->beginResetModel();
0283     list->clear();
0284     model->endResetModel();
0285 }