~ubuntu-branches/debian/sid/baloo-kf5/sid

« back to all changes in this revision

Viewing changes to src/file/fileindexerconfig.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2014-07-10 21:13:07 UTC
  • Revision ID: package-import@ubuntu.com-20140710211307-iku0qs6vlplgn06m
Tags: upstream-5.0.0b
ImportĀ upstreamĀ versionĀ 5.0.0b

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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>
 
4
 
 
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.
 
8
 
 
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.
 
13
 
 
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.
 
18
*/
 
19
 
 
20
#include "fileindexerconfig.h"
 
21
#include "fileexcludefilters.h"
 
22
 
 
23
#include <QUrl>
 
24
#include <QStringList>
 
25
#include <QDir>
 
26
 
 
27
#include <KDirWatch>
 
28
#include <QStandardPaths>
 
29
#include <KConfigGroup>
 
30
#include <QDebug>
 
31
 
 
32
 
 
33
namespace
 
34
{
 
35
/// recursively check if a folder is hidden
 
36
bool isDirHidden(QDir& dir)
 
37
{
 
38
#ifdef __unix__
 
39
    return dir.absolutePath().contains(QLatin1String("/."));
 
40
#else
 
41
    if (QFileInfo(dir.path()).isHidden())
 
42
        return true;
 
43
    else if (dir.cdUp())
 
44
        return isDirHidden(dir);
 
45
    else
 
46
        return false;
 
47
#endif
 
48
}
 
49
}
 
50
 
 
51
using namespace Baloo;
 
52
 
 
53
FileIndexerConfig::FileIndexerConfig(QObject* parent)
 
54
    : QObject(parent)
 
55
    , m_config(QLatin1String("baloofilerc"), KConfig::SimpleConfig)
 
56
    , m_indexHidden(false)
 
57
{
 
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()));
 
64
 
 
65
    forceConfigUpdate();
 
66
}
 
67
 
 
68
 
 
69
FileIndexerConfig::~FileIndexerConfig()
 
70
{
 
71
}
 
72
 
 
73
 
 
74
QList<QPair<QString, bool> > FileIndexerConfig::folders() const
 
75
{
 
76
    return m_folderCache;
 
77
}
 
78
 
 
79
 
 
80
QStringList FileIndexerConfig::includeFolders() const
 
81
{
 
82
    QStringList fl;
 
83
    for (int i = 0; i < m_folderCache.count(); ++i) {
 
84
        if (m_folderCache[i].second)
 
85
            fl << m_folderCache[i].first;
 
86
    }
 
87
    return fl;
 
88
}
 
89
 
 
90
 
 
91
QStringList FileIndexerConfig::excludeFolders() const
 
92
{
 
93
    QStringList fl;
 
94
    for (int i = 0; i < m_folderCache.count(); ++i) {
 
95
        if (!m_folderCache[i].second)
 
96
            fl << m_folderCache[i].first;
 
97
    }
 
98
    return fl;
 
99
}
 
100
 
 
101
 
 
102
QStringList FileIndexerConfig::excludeFilters() const
 
103
{
 
104
    KConfigGroup cfg = m_config.group("General");
 
105
 
 
106
    // read configured exclude filters
 
107
    QSet<QString> filters = cfg.readEntry("exclude filters", defaultExcludeFilterList()).toSet();
 
108
 
 
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();
 
113
 
 
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());
 
120
    }
 
121
 
 
122
    // remove duplicates
 
123
    return QStringList::fromSet(filters);
 
124
}
 
125
 
 
126
 
 
127
bool FileIndexerConfig::indexHiddenFilesAndFolders() const
 
128
{
 
129
    return m_indexHidden;
 
130
}
 
131
 
 
132
void FileIndexerConfig::slotConfigDirty()
 
133
{
 
134
    forceConfigUpdate();
 
135
    Q_EMIT configChanged();
 
136
}
 
137
 
 
138
 
 
139
bool FileIndexerConfig::isInitialRun() const
 
140
{
 
141
    return m_config.group("General").readEntry("first run", true);
 
142
}
 
143
 
 
144
 
 
145
bool FileIndexerConfig::shouldBeIndexed(const QString& path) const
 
146
{
 
147
    QFileInfo fi(path);
 
148
    if (fi.isDir()) {
 
149
        return shouldFolderBeIndexed(path);
 
150
    } else {
 
151
        return (shouldFolderBeIndexed(fi.absolutePath()) &&
 
152
                (!fi.isHidden() || indexHiddenFilesAndFolders()) &&
 
153
                shouldFileBeIndexed(fi.fileName()));
 
154
    }
 
155
}
 
156
 
 
157
 
 
158
bool FileIndexerConfig::shouldFolderBeIndexed(const QString& path) const
 
159
{
 
160
    QString folder;
 
161
    if (folderInFolderList(path, folder)) {
 
162
        // we always index the folders in the list
 
163
        // ignoring the name filters
 
164
        if (folder == path)
 
165
            return true;
 
166
 
 
167
        // check for hidden folders
 
168
        QDir dir(path);
 
169
        if (!indexHiddenFilesAndFolders() && isDirHidden(dir))
 
170
            return false;
 
171
 
 
172
        // reset dir, cause isDirHidden modifies the QDir
 
173
        dir = path;
 
174
 
 
175
        // check the exclude filters for all components of the path
 
176
        // after folder
 
177
        const QStringList pathComponents = path.mid(folder.count()).split(QLatin1Char('/'), QString::SkipEmptyParts);
 
178
        Q_FOREACH (const QString& c, pathComponents) {
 
179
            if (!shouldFileBeIndexed(c)) {
 
180
                return false;
 
181
            }
 
182
        }
 
183
        return true;
 
184
    } else {
 
185
        return false;
 
186
    }
 
187
}
 
