- enhancement: Folder mode in "File in files" dialog.

- enhancement: When open a file, test if it contains binary contains.
This commit is contained in:
Roy Qu 2023-07-05 15:02:39 +08:00
parent eccdf68a60
commit 595156e80f
16 changed files with 752 additions and 425 deletions

View File

@ -30,6 +30,8 @@ Red Panda C++ Version 2.23
- enhancement: Sort symbols by their declaration pos in the Class Browser, if not sort by alpha order.
- fix: Keyword asm is not correctly parsed.
- fix: Tips for problem is not correctly displayed.
- enhancement: Folder mode in "File in files" dialog.
- enhancement: When open a file, test if it contains binary contains.
Red Panda C++ Version 2.22

View File

@ -6526,9 +6526,13 @@ void MainWindow::on_btnSearchAgain_clicked()
if (results->scope==SearchFileScope::wholeProject
&& pMainWindow->project()==nullptr)
return;
mSearchInFilesDialog->findInFiles(results->keyword,
mSearchInFilesDialog->findInFiles(
results->keyword,
results->scope,
results->options);
results->options,
results->folder,
results->filters,
results->searchSubfolders);
} else if (results->searchType == SearchType::FindOccurences) {
CppRefacter refactor;
refactor.findOccurence(results->statementFullname,results->scope);

View File

@ -515,7 +515,7 @@
<enum>QTabWidget::West</enum>
</property>
<property name="currentIndex">
<number>4</number>
<number>0</number>
</property>
<property name="usesScrollButtons">
<bool>true</bool>

View File

@ -7353,6 +7353,34 @@
<source>Abort</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>*.*</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Filters:</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>...</source>
<translation type="unfinished">...</translation>
</message>
<message>
<source>Folder:</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Search in subfolders</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Folder</source>
<translation type="unfinished">Pasta</translation>
</message>
<message>
<source>Choose Folder</source>
<translation type="unfinished">Escolher pasta</translation>
</message>
</context>
<context>
<name>SearchResultListModel</name>
@ -7376,6 +7404,10 @@
<source>Find Usages in Project: &apos;%1&apos;</source>
<translation>Procurar usos no projeto: &apos;%1&apos;</translation>
</message>
<message>
<source>&quot;%1&quot; in Folder &quot;%2&quot;</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SearchResultTreeModel</name>

File diff suppressed because it is too large Load Diff

View File

@ -6707,6 +6707,34 @@
<source>Abort</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>*.*</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Filters:</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>...</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Folder:</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Search in subfolders</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Folder</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Choose Folder</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SearchResultListModel</name>
@ -6730,6 +6758,10 @@
<source>Find Usages in Project: &apos;%1&apos;</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>&quot;%1&quot; in Folder &quot;%2&quot;</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SearchResultTreeModel</name>

View File

@ -53,7 +53,8 @@ enum class FileType{
enum class SearchFileScope {
currentFile,
wholeProject,
openedFiles
openedFiles,
Folder
};
enum AutoSaveTarget {

View File

@ -24,10 +24,13 @@
#include <qsynedit/searcher/regexsearcher.h>
#include "../project.h"
#include "../settings.h"
#include "../systemconsts.h"
#include <QMessageBox>
#include <QDebug>
#include <QProgressDialog>
#include <QCompleter>
#include <QStack>
#include <QFileDialog>
SearchInFileDialog::SearchInFileDialog(QWidget *parent) :
@ -40,7 +43,7 @@ SearchInFileDialog::SearchInFileDialog(QWidget *parent) :
mBasicSearchEngine= QSynedit::PSynSearchBase(new QSynedit::BasicSearcher());
mRegexSearchEngine= QSynedit::PSynSearchBase(new QSynedit::RegexSearcher());
ui->cbFind->completer()->setCaseSensitivity(Qt::CaseSensitive);
on_rbFolder_toggled(false);
}
SearchInFileDialog::~SearchInFileDialog()
@ -56,7 +59,7 @@ void SearchInFileDialog::findInFiles(const QString &text)
show();
}
void SearchInFileDialog::findInFiles(const QString &keyword, SearchFileScope scope, QSynedit::SearchOptions options)
void SearchInFileDialog::findInFiles(const QString &keyword, SearchFileScope scope, QSynedit::SearchOptions options, const QString& folder, const QString& filters, bool searchSubfolders)
{
ui->cbFind->setCurrentText(keyword);
ui->cbFind->setFocus();
@ -71,6 +74,12 @@ void SearchInFileDialog::findInFiles(const QString &keyword, SearchFileScope sco
case SearchFileScope::wholeProject:
ui->rbProject->setChecked(true);
break;
case SearchFileScope::Folder:
ui->txtFolder->setText(folder);
ui->txtFilters->setText(filters);
ui->cbSearchSubFolders->setChecked(searchSubfolders);
ui->rbFolder->setChecked(true);
break;
}
// Apply options
ui->chkRegExp->setChecked(options.testFlag(QSynedit::ssoRegExp));
@ -97,7 +106,6 @@ void SearchInFileDialog::on_btnExecute_clicked()
void SearchInFileDialog::doSearch(bool replace)
{
int findCount = 0;
saveComboHistory(ui->cbFind,ui->cbFind->currentText());
mSearchOptions&=0;
@ -117,7 +125,7 @@ void SearchInFileDialog::doSearch(bool replace)
close();
// Find the first one, then quit
int findCount=0;
int fileSearched = 0;
int fileHitted = 0;
QString keyword = ui->cbFind->currentText();
@ -145,6 +153,97 @@ void SearchInFileDialog::doSearch(bool replace)
}
}
pMainWindow->searchResultModel()->notifySearchResultsUpdated();
} else if (ui->rbFolder->isChecked()) {
PSearchResults results = pMainWindow->searchResultModel()->addSearchResults(
keyword,
mSearchOptions,
SearchFileScope::Folder,
ui->txtFolder->text(),
ui->txtFilters->text(),
ui->cbSearchSubFolders
);
if (ui->txtFilters->text().trimmed().isEmpty()) {
ui->txtFilters->setText("*.*");
}
QDir rootDir(ui->txtFolder->text());
// loop through editors, add results to message control
QProgressDialog progressDlg(
tr("Searching..."),
tr("Abort"),
0,
1,
pMainWindow);
progressDlg.setWindowModality(Qt::WindowModal);
QStack<QDir> dirs;
QSet<QString> searched;
QList<QFileInfo> files;
dirs.push(rootDir);
QDir::Filters filterOptions=QDir::Files | QDir::NoSymLinks;
if (PATH_SENSITIVITY==Qt::CaseSensitive)
filterOptions |= QDir::CaseSensitive;
while (!dirs.isEmpty()) {
QDir dir=dirs.back();
dirs.pop_back();
foreach(const QFileInfo& entry, dir.entryInfoList(QDir::NoSymLinks | QDir::Dirs)) {
if (entry.fileName()==".." || entry.fileName()==".")
continue;
if (!searched.contains(entry.absoluteFilePath())) {
dirs.push_back(QDir(entry.absoluteFilePath()));
searched.insert(entry.absoluteFilePath());
}
}
foreach(const QFileInfo& entry, dir.entryInfoList(ui->txtFilters->text().split(";"), filterOptions)) {
files.append(entry);
}
}
progressDlg.setMaximum(files.count());
int i=0;
foreach (const QFileInfo &info, files) {
QString curFilename = info.absoluteFilePath();
i++;
progressDlg.setValue(i);
progressDlg.setLabelText(tr("Searching...")+"<br/>"+curFilename);
if (progressDlg.wasCanceled())
break;
Editor * e = pMainWindow->editorList()->getOpenedEditorByFilename(curFilename);
if (e) {
fileSearched++;
PSearchResultTreeItem parentItem = batchFindInEditor(
e,
e->filename(),
keyword);
int t = parentItem->results.size();
findCount+=t;
if (t>0) {
fileHitted++;
results->results.append(parentItem);
}
} else if (fileExists(curFilename)) {
QSynedit::QSynEdit editor;
QByteArray realEncoding;
try{
editor.document()->loadFromFile(curFilename,ENCODING_AUTO_DETECT, realEncoding);
} catch (QSynedit::BinaryFileError e) {
continue;
} catch (FileError e) {
continue;
}
fileSearched++;
PSearchResultTreeItem parentItem = batchFindInEditor(
&editor,
curFilename,
keyword);
int t = parentItem->results.size();
findCount+=t;
if (t>0) {
fileHitted++;
results->results.append(parentItem);
}
}
}
pMainWindow->searchResultModel()->notifySearchResultsUpdated();
} else if (ui->rbCurrentFile->isChecked()) {
PSearchResults results = pMainWindow->searchResultModel()->addSearchResults(
keyword,
@ -211,7 +310,13 @@ void SearchInFileDialog::doSearch(bool replace)
if (encoding==ENCODING_PROJECT)
encoding = projectEncoding;
QByteArray realEncoding;
try {
editor.document()->loadFromFile(curFilename,encoding, realEncoding);
} catch (QSynedit::BinaryFileError e) {
continue;
} catch (FileError e) {
continue;
}
fileSearched++;
PSearchResultTreeItem parentItem = batchFindInEditor(
&editor,
@ -320,3 +425,27 @@ void SearchInFileDialog::on_btnReplace_clicked()
doSearch(true);
}
void SearchInFileDialog::on_rbFolder_toggled(bool checked)
{
ui->lblFilters->setVisible(checked);
ui->txtFilters->setVisible(checked);
ui->lblFolder->setVisible(checked);
ui->txtFolder->setVisible(checked);
ui->btnChangeFolder->setVisible(checked);
ui->cbSearchSubFolders->setVisible(checked);
if (checked) {
if (!directoryExists(ui->txtFolder->text()))
ui->txtFolder->setText(pSettings->environment().currentFolder());
}
}
void SearchInFileDialog::on_btnChangeFolder_clicked()
{
QString folder = QFileDialog::getExistingDirectory(this,tr("Choose Folder"),
ui->txtFolder->text());
if (directoryExists(folder))
ui->txtFolder->setText(folder);
}

View File

@ -36,7 +36,7 @@ public:
explicit SearchInFileDialog(QWidget *parent = nullptr);
~SearchInFileDialog();
void findInFiles(const QString& text);
void findInFiles(const QString& keyword, SearchFileScope scope, QSynedit::SearchOptions options);
void findInFiles(const QString& keyword, SearchFileScope scope, QSynedit::SearchOptions options, const QString& folder, const QString& filters, bool searchSubfolders );
QSynedit::PSynSearchBase searchEngine() const;
private slots:
@ -47,6 +47,10 @@ private slots:
void on_btnExecute_clicked();
void on_btnReplace_clicked();
void on_rbFolder_toggled(bool checked);
void on_btnChangeFolder_clicked();
private:
void doSearch(bool replace);
int execute(QSynedit::QSynEdit* editor, const QString& sSearch,

View File

@ -53,6 +53,13 @@
<property name="bottomMargin">
<number>0</number>
</property>
<item row="1" column="1" colspan="2">
<widget class="QLineEdit" name="txtFilters">
<property name="text">
<string>*.*</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="lblFind">
<property name="text">
@ -60,7 +67,21 @@
</property>
</widget>
</item>
<item row="0" column="1">
<item row="1" column="0">
<widget class="QLabel" name="lblFilters">
<property name="text">
<string>Filters:</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QToolButton" name="btnChangeFolder">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="0" column="1" colspan="2">
<widget class="QComboBox" name="cbFind">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
@ -76,6 +97,26 @@
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="txtFolder"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="lblFolder">
<property name="text">
<string>Folder:</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="3">
<widget class="QCheckBox" name="cbSearchSubFolders">
<property name="text">
<string>Search in subfolders</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@ -130,6 +171,13 @@
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="rbFolder">
<property name="text">
<string>Folder</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>

View File

@ -20,7 +20,7 @@
#include <QStyledItemDelegate>
#include "mainwindow.h"
PSearchResults SearchResultModel::addSearchResults(const QString &keyword, QSynedit::SearchOptions options, SearchFileScope scope)
PSearchResults SearchResultModel::addSearchResults(const QString &keyword, QSynedit::SearchOptions options, SearchFileScope scope, const QString& folder, const QString& filters, bool searchSubfolders)
{
int index=-1;
for (int i=0;i<mSearchResults.size();i++) {
@ -42,6 +42,9 @@ PSearchResults SearchResultModel::addSearchResults(const QString &keyword, QSyne
results->options = options;
results->scope = scope;
results->searchType = SearchType::Search;
results->folder=folder;
results->filters=filters;
results->searchSubfolders=searchSubfolders;
mSearchResults.push_front(results);
mCurrentIndex = 0;
return results;
@ -384,6 +387,8 @@ QVariant SearchResultListModel::data(const QModelIndex &index, int role) const
return tr("Files In Project:") + QString(" \"%1\"").arg(results->keyword);
case SearchFileScope::openedFiles:
return tr("Open Files:") + QString(" \"%1\"").arg(results->keyword);
case SearchFileScope::Folder:
return tr("\"%1\" in Folder \"%2\"").arg(results->keyword).arg(results->folder);
}
} else if (results->searchType == SearchType::FindOccurences) {
if (results->scope == SearchFileScope::currentFile) {

View File

@ -52,6 +52,9 @@ struct SearchResults{
SearchFileScope scope;
SearchType searchType;
QString filename;
QString folder;
QString filters;
bool searchSubfolders;
QList<PSearchResultTreeItem> results;
};
@ -62,7 +65,7 @@ class SearchResultModel : public QObject {
public:
explicit SearchResultModel(QObject* parent=nullptr);
PSearchResults addSearchResults(const QString& keyword,QSynedit::SearchOptions options,
SearchFileScope scope);
SearchFileScope scope, const QString& folder=QString(), const QString& filters=QString(), bool searchSubfolders=true);
PSearchResults addSearchResults(
const QString& keyword,
const QString& symbolFullname,

View File

@ -645,6 +645,8 @@ void Document::loadFromFile(const QString& filename, const QByteArray& encoding,
} else if (line.endsWith("\n")){
line.remove(line.length()-1,1);
}
if (isBinaryContent(line))
throw BinaryFileError(tr("This is a binaray File!"));
if (allAscii) {
allAscii = isTextAllAscii(line);
}
@ -1300,4 +1302,10 @@ int RedoList::itemCount()
return mItems.count();
}
BinaryFileError::BinaryFileError(const QString& reason):
FileError(reason)
{
}
}

View File

@ -50,6 +50,11 @@ class Document;
typedef std::shared_ptr<Document> PDocument;
class BinaryFileError : public FileError {
public:
explicit BinaryFileError (const QString& reason);
};
class Document : public QObject
{
Q_OBJECT

View File

@ -114,7 +114,7 @@ const QByteArray guessTextEncoding(const QByteArray& text){
bool isTextAllAscii(const QByteArray& text) {
for (char c:text) {
if (c<=0) {
if (c<0 || c>127) {
return false;
}
}
@ -724,3 +724,13 @@ QStringList absolutePaths(const QString &dirPath, const QStringList &relativePat
}
bool isBinaryContent(const QByteArray &text)
{
for (char c:text) {
if (c>=0 && c<' ' && c!='\t' && c!='\n' && c!='\r') {
return true;
}
}
return false;
}

View File

@ -69,6 +69,7 @@ public:
/* text processing utils */
const QByteArray guessTextEncoding(const QByteArray& text);
bool isBinaryContent(const QByteArray& text);
bool isTextAllAscii(const QByteArray& text);
bool isTextAllAscii(const QString& text);