diff --git a/src/contentlist/BalooContentLister.cpp b/src/contentlist/BalooContentLister.cpp index 66ad83e..24c2a8c 100644 --- a/src/contentlist/BalooContentLister.cpp +++ b/src/contentlist/BalooContentLister.cpp @@ -1,190 +1,189 @@ /* * Copyright (C) 2015 Dan Leinir Turthra Jensen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * */ #include "BalooContentLister.h" #include #include #include #include #include #include #include #include #include #include #include "ContentQuery.h" class BalooContentLister::Private { public: Private(BalooContentLister* qq) : q(qq) {} BalooContentLister* q = nullptr; Baloo::QueryRunnable* createQuery(ContentQuery* contentQuery, const QString& location = QString{}); QStringList knownFiles; QStringList locations; QString searchString; QList queries; QList queryLocations; }; BalooContentLister::BalooContentLister(QObject* parent) : ContentListerBase(parent) , d(new Private(this)) { } BalooContentLister::~BalooContentLister() { QThreadPool::globalInstance()->waitForDone(); delete d; } bool BalooContentLister::balooEnabled() const { Baloo::IndexerConfig config; bool result = config.fileIndexingEnabled(); if(result) { // It would be terribly nice with a bit of baloo engine exporting, so // we can ask the database about whether or not it is accessible... // But, this is a catch-all check anyway, so we get a complete "everything's broken" // result if anything is broken... guess it will do :) QProcess statuscheck; statuscheck.start("balooctl", QStringList() << "status"); statuscheck.waitForFinished(); QString output = statuscheck.readAll(); - qDebug() << "Baloo status check says:" << output; if(statuscheck.exitStatus() == QProcess::CrashExit || statuscheck.exitCode() != 0) { result = false; } } return result; } void BalooContentLister::startSearch(const QList& queries) { for(const auto& query : queries) { for(const auto& location : query->locations()) { d->queries.append(d->createQuery(query, location)); } if(query->locations().isEmpty()) d->queries.append(d->createQuery(query)); } if(!d->queries.empty()) { QThreadPool::globalInstance()->start(d->queries.first()); } } void BalooContentLister::queryCompleted(Baloo::QueryRunnable* query) { d->queries.removeAll(query); if(d->queries.empty()) { emit searchCompleted(); } else { QThreadPool::globalInstance()->start(d->queries.first()); } } void BalooContentLister::queryResult(Baloo::QueryRunnable* query, QString file) { if(d->knownFiles.contains(file)) { return; } // wow, this isn't nice... why is baloo not limiting searches like it's supposed to? if(!file.startsWith(query->property("__location").toString())) { return; } // Like the one above, this is also not nice: apparently Baloo can return results to // files that no longer exist on the file system. So we have to check manually whether // the results provided are actually sensible results... if(!QFile::exists(file)) { return; } auto metadata = metaDataForFile(file); Baloo::File balooFile(file); balooFile.load(); KFileMetaData::PropertyMap properties = balooFile.properties(); KFileMetaData::PropertyMap::const_iterator it = properties.constBegin(); for (; it != properties.constEnd(); it++) { KFileMetaData::PropertyInfo propInfo(it.key()); metadata[propInfo.name()] = it.value(); } emit fileFound(file, metadata); } Baloo::QueryRunnable* BalooContentLister::Private::createQuery(ContentQuery* contentQuery, const QString& location) { auto balooQuery = Baloo::Query{}; if(!location.isEmpty()) balooQuery.setIncludeFolder(location); switch(contentQuery->type()) { case ContentQuery::Audio: balooQuery.setType("Audio"); break; case ContentQuery::Documents: balooQuery.setType("Document"); break; case ContentQuery::Images: balooQuery.setType("Image"); break; case ContentQuery::Video: balooQuery.setType("Video"); break; default: break; } if(!contentQuery->searchString().isEmpty()) balooQuery.setSearchString(contentQuery->searchString()); auto runnable = new Baloo::QueryRunnable{balooQuery}; connect(runnable, &Baloo::QueryRunnable::queryResult, q, &BalooContentLister::queryResult); connect(runnable, &Baloo::QueryRunnable::finished, q, &BalooContentLister::queryCompleted); runnable->setProperty("__contentQuery", QVariant::fromValue(contentQuery)); runnable->setProperty("__location", location); return runnable; } diff --git a/src/contentlist/ContentList.cpp b/src/contentlist/ContentList.cpp index 8f7b736..cf669ed 100644 --- a/src/contentlist/ContentList.cpp +++ b/src/contentlist/ContentList.cpp @@ -1,231 +1,229 @@ /* * Copyright (C) 2015 Dan Leinir Turthra Jensen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * */ #include "ContentList.h" #include "FilesystemContentLister.h" #ifdef BALOO_FOUND #include "BalooContentLister.h" #endif #include #include #include #include struct ContentEntry { QString filename; QUrl filePath; QVariantMap metadata; }; class ContentList::Private { public: typedef QQmlListProperty QueryListProperty; Private() : actualContentList(nullptr) {} QList entries; ContentListerBase* actualContentList; QList queries; QueryListProperty listProperty; bool autoSearch = false; bool completed = false; static void appendToList(QueryListProperty* property, ContentQuery* value); static ContentQuery* listValueAt(QueryListProperty* property, int index); static void clearList(QueryListProperty* property); static int countList(QueryListProperty* property); }; ContentList::ContentList(QObject* parent) : QAbstractListModel(parent) , d(new Private) { #ifdef BALOO_FOUND BalooContentLister* baloo = new BalooContentLister(this); if(baloo->balooEnabled()) { d->actualContentList = baloo; - qDebug() << "Baloo support enabled"; } else { baloo->deleteLater(); d->actualContentList = new FilesystemContentLister(this); - qDebug() << "Baloo is disabled for the system, use the filesystem scraper"; } #else d->actualContentList = new FilesystemContentLister(this); #endif connect(d->actualContentList, &ContentListerBase::fileFound, this, &ContentList::fileFound); connect(d->actualContentList, &ContentListerBase::searchCompleted, this, &ContentList::searchCompleted); d->listProperty = QQmlListProperty{this, &d->queries, &ContentList::Private::appendToList, &ContentList::Private::countList, &ContentList::Private::listValueAt, &ContentList::Private::clearList }; } ContentList::~ContentList() { delete d; } QQmlListProperty ContentList::queries() { return d->listProperty; } bool ContentList::autoSearch() const { return d->autoSearch; } QString ContentList::getMimetype(QString filePath) { QMimeDatabase db; QMimeType mime = db.mimeTypeForFile(filePath); return mime.name(); } void ContentList::startSearch() { QTimer::singleShot(1, [this]() { d->actualContentList->startSearch(d->queries); }); } void ContentList::fileFound(const QString& filePath, const QVariantMap& metaData) { auto fileUrl = QUrl::fromLocalFile(filePath); ContentEntry* entry = new ContentEntry(); entry->filename = fileUrl.fileName(); entry->filePath = fileUrl; entry->metadata = metaData; int newRow = d->entries.count(); beginInsertRows(QModelIndex(), newRow, newRow); d->entries.append(entry); endInsertRows(); } void ContentList::setAutoSearch(bool autoSearch) { if(autoSearch == d->autoSearch) return; d->autoSearch = autoSearch; emit autoSearchChanged(); } QHash ContentList::roleNames() const { QHash roles; roles[FilenameRole] = "filename"; roles[FilePathRole] = "filePath"; roles[MetadataRole] = "metadata"; return roles; } QVariant ContentList::data(const QModelIndex& index, int role) const { if(index.isValid() && index.row() > -1 && index.row() < d->entries.count()) { const ContentEntry* entry = d->entries[index.row()]; switch(role) { case FilenameRole: return entry->filename; break; case FilePathRole: return entry->filePath; break; case MetadataRole: return entry->metadata; break; default: return QString("Unknown role"); break; } } return QVariant(); } int ContentList::rowCount(const QModelIndex& parent) const { if(parent.isValid()) return 0; return d->entries.count(); } void ContentList::classBegin() { } void ContentList::componentComplete() { d->completed = true; if(!d->autoSearch) return; d->actualContentList->startSearch(d->queries); } bool ContentList::isComplete() const { return d->completed; } void ContentList::Private::appendToList(Private::QueryListProperty* property, ContentQuery* value) { auto list = static_cast*>(property->data); auto model = static_cast(property->object); list->append(value); if(model->autoSearch() && model->isComplete()) model->startSearch(); } ContentQuery* ContentList::Private::listValueAt(Private::QueryListProperty* property, int index) { return static_cast*>(property->data)->at(index); } int ContentList::Private::countList(Private::QueryListProperty* property) { return static_cast*>(property->data)->size(); } void ContentList::Private::clearList(Private::QueryListProperty* property) { auto list = static_cast*>(property->data); auto model = static_cast(property->object); model->beginResetModel(); list->clear(); model->endResetModel(); }