188
 
 
189
 
 
190
bool FileIndexerConfig::shouldFileBeIndexed(const QString& fileName) const
 
191
{
 
192
    // check the filters
 
193
    return !m_excludeFilterRegExpCache.exactMatch(fileName);
 
194
}
 
195
 
 
196
bool FileIndexerConfig::shouldMimeTypeBeIndexed(const QString& mimeType) const
 
197
{
 
198
    return !m_excludeMimetypes.contains(mimeType);
 
199
}
 
200
 
 
201
 
 
202
bool FileIndexerConfig::folderInFolderList(const QString& path)
 
203
{
 
204
    QString str;
 
205
    return folderInFolderList(path, str);
 
206
}
 
207
 
 
208
bool FileIndexerConfig::folderInFolderList(const QString& path, QString& folder) const
 
209
{
 
210
    const QString p = QUrl(path).adjusted(QUrl::StripTrailingSlash).path();
 
211
 
 
212
    // we traverse the list backwards to catch all exclude folders
 
213
    int i = m_folderCache.count();
 
214
    while (--i >= 0) {
 
215
        const QString& f = m_folderCache[i].first;
 
216
        const bool include = m_folderCache[i].second;
 
217
        if (p.startsWith(f)) {
 
218
            folder = f;
 
219
            return include;
 
220
        }
 
221
    }
 
222
    // path is not in the list, thus it should not be included
 
223
    folder.clear();
 
224
    return false;
 
225
}
 
226
 
 
227
 
 
228
namespace
 
229
{
 
230
/**
 
231
 * Returns true if the specified folder f would already be excluded using the list
 
232
 * folders.
 
233
 */
 
234
bool alreadyExcluded(const QList<QPair<QString, bool> >& folders, const QString& f)
 
235
{
 
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('/'));
 
241
 
 
242
        if (f != folders[i].first && f.startsWith(path)) {
 
243
            included = folders[i].second;
 
244
        }
 
245
    }
 
246
    return !included;
 
247
}
 
248
 
 
249
/**
 
250
 * Simple insertion sort
 
251
 */
 
252
void insertSortFolders(const QStringList& folders, bool include, QList<QPair<QString, bool> >& result)
 
253
{
 
254
    Q_FOREACH (const QString& f, folders) {
 
255
        int pos = 0;
 
256
        QString path = QUrl(f).adjusted(QUrl::StripTrailingSlash).path();
 
257
        while (result.count() > pos &&
 
258
                result[pos].first < path)
 
259
            ++pos;
 
260
        result.insert(pos, qMakePair(path, include));
 
261
    }
 
262
}
 
263
 
 
264
/**
 
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.
 
268
 */
 
269
void cleanupList(QList<QPair<QString, bool> >& result)
 
270
{
 
271
    int i = 0;
 
272
    while (i < result.count()) {
 
273
        if (result[i].first.isEmpty() ||
 
274
                (!result[i].second &&
 
275
                 alreadyExcluded(result, result[i].first)))
 
276
            result.removeAt(i);
 
277
        else
 
278
            ++i;
 
279
    }
 
280
}
 
281
}
 
282
 
 
283
void FileIndexerConfig::buildFolderCache()
 
284
{
 
285
    KConfigGroup group = m_config.group("General");
 
286
    QStringList includeFoldersPlain = group.readPathEntry("folders", QStringList() << QDir::homePath());
 
287
    QStringList excludeFoldersPlain = group.readPathEntry("exclude folders", QStringList());
 
288
 
 
289
    m_folderCache.clear();
 
290
    insertSortFolders(includeFoldersPlain, true, m_folderCache);
 
291
    insertSortFolders(excludeFoldersPlain, false, m_folderCache);
 
292
 
 
293
    cleanupList(m_folderCache);
 
294
}
 
295
 
 
296
 
 
297
void FileIndexerConfig::buildExcludeFilterRegExpCache()
 
298
{
 
299
    QStringList newFilters = excludeFilters();
 
300
    m_excludeFilterRegExpCache.rebuildCacheFromFilterList(newFilters);
 
301
}
 
302
 
 
303
void FileIndexerConfig::buildMimeTypeCache()
 
304
{
 
305
    m_excludeMimetypes = m_config.group("General").readPathEntry("exclude mimetypes", defaultExcludeMimetypes()).toSet();
 
306
}
 
307
 
 
308
void FileIndexerConfig::forceConfigUpdate()
 
309
{
 
310
    m_config.reparseConfiguration();
 
311
 
 
312
    buildFolderCache();
 
313
    buildExcludeFilterRegExpCache();
 
314
    buildMimeTypeCache();
 
315
 
 
316
    m_indexHidden = m_config.group("General").readEntry("index hidden folders", false);
 
317
}
 
318
 
 
319
void FileIndexerConfig::setInitialRun(bool isInitialRun)
 
320
{
 
321
    m_config.group("General").writeEntry("first run", isInitialRun);
 
322
    m_config.sync();
 
323
}
 
324
 
 
325
bool FileIndexerConfig::initialUpdateDisabled() const
 
326
{
 
327
    return m_config.group("General").readEntry("disable initial update", true);
 
328
}