1
/* This file is part of the KDE Project
2
Copyright (c) 2008-2010 Sebastian Trueg <trueg@kde.org>
3
Copyright (c) 2013-2014 Vishesh Handa <me@vhanda.in>
5
This library is free software; you can redistribute it and/or
6
modify it under the terms of the GNU Library General Public
7
License version 2 as published by the Free Software Foundation.
9
This library is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
Library General Public License for more details.
14
You should have received a copy of the GNU Library General Public License
15
along with this library; see the file COPYING.LIB. If not, write to
16
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17
Boston, MA 02110-1301, USA.
20
#include "fileindexerconfig.h"
21
#include "fileexcludefilters.h"
24
#include <QStringList>
28
#include <QStandardPaths>
29
#include <KConfigGroup>
35
/// recursively check if a folder is hidden
36
bool isDirHidden(QDir& dir)
39
return dir.absolutePath().contains(QLatin1String("/."));
41
if (QFileInfo(dir.path()).isHidden())
44
return isDirHidden(dir);
51
using namespace Baloo;
53
FileIndexerConfig::FileIndexerConfig(QObject* parent)
55
, m_config(QLatin1String("baloofilerc"), KConfig::SimpleConfig)
56
, m_indexHidden(false)
58
KDirWatch* dirWatch = KDirWatch::self();
59
connect(dirWatch, SIGNAL(dirty(QString)),
60
this, SLOT(slotConfigDirty()));
61
connect(dirWatch, SIGNAL(created(QString)),
62
this, SLOT(slotConfigDirty()));
63
dirWatch->addFile(QStandardPaths::locate(QStandardPaths::ConfigLocation, m_config.name()));
69
FileIndexerConfig::~FileIndexerConfig()
74
QList<QPair<QString, bool> > FileIndexerConfig::folders() const
80
QStringList FileIndexerConfig::includeFolders() const
83
for (int i = 0; i < m_folderCache.count(); ++i) {
84
if (m_folderCache[i].second)
85
fl << m_folderCache[i].first;
91
QStringList FileIndexerConfig::excludeFolders() const
94
for (int i = 0; i < m_folderCache.count(); ++i) {
95
if (!m_folderCache[i].second)
96
fl << m_folderCache[i].first;
102
QStringList FileIndexerConfig::excludeFilters() const
104
KConfigGroup cfg = m_config.group("General");
106
// read configured exclude filters
107
QSet<QString> filters = cfg.readEntry("exclude filters", defaultExcludeFilterList()).toSet();
109
// make sure we always keep the latest default exclude filters
110
// TODO: there is one problem here. What if the user removed some of the default filters?
111
if (cfg.readEntry("exclude filters version", 0) < defaultExcludeFilterListVersion()) {
112
filters += defaultExcludeFilterList().toSet();
114
// write the config directly since the KCM does not have support for the version yet
115
// TODO: make this class public and use it in the KCM
116
KConfig config(m_config.name());
117
KConfigGroup cfg = config.group("General");
118
cfg.writeEntry("exclude filters", QStringList::fromSet(filters));
119
cfg.writeEntry("exclude filters version", defaultExcludeFilterListVersion());
123
return QStringList::fromSet(filters);
127
bool FileIndexerConfig::indexHiddenFilesAndFolders() const
129
return m_indexHidden;
132
void FileIndexerConfig::slotConfigDirty()
135
Q_EMIT configChanged();
139
bool FileIndexerConfig::isInitialRun() const
141
return m_config.group("General").readEntry("first run", true);
145
bool FileIndexerConfig::shouldBeIndexed(const QString& path) const
149
return shouldFolderBeIndexed(path);
151
return (shouldFolderBeIndexed(fi.absolutePath()) &&
152
(!fi.isHidden() || indexHiddenFilesAndFolders()) &&
153
shouldFileBeIndexed(fi.fileName()));
158
bool FileIndexerConfig::shouldFolderBeIndexed(const QString& path) const
161
if (folderInFolderList(path, folder)) {
162
// we always index the folders in the list
163
// ignoring the name filters
167
// check for hidden folders
169
if (!indexHiddenFilesAndFolders() && isDirHidden(dir))
172
// reset dir, cause isDirHidden modifies the QDir
175
// check the exclude filters for all components of the path
177
const QStringList pathComponents = path.mid(folder.count()).split(QLatin1Char('/'), QString::SkipEmptyParts);
178
Q_FOREACH (const QString& c, pathComponents) {
179
if (!shouldFileBeIndexed(c)) {
190
bool FileIndexerConfig::shouldFileBeIndexed(const QString& fileName) const
193
return !m_excludeFilterRegExpCache.exactMatch(fileName);
196
bool FileIndexerConfig::shouldMimeTypeBeIndexed(const QString& mimeType) const
198
return !m_excludeMimetypes.contains(mimeType);
202
bool FileIndexerConfig::folderInFolderList(const QString& path)
205
return folderInFolderList(path, str);
208
bool FileIndexerConfig::folderInFolderList(const QString& path, QString& folder) const
210
const QString p = QUrl(path).adjusted(QUrl::StripTrailingSlash).path();
212
// we traverse the list backwards to catch all exclude folders
213
int i = m_folderCache.count();
215
const QString& f = m_folderCache[i].first;
216
const bool include = m_folderCache[i].second;
217
if (p.startsWith(f)) {
222
// path is not in the list, thus it should not be included
231
* Returns true if the specified folder f would already be excluded using the list
234
bool alreadyExcluded(const QList<QPair<QString, bool> >& folders, const QString& f)
236
bool included = false;
237
for (int i = 0; i < folders.count(); ++i) {
238
QString path = QUrl(folders[i].first).path();
239
if (!path.endsWith(QLatin1Char('/')))
240
path.append(QLatin1Char('/'));
242
if (f != folders[i].first && f.startsWith(path)) {
243
included = folders[i].second;
250
* Simple insertion sort
252
void insertSortFolders(const QStringList& folders, bool include, QList<QPair<QString, bool> >& result)
254
Q_FOREACH (const QString& f, folders) {
256
QString path = QUrl(f).adjusted(QUrl::StripTrailingSlash).path();
257
while (result.count() > pos &&
258
result[pos].first < path)
260
result.insert(pos, qMakePair(path, include));
265
* Remove useless exclude entries which would confuse the folderInFolderList algo.
266
* This makes sure all top-level items are include folders.
267
* This runs in O(n^2) and could be optimized but what for.
269
void cleanupList(QList<QPair<QString, bool> >& result)
272
while (i < result.count()) {
273
if (result[i].first.isEmpty() ||
274
(!result[i].second &&
275
alreadyExcluded(result, result[i].first)))
283
void FileIndexerConfig::buildFolderCache()
285
KConfigGroup group = m_config.group("General");
286
QStringList includeFoldersPlain = group.readPathEntry("folders", QStringList() << QDir::homePath());
287
QStringList excludeFoldersPlain = group.readPathEntry("exclude folders", QStringList());
289
m_folderCache.clear();
290
insertSortFolders(includeFoldersPlain, true, m_folderCache);
291
insertSortFolders(excludeFoldersPlain, false, m_folderCache);
293
cleanupList(m_folderCache);
297
void FileIndexerConfig::buildExcludeFilterRegExpCache()
299
QStringList newFilters = excludeFilters();
300
m_excludeFilterRegExpCache.rebuildCacheFromFilterList(newFilters);
303
void FileIndexerConfig::buildMimeTypeCache()
305
m_excludeMimetypes = m_config.group("General").readPathEntry("exclude mimetypes", defaultExcludeMimetypes()).toSet();
308
void FileIndexerConfig::forceConfigUpdate()
310
m_config.reparseConfiguration();
313
buildExcludeFilterRegExpCache();
314
buildMimeTypeCache();
316
m_indexHidden = m_config.group("General").readEntry("index hidden folders", false);
319
void FileIndexerConfig::setInitialRun(bool isInitialRun)
321
m_config.group("General").writeEntry("first run", isInitialRun);
325
bool FileIndexerConfig::initialUpdateDisabled() const
327
return m_config.group("General").readEntry("disable initial update", true);