--- /dev/null
+#include "research.hpp"
+#include <QFile>
+/**
+ * Constructor.
+ *
+ * @param filename filename with path
+ */
+FileCacheItem::FileCacheItem(const QString &filename) :
+ m_lines(),
+ m_filename(filename),
+ m_lastModified()
+{
+ read();
+}
+
+/**
+ * Reads the content of the file into the line list.
+ */
+void FileCacheItem::read()
+{
+ QFileInfo info(m_filename);
+ m_lastModified = info.lastModified();
+ QFile file(m_filename);
+ file.open(QFile::ReadOnly);
+ m_lines.clear();
+ QTextStream textStream(&file);
+ QString line;
+ while (true)
+ {
+ line = textStream.readLine();
+ if (line.isNull())
+ break;
+ else
+ m_lines.append(line);
+ }
+}
+
+/**
+ * Tests whether the file content has changed.
+ * If changed the file is read.
+ */
+void FileCacheItem::update()
+{
+ QFileInfo info(m_filename);
+ if (m_lastModified != info.lastModified()){
+ read();
+ }
+}
+
+/**
+ * Returns the lines of the file.
+ *
+ * @return the list of lines of the file
+ */
+const QStringList& FileCacheItem::lines() const
+{
+ return m_lines;
+}
+
+/**
+ * Constructor.
+ */
+FileCache::FileCache() :
+ m_cache(),
+ m_emptyLines()
+{
+
+}
+
+/**
+ * Adds a file to the file cache.
+ *
+ * @param filename
+ */
+void FileCache::addOrUpdate(const QString &filename)
+{
+ if (m_cache.contains(filename)) {
+ m_cache.value(filename)->update();
+ } else {
+ m_cache.insert(filename, new FileCacheItem(filename));
+ }
+
+}
+
+/**
+ * Returns the line list of a given file.
+ *
+ * @param filename filename with path
+ * @return the list of lines of the files
+ */
+const QStringList &FileCache::lines(const QString &filename) const
+{
+ FileCacheItem* item = m_cache.value(filename, NULL);
+ return item == NULL ? m_emptyLines : item->lines();
+}
+
+
--- /dev/null
+#ifndef FILECACHE_H
+#define FILECACHE_H
+
+class FileCacheItem {
+public:
+ FileCacheItem(const QString& filename);
+public:
+ const QStringList& lines() const;
+ void read();
+ void update();
+private:
+ QStringList m_lines;
+ QString m_filename;
+ QDateTime m_lastModified;
+};
+
+class FileCache
+{
+public:
+ FileCache();
+public:
+ void addOrUpdate(const QString& filename);
+ const QStringList& lines(const QString& filename) const;
+private:
+ QMap<QString, FileCacheItem*> m_cache;
+ QStringList m_emptyLines;
+};
+
+#endif // FILECACHE_H
--- /dev/null
+#include "research.hpp"
+
+/**
+ * Construcctor.
+ *
+ * @param table table containing the files
+ * @param list list widget to store the filtered lines
+ */
+FileFilter::FileFilter(QTableWidget &table, QListWidget &list, FileCache& cache) :
+ m_table(table),
+ m_list(list),
+ m_cache(cache),
+ m_includeExpr(),
+ m_excludeExpr(),
+ m_caseSensitive(false),
+ m_fromHit(0),
+ m_toHit(0),
+ m_linesAbove(0),
+ m_linesBelow(0)
+
+{
+
+}
+
+/**
+ * Puts all filtered lines from the files in the table into the list.
+ *
+ * @param includePattern regular expression to find lines to filter
+ * @param excludePattern regular expression to prevent lines from filtering
+ * @param fromHit first hit which is visible in the list
+ * @param toHit the filtering stops behind this hit
+ * @param linesAbove number of lines above the hit which will put into the list
+ * @param linesBelow number of lines below the hit which will put into the list
+ */
+void FileFilter::filter(const QString &includePattern,
+ const QString &excludePattern,
+ int fromHit, int toHit,
+ int linesAbove, int linesBelow,
+ bool caseSensitive)
+{
+ int ixFile = -1;
+ int hitNo = 0;
+ int fileCount = m_table.rowCount();
+ m_list.clear();
+ m_fromHit = fromHit;
+ m_toHit = toHit;
+ m_linesAbove = linesAbove;
+ m_linesBelow = linesBelow;
+ delete m_includeExpr;
+ delete m_excludeExpr;
+
+ QRegularExpression::PatternOption option = caseSensitive
+ ? QRegularExpression::NoPatternOption
+ : QRegularExpression::CaseInsensitiveOption;
+ m_includeExpr = includePattern.isEmpty() ? NULL : new QRegularExpression(includePattern, option);
+ m_excludeExpr = excludePattern.isEmpty() ? NULL : new QRegularExpression(excludePattern, option);
+
+ while (ixFile < fileCount - 1 && hitNo <= toHit){
+ ++ixFile;
+ QString full = m_table.item(ixFile, colPath)->text();
+ full += OS_SEPARATOR_STR;
+ full += m_table.item(ixFile, colNode)->text();
+
+ hitNo = filterOneFile(full, hitNo);
+ }
+}
+
+/**
+ * Filters the lines of one file.
+ *
+ * @param filename filename with path
+ * @param lastHit the last found hit in the previous files
+ * @return the number of hits including the hits in the file
+ */
+int FileFilter::filterOneFile(const QString& filename, int lastHit)
+{
+ m_cache.addOrUpdate(filename);
+ const QStringList& lines = m_cache.lines(filename);
+
+ int lineNo = 0;
+ int lastLine = -1;
+ int count = lines.size();
+ QString prefixHit = filename + "-";
+ QString prefixOther = prefixHit;
+ if (m_linesAbove + m_linesBelow > 0){
+ prefixHit = ">" + prefixHit;
+ prefixOther = " " + prefixOther;
+ }
+ while(lastHit <= m_toHit && lineNo < count){
+ QString line = lines[lineNo++];
+ if (m_includeExpr != NULL && ! m_includeExpr->match(line).hasMatch())
+ continue;
+ if (m_excludeExpr != NULL && m_excludeExpr->match(line).hasMatch())
+ continue;
+ if (++lastHit >= m_fromHit){
+ for (int ix = max(lastLine + 1, max(0, lineNo - m_linesAbove));
+ ix <= min(lineNo + m_linesBelow, count - 1);
+ ix++){
+ m_list.addItem((ix == lineNo ? prefixHit : prefixOther)
+ + QString::number(ix + 1) + ": " + lines[ix]);
+ }
+ }
+ }
+ return lastHit;
+}
+
--- /dev/null
+#ifndef FILEFILTER_H
+#define FILEFILTER_H
+
+
+class FileFilter
+{
+public:
+ FileFilter(QTableWidget& table, QListWidget& list, FileCache& cache);
+public:
+ void filter(const QString& includePattern, const QString& excludePattern,
+ int fromHit, int toHit, int linesAbove, int linesBelow,
+ bool caseSensitive);
+private:
+ int filterOneFile(const QString &filename, int lastHit);
+private:
+ QTableWidget& m_table;
+ QListWidget& m_list;
+ FileCache& m_cache;
+ QRegularExpression* m_includeExpr;
+ QRegularExpression* m_excludeExpr;
+ bool m_caseSensitive;
+ int m_fromHit;
+ int m_toHit;
+ int m_linesAbove;
+ int m_linesBelow;
+};
+
+#endif // FILEFILTER_H
#include "research.hpp"
-const int IX_NODE = 0;
-const int IX_SIZE = 1;
-const int IX_DATE = 2;
-const int IX_PATH = 3;
-
/**
* Constructor.
FileFinder::FileFinder(QTableWidget& table) :
ReFileSearch(),
m_table(table),
- m_files()
+ m_files(),
+ m_dirs(0),
+ m_foundFiles(0),
+ m_ignoredFiles(0)
{
setSearchMode(smFiles);
}
+/**
+ * Destructor.
+ */
+FileFinder::~FileFinder()
+{
+
+}
+
/**
* Adds a file to the file table.
*
void FileFinder::addToTable(const QString& full, const QString &path,
const QString &node, const QFileInfo& info)
{
- if (! m_files.contains(full)){
+ if (m_files.contains(full)){
+ ++m_ignoredFiles;
+ } else {
+ ++m_foundFiles;
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())));
+ m_table.setItem(last, colNode, new QTableWidgetItem(node));
+ m_table.setItem(last, colSize, 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));
+ m_table.setItem(last, colDate, new QTableWidgetItem(date));
+ m_table.setItem(last, colPath, new QTableWidgetItem(path));
}
}
+/**
+ * Clears the table.
+ */
+void FileFinder::clear()
+{
+ m_table.setRowCount(0);
+ m_files.clear();
+}
+
+/**
+ * Resturn the number of found files of the last search.
+ *
+ * @return the number of found files
+ */
+int FileFinder::foundFiles() const
+{
+ return m_foundFiles;
+}
+
+
+/**
+ * Returns the number of files which are ignored because they are already in the table.
+ *
+ * @return the number of ignored files
+ */
+int FileFinder::ignoredFiles() const
+{
+ return m_ignoredFiles;
+}
+
/**
* Handle a file found by the file search criteria.
setMinDepth(minDepth);
setMaxDepth(maxDepth);
setPatterns(patterns);
+ m_ignoredFiles = 0;
+ m_foundFiles = 0;
oneDirectory(baseDirectory, 0);
}
{
public:
FileFinder( QTableWidget& m_table);
+ virtual ~FileFinder();
public:
+ void addToTable(const QString& full, const QString &path,
+ const QString &node, const QFileInfo &info);
+ void clear();
+ int foundFiles() const;
bool handleFile(const QString &full, const QString &path,
const QString &node, const QFileInfo &info);
+ int ignoredFiles() const;
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;
+ int m_dirs;
+ int m_foundFiles;
+ int m_ignoredFiles;
};
#endif // FILEFINDER_H
ReGuiApplication(application, "rsearch", homeDir, 2, 10100100, "de", parent),
ReGuiValidator(),
ui(new Ui::MainWindow),
- m_fileFinder(NULL)
+ m_fileFinder(NULL),
+ m_fileCache(new FileCache()),
+ m_test(true)
{
ReComboBox::setDefaultHistorySize(20);
initializeGui();
}
+/**
+ * Destructor.
+ */
MainWindow::~MainWindow()
{
delete ui;
+ delete m_fileCache;
+ delete m_fileFinder;
+}
+
+/**
+ * Gets an integer from a combobox.
+ *
+ * If the text is not an integer the default value will be used.
+ *
+ * @param combobox the source of the integer
+ * @param defaultValue the value if the source value is invalid
+ */
+int MainWindow::comboboxToInt(QComboBox& combobox, int defaultValue){
+ QString text = combobox.currentText();
+ uint rc = 0;
+ if (ReQStringUtils::lengthOfUInt(text, 0, 10, &rc) != text.length()){
+ say(LOG_ERROR, tr("not an integer: %1 using instead: %2").arg(text).arg(defaultValue));
+ combobox.setCurrentText(QString::number(defaultValue));
+ rc = (uint) defaultValue;
+ }
+ return (int) rc;
}
/**
connect(ui->pushButtonSelectBase, SIGNAL(clicked()), this, SLOT(onSelectBaseDirectory()));
connect(ui->pushButtonAdd, SIGNAL(clicked()), this, SLOT(onAdd()));
connect(ui->pushButtonClear, SIGNAL(clicked()), this, SLOT(onClear()));
+ connect(ui->pushButtonFilter, SIGNAL(clicked()), this, SLOT(onFilter()));
delete m_fileFinder;
m_fileFinder = new FileFinder(*ui->tableWidget);
+ ui->tableWidget->setColumnWidth(colNode, 200);
+ ui->tableWidget->setColumnWidth(colSize, 125);
+ ui->tableWidget->setColumnWidth(colDate, 175);
+
+ if (m_test){
+ ui->comboBoxBaseDirectory->setCurrentText("/etc");
+ ui->comboBoxFilePatterns->setCurrentText("*asu*");
+ ui->comboBoxIncludingPattern->setCurrentText("e");
+ onAdd();
+ }
}
/**
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()));
+ atoi(ui->lineEditMinDepth->text().toLocal8Bit().data()),
+ atoi(ui->lineEditMaxDepth->text().toLocal8Bit().data()));
+ int files = ui->tableWidget->rowCount();
+ ui->labelFileCount->setText(QString::number(files)
+ + " " + tr("file(s)"));
+ say(LOG_INFO, tr("files: %1 already found: %2 processed directories: %3")
+ .arg(m_fileFinder->foundFiles())
+ .arg(m_fileFinder->ignoredFiles())
+ .arg(m_fileFinder->processedDirs()));
}
}
*/
void MainWindow::onClear()
{
+ m_fileFinder->clear();
+ ui->labelFileCount->setText("");
+}
+/**
+ * Handles the click of the "Filter" button.
+ */
+void MainWindow::onFilter()
+{
+ FileFilter filter(*ui->tableWidget, *ui->listWidgetHits, *m_fileCache);
+ int from = comboboxToInt(*ui->comboBoxFromHit, 0);
+ int to = comboboxToInt(*ui->comboBoxToHit, from + 100);
+ int above = comboboxToInt(*ui->comboBoxLinesAbove, 0);
+ int below = comboboxToInt(*ui->comboBoxLinesBelow, 0);
+
+ filter.filter(ui->comboBoxIncludingPattern->currentText(),
+ ui->comboBoxExcludingPattern->currentText(),
+ from, to, above, below, false);
}
/**
#include <QMainWindow>
class FileFinder;
+class FileCache;
namespace Ui {
class MainWindow;
}
virtual bool say(ReLoggerLevel level, const QString& message);
private:
- void initializeGui();
+ int comboboxToInt(QComboBox &combobox, int defaultValue);
+ void initializeGui();
virtual void onAboutToQuit();
virtual void onGuiTimerUpdate();
virtual void onLanguageChange();
private slots:
- void onAbout();
- void onAdd();
- void onClear();
- void onSelectBaseDirectory();
- void textEdited(const QString& oldString, const QString& newString);
-
+ void onAbout();
+ void onAdd();
+ void onClear();
+ void onFilter();
+ void onSelectBaseDirectory();
+ void textEdited(const QString& oldString, const QString& newString);
private:
Ui::MainWindow *ui;
FileFinder* m_fileFinder;
+ FileCache* m_fileCache;
+ bool m_test;
};
#endif // MAINWINDOW_H
<string>&Clear</string>
</property>
</widget>
+ <widget class="QLabel" name="labelFileCount">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>120</y>
+ <width>131</width>
+ <height>20</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string notr="true"> </string>
+ </property>
+ </widget>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
- <widget class="QWidget" name="tabText">
+ <widget class="QWidget" name="tabFilter">
<attribute name="title">
- <string>Text</string>
+ <string>Filter</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
</size>
</property>
<property name="currentIndex">
- <number>1</number>
+ <number>0</number>
</property>
<widget class="QWidget" name="tabFileFilterPatterns">
<attribute name="title">
<widget class="QWidget" name="layoutWidget">
<property name="geometry">
<rect>
- <x>175</x>
- <y>10</y>
- <width>321</width>
+ <x>11</x>
+ <y>11</y>
+ <width>298</width>
<height>38</height>
</rect>
</property>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
+ <item>
+ <widget class="QPushButton" name="pushButtonFilter">
+ <property name="text">
+ <string>&Filter</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
</property>
</spacer>
</item>
+ <item>
+ <widget class="QPushButton" name="pushButtonPrevious">
+ <property name="maximumSize">
+ <size>
+ <width>25</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="text">
+ <string notr="true"><</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="pushButtonNext">
+ <property name="maximumSize">
+ <size>
+ <width>25</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>></string>
+ </property>
+ </widget>
+ </item>
<item>
<widget class="QLabel" name="label_10">
<property name="text">
#include "base/rebase.hpp"
#include "gui/regui.hpp"
#include "filefinder.hpp"
+#include "filecache.hpp"
+#include "filefilter.hpp"
+
+enum ColumnFiles {
+ colNode = 0,
+ colSize,
+ colDate,
+ colPath
+};
+
+
#endif // RESEARCH_HPP
mainwindow.cpp \
aboutdialog.cpp \
../../base/ReFileSearch.cpp \
- filefinder.cpp
+ filefinder.cpp \
+ filecache.cpp \
+ filefilter.cpp
HEADERS += mainwindow.hpp \
../../base/rebase.hpp \
aboutdialog.hpp \
research.hpp \
../../base/ReFileSearch.hpp \
- filefinder.hpp
+ filefinder.hpp \
+ filecache.hpp \
+ filefilter.hpp
FORMS += mainwindow.ui \
aboutdialog.ui
m_minDepth(0),
m_maxDepth(9999),
m_searchMode(smFilesAndDirs),
- m_matcher()
+ m_matcher(),
+ m_processedDirs(0)
+{
+}
+
+/**
+ * Destructor.
+ */
+ReFileSearch::~ReFileSearch()
{
}
return m_minDepth;
}
+/**
+ * Does the search in one directory.
+ *
+ * Note: this method is recursiv.
+ *
+ * @param directory the directory to process
+ * @param depth the depth of the directory (distance from the base)
+ */
void ReFileSearch::oneDirectory(const QString& directory, int depth)
{
QDir dir(directory);
QString full;
QStringList dirs;
bool stop = false;
+ if (depth == 0)
+ m_processedDirs = 1;
+ else
+ ++m_processedDirs;
for (int ix = 0; ! stop && ix < files.size(); ix++){
node = files[ix];
if (node == "." || node == "..")
m_searchMode = searchMode;
}
+int ReFileSearch::processedDirs() const
+{
+ return m_processedDirs;
+}
+
/**
* Sets the maximal depth.
*
public:
ReFileSearch();
+ virtual ~ReFileSearch();
public:
/**
* Handles the found file.
int maxDepth() const;
int minDepth() const;
void oneDirectory(const QString& directory, int depth);
+ int processedDirs() const;
SearchMode searchMode() const;
void setMaxDepth(int maxDepth);
void setMinDepth(int minDepth);
void setPatterns(const QString& includeExcludePattern);
void setSearchMode(const SearchMode& searchMode);
-public:
- int m_minDepth;
- int m_maxDepth;
+
+protected:
+ int m_minDepth;
+ int m_maxDepth;
SearchMode m_searchMode;
ReIncludeExcludeMatcher m_matcher;
+ int m_processedDirs;
};
#endif // REFILESEARCH_HPP
NULL);
static int lengthOfUInt64(const ReString& text, int start = 0, int radix =
10, quint64* value = NULL);
- static int lengthOfUInt(const ReString& text, int start, int radix,
- uint* pValue);
+ static int lengthOfUInt(const ReString& text, int start = 0, int radix = 10,
+ uint* pValue = NULL);
static QString longestPrefix(const QStringList& list);
static bool match(const QString& heap, const QStringList& needles);
/**