The FileFinder application is used to search for files that match file and/or content patterns.
+set(eVaf_INCLUDE ${eVaf_INCLUDE} ${CMAKE_SOURCE_DIR}/src/apps/FileFinder)
+
add_subdirectory(PswGen)
+add_subdirectory(FileFinder)
--- /dev/null
+add_subdirectory(Engine)
+add_subdirectory(GUI)
--- /dev/null
+# Name of the target
+set(TARGET FileFinderEngine)
+
+# Qt modules
+set(QT_DONT_USE_QTGUI TRUE)
+include(${QT_USE_FILE})
+
+# Needed for exporting/importing symbols
+add_definitions(-DFILEFINDER_ENGINE_LIBRARY)
+
+# Include files
+include_directories(${eVaf_INCLUDE})
+
+# Required eVaf libraries
+set(eVaf_LIBRARIES CommonLib PluginsLib)
+
+# Source files
+set(SRCS
+ engine.cpp
+)
+
+# Header files for the meta-object compiler
+set(MOC_HDRS
+ ifilefinder.h
+ engine.h
+)
+
+# Version info resource file for Windows builds
+if(WIN32)
+ set(SRCS ${SRCS} version.rc)
+endif(WIN32)
+
+qt4_wrap_cpp(MOC_SRCS ${MOC_HDRS})
+
+add_library(${TARGET} SHARED ${SRCS} ${MOC_SRCS})
+
+target_link_libraries(${TARGET} ${QT_LIBRARIES} ${eVaf_LIBRARIES})
+
+install(TARGETS ${TARGET} DESTINATION bin)
--- /dev/null
+/**
+ * @file FileFinder/Engine/engine.h
+ * @brief Module for the FileFinder application that searches for files
+ * @author Enar Vaikene
+ *
+ * Copyright (c) 2011 Enar Vaikene
+ *
+ * This file is part of the eVaf C++ cross-platform application development framework.
+ *
+ * This file can be used under the terms of the GNU General Public License
+ * version 3.0 as published by the Free Software Foundation and appearing in
+ * the file LICENSE included in the packaging of this file. Please review the
+ * the following information to ensure the GNU General Public License version
+ * 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
+ *
+ * Alternatively, this file may be used in accordance with the Commercial License
+ * Agreement provided with the Software.
+ */
+
+
+#include "engine.h"
+#include "version.h"
+
+#include <Common/iLogger>
+#include <Common/iRegistry>
+
+#include <QtCore>
+
+VER_EXPORT_VERSION_INFO()
+Q_EXPORT_PLUGIN2(VER_MODULE_NAME_STR, eVaf::FileFinder::Engine::Module)
+
+using namespace eVaf;
+using namespace eVaf::FileFinder;
+using namespace eVaf::FileFinder::Engine;
+
+//-------------------------------------------------------------------
+
+Module::Module()
+ : Plugins::iPlugin()
+ , mReady(false)
+{
+ setObjectName(QString("%1.Module").arg(VER_MODULE_NAME_STR));
+
+ mEngine = new Internal::Engine;
+
+ EVAF_INFO("%s created", qPrintable(objectName()));
+}
+
+Module::~Module()
+{
+ delete mEngine;
+
+ EVAF_INFO("%s destroyed", qPrintable(objectName()));
+}
+
+bool Module::init(QString const & args)
+{
+ Q_UNUSED(args)
+
+ if (!mEngine->init())
+ return false;
+
+ mReady = true;
+
+ EVAF_INFO("%s initialized", qPrintable(objectName()));
+
+ return true;
+}
+
+void Module::done()
+{
+ mReady = false;
+
+ mEngine->done();
+
+ EVAF_INFO("%s finalized", qPrintable(objectName()));
+}
+
+
+//-------------------------------------------------------------------
+
+Internal::Engine::Engine()
+ : iFileFinder()
+ , mWorker(0)
+{
+ setObjectName(QString("%1.Engine").arg(VER_MODULE_NAME_STR));
+
+ EVAF_INFO("%s created", qPrintable(objectName()));
+}
+
+Internal::Engine::~Engine()
+{
+ EVAF_INFO("%s destroyed", qPrintable(objectName()));
+}
+
+bool Internal::Engine::init()
+{
+ // Register the iFileFinder interface
+ Common::iRegistry::instance()->registerInterface("iFileFinder", this);
+
+ mWorker = new Internal::Worker(this);
+ connect(mWorker, SIGNAL(found(QString, QString)), this, SIGNAL(found(QString,QString)));
+ connect(mWorker, SIGNAL(finished(bool)), this, SIGNAL(finished(bool)));
+ mWorker->start();
+
+ EVAF_INFO("%s initialized", qPrintable(objectName()));
+
+ return true;
+}
+
+void Internal::Engine::done()
+{
+ if (mWorker) {
+ mWorker->stop();
+ delete mWorker;
+ mWorker = 0;
+ }
+
+ EVAF_INFO("%s finalized", qPrintable(objectName()));
+}
+
+void Internal::Engine::search(QString const & dir, bool recursive, Filter const & filter)
+{
+ if (mWorker)
+ mWorker->search(dir, recursive, filter);
+}
+
+bool Internal::Engine::busy() const
+{
+ if (mWorker)
+ return mWorker->busy();
+ return false;
+}
+
+void Internal::Engine::cancel()
+{
+ if (mWorker)
+ mWorker->cancel();
+}
+
+
+//-------------------------------------------------------------------
+
+Internal::RegExpChain::~RegExpChain()
+{
+ clear();
+}
+
+void Internal::RegExpChain::clear()
+{
+ foreach (QRegExp * pattern, mPatterns) {
+ delete pattern;
+ }
+ mPatterns.clear();
+ mValid = false;
+}
+
+void Internal::RegExpChain::setPattern(QString const & pattern)
+{
+ clear();
+
+ QStringList patterns = split(pattern);
+
+ foreach (QString s, patterns) {
+ if (s.isEmpty())
+ continue;
+ QRegExp * rx = new QRegExp(s, Qt::CaseSensitive, QRegExp::WildcardUnix);
+ if (!rx->isValid()) {
+ delete rx;
+ continue;
+ }
+ mPatterns.append(rx);
+ }
+
+ mValid = !mPatterns.isEmpty();
+}
+
+bool Internal::RegExpChain::exactMatch(const QString& str) const
+{
+ if (mPatterns.isEmpty())
+ return false;
+
+ foreach (QRegExp * pattern, mPatterns) {
+ if (pattern->exactMatch(str))
+ return true;
+ }
+ return false;
+}
+
+QStringList Internal::RegExpChain::split(const QString & pattern)
+{
+ QStringList rval;
+ int offset = 0;
+ int sz = pattern.size();
+ QString s;
+ bool e = false;
+
+ while (offset < sz) {
+ QChar ch = pattern.at(offset++);
+ if (e) {
+ e = false;
+ if (ch == '*' || ch == '?' || ch == '[' || ch == ']')
+ s.append('\\');
+ s.append(ch);
+ }
+ else {
+ if (ch == '\\')
+ e = true;
+ else if (ch == ',') {
+ rval.append(s);
+ s.clear();
+ }
+ else
+ s.append(ch);
+ }
+ }
+ if (!s.isEmpty())
+ rval.append(s);
+
+ return rval;
+}
+
+
+//-------------------------------------------------------------------
+
+int const Internal::Worker::ReadBufferSize = 4096;
+
+Internal::Worker::Worker(QObject * parent)
+ : QThread(parent)
+ , mNewRecursive(false)
+ , mRecursive(false)
+ , mDoSearch(false)
+ , mDoTerminate(false)
+ , mDoCancel(false)
+ , mBusy(false)
+{
+ setObjectName(QString("%1.Worker").arg(VER_MODULE_NAME_STR));
+}
+
+void Internal::Worker::cancel()
+{
+ mLock.lock();
+ mDoCancel = true;
+ mSomethingToDo.wakeAll();
+ mLock.unlock();
+}
+
+void Internal::Worker::stop()
+{
+ mLock.lock();
+ mDoTerminate = true;
+ mDoCancel = true;
+ mSomethingToDo.wakeAll();
+ mLock.unlock();
+ wait();
+}
+
+void Internal::Worker::search(QString const & dir, bool recursive, Filter const & filter)
+{
+ mLock.lock();
+ mDoCancel = true;
+ mNewDir = dir;
+ mNewRecursive = recursive;
+ mNewFilter = filter;
+ mDoSearch = true;
+ mSomethingToDo.wakeAll();
+ mLock.unlock();
+}
+
+bool Internal::Worker::busy() const
+{
+ QMutexLocker l(&mLock);
+ return mBusy;
+}
+
+void Internal::Worker::run()
+{
+ forever {
+ QMutexLocker lock(&mLock);
+
+ mSomethingToDo.wait(&mLock);
+
+ if (mDoTerminate)
+ break;
+
+ mDoCancel = false;
+
+ if (mDoSearch) {
+ mDoSearch = false;
+ mBusy = true;
+
+ // Copy search arguments
+ mDir.setPath(mNewDir);
+ mRecursive = mNewRecursive;
+ mRxIncludeNames.setPattern(mNewFilter.includeNames);
+ mRxExcludeNames.setPattern(mNewFilter.excludeNames);
+ mRxIncludeContent.setPattern(mNewFilter.includeContent);
+ mRxExcludeContent.setPattern(mNewFilter.excludeContent);
+
+ lock.unlock();
+
+ // Perform the actual search
+ recursiveSearch(mDir.path());
+
+ lock.relock();
+ mBusy = false;
+
+ emit finished(mDoCancel);
+ }
+ }
+}
+
+void Internal::Worker::recursiveSearch(QString const & path)
+{
+ QString l = path;
+ if (!l.endsWith(QChar('/')))
+ l.append(QChar('/'));
+ QDir dir(l);
+
+ // Get the list of files in this directory
+ QStringList files = dir.entryList(QDir::Files | QDir::NoSymLinks);
+ foreach (QString const & file, files) {
+
+ // Check for the cancel flag
+ {
+ QMutexLocker l(&mLock);
+ if (mDoCancel)
+ break;
+ }
+
+ // Check for the file name to match the include filter and not the exclude filter
+ if (mRxIncludeNames.isValid() && !mRxIncludeNames.isEmpty()) {
+ if (!mRxIncludeNames.exactMatch(file))
+ continue;
+ }
+ if (mRxExcludeNames.isValid() && !mRxExcludeNames.isEmpty()) {
+ if (mRxExcludeNames.exactMatch(file))
+ continue;
+ }
+
+ // Check for the file content to match the include filter and not the exclude filter
+ if ((mRxIncludeContent.isValid() && !mRxIncludeContent.isEmpty()) ||
+ (mRxExcludeContent.isValid() && !mRxExcludeContent.isEmpty())) {
+
+ QFile f(l + file);
+ if (!f.open(QFile::ReadOnly))
+ continue; // Ignore silently if opening fails
+
+ int includeFilterMatched = 0;
+ if (!mRxIncludeContent.isValid() || mRxIncludeContent.isEmpty())
+ includeFilterMatched = 1;
+ int excludeFilterMatched = 0;
+ if (!mRxExcludeContent.isValid() || mRxExcludeContent.isEmpty())
+ excludeFilterMatched = -1;
+ QByteArray buf;
+ while (!f.atEnd() && (includeFilterMatched <= 0 || excludeFilterMatched <= 0)) {
+
+ /* We read ReadBufferSize bytes from the file and append to the buffer.
+ * We keep max 2 x ReadBufferSize bytes in the buffer and throw away the oldest
+ * ReadBufferSize bytes of data. Every block is checked twice, but we make sure that
+ * also strings that stretch from one block to another are checked.
+ */
+ QByteArray b = f.read(ReadBufferSize);
+ buf.append(b);
+ if (buf.size() > (2 * ReadBufferSize))
+ buf.remove(0, ReadBufferSize);
+ if (includeFilterMatched == 0 && mRxIncludeContent.indexIn(buf) >= 0)
+ ++includeFilterMatched;
+ if (excludeFilterMatched == 0 && mRxExcludeContent.indexIn(buf) >= 0)
+ ++excludeFilterMatched;
+
+ }
+
+ if (includeFilterMatched == 0 || excludeFilterMatched > 0)
+ continue;
+ }
+
+ // Found a file
+ emit found(mDir.relativeFilePath(l + file), mDir.path());
+ }
+
+ // Process sub-directories
+ if (mRecursive) {
+ QStringList dirs = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks);
+ foreach (QString const & directory, dirs) {
+
+ // Check for the cancel flag
+ {
+ QMutexLocker l(&mLock);
+ if (mDoCancel)
+ break;
+ }
+
+ recursiveSearch(l + directory);
+ }
+ }
+}
--- /dev/null
+/**
+ * @file FileFinder/Engine/engine.h
+ * @brief Module for the FileFinder application that searches for files
+ * @author Enar Vaikene
+ *
+ * Copyright (c) 2011 Enar Vaikene
+ *
+ * This file is part of the eVaf C++ cross-platform application development framework.
+ *
+ * This file can be used under the terms of the GNU General Public License
+ * version 3.0 as published by the Free Software Foundation and appearing in
+ * the file LICENSE included in the packaging of this file. Please review the
+ * the following information to ensure the GNU General Public License version
+ * 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
+ *
+ * Alternatively, this file may be used in accordance with the Commercial License
+ * Agreement provided with the Software.
+ */
+
+#ifndef __FILEFINDER_ENGINE_ENGINE_H
+# define __FILEFINDER_ENGINE_ENGINE_H
+
+#include "ifilefinder.h"
+
+#include <Plugins/iPlugin>
+
+#include <QDir>
+#include <QRegExp>
+#include <QVector>
+#include <QThread>
+#include <QMutex>
+#include <QWaitCondition>
+#include <QStringList>
+
+
+namespace eVaf {
+
+/**
+ * Application for searching files.
+ */
+namespace FileFinder {
+
+/**
+ * Module that implements the engine for searching files.
+ */
+namespace Engine {
+
+/**
+ * Internal implementation of the FileFinder engine.
+ */
+namespace Internal {
+ class Engine;
+} // namespace eVaf::FileFinder::Engine::Internal
+
+/**
+ * Module for the FileFinder application that searches for files.
+ *
+ * The Module class implements the Plugins::iPlugin interface and
+ * creates the Internal::Engine object for file searching.
+ */
+class Module : public Plugins::iPlugin
+{
+ Q_OBJECT
+ Q_INTERFACES(eVaf::Plugins::iPlugin)
+
+public:
+
+ Module();
+
+ virtual ~Module();
+
+ virtual bool init(QString const & args);
+
+ virtual void done();
+
+ virtual bool isReady() const { return mReady; }
+
+
+private: // Members
+
+ /// Flag indicating that the module is ready
+ bool mReady;
+
+ /// iFileFinder interface implementation
+ Internal::Engine * mEngine;
+
+};
+
+
+namespace Internal {
+
+class Worker;
+
+/**
+ * Implements the iFileFinder interface.
+ *
+ * The Internal::Engine class implements the iFileFinder interface.
+ * Searching for files is done in a separate worker thread Internal::Worker.
+ */
+class Engine : public iFileFinder
+{
+ Q_OBJECT
+ Q_INTERFACES(eVaf::FileFinder::iFileFinder)
+
+public:
+
+ Engine();
+
+ virtual ~Engine();
+
+ bool init();
+
+ void done();
+
+ virtual void search(QString const & dir, bool recursive, Filter const & filter);
+
+ virtual void cancel();
+
+ virtual bool busy() const;
+
+
+private: // Members
+
+ /// Worker thread
+ Worker * mWorker;
+
+};
+
+/**
+ * A chain of QRegExp patterns.
+ */
+class RegExpChain
+{
+public:
+
+ RegExpChain()
+ : mValid(false)
+ {}
+
+ ~RegExpChain();
+
+ void setPattern(QString const & pattern);
+
+ void clear();
+
+ bool isEmpty() const { return mPatterns.isEmpty(); }
+
+ bool isValid() const { return mValid; }
+
+ bool exactMatch(QString const & str) const;
+
+
+private:
+
+ QVector<QRegExp *> mPatterns;
+
+ bool mValid;
+
+ /**
+ * Splits the string str into individual patterns separated by commas
+ * @param str Input string
+ * @return List of individual patterns
+ *
+ * The split() function splits the string str into individual patterns. Patterns are
+ * separated with commas. To use the comma as part of the pattern, escape it with '\'.
+ */
+ QStringList split(QString const & str);
+};
+
+/**
+ * Worker thread searching for files.
+ *
+ * The Worker class is a separate thread that searches for files and then emits
+ * the found() signal on every file found.
+ */
+class Worker : public QThread
+{
+ Q_OBJECT
+
+public:
+
+ Worker(QObject * parent = 0);
+
+ /**
+ * Starts a new search.
+ * @param dir Directory where to search
+ * @param recursive If true, searches recurively in sub-directories
+ * @param filter Search filter
+ *
+ * The search() function starts a new search. If a search is already ongoing,
+ * cancels it and starts a new one.
+ *
+ * Search results are reported back with the found() signal and the finished()
+ * signal indicates that the search is done.
+ */
+ void search(QString const & dir, bool recursive, Filter const & filter);
+
+ /**
+ * Indicates that a search is ongoing and the worker thread busy.
+ */
+ bool busy() const;
+
+ /**
+ * Cancels an ongoing search.
+ */
+ void cancel();
+
+ /**
+ * Stops and terminates the worker thread.
+ */
+ void stop();
+
+
+signals:
+
+ /**
+ * A file was found during the search.
+ * @param fileName Name of the file with a path relative to the search directory
+ * @param dir Search directory
+ */
+ void found(QString const & fileName, QString const & dir);
+
+ /**
+ * Signal indicating that a search is finished.
+ * @param canceled True if the search was canceled instead of finished
+ */
+ void finished(bool canceled);
+
+
+protected:
+
+ virtual void run();
+
+
+private: // Members
+
+ /// Size of the read buffer
+ static int const ReadBufferSize;
+
+ /// RW access lock
+ mutable QMutex mLock;
+
+ /// Wait for something to do
+ QWaitCondition mSomethingToDo;
+
+ QString mNewDir;
+ QDir mDir;
+
+ bool mNewRecursive;
+ bool mRecursive;
+
+ Filter mNewFilter;
+ RegExpChain mRxIncludeNames;
+ RegExpChain mRxExcludeNames;
+ QRegExp mRxIncludeContent;
+ QRegExp mRxExcludeContent;
+
+ bool mDoSearch;
+
+ bool mDoTerminate;
+
+ bool mDoCancel;
+
+ bool mBusy;
+
+
+private: // Methods
+
+ /**
+ * Searches for files in the given directory
+ * @param path Path to the directory
+ *
+ * The recursiveSearch() function searches for files in the given directory and emits found()
+ * signals for every file found. If the mRecursive flag is set to true, searches recurively
+ * in all the sub-directories.
+ */
+ void recursiveSearch(QString const & path);
+
+};
+
+} // namespace eVaf::FileFinder::Engine::Internal
+} // namespace eVaf::FileFinder::Engine
+} // namespace eVaf::FileFinder
+} // namespace eVaf
+
+#endif // engine.h
--- /dev/null
+#include "ifilefinder.h"
--- /dev/null
+/**
+ * @file FileFinder/Engine/ifilefinder.h
+ * @brief Interface for the file finder engine
+ * @author Enar Vaikene
+ *
+ * Copyright (c) 2011 Enar Vaikene
+ *
+ * This file is part of the eVaf C++ cross-platform application development framework.
+ *
+ * This file can be used under the terms of the GNU General Public License
+ * version 3.0 as published by the Free Software Foundation and appearing in
+ * the file LICENSE included in the packaging of this file. Please review the
+ * the following information to ensure the GNU General Public License version
+ * 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
+ *
+ * Alternatively, this file may be used in accordance with the Commercial License
+ * Agreement provided with the Software.
+ */
+
+#ifndef __FILEFINDER_ENGINE_IFILEFINDER_H
+# define __FILEFINDER_ENGINE_IFILEFINDER_H
+
+#include <QObject>
+#include <QString>
+
+namespace eVaf {
+namespace FileFinder {
+
+/**
+ * File filter defining patterns for file names and contents.
+ *
+ * File name patterns are wildcards (QRegExp::WildcardUnix). Multiple patterns can be separated by comma like,
+ * for example, "*.cpp,*.h". To include a comma in the pattern, escape it with '\'.
+ *
+ * Content patterns are regular expressions (QRegExp::RegExp).
+ *
+ * A file matches the filter if:
+ * @li file name matches the includeNames pattern or the includeNames pattern is empty;
+ * @li and; file name does not match the excludeNames pattern or the excludeNames pattern is empty;
+ * @li and; file content matches the includeContent pattern or the includeContent pattern is empty;
+ * @li and; file content does not match the excludeContent pattern or the excludeContent patytern is empty.
+ */
+struct Filter
+{
+ Filter()
+ {}
+
+ Filter(QString const & in, QString const & en, QString const & ic, QString const & ec)
+ : includeNames(in)
+ , excludeNames(en)
+ , includeContent(ic)
+ , excludeContent(ec)
+ {}
+
+ /// QRegExp expression specifying file names that are included in the search result
+ QString includeNames;
+
+ /// QRegExp expression specifying file names that are excluded from the search result
+ QString excludeNames;
+
+ /// QRegExp expression specifying file content that is included in the search result
+ QString includeContent;
+
+ /// QRegExp expression specifying file content that is excluded from the search result
+ QString excludeContent;
+};
+
+/**
+ * File finder interface.
+ *
+ * The iFileFinder interface is used to search for files using name and content filters.
+ */
+class iFileFinder : public QObject
+{
+ Q_OBJECT
+
+public:
+
+ /// Interface constructor
+ iFileFinder() : QObject() {}
+
+ /// Empty virtual destructor
+ virtual ~iFileFinder() {}
+
+ /**
+ * Starts a file search in the directory dir using filter.
+ * @param dir Directory where to search
+ * @param recursive If True, searches also in sub-directories
+ * @param filter File name and content filter
+ *
+ * The search() function searches for files matching the given filter. The search is started
+ * in the directory dir and continues recursively into sub-directories if the recursive flag
+ * is set to true.
+ *
+ * The function is non-blocking and returns immediately. Results of the search are reported
+ * with found() signals and the finished() signal indicates that the search is either finished
+ * or canceled.
+ *
+ * If a new search is started before the current search is finished, then the current search is canceled.
+ */
+ virtual void search(QString const & dir, bool recursive, Filter const & filter) = 0;
+
+ /**
+ * Cancels an ongoing search.
+ */
+ virtual void cancel() = 0;
+
+ /**
+ * Indicates that a search is ongoing
+ */
+ virtual bool busy() const = 0;
+
+
+signals:
+
+ /**
+ * Signal emitted for every file found during the search.
+ * @param fileName name of the file with a path relative to the search directory
+ * @param dir Search directory
+ */
+ void found(QString const & fileName, QString const & dir);
+
+ /**
+ * Signal emitted when the search is finished
+ * @param canceled True if the search was canceled instead of finished
+ */
+ void finished(bool canceled);
+
+};
+
+
+} // namespace eVaf::FileFinder
+} // namespace eVaf
+
+Q_DECLARE_INTERFACE(eVaf::FileFinder::iFileFinder, "eVaf.FileFinder.iFileFinder/1.0")
+
+#endif // ifilefinder.h
--- /dev/null
+/**
+ * @file FileFinder/Engine/version.h
+ * @brief Version information for eVaf modules
+ * @author Enar Vaikene
+ *
+ * Copyright (c) 2011 Enar Vaikene
+ *
+ * This file is part of the eVaf C++ cross-platform application development framework.
+ *
+ * This file can be used under the terms of the GNU General Public License
+ * version 3.0 as published by the Free Software Foundation and appearing in
+ * the file LICENSE included in the packaging of this file. Please review the
+ * the following information to ensure the GNU General Public License version
+ * 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
+ *
+ * Alternatively, this file may be used in accordance with the Commercial License
+ * Agreement provided with the Software.
+ */
+
+#ifndef __FILEFINDER_ENGINE_VERSION_H
+# define __FILEFINDER_ENGINE_VERSION_H
+
+#include <version_rc.h>
+
+/**
+ * Module/library version number in the form major,minor,release,build
+ */
+#define VER_FILE_VERSION 0,1,1,1
+
+/**
+ * Module/library version number in the string format (shall end with \0)
+ */
+#define VER_FILE_VERSION_STR "0.1.1.1\0"
+
+/**
+ * Module/library name (shall end with \0)
+ */
+#define VER_MODULE_NAME_STR "FileFinderEngine\0"
+
+/**
+ * Module type (see version_rc.h for all the types)
+ */
+#define VER_MODULE_TYPE MT_GENERIC
+
+/**
+ * Module type in the string format (see version_rc for all the types)
+ */
+#define VER_MODULE_TYPE_STR MT_GENERIC
+
+/**
+ * Original file name for windows (shall end with \0)
+ */
+#define VER_ORIGINAL_FILE_NAME_STR "FileFinderEngine.dll\0"
+
+/**
+ * Description of the module/library (shall end with \0)
+ */
+#define VER_FILE_DESCRIPTION_STR "Search engine for the FileFinder application.\0"
+
+#endif // version.h
--- /dev/null
+/**
+ * @file PswGen/Generator/version.rc
+ * @brief Windows resource file with module/library version information.
+ * @author Enar Vaikene
+ *
+ * Copyright (c) 2011 Enar Vaikene
+ *
+ * This file is part of the eVaf C++ cross-platform application development framework.
+ *
+ * This file can be used under the terms of the GNU General Public License
+ * version 3.0 as published by the Free Software Foundation and appearing in
+ * the file LICENSE included in the packaging of this file. Please review the
+ * the following information to ensure the GNU General Public License version
+ * 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
+ *
+ * Alternatively, this file may be used in accordance with the Commercial License
+ * Agreement provided with the Software.
+ */
+
+#include "version.h"
+#include <version_rc.h>
+#include <winver.h>
+
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION VER_FILE_VERSION
+ PRODUCTVERSION VER_PRODUCT_VERSION
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS VS_FF_DEBUG
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS VOS__WINDOWS32
+ FILETYPE VFT_DLL
+ FILESUBTYPE 0x0L
+ BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904B0"
+ BEGIN
+ VALUE "CompanyName", VER_COMPANY_NAME_STR
+ VALUE "FileDescription", VER_FILE_DESCRIPTION_STR
+ VALUE "FileVersion", VER_FILE_VERSION_STR
+ VALUE "LegalCopyright", VER_LEGAL_COPYRIGHT_STR
+ VALUE "OriginalFilename", VER_ORIGINAL_FILE_NAME_STR
+ VALUE "ProductName", VER_PRODUCT_NAME_STR
+ VALUE "ProductVersion", VER_PRODUCT_VERSION_STR
+ VALUE "Build Date", VER_PRODUCT_DATE_STR
+ VALUE "Module Name", VER_MODULE_NAME_STR
+ VALUE "Module Type", VER_MODULE_TYPE_STR
+ END
+ END
+ END
--- /dev/null
+# Name of the target
+set(TARGET FileFinderGui)
+
+# Qt modules
+include(${QT_USE_FILE})
+
+# Include files
+include_directories(${eVaf_INCLUDE})
+
+# Required eVaf libraries
+set(eVaf_LIBRARIES CommonLib PluginsLib)
+
+# Source files
+set(SRCS
+ gui.cpp
+)
+
+# Header files for the meta-object compiler
+set(MOC_HDRS
+ gui.h
+)
+
+# Resources
+#set(RCCS
+# gui.qrc
+#)
+
+# Version info resource file for Windows builds
+if(WIN32)
+ set(SRCS ${SRCS} version.rc)
+endif(WIN32)
+
+qt4_add_resources(RCC_SRCS ${RCCS})
+
+qt4_wrap_cpp(MOC_SRCS ${MOC_HDRS})
+
+add_library(${TARGET} SHARED ${SRCS} ${MOC_SRCS} ${RCC_SRCS})
+
+target_link_libraries(${TARGET} ${QT_LIBRARIES} ${eVaf_LIBRARIES})
+
+install(TARGETS ${TARGET} DESTINATION bin)
--- /dev/null
+/**
+ * @file FileFinder/GUI/gui.cpp
+ * @brief GUI for the FileFinder application
+ * @author Enar Vaikene
+ *
+ * Copyright (c) 2011 Enar Vaikene
+ *
+ * This file is part of the eVaf C++ cross-platform application development framework.
+ *
+ * This file can be used under the terms of the GNU General Public License
+ * version 3.0 as published by the Free Software Foundation and appearing in
+ * the file LICENSE included in the packaging of this file. Please review the
+ * the following information to ensure the GNU General Public License version
+ * 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
+ *
+ * Alternatively, this file may be used in accordance with the Commercial License
+ * Agreement provided with the Software.
+ */
+
+#include "gui.h"
+#include "version.h"
+
+#include "Engine/iFileFinder"
+
+#include <Common/Globals>
+#include <Common/iLogger>
+#include <Common/iRegistry>
+#include <Common/iApp>
+#include <SdiWindow/iSdiWindow>
+
+#include <QtGui>
+
+VER_EXPORT_VERSION_INFO()
+Q_EXPORT_PLUGIN2(VER_MODULE_NAME_STR, eVaf::FileFinder::GUI::Module)
+
+using namespace eVaf;
+
+
+//-------------------------------------------------------------------
+
+void FileFinder::GUI::Internal::MainWidget::keyPressEvent(QKeyEvent * e)
+{
+ if (!e->modifiers() || ((e->modifiers() & Qt::KeypadModifier) && e->key() == Qt::Key_Enter)) {
+ switch (e->key()) {
+ case Qt::Key_Enter:
+ case Qt::Key_Return: {
+ QList<QPushButton *> buttons = qFindChildren<QPushButton *>(this);
+ foreach (QPushButton * btn, buttons) {
+ if (btn->isDefault() && btn->isVisible()) {
+ if (btn->isEnabled())
+ btn->click();
+ return;
+ }
+ }
+ break;
+ }
+ case Qt::Key_Escape:
+ emit quit();
+ break;
+ case Qt::Key_Up:
+ focusPreviousChild();
+ break;
+ case Qt::Key_Down:
+ focusNextChild();
+ break;
+ default:
+ e->ignore();
+ }
+ }
+ else {
+ e->ignore();
+ }
+}
+
+
+//-------------------------------------------------------------------
+
+FileFinder::GUI::Module::Module()
+ : Plugins::iPlugin()
+ , mReady(false)
+ , mFinder(0)
+ , mOpenFileAction(0)
+ , mOpenDirectoryAction(0)
+ , wMain(0)
+ , wDirectory(0)
+ , wRecursive(0)
+ , wIncludeNames(0)
+ , wExcludeNames(0)
+ , wIncludeContent(0)
+ , wExcludeContent(0)
+ , wFind(0)
+{
+ setObjectName(QString("%1.Module").arg(VER_MODULE_NAME_STR));
+
+ EVAF_INFO("%s created", qPrintable(objectName()));
+}
+
+FileFinder::GUI::Module::~Module()
+{
+ EVAF_INFO("%s destroyed", qPrintable(objectName()));
+}
+
+bool FileFinder::GUI::Module::init(QString const & args)
+{
+ Q_UNUSED(args)
+
+ // Get the iFileFinder interface
+ EVAF_TEST_X((mFinder = evafQueryInterface<FileFinder::iFileFinder>("iFileFinder")), "No iFileFinder interface");
+ connect(mFinder, SIGNAL(found(QString,QString)), this, SLOT(found(QString,QString)));
+ connect(mFinder, SIGNAL(finished(bool)), this, SLOT(finished(bool)));
+
+ // Get the main window interface and fill it with widgets
+ SdiWindow::iSdiWindow * win = evafQueryInterface<SdiWindow::iSdiWindow>("iSdiWindow");
+ EVAF_TEST_X(win, "No iSdiWindow interface");
+
+ // Create the main widget for this window
+ wMain = new Internal::MainWidget;
+ connect(wMain, SIGNAL(quit()), qApp, SLOT(quit()));
+ win->addWidget(wMain);
+
+ // Create actions for the window and widgets on it
+ createActions();
+
+ // Create all the other widgets
+ createWidgets();
+
+ // Load stored searches
+ loadHistory();
+
+ mReady = true;
+
+ EVAF_INFO("%s initialized", qPrintable(objectName()));
+
+ return true;
+}
+
+void FileFinder::GUI::Module::done()
+{
+ mReady = false;
+
+ /*
+ * Widgets are deleted by the SdiWindow module. We use wMain to track calls to done() without
+ * proper init().
+ */
+ if (wMain) {
+ wMain = 0;
+ saveHistory();
+ }
+
+ EVAF_INFO("%s finalized", qPrintable(objectName()));
+}
+
+void FileFinder::GUI::Module::saveHistory()
+{
+ QSettings settings(VER_COMPANY_NAME_STR, Common::iApp::instance()->name());
+
+ QStringList t;
+ for (int i = 0; i < wDirectory->count(); ++i)
+ t.append(wDirectory->itemText(i));
+ settings.setValue("FileFinder/Directories", t);
+
+ t.clear();
+ for (int i = 0; i < wIncludeNames->count(); ++i)
+ t.append(wIncludeNames->itemText(i));
+ settings.setValue("FileFinder/IncludeNames", t);
+
+ t.clear();
+ for (int i = 0; i < wExcludeNames->count(); ++i)
+ t.append(wExcludeNames->itemText(i));
+ settings.setValue("FileFinder/ExcludeNames", t);
+
+ t.clear();
+ for (int i = 0; i < wIncludeContent->count(); ++i)
+ t.append(wIncludeContent->itemText(i));
+ settings.setValue("FileFinder/IncludeContent", t);
+
+ t.clear();
+ for (int i = 0; i < wExcludeContent->count(); ++i)
+ t.append(wExcludeContent->itemText(i));
+ settings.setValue("FileFinder/ExcludeContent", t);
+
+}
+
+void FileFinder::GUI::Module::loadHistory()
+{
+ QSettings settings(VER_COMPANY_NAME_STR, Common::iApp::instance()->name());
+
+ wDirectory->addItems(settings.value("FileFinder/Directories").toStringList());
+ wDirectory->setEditText(QDir::currentPath());
+
+ wIncludeNames->addItems(settings.value("FileFinder/IncludeNames").toStringList());
+ wIncludeNames->setEditText("");
+
+ wExcludeNames->addItems(settings.value("FileFinder/ExcludeNames").toStringList());
+ wExcludeNames->setEditText("");
+
+ wIncludeContent->addItems(settings.value("FileFinder/IncludeContent").toStringList());
+ wIncludeContent->setEditText("");
+
+ wExcludeContent->addItems(settings.value("FileFinder/ExcludeContent").toStringList());
+ wExcludeContent->setEditText("");
+}
+
+void FileFinder::GUI::Module::createWidgets()
+{
+ QVBoxLayout * vbox = new QVBoxLayout;
+ wMain->setLayout(vbox);
+
+ QHBoxLayout * hbox = new QHBoxLayout;
+ vbox->addLayout(hbox);
+
+ QLabel * l = new QLabel(tr("&Directory:"));
+ hbox->addWidget(l);
+
+ wDirectory = new QComboBox;
+ wDirectory->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+ wDirectory->setEditable(true);
+ wDirectory->setInsertPolicy(QComboBox::InsertAtTop);
+ l->setBuddy(wDirectory);
+ hbox->addWidget(wDirectory);
+
+ QPushButton * btn = new QPushButton(tr("&Browse"));
+ connect(btn, SIGNAL(clicked()), this, SLOT(browseDirectory()));
+ hbox->addWidget(btn);
+
+ wRecursive = new QCheckBox(tr("&Recursive"));
+ wRecursive->setChecked(true);
+ hbox->addWidget(wRecursive);
+
+ QGridLayout * gr = new QGridLayout;
+ vbox->addLayout(gr);
+
+ gr->setColumnStretch(1, 1);
+ gr->setColumnStretch(3, 1);
+
+ l = new QLabel(tr("&File filter:"));
+ gr->addWidget(l, 0, 0);
+
+ wIncludeNames = new QComboBox;
+ wIncludeNames->setEditable(true);
+ wIncludeNames->setInsertPolicy(QComboBox::InsertAtTop);
+ l->setBuddy(wIncludeNames);
+ gr->addWidget(wIncludeNames, 0, 1);
+
+ l = new QLabel(tr("¬:"));
+ gr->addWidget(l, 0, 2);
+
+ wExcludeNames = new QComboBox;
+ wExcludeNames->setEditable(true);
+ wExcludeNames->setInsertPolicy(QComboBox::InsertAtTop);
+ l->setBuddy(wExcludeNames);
+ gr->addWidget(wExcludeNames);
+
+ l = new QLabel(tr("C&ontains:"));
+ gr->addWidget(l, 1, 0);
+
+ wIncludeContent = new QComboBox;
+ wIncludeContent->setEditable(true);
+ wIncludeContent->setInsertPolicy(QComboBox::InsertAtTop);
+ l->setBuddy(wIncludeContent);
+ gr->addWidget(wIncludeContent, 1, 1);
+
+ l = new QLabel(tr("no&t:"));
+ gr->addWidget(l, 1, 2);
+
+ wExcludeContent = new QComboBox;
+ wExcludeContent->setEditable(true);
+ wExcludeContent->setInsertPolicy(QComboBox::InsertAtTop);
+ l->setBuddy(wExcludeContent);
+ gr->addWidget(wExcludeContent, 1, 3);
+
+ wResults = new QListWidget;
+ wResults->setContextMenuPolicy(Qt::ActionsContextMenu);
+ wResults->addAction(mOpenFileAction);
+ wResults->addAction(mOpenDirectoryAction);
+ connect(wResults, SIGNAL(currentRowChanged(int)), this, SLOT(currentRowChanged(int)));
+ connect(wResults, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(openFile(QModelIndex)));
+ vbox->addWidget(wResults);
+
+ hbox = new QHBoxLayout;
+ vbox->addLayout(hbox);
+ hbox->addStretch();
+
+ wFind = new QPushButton(tr("&Search"));
+ wFind->setDefault(true);
+ connect(wFind, SIGNAL(clicked()), this, SLOT(find()));
+ hbox->addWidget(wFind);
+
+ btn = new QPushButton(tr("&Close"));
+ connect(btn, SIGNAL(clicked()), qApp, SLOT(quit()));
+ hbox->addWidget(btn);
+}
+
+void FileFinder::GUI::Module::createActions()
+{
+ QAction * a = new QAction(wMain);
+ a->setShortcuts(QKeySequence::Quit);
+ connect(a, SIGNAL(triggered()), qApp, SLOT(quit()));
+ wMain->addAction(a);
+
+ mOpenFileAction = new QAction(tr("&Open"), wMain);
+ mOpenFileAction->setEnabled(false);
+ connect(mOpenFileAction, SIGNAL(triggered()), this, SLOT(openFile()));
+
+ mOpenDirectoryAction = new QAction(tr("Open &location"), wMain);
+ mOpenDirectoryAction->setEnabled(false);
+ connect(mOpenDirectoryAction, SIGNAL(triggered()), this, SLOT(openDirectory()));
+}
+
+void FileFinder::GUI::Module::browseDirectory()
+{
+ QString s = QFileDialog::getExistingDirectory(wMain, tr("Select the directory"), wDirectory->currentText());
+ if (!s.isEmpty())
+ wDirectory->setEditText(s);
+}
+
+void FileFinder::GUI::Module::find()
+{
+ if (!mFinder)
+ return;
+ if (mFinder->busy()) {
+ mFinder->cancel();
+ }
+ else {
+ wResults->clear();
+
+ mFinder->search(wDirectory->currentText(),
+ wRecursive->isChecked(),
+ FileFinder::Filter(
+ wIncludeNames->currentText(),
+ wExcludeNames->currentText(),
+ wIncludeContent->currentText(),
+ wExcludeContent->currentText()
+ )
+ );
+
+ wFind->setText(tr("&Stop"));
+ }
+}
+
+void FileFinder::GUI::Module::found(QString const & file, QString const & dir)
+{
+ QString result = dir;
+ if (!result.endsWith(QChar('/')))
+ result.append(QChar('/'));
+ result.append(file);
+ wResults->addItem(result);
+}
+
+void FileFinder::GUI::Module::finished(bool canceled)
+{
+ Q_UNUSED(canceled)
+
+ wFind->setText(tr("&Search"));
+}
+
+void FileFinder::GUI::Module::currentRowChanged(int currentRow)
+{
+ mOpenFileAction->setEnabled(currentRow >= 0);
+ mOpenDirectoryAction->setEnabled(currentRow >= 0);
+}
+
+void FileFinder::GUI::Module::openFile(QModelIndex const & index)
+{
+ Q_UNUSED(index)
+ if (wResults->currentItem())
+ QDesktopServices::openUrl(QUrl(QString("file:///%1").arg(wResults->currentItem()->text())));
+}
+
+void FileFinder::GUI::Module::openDirectory()
+{
+ if (wResults->currentItem()) {
+ QFileInfo fi(wResults->currentItem()->text());
+ QDesktopServices::openUrl(QUrl(QString("file:///%1").arg(fi.path())));
+ }
+}
--- /dev/null
+/**
+ * @file FileFinder/GUI/gui.h
+ * @brief GUI for the FileFinder application
+ * @author Enar Vaikene
+ *
+ * Copyright (c) 2011 Enar Vaikene
+ *
+ * This file is part of the eVaf C++ cross-platform application development framework.
+ *
+ * This file can be used under the terms of the GNU General Public License
+ * version 3.0 as published by the Free Software Foundation and appearing in
+ * the file LICENSE included in the packaging of this file. Please review the
+ * the following information to ensure the GNU General Public License version
+ * 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
+ *
+ * Alternatively, this file may be used in accordance with the Commercial License
+ * Agreement provided with the Software.
+ */
+
+#ifndef __FILEFINDER_GUI_GUI_H
+# define __FILEFINDER_GUI_GUI_H
+
+#include <Plugins/iPlugin>
+
+#include <QObject>
+#include <QString>
+#include <QModelIndex>
+#include <QWidget>
+
+class QWidget;
+class QCheckBox;
+class QComboBox;
+class QPushButton;
+class QListWidget;
+class QAction;
+
+namespace eVaf {
+namespace SdiWindow {
+ struct iSdiWindow;
+} // namespace eVaf::SdiWindow
+namespace FileFinder {
+ struct iFileFinder;
+namespace GUI {
+
+namespace Internal {
+
+/**
+ * Main widget for the FileFinder window
+ */
+class MainWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+
+ MainWidget(QWidget * parent = 0)
+ : QWidget(parent)
+ {}
+
+ virtual void keyPressEvent(QKeyEvent * e);
+
+
+signals:
+
+ /**
+ * Request to close the windows/application
+ */
+ void quit();
+
+};
+
+} // namespace eVaf::FileFinder::GUI::Internal
+
+/**
+ * Graphical User Interface for the FileFinder application.
+ *
+ * This module adds a GUI window to the FileFinder application using the SdiWindow module.
+ */
+class Module : public Plugins::iPlugin
+{
+ Q_OBJECT
+ Q_INTERFACES(eVaf::Plugins::iPlugin)
+
+public:
+
+ Module();
+
+ virtual ~Module();
+
+ virtual bool init(QString const & args);
+
+ virtual void done();
+
+ virtual bool isReady() const { return mReady; }
+
+
+private slots:
+
+ void browseDirectory();
+
+ void find();
+
+ void found(QString const & file, QString const & dir);
+
+ void finished(bool);
+
+ void currentRowChanged(int currentRow);
+
+ void openFile(QModelIndex const & index = QModelIndex());
+
+ void openDirectory();
+
+
+private: // Members
+
+ /// Flag indicating that the module is ready
+ bool mReady;
+
+ /// The iFileFinder interface
+ eVaf::FileFinder::iFileFinder * mFinder;
+
+ /// Actions
+ QAction * mOpenFileAction;
+ QAction * mOpenDirectoryAction;
+
+ /// Widgets on the screen
+ Internal::MainWidget * wMain;
+ QComboBox * wDirectory;
+ QCheckBox * wRecursive;
+ QComboBox * wIncludeNames;
+ QComboBox * wExcludeNames;
+ QComboBox * wIncludeContent;
+ QComboBox * wExcludeContent;
+ QListWidget * wResults;
+ QPushButton * wFind;
+
+
+private: // Methods
+
+ void createWidgets();
+
+ void createActions();
+
+ void saveHistory();
+
+ void loadHistory();
+
+};
+
+} // namespace eVaf::FileFinder::GUI
+} // namespace eVaf::FileFinder
+} // namespace eVaf
+
+#endif // gui.h
--- /dev/null
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="/FileFinder">
+</qresource>
+</RCC>
--- /dev/null
+/**
+ * @file FileFinder/GUI/version.h
+ * @brief Version information for eVaf modules
+ * @author Enar Vaikene
+ *
+ * Copyright (c) 2011 Enar Vaikene
+ *
+ * This file is part of the eVaf C++ cross-platform application development framework.
+ *
+ * This file can be used under the terms of the GNU General Public License
+ * version 3.0 as published by the Free Software Foundation and appearing in
+ * the file LICENSE included in the packaging of this file. Please review the
+ * the following information to ensure the GNU General Public License version
+ * 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
+ *
+ * Alternatively, this file may be used in accordance with the Commercial License
+ * Agreement provided with the Software.
+ */
+
+#ifndef __FILEFINDER_GUI_VERSION_H
+# define __FILEFINDER_GUI_VERSION_H
+
+#include <version_rc.h>
+
+/**
+ * Module/library version number in the form major,minor,release,build
+ */
+#define VER_FILE_VERSION 0,1,1,1
+
+/**
+ * Module/library version number in the string format (shall end with \0)
+ */
+#define VER_FILE_VERSION_STR "0.1.1.1\0"
+
+/**
+ * Module/library name (shall end with \0)
+ */
+#define VER_MODULE_NAME_STR "FileFinderGui\0"
+
+/**
+ * Module type (see version_rc.h for all the types)
+ */
+#define VER_MODULE_TYPE MT_GENERIC
+
+/**
+ * Module type in the string format (see version_rc for all the types)
+ */
+#define VER_MODULE_TYPE_STR MT_GENERIC
+
+/**
+ * Original file name for windows (shall end with \0)
+ */
+#define VER_ORIGINAL_FILE_NAME_STR "FileFinderGui.dll\0"
+
+/**
+ * Description of the module/library (shall end with \0)
+ */
+#define VER_FILE_DESCRIPTION_STR "GUI for the FileFinder application.\0"
+
+#endif // version.h
--- /dev/null
+/**
+ * @file PswGen/Generator/version.rc
+ * @brief Windows resource file with module/library version information.
+ * @author Enar Vaikene
+ *
+ * Copyright (c) 2011 Enar Vaikene
+ *
+ * This file is part of the eVaf C++ cross-platform application development framework.
+ *
+ * This file can be used under the terms of the GNU General Public License
+ * version 3.0 as published by the Free Software Foundation and appearing in
+ * the file LICENSE included in the packaging of this file. Please review the
+ * the following information to ensure the GNU General Public License version
+ * 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
+ *
+ * Alternatively, this file may be used in accordance with the Commercial License
+ * Agreement provided with the Software.
+ */
+
+#include "version.h"
+#include <version_rc.h>
+#include <winver.h>
+
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION VER_FILE_VERSION
+ PRODUCTVERSION VER_PRODUCT_VERSION
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS VS_FF_DEBUG
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS VOS__WINDOWS32
+ FILETYPE VFT_DLL
+ FILESUBTYPE 0x0L
+ BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904B0"
+ BEGIN
+ VALUE "CompanyName", VER_COMPANY_NAME_STR
+ VALUE "FileDescription", VER_FILE_DESCRIPTION_STR
+ VALUE "FileVersion", VER_FILE_VERSION_STR
+ VALUE "LegalCopyright", VER_LEGAL_COPYRIGHT_STR
+ VALUE "OriginalFilename", VER_ORIGINAL_FILE_NAME_STR
+ VALUE "ProductName", VER_PRODUCT_NAME_STR
+ VALUE "ProductVersion", VER_PRODUCT_VERSION_STR
+ VALUE "Build Date", VER_PRODUCT_DATE_STR
+ VALUE "Module Name", VER_MODULE_NAME_STR
+ VALUE "Module Type", VER_MODULE_TYPE_STR
+ END
+ END
+ END