Changeset View
Changeset View
Standalone View
Standalone View
src/contentlist/BalooContentLister.cpp
Show All 27 Lines | |||||
28 | 28 | | |||
29 | #include <QDateTime> | 29 | #include <QDateTime> | ||
30 | #include <QDebug> | 30 | #include <QDebug> | ||
31 | #include <QList> | 31 | #include <QList> | ||
32 | #include <QFileInfo> | 32 | #include <QFileInfo> | ||
33 | #include <QProcess> | 33 | #include <QProcess> | ||
34 | #include <QThreadPool> | 34 | #include <QThreadPool> | ||
35 | 35 | | |||
36 | #include "ContentQuery.h" | ||||
37 | | ||||
36 | class BalooContentLister::Private | 38 | class BalooContentLister::Private | ||
37 | { | 39 | { | ||
38 | public: | 40 | public: | ||
39 | Private() {} | 41 | Private(BalooContentLister* qq) : q(qq) {} | ||
42 | | ||||
43 | BalooContentLister* q = nullptr; | ||||
44 | | ||||
45 | Baloo::QueryRunnable* createQuery(ContentQuery* contentQuery, const QString& location = QString{}); | ||||
46 | | ||||
40 | QStringList knownFiles; | 47 | QStringList knownFiles; | ||
41 | QStringList locations; | 48 | QStringList locations; | ||
42 | QString searchString; | 49 | QString searchString; | ||
43 | QList<Baloo::QueryRunnable*> queries; | 50 | QList<Baloo::QueryRunnable*> queries; | ||
44 | QList<QString> queryLocations; | 51 | QList<QString> queryLocations; | ||
45 | }; | 52 | }; | ||
46 | 53 | | |||
47 | BalooContentLister::BalooContentLister(QObject* parent) | 54 | BalooContentLister::BalooContentLister(QObject* parent) | ||
48 | : ContentListerBase(parent) | 55 | : ContentListerBase(parent) | ||
49 | , d(new Private) | 56 | , d(new Private(this)) | ||
50 | { | 57 | { | ||
51 | } | 58 | } | ||
52 | 59 | | |||
53 | BalooContentLister::~BalooContentLister() | 60 | BalooContentLister::~BalooContentLister() | ||
54 | { | 61 | { | ||
62 | QThreadPool::globalInstance()->waitForDone(); | ||||
55 | delete d; | 63 | delete d; | ||
56 | } | 64 | } | ||
57 | 65 | | |||
58 | bool BalooContentLister::balooEnabled() const | 66 | bool BalooContentLister::balooEnabled() const | ||
59 | { | 67 | { | ||
60 | Baloo::IndexerConfig config; | 68 | Baloo::IndexerConfig config; | ||
61 | bool result = config.fileIndexingEnabled(); | 69 | bool result = config.fileIndexingEnabled(); | ||
62 | 70 | | |||
63 | if(result) | 71 | if(result) | ||
64 | { | 72 | { | ||
65 | // It would be terribly nice with a bit of baloo engine exporting, so | 73 | // It would be terribly nice with a bit of baloo engine exporting, so | ||
66 | // we can ask the database about whether or not it is accessible... | 74 | // we can ask the database about whether or not it is accessible... | ||
67 | // But, this is a catch-all check anyway, so we get a complete "everything's broken" | 75 | // But, this is a catch-all check anyway, so we get a complete "everything's broken" | ||
68 | // result if anything is broken... guess it will do :) | 76 | // result if anything is broken... guess it will do :) | ||
69 | QProcess statuscheck; | 77 | QProcess statuscheck; | ||
70 | statuscheck.start("balooctl", QStringList() << "status"); | 78 | statuscheck.start("balooctl", QStringList() << "status"); | ||
71 | statuscheck.waitForFinished(); | 79 | statuscheck.waitForFinished(); | ||
72 | QString output = statuscheck.readAll(); | 80 | QString output = statuscheck.readAll(); | ||
73 | qDebug() << "Baloo status check says:" << output; | | |||
74 | if(statuscheck.exitStatus() == QProcess::CrashExit || statuscheck.exitCode() != 0) | 81 | if(statuscheck.exitStatus() == QProcess::CrashExit || statuscheck.exitCode() != 0) | ||
75 | { | 82 | { | ||
76 | result = false; | 83 | result = false; | ||
77 | } | 84 | } | ||
78 | } | 85 | } | ||
79 | 86 | | |||
80 | return result; | 87 | return result; | ||
81 | } | 88 | } | ||
82 | 89 | | |||
83 | void BalooContentLister::addLocation(QString path) | 90 | void BalooContentLister::startSearch(const QList<ContentQuery*>& queries) | ||
84 | { | 91 | { | ||
85 | d->locations.append(path); | 92 | for(const auto& query : queries) | ||
86 | } | | |||
87 | | ||||
88 | void BalooContentLister::addMimetype(QString mimetype) | | |||
89 | { | 93 | { | ||
90 | Q_UNUSED(mimetype) | 94 | for(const auto& location : query->locations()) | ||
91 | // yes, unsatisfactory... we're using this to find comic books for now, and their mimetypes are terrible | | |||
92 | } | | |||
93 | | ||||
94 | void BalooContentLister::setSearchString(const QString& searchString) | | |||
95 | { | 95 | { | ||
96 | d->searchString = searchString; | 96 | d->queries.append(d->createQuery(query, location)); | ||
97 | } | 97 | } | ||
98 | 98 | | |||
99 | void BalooContentLister::setKnownFiles(QStringList knownFiles) | 99 | if(query->locations().isEmpty()) | ||
100 | { | 100 | d->queries.append(d->createQuery(query)); | ||
101 | d->knownFiles = knownFiles; | | |||
102 | } | 101 | } | ||
103 | 102 | | |||
104 | void BalooContentLister::startSearch() | | |||
105 | { | | |||
106 | Q_FOREACH(const QString& location, d->locations) | | |||
107 | { | | |||
108 | Baloo::Query query; | | |||
109 | query.setSearchString(d->searchString); | | |||
110 | query.setIncludeFolder(location); | | |||
111 | | ||||
112 | Baloo::QueryRunnable *runnable = new Baloo::QueryRunnable(query); | | |||
113 | connect(runnable, SIGNAL(queryResult(Baloo::QueryRunnable*, QString)), | | |||
114 | this, SLOT(queryResult(Baloo::QueryRunnable*, QString)), Qt::QueuedConnection); | | |||
115 | connect(runnable, SIGNAL(finished(Baloo::QueryRunnable*)), | | |||
116 | this, SLOT(queryCompleted(Baloo::QueryRunnable*))); | | |||
117 | | ||||
118 | d->queries.append(runnable); | | |||
119 | d->queryLocations.append(location); | | |||
120 | } | | |||
121 | // This ensures that, should we decide to search more stuff later, we can do so granularly | | |||
122 | d->locations.clear(); | | |||
123 | | ||||
124 | if(!d->queries.empty()) | 103 | if(!d->queries.empty()) | ||
125 | { | 104 | { | ||
126 | QThreadPool::globalInstance()->start(d->queries.first()); | 105 | QThreadPool::globalInstance()->start(d->queries.first()); | ||
127 | } | 106 | } | ||
128 | } | 107 | } | ||
129 | 108 | | |||
130 | void BalooContentLister::queryCompleted(Baloo::QueryRunnable* query) | 109 | void BalooContentLister::queryCompleted(Baloo::QueryRunnable* query) | ||
131 | { | 110 | { | ||
132 | d->queries.removeAll(query); | 111 | d->queries.removeAll(query); | ||
133 | d->queryLocations.takeFirst(); | | |||
134 | if(d->queries.empty()) | 112 | if(d->queries.empty()) | ||
135 | { | 113 | { | ||
136 | emit searchCompleted(); | 114 | emit searchCompleted(); | ||
137 | } | 115 | } | ||
138 | else | 116 | else | ||
139 | { | 117 | { | ||
140 | QThreadPool::globalInstance()->start(d->queries.first()); | 118 | QThreadPool::globalInstance()->start(d->queries.first()); | ||
141 | } | 119 | } | ||
142 | } | 120 | } | ||
143 | 121 | | |||
144 | void BalooContentLister::queryResult(Baloo::QueryRunnable* query, QString file) | 122 | void BalooContentLister::queryResult(Baloo::QueryRunnable* query, QString file) | ||
145 | { | 123 | { | ||
146 | Q_UNUSED(query) | | |||
147 | | ||||
148 | if(d->knownFiles.contains(file)) { | 124 | if(d->knownFiles.contains(file)) { | ||
149 | return; | 125 | return; | ||
150 | } | 126 | } | ||
151 | 127 | | |||
152 | // wow, this isn't nice... why is baloo not limiting searches like it's supposed to? | 128 | // wow, this isn't nice... why is baloo not limiting searches like it's supposed to? | ||
153 | if(!file.startsWith(d->queryLocations.first())) { | 129 | if(!file.startsWith(query->property("__location").toString())) { | ||
leinir: This line crashes for me, when attempting to read the __location property (also, a quick check… | |||||
It seems Baloo passes an invalid runnable. :( Fixed now by using a lambda as discussed on IRC. :) ahiemstra: It seems Baloo passes an invalid runnable. :( Fixed now by using a lambda as discussed on IRC. | |||||
Silly Baloo... Oh well, this is nice and clean anyway, so that works! :) Yay for lamdas ;) leinir: Silly Baloo... Oh well, this is nice and clean anyway, so that works! :) Yay for lamdas ;) | |||||
154 | return; | 130 | return; | ||
155 | } | 131 | } | ||
156 | 132 | | |||
157 | QVariantHash metadata; | 133 | // Like the one above, this is also not nice: apparently Baloo can return results to | ||
134 | // files that no longer exist on the file system. So we have to check manually whether | ||||
135 | // the results provided are actually sensible results... | ||||
136 | if(!QFile::exists(file)) { | ||||
137 | return; | ||||
138 | } | ||||
139 | | ||||
140 | auto metadata = metaDataForFile(file); | ||||
158 | 141 | | |||
159 | Baloo::File balooFile(file); | 142 | Baloo::File balooFile(file); | ||
160 | balooFile.load(); | 143 | balooFile.load(); | ||
161 | KFileMetaData::PropertyMap properties = balooFile.properties(); | 144 | KFileMetaData::PropertyMap properties = balooFile.properties(); | ||
162 | KFileMetaData::PropertyMap::const_iterator it = properties.constBegin(); | 145 | KFileMetaData::PropertyMap::const_iterator it = properties.constBegin(); | ||
163 | for (; it != properties.constEnd(); it++) | 146 | for (; it != properties.constEnd(); it++) | ||
164 | { | 147 | { | ||
165 | KFileMetaData::PropertyInfo propInfo(it.key()); | 148 | KFileMetaData::PropertyInfo propInfo(it.key()); | ||
166 | metadata[propInfo.name()] = it.value(); | 149 | metadata[propInfo.name()] = it.value(); | ||
167 | // qDebug() << KFileMetaData::PropertyInfo(it.key()).name() << " --> " | | |||
168 | // << it.value().toString() << " (" << it.value().typeName() << ")\n"; | | |||
169 | } | 150 | } | ||
170 | QFileInfo info(file); | | |||
171 | metadata["lastModified"] = info.lastModified(); | | |||
172 | metadata["created"] = info.created(); | | |||
173 | metadata["lastRead"] = info.lastRead(); | | |||
174 | | ||||
175 | KFileMetaData::UserMetaData data(file); | | |||
176 | int currentPage = data.attribute("peruse.currentPage").toInt(); | | |||
177 | metadata["currentPage"] = QVariant::fromValue<int>(currentPage); | | |||
178 | int totalPages = data.attribute("peruse.totalPages").toInt(); | | |||
179 | metadata["totalPages"] = QVariant::fromValue<int>(totalPages); | | |||
180 | 151 | | |||
181 | emit fileFound(file, metadata); | 152 | emit fileFound(file, metadata); | ||
182 | } | 153 | } | ||
154 | | ||||
155 | Baloo::QueryRunnable* BalooContentLister::Private::createQuery(ContentQuery* contentQuery, const QString& location) | ||||
156 | { | ||||
157 | auto balooQuery = Baloo::Query{}; | ||||
158 | if(!location.isEmpty()) | ||||
159 | balooQuery.setIncludeFolder(location); | ||||
160 | | ||||
161 | switch(contentQuery->type()) | ||||
162 | { | ||||
163 | case ContentQuery::Audio: | ||||
164 | balooQuery.setType("Audio"); | ||||
165 | break; | ||||
166 | case ContentQuery::Documents: | ||||
167 | balooQuery.setType("Document"); | ||||
168 | break; | ||||
169 | case ContentQuery::Images: | ||||
170 | balooQuery.setType("Image"); | ||||
171 | break; | ||||
172 | case ContentQuery::Video: | ||||
173 | balooQuery.setType("Video"); | ||||
174 | break; | ||||
175 | default: | ||||
176 | break; | ||||
177 | } | ||||
178 | | ||||
179 | if(!contentQuery->searchString().isEmpty()) | ||||
180 | balooQuery.setSearchString(contentQuery->searchString()); | ||||
181 | | ||||
182 | auto runnable = new Baloo::QueryRunnable{balooQuery}; | ||||
183 | connect(runnable, &Baloo::QueryRunnable::queryResult, q, &BalooContentLister::queryResult); | ||||
184 | connect(runnable, &Baloo::QueryRunnable::finished, q, &BalooContentLister::queryCompleted); | ||||
185 | runnable->setProperty("__contentQuery", QVariant::fromValue(contentQuery)); | ||||
186 | runnable->setProperty("__location", location); | ||||
187 | | ||||
188 | return runnable; | ||||
189 | } |
This line crashes for me, when attempting to read the __location property (also, a quick check and it looks to be crashing on the very first result):
Thread 1 (Thread 0x7ffff7f9a8c0 (LWP 27790)):