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 }