--- /dev/null
+#include "research.hpp"
+
+const int IX_NODE = 0;
+const int IX_SIZE = 1;
+const int IX_DATE = 2;
+const int IX_PATH = 3;
+
+
+/**
+ * Constructor.
+ *
+ * @param table the table for the found files
+ */
+FileFinder::FileFinder(QTableWidget& table) :
+ ReFileSearch(),
+ m_table(table),
+ m_files()
+{
+ setSearchMode(smFiles);
+}
+
+/**
+ * Adds a file to the file table.
+ *
+ * @param full the filename with path
+ * @param path the path of the file
+ * @param node the filename without path
+ * @param info the info about the file
+ */
+void FileFinder::addToTable(const QString& full, const QString &path,
+ const QString &node, const QFileInfo& info)
+{
+ if (! m_files.contains(full)){
+ int last = m_table.rowCount();
+ m_files.insert(full);
+ m_table.setRowCount(last + 1);
+ m_table.setItem(last, IX_NODE, new QTableWidgetItem(node));
+ m_table.setItem(last, IX_SIZE, new QTableWidgetItem(QString::number(info.size())));
+ QString date = info.lastModified().toString("yyyy.MM.dd hh:mm.ss");
+ m_table.setItem(last, IX_DATE, new QTableWidgetItem(date));
+ m_table.setItem(last, IX_PATH, new QTableWidgetItem(path));
+ }
+}
+
+
+/**
+ * Handle a file found by the file search criteria.
+ *
+ * @param full the filename with path
+ * @param path the path of the file
+ * @param node the filename without path
+ */
+bool FileFinder::handleFile(const QString &full, const QString &path,
+ const QString &node, const QFileInfo& info)
+{
+ addToTable(full, path, node, info);
+ return true;
+}
+
+/**
+ * Searches files in a directory tree and put them into a table widget.
+ *
+ * @param baseDirectory the start directory
+ * @param patterns the patterns describing the files to find: comma
+ * separated list of include patterns or exclude patterns
+ * (starting with '-')
+ * @param minDepth the minimal depth of the directory tree which contain
+ * files to find
+ * @param maxDepth the maximal depth of the directory tree which contain
+ * files to find
+ */
+void FileFinder::search(const QString &baseDirectory, const QString &patterns,
+ int minDepth, int maxDepth)
+{
+ setMinDepth(minDepth);
+ setMaxDepth(maxDepth);
+ setPatterns(patterns);
+ oneDirectory(baseDirectory, 0);
+}
+
--- /dev/null
+#ifndef FILEFINDER_H
+#define FILEFINDER_H
+
+
+class FileFinder : public ReFileSearch
+{
+public:
+ FileFinder( QTableWidget& m_table);
+public:
+ bool handleFile(const QString &full, const QString &path,
+ const QString &node, const QFileInfo &info);
+ void search(const QString& baseDirectory, const QString& patterns,
+ int minDepth, int maxDepth);
+public:
+ void addToTable(const QString& full, const QString &path,
+ const QString &node, const QFileInfo &info);
+private:
+ QTableWidget& m_table;
+ QSet<QString> m_files;
+};
+
+#endif // FILEFINDER_H
#include "ui_mainwindow.h"
#include "aboutdialog.hpp"
+#include "QFileDialog"
+
static const char* VERSION = "2016.11.16";
MainWindow::MainWindow(QApplication& application, const QString& homeDir,
QWidget *parent) :
ReGuiApplication(application, "rsearch", homeDir, 2, 10100100, "de", parent),
ReGuiValidator(),
- ui(new Ui::MainWindow)
+ ui(new Ui::MainWindow),
+ m_fileFinder(NULL)
{
ReComboBox::setDefaultHistorySize(20);
initializeGui();
connect(ui->actionAbout, SIGNAL(triggered()), this, SLOT(onAbout()));
connect(ui->comboBoxBaseDirectory, SIGNAL(textEdited(const QString&, const QString&)),
this, SLOT(textEdited(const QString&, const QString&)));
+ connect(ui->pushButtonSelectBase, SIGNAL(clicked()), this, SLOT(onSelectBaseDirectory()));
+ connect(ui->pushButtonAdd, SIGNAL(clicked()), this, SLOT(onAdd()));
+ connect(ui->pushButtonClear, SIGNAL(clicked()), this, SLOT(onClear()));
+
+ delete m_fileFinder;
+ m_fileFinder = new FileFinder(*ui->tableWidget);
}
ReGuiApplication::onAboutToQuit();
}
+/**
+ * Handles the click of the "Add" button.
+ */
+void MainWindow::onAdd()
+{
+ QString base = ui->comboBoxBaseDirectory->currentText();
+ if (base.isEmpty()){
+ say(LOG_ERROR, tr("missing a base directory"));
+ } else {
+ m_fileFinder->search(base, ui->comboBoxFilePatterns->currentText(),
+ atoi(ui->lineEditMaxDepth->text().toLocal8Bit().data()),
+ atoi(ui->lineEditMinDepth->text().toLocal8Bit().data()));
+ }
+}
+
+/**
+ * Handles the click of the "Clear" button.
+ */
+void MainWindow::onClear()
+{
+
+}
+
/**
* Set GUI elements from the queue when the GUI timer is triggered.
*/
initializeGui();
}
+/**
+ * Handles the push of the button "select directory".
+ */
+void MainWindow::onSelectBaseDirectory(){
+QString dir = QFileDialog::getExistingDirectory(this, tr("Select Directory"),
+ ui->comboBoxBaseDirectory->currentText(), QFileDialog::ShowDirsOnly);
+if (!dir.isEmpty())
+ ui->comboBoxBaseDirectory->setCurrentText(ReFileUtils::nativePath(dir));
+}
+
/**
* Writes a message.
*
#ifndef REGUI_HPP
#include "gui/regui.hpp"
#endif
+#include <QMainWindow>
+class FileFinder;
namespace Ui {
class MainWindow;
}
private:
void initializeGui();
-
+ virtual void onAboutToQuit();
+ virtual void onGuiTimerUpdate();
+ virtual void onLanguageChange();
private slots:
void onAbout();
- virtual void onAboutToQuit();
- virtual void onGuiTimerUpdate();
- virtual void onLanguageChange();
+ void onAdd();
+ void onClear();
+ void onSelectBaseDirectory();
void textEdited(const QString& oldString, const QString& newString);
private:
Ui::MainWindow *ui;
+ FileFinder* m_fileFinder;
};
#endif // MAINWINDOW_H
<height>16777215</height>
</size>
</property>
+ <property name="toolTip">
+ <string>Starts a dialog to choose the base directory</string>
+ </property>
<property name="text">
<string notr="true">...</string>
</property>
</item>
<item row="1" column="1">
<layout class="QHBoxLayout" name="horizontalLayout">
- <item>
- <widget class="QCheckBox" name="checkBoxRecursive">
- <property name="text">
- <string>Recursive</string>
- </property>
- <property name="checked">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="horizontalSpacer">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>188</width>
- <height>17</height>
- </size>
- </property>
- </spacer>
- </item>
<item>
<widget class="QLabel" name="label_3">
<property name="text">
</property>
</widget>
</item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>188</width>
+ <height>17</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
</layout>
</item>
<item row="2" column="0">
<height>33</height>
</rect>
</property>
+ <property name="toolTip">
+ <string>Adds the described files into the table below</string>
+ </property>
<property name="text">
<string>&Add</string>
</property>
<height>33</height>
</rect>
</property>
+ <property name="toolTip">
+ <string>Clears the table below</string>
+ </property>
<property name="text">
<string>&Clear</string>
</property>
<attribute name="title">
<string>Options</string>
</attribute>
- <widget class="QWidget" name="">
+ <widget class="QWidget" name="layoutWidget">
<property name="geometry">
<rect>
<x>175</x>
<y>10</y>
<width>321</width>
- <height>35</height>
+ <height>38</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<x>0</x>
<y>0</y>
<width>869</width>
- <height>31</height>
+ <height>30</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
#define RESEARCH_HPP
#include "base/rebase.hpp"
#include "gui/regui.hpp"
-#include <QMainWindow>
+#include "filefinder.hpp"
#endif // RESEARCH_HPP
../../gui/ReGuiUtils.cpp \
mainwindow.cpp \
aboutdialog.cpp \
- ../../base/ReFileSearch.cpp
+ ../../base/ReFileSearch.cpp \
+ filefinder.cpp
HEADERS += mainwindow.hpp \
../../base/rebase.hpp \
../../gui/ReGuiUtils.hpp \
aboutdialog.hpp \
research.hpp \
- ../../base/ReFileSearch.hpp
+ ../../base/ReFileSearch.hpp \
+ filefinder.hpp
FORMS += mainwindow.ui \
aboutdialog.ui
QString node;
QString full;
QStringList dirs;
- for (int ix = 0; ix < files.size(); ix++){
+ bool stop = false;
+ for (int ix = 0; ! stop && ix < files.size(); ix++){
node = files[ix];
if (node == "." || node == "..")
continue;
}
} else {
if (depth < m_maxDepth)
- dirs += full;
+ dirs += node;
if (m_searchMode == smFiles || depth < m_minDepth){
continue;
}
}
if (m_matcher.matches(node))
- handleFile(full, directory, node);
- }
- ++depth;
- for (int ix = 0; ix < dirs.size(); ix++){
- oneDirectory(directory + OS_SEPARATOR_STR + dirs[ix], depth);
+ stop = ! handleFile(full, directory, node, info);
}
+ if (! stop){
+ ++depth;
+ for (int ix = 0; ix < dirs.size(); ix++){
+ oneDirectory(directory + OS_SEPARATOR_STR + dirs[ix], depth);
+ }
+ }
}
/**
public:
ReFileSearch();
public:
- virtual void handleFile(const QString& full, const QString& path, const QString& node) = 0;
+ /**
+ * Handles the found file.
+ *
+ * @param full the filename with path
+ * @param path the file's path
+ * @param node the filename without path
+ * @param info the info about the found file
+ * @return <i>true</i>: continue searching
+ * <i>false</i>: stop searching
+ */
+ virtual bool handleFile(const QString& full, const QString& path,
+ const QString& node, const QFileInfo& info) = 0;
int maxDepth() const;
int minDepth() const;
void oneDirectory(const QString& directory, int depth);
if (length > 0){
if (patterns.at(start) == excludeMarker){
if (length > 1)
- excludes.append(patterns.mid(start, length - 1));
+ excludes.append(patterns.mid(start + 1, length - 1));
} else {
includes.append(patterns.mid(start, length));
}
void testReFile();
void testReMatcher();
testReFileSearch();
+ testReMatcher();
testReFileUtils();
testReQStringUtil();
testReProgArgs();
testReProcess();
testReRandomizer();
- testReMatcher();
testReFile();
if (s_allTest) {
testReProcess();
}
public:
+ /**
+ * Tests the standard behaviour: all depths, only one pattern, only files.
+ */
void testBasic() {
m_found.clear();
- setPatterns("test3.txt");
+ setPatterns("file3.txt");
setSearchMode(smFiles);
+ setMaxDepth(99);
+ setMinDepth(0);
oneDirectory(m_baseDir, 0);
checkEqu(5, m_found.size());
checkT(m_found.contains("file3.txt"));
checkT(m_found.contains("dir1/dir2/dir3/file3.txt"));
checkT(m_found.contains("dir1/dir2/dir3/dir4/file3.txt"));
}
- virtual void handleFile(const QString& full, const QString& path, const QString& node){
+ /**
+ * Tests more features:
+ * min. depth, max. depth, multiple patterns, excluding pattern.
+ */
+ void testOneDirectoryDepthExclude(){
+ m_found.clear();
+ setPatterns("*.txt,-*1*,-*2*,-*4*,-file5.txt,dir*,-dir2");
+ setMinDepth(1);
+ setMaxDepth(3);
+ setSearchMode(smFilesAndDirs);
+ oneDirectory(m_baseDir, 0);
+ checkEqu(4, m_found.size());
+ checkT(m_found.contains("dir1/file3.txt"));
+ checkT(m_found.contains("dir1/dir2/file3.txt"));
+ checkT(m_found.contains("dir1/dir2/dir3/file3.txt"));
+ checkT(m_found.contains("dir1/dir2/dir3"));
+ }
+
+ virtual bool handleFile(const QString& full, const QString& path,
+ const QString& node, const QFileInfo& info){
+ ReUseParameter(info);
checkEqu(full, path + OS_SEPARATOR_STR + node);
QString relPath = full.mid(m_baseDir.length() + 1);
relPath.replace(OS_SEPARATOR, "/");
m_found.insert(relPath, 0);
+ return true;
}
private:
void makeFile(const QString& name){
virtual void runTests() {
makeTree();
+ testOneDirectoryDepthExclude();
testBasic();
}
private:
checkT(matcher2.matches("abc"));
}
+ void testIncludeExcludeMatcher(){
+ ReIncludeExcludeMatcher matcher;
+ matcher.setCaseSensivitiy(Qt::CaseSensitive);
+ matcher.setPatterns("a*,-*.txt,b*,-*ef*");
+ checkT(matcher.matches("abc"));
+ checkF(matcher.matches("abc.txt"));
+ checkT(matcher.matches("b"));
+ checkF(matcher.matches("b.txt"));
+ checkT(matcher.matches("bEfg"));
+ checkF(matcher.matches("efg"));
+ checkF(matcher.matches(".efg"));
+ }
virtual void runTests(void) {
testBasics();
test0Star();
test1Star();
testList();
+ testIncludeExcludeMatcher();
}
};
void testReMatcher() {