diff --git a/NEWS.md b/NEWS.md
index f3587685..46b9b802 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -10,6 +10,9 @@ Version 0.6.0
- enhancement: don't add encoding options when using clang to compile (clang only support utf-8)
- enhancement: find occurence in project
- implement: refactor in file
+ - enhancement: replace in files
+ - enhancement: refactor in project (using search symbol occurence and replace in files)
+ - fix: search in files
Version 0.5.0
- enhancement: support C++ using type alias;
diff --git a/RedPandaIDE/RedPandaIDE_zh_CN.ts b/RedPandaIDE/RedPandaIDE_zh_CN.ts
index 7ef8dcfc..62b012cc 100644
--- a/RedPandaIDE/RedPandaIDE_zh_CN.ts
+++ b/RedPandaIDE/RedPandaIDE_zh_CN.ts
@@ -394,7 +394,7 @@
[说明]
-
+
无法启动编译器进程'%1'。
@@ -403,27 +403,27 @@
无法启动编译进程。
-
+
编译进程启动后崩溃。
-
+
waitFor()函数等待超时。
-
+
在向编译进程输入内容时出错。
-
+
在从编译进程读取内容时出错。
-
+
发生了未知错误。
@@ -459,32 +459,47 @@
CompilerManager
-
-
-
-
-
+
+
+
+
+
无编译器设置
-
-
-
-
-
+
+
+
+
+
没有配置编译器设置。
-
-
-
-
-
+
+
+
+
+
无法启动调试器
+
+
+
+ 不支持字符编码
+
+
+
+
+ Clang只支持UTF-8编码
+
+
+
+
+ 程序中的文字内容可能无法被正确处理和显示。
+
CompilerSetDirectoriesWidget
@@ -699,6 +714,25 @@ Are you really want to continue?
新名称
+
+ CppRefacter
+
+
+
+
+ 重命名符号失败
+
+
+
+
+ 无法重命名不在本文件中定义的符号
+
+
+
+
+ 新符号名称已被使用!
+
+
CustomMakefileInfoDialog
@@ -2461,40 +2495,40 @@ Are you really want to continue?
小熊猫C++
-
-
+
+
编译器
-
+
编译日志
-
+
文件
-
+
工具
-
-
+
+
运行
-
+
编辑
-
+
项目
@@ -2509,91 +2543,90 @@ Are you really want to continue?
结构
-
- 文件
+ 文件
资源
-
-
-
-
+
+
+
+
调试
-
+
求值
-
+
调试主控台
-
+
调用栈
-
+
断点
-
+
本地变量
-
-
+
+
查找
-
+
历史:
-
+
重新查找
-
+
替换为:
-
+
替换
-
+
关闭
-
+
运行
-
-
+
+
代码
-
+
窗口
@@ -2606,627 +2639,643 @@ Are you really want to continue?
工具栏2
-
+
新建
-
+
Ctrl+N
-
+
打开...
-
+
Ctrl+O
-
+
保存
-
+
Ctrl+S
-
+
另存为...
-
+
另存为
-
+
全部保存
-
+
Ctrl+Shift+S
-
+
选项
-
-
-
-
-
-
-
+
+
+
+
+
+
+
编译
-
+
F9
-
+
F10
-
+
恢复
-
+
Ctrl+Z
-
+
重做
-
+
Ctrl+Y
-
+
剪切
-
+
Ctrl+X
-
-
-
+
+
+
复制
-
+
Ctrl+C
-
-
+
+
粘贴
-
+
Ctrl+V
-
-
+
+
选择全部
-
+
Ctrl+A
-
+
缩进
-
+
取消缩进
-
+
切换注释
-
+
Ctrl+/
-
+
全部收起
-
+
全部展开
-
+
使用ANSI编码
-
+
使用UTF-8编码
-
+
自动检测
-
+
转换为ANSI编码
-
+
转换为UTF-8编码
-
-
+
+
编译运行
-
+
F11
-
-
+
+
全部重编译
-
+
F12
-
+
停止执行
-
+
F6
-
+
F5
-
+
单步跳过
-
+
F7
-
+
单步进入
-
+
内存
-
+
Address:
地址表达式:
-
+
TODO
-
+
帮助
-
+
+
+ 重构
+
+
+
主工具栏
-
+
编译器配置集
-
-
+
+
新建源代码文件
-
+
F8
-
+
单步跳出
-
+
Ctrl+F8
-
+
执行到光标处
-
+
Ctrl+F5
-
+
继续执行
-
+
F4
-
+
添加监视
-
+
打开CPU信息窗口...
-
+
退出
-
+
查找...
-
+
Ctrl+F
-
+
在文件中查找...
-
+
Ctrl+Shift+F
-
+
替换
-
+
Ctrl+R
-
+
查找下一个
-
+
F3
-
+
查找前一个
-
+
Shift+F3
-
+
删除监视
-
+
清除全部监视
-
+
修改监视值
-
+
对代码重新排版
-
+
Ctrl+Shift+A
-
+
前一次编辑位置
-
+
Ctrl+Alt+Left
-
+
后一次编辑位置
-
+
Ctrl+Alt+Right
-
+
Ctrl+W
-
+
全部关闭
-
+
Ctrl+Shift+W
-
+
最大化编辑器
-
+
Ctrl+F11
-
+
下一窗口
-
+
Ctrl+Tab
-
+
前一窗口
-
+
Ctrl+Shift+Tab
-
+
切换断点
-
+
Ctrl+F4
-
-
+
+
删除所有断点
-
+
设置断点条件...
-
+
跳转到声明处
-
+
跳转到定义处
-
+
查找符号的引用
-
+
打开所在的文件夹
-
+
Ctrl+B
-
+
打开命令行窗口
-
+
文件属性...
-
+
关闭项目
-
+
项目属性
-
+
新建项目...
-
+
新建项目文件
-
+
添加到项目...
-
+
从项目删除
-
+
查看Makefile
-
+
清理构建文件
-
+
在浏览器中打开
-
+
在终端中打开
-
+
关于
-
+
+
+
+ 重命名符号
+
+
+
+
+ Shift+F6
+
+
+
文件编码
-
+
文件历史
-
-
-
-
-
-
+
+
+
+
+
+
正在调试
-
-
-
-
-
-
+
+
+
+
+
+
正在运行
-
-
-
-
-
-
+
+
+
+
+
+
正在编译
@@ -3235,433 +3284,454 @@ Are you really want to continue?
行:%1 列:%2 已选择:%3 总行数:%4 总长度:%5
-
+
行:%1 列:%2 已选择:%3 总行数:%4 总长度:%5
-
+
只读
-
+
插入
-
+
覆写
-
+
关闭项目
-
+
你确定要关闭'%1'吗?
-
-
+
+
确认
-
-
-
+
+
+
源文件尚未编译。
-
-
+
+
现在编译?
-
-
+
+
源文件比可执行程序新。
-
+
重新编译?
-
+
无编译器设置
-
+
没有配置编译器设置。
-
+
无法启动调试器
-
-
+
+
启用调试参数
-
-
+
+
当前编译设置中未启用调试选项(-g3),或启用了信息剥除选项(-s)<br /><br/>是否纠正这一问题?
-
+
项目尚未构建
-
+
项目尚未构建。是否构建?
-
+
宿主程序不存在
-
+
动态链接库(DLL)需要一个宿主程序来运行。
-
+
但它不存在。
-
+
宿主程序不存在
-
+
宿主程序'%1'不存在。
-
+
重新编译?
-
-
+
+
保存上次打开信息失败
-
+
无法删除旧上次打开信息文件'%1'
-
+
无法保存上次打开信息文件'%1'
-
+
载入上次打开信息失败
-
+
无法载入上次打开信息文件'%1'
-
+
全部复制
-
-
+
+
清除
-
+
在调试主控台中显示调试器输出
-
+
清除这次搜索
-
+
删除所有搜索
-
+
断点条件...
-
+
断点条件
-
+
输入当前断点的生效条件:
-
+
清除所有断点
-
+
重命名文件
-
-
+
+
添加文件夹
-
+
新文件夹
-
+
文件夹:
-
+
重命名
-
+
删除文件夹
-
+
按类型排序
-
+
按名称排序
-
+
显示继承的成员
-
+
跳转到声明处
-
+
跳转到定义处
-
+
字符集
-
+
已自动保存%1个文件
-
+
保存项目
-
+
项目'%1'有改动。
-
+
需要保存吗?
-
+
您真的要清除该文件的所有断点吗?
-
+
新建项目
-
+
关闭'%1'以打开新项目?
-
+
文件夹不存在
-
+
文件夹'%1'不存在。是否创建?
-
+
无法创建文件夹
-
+
创建文件夹'%1'失败。
-
+
-
+
小熊猫Dev-C++项目文件 (*.dev)
-
+
新建项目失败
-
+
无法使用模板创建项目
-
+
添加到项目
-
-
-
-
-
-
-
-
-
+
+
+ 新名称
+
+
+
+
+
+ 替换出错
+
+
+
+
+ 无法打开文件'%1'进行替换!
+
+
+
+
+ 内容和上次查找时不一致。
+
+
+
+
+
+
+
+
+
+
+
错误
-
+
项目历史
-
+
磁盘文件'%1'已被修改。
-
+
是否重新读取它的内容?
-
+
磁盘文件'%1'已被删除。
-
+
是否保持它在小熊猫C++中打开的编辑窗口?
-
+
打开
-
+
编译失败
-
+
运行失败
-
-
+
+
确认转换
-
-
+
+
当前编辑器中的文件将会使用%1编码保存。<br />这项操作无法被撤回。<br />你确定要继续吗?
-
+
新监视表达式
-
+
输入监视表达式
-
+
(%1/%2)正在解析文件"%3"
-
-
+
+
完成%1个文件的解析,用时%2秒
-
+
(每秒%1个文件)
@@ -4495,175 +4565,175 @@ Are you really want to continue?
无法载入自动链接设置
-
-
-
-
+
+
+
+
下列%1文件夹不存在:
-
-
+
+
二进制
-
+
未指定%1文件夹
-
+
C包含
-
-
+
+
C++包含
-
-
-
-
+
+
+
+
无法找到%1程序"%2"
-
+
C语言选项
-
+
支持所有ANSI标准C程序(-ansi)
-
+
不支持将asm、inline和typeof作为关键字(-fno-asm)
-
+
模仿传统C预处理器行为(-traditional-cpp)
-
+
代码生成
-
+
生成特定机器的专用指令(-march)
-
+
完整兼容特定机器,较少优化(-tune)
-
+
启用特定指令集(-mx)
-
+
优化级别(-Ox)
-
+
使用下列指针大小编译(-mx)
-
+
语言标准(-std)
-
+
性能分析
-
+
生成调试信息(-g3)
-
+
生成性能分析信息(-pg)
-
+
代码警告
-
+
忽略所有警告信息(-w)
-
+
启用常见问题警告(-Wall)
-
+
启用更多问题警告(-Wextra)
-
+
检查ISO C/C++/C++0x语法一致性(-pedantic)
-
+
只进行语法检查(不编译)(-fsyntax-only)
-
+
将警告作为错误处理(-Werror)
-
+
遇到第一个错误后立即中止编译(-Wfatal-errors)
-
+
链接器
-
+
链接Objective-C程序 (-lobjc)
-
+
不使用标准库和系统启动文件(-nostdlib)
-
+
不产生控制台窗口(-mwindows)
-
+
剥除附加信息(-s)
@@ -4672,43 +4742,43 @@ Are you really want to continue?
链接Ojbective C程序(-lobjc)
-
+
输出
-
+
在生成的汇编代码中加入注释(-fverbose-asm)
-
+
编译时使用管道而不是临时文件(-pipe)
-
+
只生成汇编代码(-S)
-
+
确认
-
+
在验证编译器设置"%1"时遇到了下列问题:
-
+
未配置编译器设置。
-
+
您需要小熊猫C++在下列位置搜索编译器吗:<br />%1<br />%2
@@ -5182,7 +5252,7 @@ Are you really want to continue?
-
+
查找
@@ -5198,13 +5268,18 @@ Are you really want to continue?
-
-
+
+
替换
-
+
+
+ 在文件中替换
+
+
+
替换这里的"%1"?
@@ -5212,30 +5287,30 @@ Are you really want to continue?
SearchResultListModel
-
+
当前文件:
-
+
项目中的文件:
-
+
打开的文件:
-
+
- 符号'%1'出现在'%2':'%3'
+ 符号'%1'出现在'%2': %3
SearchResultTreeModel
-
+
行
@@ -5243,8 +5318,8 @@ Are you really want to continue?
SearchResultTreeViewDelegate
-
-
+
+
行
diff --git a/RedPandaIDE/mainwindow.cpp b/RedPandaIDE/mainwindow.cpp
index 753aaddc..d1f38dbb 100644
--- a/RedPandaIDE/mainwindow.cpp
+++ b/RedPandaIDE/mainwindow.cpp
@@ -1272,9 +1272,10 @@ void MainWindow::debug()
}
}
-void MainWindow::showSearchPanel()
+void MainWindow::showSearchPanel(bool showReplace)
{
openCloseBottomPanel(true);
+ showSearchReplacePanel(showReplace);
ui->tabMessages->setCurrentWidget(ui->tabSearch);
}
@@ -3539,8 +3540,7 @@ void MainWindow::on_actionFind_references_triggered()
if (editor && editor->pointToCharLine(mEditorContextMenuPos,pos)) {
CppRefacter refactor;
refactor.findOccurence(editor,pos);
- ui->tabMessages->setCurrentWidget(ui->tabSearch);
- openCloseBottomPanel(true);
+ showSearchPanel(true);
}
}
@@ -3973,6 +3973,37 @@ void MainWindow::on_actionRename_Symbol_triggered()
return;
}
+ BufferCoord oldCaretXY = editor->caretXY();
+ if (editor->inProject() && mProject) {
+ mProject->cppParser()->parseFileList();
+ BufferCoord pBeginPos,pEndPos;
+ QString phrase = getWordAtPosition(editor,oldCaretXY,pBeginPos,pEndPos,Editor::WordPurpose::wpInformation);
+ // Find it's definition
+ PStatement oldStatement = editor->parser()->findStatementOf(
+ editor->filename(),
+ phrase,
+ oldCaretXY.Line);
+ // definition of the symbol not found
+ if (!oldStatement)
+ return;
+ // found but not in this file
+ if (editor->filename() != oldStatement->fileName
+ || editor->filename() != oldStatement->definitionFileName) {
+ // it's defined in system header, dont rename
+ if (mProject->cppParser()->isSystemHeaderFile(oldStatement->fileName)) {
+ QMessageBox::critical(editor,
+ tr("Rename Error"),
+ tr("Symbol '%1' is defined in system header.")
+ .arg(oldStatement->fullName));
+ return;
+ }
+ CppRefacter refactor;
+ refactor.findOccurence(editor,oldCaretXY);
+ showSearchPanel(true);
+ return;
+ }
+ }
+
bool ok;
QString newWord = QInputDialog::getText(editor,
tr("Rename Symbol"),
@@ -3985,7 +4016,6 @@ void MainWindow::on_actionRename_Symbol_triggered()
return;
PCppParser parser = editor->parser();
- BufferCoord oldCaretXY = editor->caretXY();
//here we must reparse the file in sync, or rename may fail
parser->parseFile(editor->filename(), editor->inProject(), false, false);
CppRefacter refactor;
@@ -3994,3 +4024,53 @@ void MainWindow::on_actionRename_Symbol_triggered()
}
+
+void MainWindow::showSearchReplacePanel(bool show)
+{
+ ui->replacePanel->setVisible(show);
+ ui->cbSearchHistory->setDisabled(show);
+ if (show && mSearchResultModel.currentResults()) {
+ ui->cbReplaceInHistory->setCurrentText(
+ mSearchResultModel.currentResults()->keyword);
+ }
+ mSearchResultTreeModel->setSelectable(show);
+}
+
+
+void MainWindow::on_btnReplace_clicked()
+{
+ //select all items by default
+ PSearchResults results = mSearchResultModel.currentResults();
+ if (!results) {
+ return;
+ }
+ QString newWord = ui->cbReplaceInHistory->currentText();
+ foreach (const PSearchResultTreeItem& file, results->results) {
+ QStringList contents;
+ Editor* editor = mEditorList->getEditorByFilename(file->filename);
+ if (!editor) {
+ QMessageBox::critical(this,
+ tr("Replace Error"),
+ tr("Can't open file '%1' for replace!").arg(file->filename));
+ return;
+ }
+ contents = editor->lines()->contents();
+ for (int i=file->results.count()-1;i>=0;i--) {
+ const PSearchResultTreeItem& item = file->results[i];
+ QString line = contents[item->line-1];
+ if (line.mid(item->start-1,results->keyword.length())!=results->keyword) {
+ QMessageBox::critical(editor,
+ tr("Replace Error"),
+ tr("Contents has changed since last search!"));
+ return;
+ }
+ line.remove(item->start-1,results->keyword.length());
+ line.insert(item->start-1, newWord);
+ contents[item->line-1] = line;
+ }
+ editor->selectAll();
+ editor->setSelText(contents.join(editor->lineBreak()));
+ }
+ showSearchReplacePanel(false);
+ openCloseBottomPanel(false);
+}
diff --git a/RedPandaIDE/mainwindow.h b/RedPandaIDE/mainwindow.h
index 75e86d15..c1c58419 100644
--- a/RedPandaIDE/mainwindow.h
+++ b/RedPandaIDE/mainwindow.h
@@ -72,7 +72,7 @@ public:
void runExecutable(const QString& exeName, const QString& filename=QString());
void runExecutable();
void debug();
- void showSearchPanel();
+ void showSearchPanel(bool showReplace = false);
void applySettings();
void applyUISettings();
@@ -173,6 +173,8 @@ private:
QKeySequence shortcut=QKeySequence());
void scanActiveProject(bool parse=false);
void includeOrSkipDirs(const QStringList& dirs, bool skip);
+ void showSearchReplacePanel(bool show);
+
private slots:
void onAutoSaveTimeout();
void onFileChanged(const QString& path);
@@ -373,6 +375,8 @@ private slots:
void on_actionRename_Symbol_triggered();
+ void on_btnReplace_clicked();
+
private:
Ui::MainWindow *ui;
EditorList *mEditorList;
diff --git a/RedPandaIDE/mainwindow.ui b/RedPandaIDE/mainwindow.ui
index eff80faf..8124e831 100644
--- a/RedPandaIDE/mainwindow.ui
+++ b/RedPandaIDE/mainwindow.ui
@@ -283,7 +283,7 @@
QTabWidget::South
- 2
+ 3
diff --git a/RedPandaIDE/qsynedit/Search.cpp b/RedPandaIDE/qsynedit/Search.cpp
index fb09561a..974e4988 100644
--- a/RedPandaIDE/qsynedit/Search.cpp
+++ b/RedPandaIDE/qsynedit/Search.cpp
@@ -24,7 +24,7 @@ int SynSearch::resultCount()
return mResults.count();
}
-int SynSearch::findAll(const QString &keyword)
+int SynSearch::findAll(const QString &text)
{
mResults.clear();
if (pattern().isEmpty())
@@ -33,18 +33,18 @@ int SynSearch::findAll(const QString &keyword)
int next=-1;
while (true) {
if (options().testFlag(ssoMatchCase)) {
- next = keyword.indexOf(pattern(),start,Qt::CaseSensitive);
+ next = text.indexOf(pattern(),start,Qt::CaseSensitive);
} else {
- next = keyword.indexOf(pattern(),start,Qt::CaseInsensitive);
+ next = text.indexOf(pattern(),start,Qt::CaseInsensitive);
}
if (next<0) {
break;
}
- start = next + keyword.length();
+ start = next + pattern().length();
if (options().testFlag(ssoWholeWord)) {
- if (((next<=0) || isDelimitChar(keyword[next-1]))
+ if (((next<=0) || isDelimitChar(text[next-1]))
&&
- ( (start>=keyword.length()) || isDelimitChar(keyword[start]) )
+ ( (start>=text.length()) || isDelimitChar(text[start]) )
) {
mResults.append(next);
}
diff --git a/RedPandaIDE/qsynedit/Search.h b/RedPandaIDE/qsynedit/Search.h
index 3032c8ed..54e2b0f2 100644
--- a/RedPandaIDE/qsynedit/Search.h
+++ b/RedPandaIDE/qsynedit/Search.h
@@ -14,7 +14,7 @@ public:
int length(int aIndex) override;
int result(int aIndex) override;
int resultCount() override;
- int findAll(const QString &keyword) override;
+ int findAll(const QString &text) override;
QString replace(const QString &aOccurrence, const QString &aReplacement) override;
private:
bool isDelimitChar(QChar ch);
diff --git a/RedPandaIDE/qsynedit/SearchBase.h b/RedPandaIDE/qsynedit/SearchBase.h
index 9e3adacb..c832fd4f 100644
--- a/RedPandaIDE/qsynedit/SearchBase.h
+++ b/RedPandaIDE/qsynedit/SearchBase.h
@@ -26,7 +26,7 @@ public:
virtual int length(int aIndex) = 0;
virtual int result(int aIndex) = 0;
virtual int resultCount() = 0;
- virtual int findAll(const QString& keyword) = 0;
+ virtual int findAll(const QString& text) = 0;
virtual QString replace(const QString& aOccurrence, const QString& aReplacement) = 0;
SynSearchOptions options() const;
virtual void setOptions(const SynSearchOptions &options);
diff --git a/RedPandaIDE/qsynedit/SearchRegex.cpp b/RedPandaIDE/qsynedit/SearchRegex.cpp
index aed1da7e..8e764ce2 100644
--- a/RedPandaIDE/qsynedit/SearchRegex.cpp
+++ b/RedPandaIDE/qsynedit/SearchRegex.cpp
@@ -26,13 +26,13 @@ int SynSearchRegex::resultCount()
return mResults.size();
}
-int SynSearchRegex::findAll(const QString &keyword)
+int SynSearchRegex::findAll(const QString &text)
{
if (pattern().isEmpty())
return 0;
mResults.clear();
mLengths.clear();
- QRegularExpressionMatchIterator it = mRegex.globalMatch(keyword);
+ QRegularExpressionMatchIterator it = mRegex.globalMatch(text);
while (it.hasNext()) {
QRegularExpressionMatch match = it.next();
mLengths.append(match.capturedLength());
diff --git a/RedPandaIDE/qsynedit/SearchRegex.h b/RedPandaIDE/qsynedit/SearchRegex.h
index b85f43f9..1a49ca3b 100644
--- a/RedPandaIDE/qsynedit/SearchRegex.h
+++ b/RedPandaIDE/qsynedit/SearchRegex.h
@@ -15,7 +15,7 @@ public:
int length(int aIndex) override;
int result(int aIndex) override;
int resultCount() override;
- int findAll(const QString &keyword) override;
+ int findAll(const QString &text) override;
QString replace(const QString &aOccurrence, const QString &aReplacement) override;
void setPattern(const QString &value) override;
void setOptions(const SynSearchOptions &options) override;
diff --git a/RedPandaIDE/widgets/searchdialog.cpp b/RedPandaIDE/widgets/searchdialog.cpp
index 484c6f26..64a7f41e 100644
--- a/RedPandaIDE/widgets/searchdialog.cpp
+++ b/RedPandaIDE/widgets/searchdialog.cpp
@@ -21,6 +21,7 @@ SearchDialog::SearchDialog(QWidget *parent) :
mTabBar->addTab(tr("Find"));
mTabBar->addTab(tr("Find in files"));
mTabBar->addTab(tr("Replace"));
+ mTabBar->addTab(tr("Replace in files"));
mTabBar->setExpanding(false);
ui->dialogLayout->insertWidget(0,mTabBar);
connect(mTabBar,&QTabBar::currentChanged,this, &SearchDialog::onTabChanged);
@@ -101,7 +102,7 @@ void SearchDialog::replace(const QString &sFind, const QString &sReplace)
void SearchDialog::onTabChanged()
{
bool isfind = (mTabBar->currentIndex() == 0);
- bool isfindfiles = (mTabBar->currentIndex() == 1);
+ bool isfindfiles = (mTabBar->currentIndex() == 1 || mTabBar->currentIndex() == 3 );
bool isreplace = (mTabBar->currentIndex() == 2);
ui->lblReplace->setVisible(isreplace);
@@ -246,7 +247,7 @@ void SearchDialog::on_btnExecute_clicked()
});
}
- } else if (actionType == SearchAction::FindFiles) {
+ } else if (actionType == SearchAction::FindFiles || actionType == SearchAction::ReplaceFiles) {
int fileSearched = 0;
int fileHitted = 0;
QString keyword = ui->cbFind->currentText();
@@ -339,7 +340,7 @@ void SearchDialog::on_btnExecute_clicked()
// end;
}
if (findCount>0)
- pMainWindow->showSearchPanel();
+ pMainWindow->showSearchPanel(actionType == SearchAction::ReplaceFiles);
}
}
diff --git a/RedPandaIDE/widgets/searchresultview.cpp b/RedPandaIDE/widgets/searchresultview.cpp
index 09c00887..19b872a8 100644
--- a/RedPandaIDE/widgets/searchresultview.cpp
+++ b/RedPandaIDE/widgets/searchresultview.cpp
@@ -119,7 +119,8 @@ void SearchResultModel::removeSearchResults(int index)
SearchResultTreeModel::SearchResultTreeModel(SearchResultModel *model, QObject *parent):
QAbstractItemModel(parent),
- mSearchResultModel(model)
+ mSearchResultModel(model),
+ mSelectable(false)
{
connect(mSearchResultModel,&SearchResultModel::currentChanged,
this,&SearchResultTreeModel::onResultModelChanged);
@@ -213,6 +214,21 @@ QVariant SearchResultTreeModel::data(const QModelIndex &index, int role) const
.arg(item->text);
}
}
+ if (role == Qt::CheckStateRole && mSelectable) {
+
+ PSearchResults results = mSearchResultModel->currentResults();
+
+ if (!results || !index.isValid() ) {
+ // This is nothing this function is supposed to handle
+ return QVariant();
+ }
+
+ if (item->parent==nullptr) { //is filename
+ return QVariant();
+ } else {
+ return (item->selected)?Qt::Checked:Qt::Unchecked;
+ }
+ }
return QVariant();
}
@@ -256,6 +272,69 @@ void SearchResultTreeModel::onResultModelChanged()
endResetModel();
}
+Qt::ItemFlags SearchResultTreeModel::flags(const QModelIndex &index) const
+{
+ Qt::ItemFlags flags=Qt::ItemIsEnabled | Qt::ItemIsSelectable;
+ if (mSelectable) {
+ flags.setFlag(Qt::ItemIsUserCheckable);
+ }
+ return flags;
+}
+
+bool SearchResultTreeModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ if (!index.isValid()){
+ return false;
+ }
+ SearchResultTreeItem *item = static_cast(index.internalPointer());
+ if (!item)
+ return false;
+ if (role == Qt::CheckStateRole && mSelectable) {
+
+ PSearchResults results = mSearchResultModel->currentResults();
+
+ if (!results || !index.isValid() ) {
+ // This is nothing this function is supposed to handle
+ return false;
+ }
+
+ if (item->parent==nullptr) { //is filename
+ return false;
+ } else {
+ item->selected = value.toBool();
+ return true;
+ }
+ }
+ return false;
+
+}
+
+bool SearchResultTreeModel::selectable() const
+{
+ return mSelectable;
+}
+
+void SearchResultTreeModel::setSelectable(bool newSelectable)
+{
+ if (newSelectable!=mSelectable) {
+ beginResetModel();
+ mSelectable = newSelectable;
+ if (mSelectable) {
+ //select all items by default
+ PSearchResults results = mSearchResultModel->currentResults();
+ if (results) {
+ foreach (const PSearchResultTreeItem& file, results->results) {
+ file->selected = false;
+ foreach (const PSearchResultTreeItem& item, file->results) {
+ item->selected = true;
+ }
+ }
+ }
+ }
+ endResetModel();
+ }
+}
+
SearchResultListModel::SearchResultListModel(SearchResultModel *model, QObject *parent):
QAbstractListModel(parent),
mSearchResultModel(model)
diff --git a/RedPandaIDE/widgets/searchresultview.h b/RedPandaIDE/widgets/searchresultview.h
index 49bbab23..9c9781e1 100644
--- a/RedPandaIDE/widgets/searchresultview.h
+++ b/RedPandaIDE/widgets/searchresultview.h
@@ -26,6 +26,7 @@ struct SearchResultTreeItem {
QString text;
SearchResultTreeItem* parent;
SearchResultTreeItemList results;
+ bool selected;
};
struct SearchResults{
@@ -98,10 +99,22 @@ public:
QString& filename,
int& line,
int& startChar);
+ bool selectable() const;
+ void setSelectable(bool newSelectable);
+
public slots:
void onResultModelChanged();
private:
SearchResultModel *mSearchResultModel;
+ bool mSelectable;
+
+ // QAbstractItemModel interface
+public:
+ Qt::ItemFlags flags(const QModelIndex &index) const override;
+
+ // QAbstractItemModel interface
+public:
+ bool setData(const QModelIndex &index, const QVariant &value, int role) override;
};
using PSearchResultTreeModel = std::shared_ptr;