m_baseDir(""),
m_checkDates(false),
m_excludedDirs(),
- m_textFinder(NULL){
+ m_textFinder(NULL),
+ m_table(NULL),
+ m_statistics(),
+ m_announcer(NULL),
+ m_observer(NULL){
m_youngerThan.setMSecsSinceEpoch(0);
m_olderThan.setMSecsSinceEpoch(0);
}
-FileFinder::~FileFinder(){
-}
-/**
- * Resets the data.
- */
-void FileFinder::clear(){
- m_lines = 0;
- m_patterns.clear();
- m_minSize = 0;
- m_maxSize = -1;
- m_youngerThan.setMSecsSinceEpoch(0);
- m_olderThan.setMSecsSinceEpoch(0);
- m_fileTypes = 0;
- m_minDepth = 0;
- m_maxDepth = 512;
- // m_baseDir;
- m_checkDates = false;
+FileFinder::~FileFinder(){
}
/**
/**
* Fills the table with the data of the filtered files of a given directory.
*
+ * This method is recursive over all directories.
+ *
* @param path the directory to inspect
* @param depth the depth of the directory (relative to base directory)
- * @param table OUT: the table to fill
- * @param statistics OUT: statistic about the found objects
*/
-void FileFinder::fillTable(const QString& path, int depth, QTableWidget* table,
- Statistics& statistics){
+void FileFinder::fillTable(const QString& path, int depth){
QFileInfoList entries;
QDir dir(path);
- table->setSortingEnabled(false);
QDir::Filters filters = m_fileTypes | QDir::NoDotAndDotDot;
if (m_patterns.count() == 0)
entries = dir.entryInfoList(filters, QDir::NoSort);
else
entries = dir.entryInfoList(m_patterns, filters, QDir::NoSort);
- QString relativePath = ReQStringUtils::nativePath(
- path.mid(1 + m_baseDir.length()));
+ //QString relativePath = ReQStringUtils::nativePath(
+ //path.mid(1 + m_baseDir.length()));
QString node, ext;
QList<QRegExp*> antiPatterns;
QStringList::const_iterator it3;
}
QList<QRegExp*>::const_iterator it2;
QList <QFileInfo>::const_iterator it;
+ clock_t nextUpdate = clock() + CLOCKS_PER_SEC;
for (it = entries.begin(); it != entries.end(); ++it){
node = it->fileName();
if (node == "." || node == "..")
if (ignore)
continue;
if (depth >= m_minDepth && isValid(*it)){
- if (m_lines >= table->rowCount()){
- table->setRowCount(m_lines + 500);
+ if (m_lines >= m_table->rowCount()){
+ m_table->setRowCount(m_lines + 500);
}
bool isDir = it->isDir();
if (isDir)
- statistics.m_dirs++;
+ m_statistics.m_dirs++;
else
- statistics.m_files++;
- table->setItem(m_lines, TC_NODE, new QTableWidgetItem(node));
+ m_statistics.m_files++;
+ m_table->setItem(m_lines, TC_NODE, new QTableWidgetItem(node));
int ix = node.lastIndexOf('.');
ext = ix <= 0 ? "" : node.mid(ix + 1).toLower();
- table->setItem(m_lines, TC_EXT, new QTableWidgetItem(ext));
- table->setItem(m_lines, TC_TYPE, new QTableWidgetItem(typeOf(*it)));
- table->setItem(m_lines, TC_PATH, new QTableWidgetItem(relativePath));
+ m_table->setItem(m_lines, TC_EXT, new QTableWidgetItem(ext));
+ m_table->setItem(m_lines, TC_TYPE, new QTableWidgetItem(typeOf(*it)));
+ m_table->setItem(m_lines, TC_PATH, new QTableWidgetItem(path));
QTableWidgetItem* item = new QTableWidgetItem(
isDir ? "" : fileSize(it->size()));
if (!isDir)
- statistics.m_bytes += it->size();
+ m_statistics.m_bytes += it->size();
item->setTextAlignment(Qt::AlignRight);
- table->setItem(m_lines, TC_SIZE, item);
- table->setItem(m_lines, TC_MODIFIED,
+ m_table->setItem(m_lines, TC_SIZE, item);
+ m_table->setItem(m_lines, TC_MODIFIED,
new QTableWidgetItem(
it->lastModified().toString("yyyy.MM.dd/hh:mm:ss")));
m_lines++;
+ clock_t now = clock();
+ if (now > nextUpdate){
+ m_table->setRowCount(m_lines);
+ nextUpdate = now + CLOCKS_PER_SEC;
+ }
}
}
for (it2 = antiPatterns.begin(); it2 != antiPatterns.end(); ++it2){
for (it = entries.begin(); it != entries.end(); ++it){
QString node = it->fileName();
if (!filtered || !isExcludedDir(node))
- fillTable(path + QDir::separator() + node, depth + 1, table,
- statistics);
+ fillTable(path + QDir::separator() + node, depth + 1);
}
}
- table->setRowCount(m_lines);
+ m_table->setRowCount(m_lines);
+}
+/**
+ * Runs a file search in a second thread.
+ */
+void FileFinder::run()
+{
+ search();
+}
+
+/**
+ * Fills the table with the data of the filtered files of a given directory.
+ */
+void FileFinder::search(){
+ if (! m_append){
+ m_statistics.clear();
+ m_lines = 0;
+ }
+ clock_t start = clock();
+ m_table->setSortingEnabled(false);
+ fillTable(ReQStringUtils::chomp(m_baseDir, OS_SEPARATOR), 0);
+ m_statistics.m_runtimeSeconds = (double) (clock() - start)
+ / CLOCKS_PER_SEC;
+ if (m_announcer != NULL){
+ QString msg;
+ msg.sprintf(
+ I18N::s2b(QObject::tr(
+ "Found: %d dir(s) and %d file(s) with %.6f MByte. Duration of the search: %.3f sec")),
+ m_statistics.m_dirs, m_statistics.m_files,
+ m_statistics.m_bytes / 1000000.0, m_statistics.m_runtimeSeconds);
+ m_announcer->say(LOG_INFO, msg);
+ }
+ m_table->setSortingEnabled(true);
+ if (m_observer != NULL)
+ m_observer->notify("ready");
}
/**
return rc;
}
+void FileFinder::setAppend(bool append)
+{
+ m_append = append;
+}
+
+/**
+ * Sets the announcer for the summary message at the end.
+ *
+ * @param announcer the announcer
+ */
+void FileFinder::setAnnouncer(ReAnnouncer* announcer)
+{
+ m_announcer = announcer;
+}
/**
* Sets the base directory.
*
* @param baseDir the directory where the search starts
*/
void FileFinder::setBaseDir(const QString& baseDir){
- m_baseDir = baseDir;
+ m_baseDir = baseDir;
}
/**
m_minSize = minSize;
}
+/**
+ * Sets the observer object. Will be notified about the search exit.
+ * @param observer
+ */
+void FileFinder::setObserver(ReObserver* observer)
+{
+ m_observer = observer;
+}
+
/**
* Sets the date time which is the lower bound.
*
}
}
+/**
+ * Sets the table to fill.
+ * @param table the table containing the found files
+ */
+void FileFinder::setTable(QTableWidget* table)
+{
+ m_table = table;
+}
+
/**
* Sets the date time which is the upper bound.
*
m_checkDates = true;
}
+
+/**
+ * Returns the statistics about the search.
+ * @return the statistics
+ */
+const Statistics& FileFinder::statistics() const
+{
+ return m_statistics;
+}
#include <QDateTime>
class TextFinder;
-class FileFinder {
+class FileFinder : public QThread{
public:
FileFinder();
~FileFinder();
public:
- void clear();
- void fillTable(const QString& path, int depth, QTableWidget* table,
- Statistics& statistics);
+ void fillTable(const QString& path, int depth);
+ void run();
+ void search();
+ void setAppend(bool append);
+ void setAnnouncer(ReAnnouncer* announcer);
void setBaseDir(const QString& baseDir);
void setFiletypes(const QDir::Filters& filetypes);
void setExcludedDirs(const QStringList& excludedDirs);
void setMaxSize(const int64_t& maxSize);
void setMinDepth(int minDepth);
void setMinSize(const int64_t& minSize);
+ void setObserver(ReObserver* observer);
void setOlderThan(const QDateTime& olderThan);
void setPatterns(const QStringList& patterns);
+ void setTable(QTableWidget* table);
void setTextFinder(TextFinder* textFinder);
void setYoungerThan(const QDateTime& youngerThan);
-
+ const Statistics& statistics() const;
private:
bool isExcludedDir(const QString& node);
bool isValid(const QFileInfo& file);
QStringList m_excludedDirs;
// Only used to hold the search parameters:
TextFinder* m_textFinder;
+ QTableWidget* m_table;
+ Statistics m_statistics;
+ ReAnnouncer* m_announcer;
+ ReObserver* m_observer;
+ bool m_append;
};
#endif // FILEFINDER_HPP
#include <QProcess>
#include <QMessageBox>
-const QString VERSION("2015.06.01");
+const QString VERSION("2015.12.15");
+
/**
* @brief Constructor.
*
m_homeDir(homeDir),
m_storageFile(),
m_contextHandlers(),
- m_logger(new ReMemoryLogger()){
+ m_logger(new ReMemoryLogger()),
+ m_finder(NULL){
ui->setupUi(this);
initializeHome();
m_statusMessage = new QLabel(tr("Welcome at refind"));
ui->tableWidget->setMainWindow(this);
statusBar()->addWidget(m_statusMessage);
connect(ui->actionSearch, SIGNAL(triggered()), this, SLOT(search()));
+ connect(ui->actionClear, SIGNAL(triggered()), this, SLOT(clear()));
connect(ui->pushButtonSearch, SIGNAL(clicked()), this, SLOT(search()));
connect(ui->pushButtonSearch2, SIGNAL(clicked()), this, SLOT(search()));
+ connect(ui->pushButtonClear, SIGNAL(clicked()), this, SLOT(clear()));
connect(ui->actionUp, SIGNAL(triggered()), this, SLOT(up()));
connect(ui->pushButtonUp, SIGNAL(clicked()), this, SLOT(up()));
connect(ui->actionSelectDirectory, SIGNAL(triggered()), this,
* @return the absolute path of the file given by the row
*/
QString MainWindow::buildAbsPath(int row, bool withNode, bool uriFormat){
- QString rc(m_lastBaseDir.absolutePath());
- QString value = cellAsText(row, TC_PATH);
- if (!value.isEmpty()){
- ReQStringUtils::ensureLastChar(rc, '/');
- rc += value;
- }
+ QString rc = cellAsText(row, TC_PATH);
if (withNode){
ReQStringUtils::ensureLastChar(rc, '/');
rc += cellAsText(row, TC_NODE);
}
void MainWindow::closing(){
- saveState();
+ saveState();
+}
+
+/**
+ * Clears the table.
+ */
+void MainWindow::clear()
+{
+ ui->tableWidget->setRowCount(0);
}
/**
if (row >= 0){
QClipboard* clipboard = QApplication::clipboard();
QString path = buildAbsPath(row);
+ ReQStringUtils::ensureLastChar(path, OS_SEPARATOR);
path += cellAsText(row, TC_NODE);
clipboard->setText(path);
}
handlePlaceholder(ui->comboBoxHeader);
}
+/**
+ * Informs the instance about some state changes.
+ *
+ * @param message description of the state change
+ * @return SUCCESS
+ */
+ReObserver::ReturnCode MainWindow::notify(const char* message)
+{
+ if (strcmp(message, "ready") == 0){
+ ui->pushButtonSearch->setEnabled(true);
+ ui->pushButtonSearch2->setEnabled(true);
+ }
+ return ReObserver::SUCCESS;
+}
+
/**
* Prepares the context menu of the result table.
*
storage.close();
}
+/**
+ * Sets the properties of the file finder.
+ *
+ * @param finder OUT: the finder to populate
+ */
+void MainWindow::populateFinder(FileFinder& finder){
+ finder.setObserver(this);
+ finder.setBaseDir(comboText(ui->comboBoxDirectory));
+ finder.setTable(ui->tableWidget);
+ m_lastBaseDir.cd(comboText(ui->comboBoxDirectory));
+ finder.setMaxSize(comboSize(ui->comboBoxMaxSize));
+ finder.setMinSize(comboSize(ui->comboBoxMinSize));
+ finder.setOlderThan(comboDate(ui->comboBoxOlder));
+ finder.setYoungerThan(comboDate(ui->comboBoxYounger));
+ finder.setMinDepth(comboInt(ui->comboBoxMinDepth, 0));
+ finder.setMaxDepth(comboInt(ui->comboBoxMaxDepth, -1));
+ finder.setFiletypes(buildFileTypes());
+ finder.setAppend(ui->checkBoxAppend->isChecked());
+ QStringList patterns;
+ QString value = comboText(ui->comboBoxFilePatterns);
+ if (!value.isEmpty())
+ patterns = value.split(",");
+ finder.setPatterns(patterns);
+ value = comboText(ui->comboBoxExcludedDirs);
+ if (value.indexOf('/') >= 0 || value.indexOf('\\') >= 0)
+ guiError(ui->comboBoxExcludedDirs, tr("no path delimiter allowed"));
+ else if (value.indexOf('*') >= 0)
+ guiError(ui->comboBoxExcludedDirs,
+ tr("no patterns allowed. Do not use '*"));
+ else if (!value.isEmpty())
+ patterns = value.split(",");
+ finder.setExcludedDirs(patterns);
+ if (m_errors == 0){
+ prepareTextFind();
+ if (!comboText(ui->comboBoxTextPattern).isEmpty())
+ finder.setTextFinder(&m_textFinder);
+ }
+}
+
/**
* Handles the "search" button.
*/
void MainWindow::search(){
-m_errors = 0;
-QApplication::setOverrideCursor (QCursor(Qt::WaitCursor));QString
-path = comboText(ui->comboBoxDirectory);
-QFileInfo dir(path);
-if (!dir.exists())
- guiError(ui->comboBoxDirectory, tr("directory not found: ") + path);
-else if (!dir.isDir())
- guiError(ui->comboBoxDirectory, tr("not a directory: ") + path);
-else{
- m_lastBaseDir.cd(path);
- FileFinder finder;
- finder.setBaseDir(path);
- finder.setMaxSize(comboSize(ui->comboBoxMaxSize));
- finder.setMinSize(comboSize(ui->comboBoxMinSize));
- finder.setOlderThan(comboDate(ui->comboBoxOlder));
- finder.setYoungerThan(comboDate(ui->comboBoxYounger));
- finder.setMinDepth(comboInt(ui->comboBoxMinDepth, 0));
- finder.setMaxDepth(comboInt(ui->comboBoxMaxDepth, -1));
- finder.setFiletypes(buildFileTypes());
- QStringList patterns;
- QString value = comboText(ui->comboBoxFilePatterns);
- if (!value.isEmpty())
- patterns = value.split(",");
- finder.setPatterns(patterns);
- value = comboText(ui->comboBoxExcludedDirs);
- if (value.indexOf('/') >= 0 || value.indexOf('\\') >= 0)
- guiError(ui->comboBoxExcludedDirs, tr("no path delimiter allowed"));
- else if (value.indexOf('*') >= 0)
- guiError(ui->comboBoxExcludedDirs,
- tr("no patterns allowed. Do not use '*"));
- else if (!value.isEmpty())
- patterns = value.split(",");
- finder.setExcludedDirs(patterns);
- prepareTextFind();
- if (m_errors == 0){
- if (!comboText(ui->comboBoxTextPattern).isEmpty())
- finder.setTextFinder(&m_textFinder);
- m_statistics.clear();
- clock_t start = clock();
- finder.fillTable(path, 0, ui->tableWidget, m_statistics);
- m_statistics.m_runtimeSeconds = (double) (clock() - start)
- / CLOCKS_PER_SEC;
- QString msg;
- msg.sprintf(
- I18N::s2b(QObject::tr(
- "Found: %d dir(s) and %d file(s) with %.6f MByte. Duration of the search: %.3f sec")),
- m_statistics.m_dirs, m_statistics.m_files,
- m_statistics.m_bytes / 1000000.0, m_statistics.m_runtimeSeconds);
- say(LOG_INFO, msg);
- }
-}
-QApplication::restoreOverrideCursor();
+ m_errors = 0;
+ QString path = comboText(ui->comboBoxDirectory);
+ QFileInfo dir(path);
+ if (!dir.exists())
+ guiError(ui->comboBoxDirectory, tr("directory not found: ") + path);
+ else if (!dir.isDir())
+ guiError(ui->comboBoxDirectory, tr("not a directory: ") + path);
+ else{
+ QApplication::setOverrideCursor (QCursor(Qt::WaitCursor));
+ if (m_finder == NULL)
+ m_finder = new FileFinder;
+ populateFinder(*m_finder);
+ if (! ui->checkBoxAppend->isChecked())
+ clear();
+ m_finder->start();
+ QApplication::restoreOverrideCursor();
+ }
}
/**
* Handles the push of the button "select directory".
}
}
}
+
enum TableColumns {
TC_NODE, TC_EXT, TC_SIZE, TC_MODIFIED, TC_TYPE, TC_PATH
};
+class FileFinder;
-class MainWindow: public QMainWindow, public ReGuiValidator {
+class MainWindow: public QMainWindow, public ReGuiValidator, public ReObserver {
Q_OBJECT
public:
void fileDragging();
protected:
+ void findFiles();
+ void populateFinder(FileFinder& finder);
private slots:
void about();
void absPathToClipboard();
void baseDirToClipboard();
void closing();
+ void clear();
void exportFiles();
void filePlaceholder();
void footerPlaceholder();
void handleTableContextMenu(const QPoint& position);
void headerClicked(int col);
void headerPlaceholder();
+ virtual ReturnCode notify(const char* message);
void options();
void preview();
void resetParameters();
+ virtual bool say(ReLoggerLevel level, const QString& message);
void saveState();
void search();
void selectDirectory();
QString replaceGlobalPlaceholders(QComboBox* combo,
QMap <QString, QString>& placeholders);
void restoreState();
- virtual bool say(ReLoggerLevel level, const QString& message);
private:
Ui::MainWindow *ui;
QLabel* m_statusMessage;
QAction* m_actionStartShell;
ContextHandlerList m_contextHandlers;
ReLogger* m_logger;
+ FileFinder* m_finder;
};
#endif // MAINWINDOW_HPP
</property>
</spacer>
</item>
+ <item>
+ <widget class="QPushButton" name="pushButtonClear">
+ <property name="toolTip">
+ <string>Clears the file table</string>
+ </property>
+ <property name="text">
+ <string>C&lear</string>
+ </property>
+ <property name="shortcut">
+ <string notr="true"/>
+ </property>
+ <property name="checkable">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="checkBoxAppend">
+ <property name="toolTip">
+ <string>Adds the result of the next search to the table</string>
+ </property>
+ <property name="text">
+ <string>Append</string>
+ </property>
+ </widget>
+ </item>
</layout>
</item>
<item row="3" column="1">
<x>10</x>
<y>11</y>
<width>981</width>
- <height>103</height>
+ <height>116</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<string>Size (MByte)</string>
</property>
<property name="textAlignment">
- <set>AlignRight|AlignBottom</set>
+ <set>AlignTrailing|AlignBottom</set>
</property>
</column>
<column>
<x>0</x>
<y>0</y>
<width>1030</width>
- <height>23</height>
+ <height>26</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
<addaction name="actionGetFullName"/>
<addaction name="actionGetBaseDirectory"/>
<addaction name="separator"/>
+ <addaction name="actionClear"/>
+ <addaction name="separator"/>
<addaction name="separator"/>
<addaction name="actionReset"/>
<addaction name="separator"/>
</attribute>
<addaction name="actionGetAbsPath"/>
<addaction name="actionGetFullName"/>
- <addaction name="actionGetBaseDirectory"/>
<addaction name="separator"/>
<addaction name="actionReset"/>
<addaction name="separator"/>
<string>Ctrl+Shift+V</string>
</property>
</action>
+ <action name="actionClear">
+ <property name="text">
+ <string>C&lear</string>
+ </property>
+ <property name="toolTip">
+ <string>Clears the file table</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+L</string>
+ </property>
+ </action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
long int lValue = atol(cols.at(3).toLatin1().constData());
handler->m_fileType = ContextHandler::FileType(lValue);
lValue = atol(cols.at(4).toLatin1().constData());
- handler->m_directoryMode = ContextHandler::DirMode(atol(lValue));
+ handler->m_directoryMode = ContextHandler::DirMode(lValue);
m_list.append(handler);
}
if (m_list.size() == 0){
inline int roundInt(double value) {
return (int) round(value);
}
+/** An observer can be informed about state changes.
+ * Pure abstract class.
+ */
+class ReObserver{
+public:
+ enum ReturnCode { SUCCESS, STOP, EXIT };
+ /** Informs the observer about a state change.
+ * @param message NULL or an info about the state change
+ * @return SUCCESS: success<br>
+ * STOP: the current action should be stopped<br>
+ * EXIT: the process should be stopped
+ */
+ virtual ReturnCode notify(const char* message) = 0;
+};
+
#define ReUseParameter(var) (void) var
#include "remodules.hpp"