]>
vaikene.ee Git - evaf/blob - src/apps/FileFinder/Engine/engine.cpp
bd15220e0f051fd3682be9bb036953b08c92eec8
2 * @file FileFinder/Engine/engine.h
3 * @brief Module for the FileFinder application that searches for files
6 * Copyright (c) 2011 Enar Vaikene
8 * This file is part of the eVaf C++ cross-platform application development framework.
10 * This file can be used under the terms of the GNU General Public License
11 * version 3.0 as published by the Free Software Foundation and appearing in
12 * the file LICENSE included in the packaging of this file. Please review the
13 * the following information to ensure the GNU General Public License version
14 * 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
16 * Alternatively, this file may be used in accordance with the Commercial License
17 * Agreement provided with the Software.
23 #include <Common/iLogger>
24 #include <Common/iRegistry>
28 VER_EXPORT_VERSION_INFO()
31 using namespace eVaf::FileFinder
;
32 using namespace eVaf::FileFinder::Engine
;
34 //-------------------------------------------------------------------
40 setObjectName(QString("%1.Module").arg(VER_MODULE_NAME_STR
));
42 mEngine
= new Internal::Engine
;
44 EVAF_INFO("%s created", qPrintable(objectName()));
51 EVAF_INFO("%s destroyed", qPrintable(objectName()));
54 bool Module::init(QString
const & args
)
63 EVAF_INFO("%s initialized", qPrintable(objectName()));
74 EVAF_INFO("%s finalized", qPrintable(objectName()));
78 //-------------------------------------------------------------------
80 Internal::Engine::Engine()
84 setObjectName(QString("%1.Engine").arg(VER_MODULE_NAME_STR
));
86 EVAF_INFO("%s created", qPrintable(objectName()));
89 Internal::Engine::~Engine()
91 EVAF_INFO("%s destroyed", qPrintable(objectName()));
94 bool Internal::Engine::init()
96 // Register the iFileFinder interface
97 Common::iRegistry::instance()->registerInterface("iFileFinder", this);
99 mWorker
= new Internal::Worker(this);
100 connect(mWorker
, SIGNAL(found(QString
, QString
)), this, SIGNAL(found(QString
,QString
)));
101 connect(mWorker
, SIGNAL(finished(bool)), this, SIGNAL(finished(bool)));
104 EVAF_INFO("%s initialized", qPrintable(objectName()));
109 void Internal::Engine::done()
117 EVAF_INFO("%s finalized", qPrintable(objectName()));
120 void Internal::Engine::search(QString
const & dir
, bool recursive
, Filter
const & filter
)
123 mWorker
->search(dir
, recursive
, filter
);
126 bool Internal::Engine::busy() const
129 return mWorker
->busy();
133 void Internal::Engine::cancel()
140 //-------------------------------------------------------------------
142 Internal::RegExpChain::~RegExpChain()
147 void Internal::RegExpChain::clear()
149 foreach (QRegExp
* pattern
, mPatterns
) {
156 void Internal::RegExpChain::setPattern(QString
const & pattern
)
160 QStringList patterns
= split(pattern
);
162 foreach (QString s
, patterns
) {
165 QRegExp
* rx
= new QRegExp(s
, Qt::CaseSensitive
, QRegExp::WildcardUnix
);
166 if (!rx
->isValid()) {
170 mPatterns
.append(rx
);
173 mValid
= !mPatterns
.isEmpty();
176 bool Internal::RegExpChain::exactMatch(const QString
& str
) const
178 if (mPatterns
.isEmpty())
181 foreach (QRegExp
* pattern
, mPatterns
) {
182 if (pattern
->exactMatch(str
))
188 QStringList
Internal::RegExpChain::split(const QString
& pattern
)
192 int sz
= pattern
.size();
196 while (offset
< sz
) {
197 QChar ch
= pattern
.at(offset
++);
200 if (ch
== '*' || ch
== '?' || ch
== '[' || ch
== ']')
207 else if (ch
== ',') {
222 //-------------------------------------------------------------------
224 int const Internal::Worker::ReadBufferSize
= 4096;
226 Internal::Worker::Worker(QObject
* parent
)
228 , mNewRecursive(false)
231 , mDoTerminate(false)
235 setObjectName(QString("%1.Worker").arg(VER_MODULE_NAME_STR
));
237 EVAF_INFO("%s created", qPrintable(objectName()));
240 Internal::Worker::~Worker()
242 EVAF_INFO("%s destroyed", qPrintable(objectName()));
245 void Internal::Worker::cancel()
249 mSomethingToDo
.wakeAll();
253 void Internal::Worker::stop()
258 mSomethingToDo
.wakeAll();
263 void Internal::Worker::search(QString
const & dir
, bool recursive
, Filter
const & filter
)
268 mNewRecursive
= recursive
;
271 mSomethingToDo
.wakeAll();
275 bool Internal::Worker::busy() const
277 QMutexLocker
l(&mLock
);
281 void Internal::Worker::run()
284 QMutexLocker
lock(&mLock
);
289 mSomethingToDo
.wait(&mLock
);
300 // Copy search arguments
301 mDir
.setPath(mNewDir
);
302 mRecursive
= mNewRecursive
;
303 mRxIncludeNames
.setPattern(mNewFilter
.includeNames
);
304 mRxExcludeNames
.setPattern(mNewFilter
.excludeNames
);
305 mRxIncludeContent
.setPattern(mNewFilter
.includeContent
);
306 mRxExcludeContent
.setPattern(mNewFilter
.excludeContent
);
310 // Perform the actual search
311 recursiveSearch(mDir
.path());
323 void Internal::Worker::recursiveSearch(QString
const & path
)
326 if (!l
.endsWith(QChar('/')))
327 l
.append(QChar('/'));
330 // Get the list of files in this directory
331 QStringList files
= dir
.entryList(QDir::Files
| QDir::NoSymLinks
);
332 foreach (QString
const & file
, files
) {
334 // Check for the cancel flag
336 QMutexLocker
l(&mLock
);
341 // Check for the file name to match the include filter and not the exclude filter
342 if (mRxIncludeNames
.isValid() && !mRxIncludeNames
.isEmpty()) {
343 if (!mRxIncludeNames
.exactMatch(file
))
346 if (mRxExcludeNames
.isValid() && !mRxExcludeNames
.isEmpty()) {
347 if (mRxExcludeNames
.exactMatch(file
))
351 // Check for the file content to match the include filter and not the exclude filter
352 if ((mRxIncludeContent
.isValid() && !mRxIncludeContent
.isEmpty()) ||
353 (mRxExcludeContent
.isValid() && !mRxExcludeContent
.isEmpty())) {
356 if (!f
.open(QFile::ReadOnly
))
357 continue; // Ignore silently if opening fails
359 int includeFilterMatched
= 0;
360 if (!mRxIncludeContent
.isValid() || mRxIncludeContent
.isEmpty())
361 includeFilterMatched
= 1;
362 int excludeFilterMatched
= 0;
363 if (!mRxExcludeContent
.isValid() || mRxExcludeContent
.isEmpty())
364 excludeFilterMatched
= -1;
366 while (!f
.atEnd() && (includeFilterMatched
<= 0 || excludeFilterMatched
<= 0)) {
368 // Check for the cancel flag
370 QMutexLocker
l(&mLock
);
375 /* We read ReadBufferSize bytes from the file and append to the buffer.
376 * We keep max 2 x ReadBufferSize bytes in the buffer and throw away the oldest
377 * ReadBufferSize bytes of data. Every block is checked twice, but we make sure that
378 * also strings that stretch from one block to another are checked.
380 QByteArray b
= f
.read(ReadBufferSize
);
382 if (buf
.size() > (2 * ReadBufferSize
))
383 buf
.remove(0, ReadBufferSize
);
384 if (includeFilterMatched
== 0 && mRxIncludeContent
.indexIn(buf
) >= 0)
385 ++includeFilterMatched
;
386 if (excludeFilterMatched
== 0 && mRxExcludeContent
.indexIn(buf
) >= 0)
387 ++excludeFilterMatched
;
391 if (includeFilterMatched
== 0 || excludeFilterMatched
> 0)
396 emit
found(mDir
.relativeFilePath(l
+ file
), mDir
.path());
399 // Process sub-directories
401 QStringList dirs
= dir
.entryList(QDir::Dirs
| QDir::NoDotAndDotDot
| QDir::NoSymLinks
);
402 foreach (QString
const & directory
, dirs
) {
404 // Check for the cancel flag
406 QMutexLocker
l(&mLock
);
411 if (mRxExcludeNames
.isValid() && !mRxExcludeNames
.isEmpty() && mRxExcludeNames
.exactMatch(directory
))
414 recursiveSearch(l
+ directory
);