]>
vaikene.ee Git - evaf/blob - src/apps/FileFinder/Engine/engine.cpp
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.
24 #include <Common/iLogger>
25 #include <Common/iRegistry>
29 VER_EXPORT_VERSION_INFO()
30 Q_EXPORT_PLUGIN2(VER_MODULE_NAME_STR
, eVaf::FileFinder::Engine::Module
)
33 using namespace eVaf::FileFinder
;
34 using namespace eVaf::FileFinder::Engine
;
36 //-------------------------------------------------------------------
42 setObjectName(QString("%1.Module").arg(VER_MODULE_NAME_STR
));
44 mEngine
= new Internal::Engine
;
46 EVAF_INFO("%s created", qPrintable(objectName()));
53 EVAF_INFO("%s destroyed", qPrintable(objectName()));
56 bool Module::init(QString
const & args
)
65 EVAF_INFO("%s initialized", qPrintable(objectName()));
76 EVAF_INFO("%s finalized", qPrintable(objectName()));
80 //-------------------------------------------------------------------
82 Internal::Engine::Engine()
86 setObjectName(QString("%1.Engine").arg(VER_MODULE_NAME_STR
));
88 EVAF_INFO("%s created", qPrintable(objectName()));
91 Internal::Engine::~Engine()
93 EVAF_INFO("%s destroyed", qPrintable(objectName()));
96 bool Internal::Engine::init()
98 // Register the iFileFinder interface
99 Common::iRegistry::instance()->registerInterface("iFileFinder", this);
101 mWorker
= new Internal::Worker(this);
102 connect(mWorker
, SIGNAL(found(QString
, QString
)), this, SIGNAL(found(QString
,QString
)));
103 connect(mWorker
, SIGNAL(finished(bool)), this, SIGNAL(finished(bool)));
106 EVAF_INFO("%s initialized", qPrintable(objectName()));
111 void Internal::Engine::done()
119 EVAF_INFO("%s finalized", qPrintable(objectName()));
122 void Internal::Engine::search(QString
const & dir
, bool recursive
, Filter
const & filter
)
125 mWorker
->search(dir
, recursive
, filter
);
128 bool Internal::Engine::busy() const
131 return mWorker
->busy();
135 void Internal::Engine::cancel()
142 //-------------------------------------------------------------------
144 Internal::RegExpChain::~RegExpChain()
149 void Internal::RegExpChain::clear()
151 foreach (QRegExp
* pattern
, mPatterns
) {
158 void Internal::RegExpChain::setPattern(QString
const & pattern
)
162 QStringList patterns
= split(pattern
);
164 foreach (QString s
, patterns
) {
167 QRegExp
* rx
= new QRegExp(s
, Qt::CaseSensitive
, QRegExp::WildcardUnix
);
168 if (!rx
->isValid()) {
172 mPatterns
.append(rx
);
175 mValid
= !mPatterns
.isEmpty();
178 bool Internal::RegExpChain::exactMatch(const QString
& str
) const
180 if (mPatterns
.isEmpty())
183 foreach (QRegExp
* pattern
, mPatterns
) {
184 if (pattern
->exactMatch(str
))
190 QStringList
Internal::RegExpChain::split(const QString
& pattern
)
194 int sz
= pattern
.size();
198 while (offset
< sz
) {
199 QChar ch
= pattern
.at(offset
++);
202 if (ch
== '*' || ch
== '?' || ch
== '[' || ch
== ']')
209 else if (ch
== ',') {
224 //-------------------------------------------------------------------
226 int const Internal::Worker::ReadBufferSize
= 4096;
228 Internal::Worker::Worker(QObject
* parent
)
230 , mNewRecursive(false)
233 , mDoTerminate(false)
237 setObjectName(QString("%1.Worker").arg(VER_MODULE_NAME_STR
));
239 EVAF_INFO("%s created", qPrintable(objectName()));
242 Internal::Worker::~Worker()
244 EVAF_INFO("%s destroyed", qPrintable(objectName()));
247 void Internal::Worker::cancel()
251 mSomethingToDo
.wakeAll();
255 void Internal::Worker::stop()
260 mSomethingToDo
.wakeAll();
265 void Internal::Worker::search(QString
const & dir
, bool recursive
, Filter
const & filter
)
270 mNewRecursive
= recursive
;
273 mSomethingToDo
.wakeAll();
277 bool Internal::Worker::busy() const
279 QMutexLocker
l(&mLock
);
283 void Internal::Worker::run()
286 QMutexLocker
lock(&mLock
);
291 mSomethingToDo
.wait(&mLock
);
302 // Copy search arguments
303 mDir
.setPath(mNewDir
);
304 mRecursive
= mNewRecursive
;
305 mRxIncludeNames
.setPattern(mNewFilter
.includeNames
);
306 mRxExcludeNames
.setPattern(mNewFilter
.excludeNames
);
307 mRxIncludeContent
.setPattern(mNewFilter
.includeContent
);
308 mRxExcludeContent
.setPattern(mNewFilter
.excludeContent
);
312 // Perform the actual search
313 recursiveSearch(mDir
.path());
325 void Internal::Worker::recursiveSearch(QString
const & path
)
328 if (!l
.endsWith(QChar('/')))
329 l
.append(QChar('/'));
332 // Get the list of files in this directory
333 QStringList files
= dir
.entryList(QDir::Files
| QDir::NoSymLinks
);
334 foreach (QString
const & file
, files
) {
336 // Check for the cancel flag
338 QMutexLocker
l(&mLock
);
343 // Check for the file name to match the include filter and not the exclude filter
344 if (mRxIncludeNames
.isValid() && !mRxIncludeNames
.isEmpty()) {
345 if (!mRxIncludeNames
.exactMatch(file
))
348 if (mRxExcludeNames
.isValid() && !mRxExcludeNames
.isEmpty()) {
349 if (mRxExcludeNames
.exactMatch(file
))
353 // Check for the file content to match the include filter and not the exclude filter
354 if ((mRxIncludeContent
.isValid() && !mRxIncludeContent
.isEmpty()) ||
355 (mRxExcludeContent
.isValid() && !mRxExcludeContent
.isEmpty())) {
358 if (!f
.open(QFile::ReadOnly
))
359 continue; // Ignore silently if opening fails
361 int includeFilterMatched
= 0;
362 if (!mRxIncludeContent
.isValid() || mRxIncludeContent
.isEmpty())
363 includeFilterMatched
= 1;
364 int excludeFilterMatched
= 0;
365 if (!mRxExcludeContent
.isValid() || mRxExcludeContent
.isEmpty())
366 excludeFilterMatched
= -1;
368 while (!f
.atEnd() && (includeFilterMatched
<= 0 || excludeFilterMatched
<= 0)) {
370 // Check for the cancel flag
372 QMutexLocker
l(&mLock
);
377 /* We read ReadBufferSize bytes from the file and append to the buffer.
378 * We keep max 2 x ReadBufferSize bytes in the buffer and throw away the oldest
379 * ReadBufferSize bytes of data. Every block is checked twice, but we make sure that
380 * also strings that stretch from one block to another are checked.
382 QByteArray b
= f
.read(ReadBufferSize
);
384 if (buf
.size() > (2 * ReadBufferSize
))
385 buf
.remove(0, ReadBufferSize
);
386 if (includeFilterMatched
== 0 && mRxIncludeContent
.indexIn(buf
) >= 0)
387 ++includeFilterMatched
;
388 if (excludeFilterMatched
== 0 && mRxExcludeContent
.indexIn(buf
) >= 0)
389 ++excludeFilterMatched
;
393 if (includeFilterMatched
== 0 || excludeFilterMatched
> 0)
398 emit
found(mDir
.relativeFilePath(l
+ file
), mDir
.path());
401 // Process sub-directories
403 QStringList dirs
= dir
.entryList(QDir::Dirs
| QDir::NoDotAndDotDot
| QDir::NoSymLinks
);
404 foreach (QString
const & directory
, dirs
) {
406 // Check for the cancel flag
408 QMutexLocker
l(&mLock
);
413 recursiveSearch(l
+ directory
);