From 788c86e1c45854267ee8b1fd9e6cfe52149ce3cb Mon Sep 17 00:00:00 2001 From: mwganson Date: Sun, 17 Sep 2023 12:53:17 -0500 Subject: [PATCH] [Macro Execute Dialog] add file name and file content filtering --- src/Gui/DlgMacroExecute.ui | 43 ++++++++++--- src/Gui/DlgMacroExecuteImp.cpp | 110 +++++++++++++++++++++++++++++---- src/Gui/DlgMacroExecuteImp.h | 3 + 3 files changed, 136 insertions(+), 20 deletions(-) diff --git a/src/Gui/DlgMacroExecute.ui b/src/Gui/DlgMacroExecute.ui index 084ecaf868..8b7871f8fc 100644 --- a/src/Gui/DlgMacroExecute.ui +++ b/src/Gui/DlgMacroExecute.ui @@ -77,7 +77,39 @@ - + + + + + + Find file: + + + + + + + Case-insensitive search for filenames, regular expressions supported + + + + + + + Find in files: + + + + + + + Filter by case-insensitive file content, regular expressions supported + + + + + + QTabWidget::North @@ -137,7 +169,7 @@ - + @@ -281,7 +313,7 @@ - + User macros location: @@ -307,15 +339,12 @@ Qt::StrongFocus - - Gui::FileChooser::Directory - - + diff --git a/src/Gui/DlgMacroExecuteImp.cpp b/src/Gui/DlgMacroExecuteImp.cpp index 3c4abe69c5..5c2cbc1b65 100644 --- a/src/Gui/DlgMacroExecuteImp.cpp +++ b/src/Gui/DlgMacroExecuteImp.cpp @@ -27,6 +27,7 @@ # include # include # include +# include #endif #include @@ -132,35 +133,108 @@ void DlgMacroExecuteImp::setupConnections() this, &DlgMacroExecuteImp::onSystemMacroListBoxCurrentItemChanged); connect(ui->tabMacroWidget, &QTabWidget::currentChanged, this, &DlgMacroExecuteImp::onTabMacroWidgetCurrentChanged); + connect(ui->LineEditFind, &QLineEdit::textChanged, + this, &DlgMacroExecuteImp::onLineEditFindTextChanged); + connect(ui->LineEditFindInFiles, &QLineEdit::textChanged, + this, &DlgMacroExecuteImp::onLineEditFindInFilesTextChanged); +} + +/** Take a folder and return a StringList of the filenames in it + * filtered by both filename *and* by content, if the user has + * put text in one or both of the search line edits. + * + * First filtering is done by file name, which reduces the + * number of files to open and read (relatively expensive operation). + * + * Then we filter by file content after reducing the number of files + * to open and read. But both loops are skipped if there is no text + * in either of the line edits. + * + * We do this as another function in order to reuse this code for + * doing both the User and System macro list boxes in the fillUpList() function. + */ + +QStringList DlgMacroExecuteImp::filterFiles(const QString& folder){ + QDir dir(folder, QLatin1String("*.FCMacro *.py")); + QStringList unfiltered = dir.entryList(); //all .fcmacro and .py files + QString fileFilter = ui->LineEditFind->text(); //used to search by filename + QString searchText = ui->LineEditFindInFiles->text(); //used to search in file content + + if (fileFilter.isEmpty() && searchText.isEmpty()){ //skip filtering if no filters + return unfiltered; + } + QStringList filteredByFileName; + if (fileFilter.isEmpty()){ + filteredByFileName = unfiltered; //skip the loop if no file filter + } else { + QRegularExpression regexFileName(fileFilter, QRegularExpression::CaseInsensitiveOption); + bool isValidFileFilter = regexFileName.isValid(); //check here instead of inside the loop + for (auto uf : unfiltered){ + if (isValidFileFilter){ + if (regexFileName.match(uf).hasMatch()) { + filteredByFileName.append(uf); + } + } else { //not valid, so do a simple text search + if (uf.contains(fileFilter, Qt::CaseInsensitive)) { + filteredByFileName.append(uf); + } + } + } + } + + if (searchText.isEmpty()){ //skip reading file contents if no find in file filter + return filteredByFileName; + } + + QRegularExpression regexContent(searchText, QRegularExpression::CaseInsensitiveOption); + bool isValidContentFilter = regexContent.isValid(); + QStringList filteredByContent; + for (auto fn : filteredByFileName) { + const QString &fileName = fn; + QString filePath = dir.filePath(fileName); + QFile file(filePath); + if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { + QTextStream in(&file); + QString fileContent = in.readAll(); + if (isValidContentFilter){ + if (regexContent.match(fileContent).hasMatch()) { + filteredByContent.append(fileName); + } + } else { + if (fileContent.contains(searchText, Qt::CaseInsensitive)){ + filteredByContent.append(fileName); + } + } + file.close(); + } + } + return filteredByContent; } /** - * Fills up the list with all macro files found in the specified location. + * Fills up the list with macro files found in the specified location + * that have been filtered by both filename and by content */ void DlgMacroExecuteImp::fillUpList() { - // lists all files in macro path - QDir dir(this->macroPath, QLatin1String("*.FCMacro *.py")); - - // fill up with the directory + QStringList filteredByContent = this->filterFiles(this->macroPath); ui->userMacroListBox->clear(); - for (unsigned int i=0; iuserMacroListBox,false); - item->setText(0, dir[i]); + item->setText(0, fn); } QString dirstr = QString::fromStdString(App::Application::getHomePath()) + QString::fromLatin1("Macro"); - dir = QDir(dirstr, QLatin1String("*.FCMacro *.py")); + filteredByContent = this->filterFiles(dirstr); ui->systemMacroListBox->clear(); - if (dir.exists()) { - for (unsigned int i=0; isystemMacroListBox,true); - item->setText(0, dir[i]); - } + for (auto fn : filteredByContent) { + auto item = new MacroItem(ui->systemMacroListBox,true); + item->setText(0, fn); } } + /** * Selects a macro file in the list view. */ @@ -188,6 +262,16 @@ void DlgMacroExecuteImp::onUserMacroListBoxCurrentItemChanged(QTreeWidgetItem* i } } +void DlgMacroExecuteImp::onLineEditFindTextChanged(const QString &text){ + Q_UNUSED(text); + this->fillUpList(); +} + +void DlgMacroExecuteImp::onLineEditFindInFilesTextChanged(const QString &text){ + Q_UNUSED(text); + this->fillUpList(); +} + void DlgMacroExecuteImp::onSystemMacroListBoxCurrentItemChanged(QTreeWidgetItem* item) { if (item) { diff --git a/src/Gui/DlgMacroExecuteImp.h b/src/Gui/DlgMacroExecuteImp.h index 88fe36ceb7..9ad454f77b 100644 --- a/src/Gui/DlgMacroExecuteImp.h +++ b/src/Gui/DlgMacroExecuteImp.h @@ -64,9 +64,12 @@ private: void onUserMacroListBoxCurrentItemChanged(QTreeWidgetItem*); void onSystemMacroListBoxCurrentItemChanged(QTreeWidgetItem*); void onTabMacroWidgetCurrentChanged(int index); + void onLineEditFindTextChanged(const QString&); + void onLineEditFindInFilesTextChanged(const QString&); protected: void fillUpList(); + QStringList filterFiles(const QString&); protected: QString macroPath;