work save
This commit is contained in:
parent
579b36ff49
commit
ecc4934fd3
|
@ -107,6 +107,13 @@ MainWindow::MainWindow(QWidget *parent)
|
||||||
connect(ui->debugConsole,&QConsole::commandInput,this,&MainWindow::onDebugCommandInput);
|
connect(ui->debugConsole,&QConsole::commandInput,this,&MainWindow::onDebugCommandInput);
|
||||||
connect(ui->cbEvaluate->lineEdit(), &QLineEdit::returnPressed,
|
connect(ui->cbEvaluate->lineEdit(), &QLineEdit::returnPressed,
|
||||||
this, &MainWindow::onDebugEvaluateInput);
|
this, &MainWindow::onDebugEvaluateInput);
|
||||||
|
|
||||||
|
mSearchResultTreeModel = std::make_shared<SearchResultTreeModel>(&mSearchResultModel);
|
||||||
|
mSearchResultListModel = std::make_shared<SearchResultListModel>(&mSearchResultModel);
|
||||||
|
mSearchViewDelegate = std::make_shared<SearchResultTreeViewDelegate>(mSearchResultTreeModel);
|
||||||
|
ui->cbSearchHistory->view()->setModel(mSearchResultListModel.get());
|
||||||
|
ui->searchView->setModel(mSearchResultTreeModel.get());
|
||||||
|
ui->searchView->setItemDelegate(mSearchViewDelegate.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
MainWindow::~MainWindow()
|
MainWindow::~MainWindow()
|
||||||
|
@ -882,6 +889,11 @@ SearchDialog *MainWindow::searchDialog() const
|
||||||
return mSearchDialog;
|
return mSearchDialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SearchResultModel *MainWindow::searchResultModel()
|
||||||
|
{
|
||||||
|
return &mSearchResultModel;
|
||||||
|
}
|
||||||
|
|
||||||
EditorList *MainWindow::editorList() const
|
EditorList *MainWindow::editorList() const
|
||||||
{
|
{
|
||||||
return mEditorList;
|
return mEditorList;
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "widgets/searchresultview.h"
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
namespace Ui { class MainWindow; }
|
namespace Ui { class MainWindow; }
|
||||||
|
@ -81,6 +82,8 @@ public:
|
||||||
|
|
||||||
SearchDialog *searchDialog() const;
|
SearchDialog *searchDialog() const;
|
||||||
|
|
||||||
|
SearchResultModel* searchResultModel();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void openFiles(const QStringList& files);
|
void openFiles(const QStringList& files);
|
||||||
void openFile(const QString& filename);
|
void openFile(const QString& filename);
|
||||||
|
@ -213,6 +216,11 @@ private:
|
||||||
SearchDialog *mSearchDialog;
|
SearchDialog *mSearchDialog;
|
||||||
QList<QAction *> mRecentFileActions;
|
QList<QAction *> mRecentFileActions;
|
||||||
|
|
||||||
|
SearchResultModel mSearchResultModel;
|
||||||
|
PSearchResultListModel mSearchResultListModel;
|
||||||
|
PSearchResultTreeModel mSearchResultTreeModel;
|
||||||
|
PSearchResultTreeViewDelegate mSearchViewDelegate;
|
||||||
|
|
||||||
bool mMessageControlChanged;
|
bool mMessageControlChanged;
|
||||||
bool mTabMessagesTogglingState;
|
bool mTabMessagesTogglingState;
|
||||||
bool mCheckSyntaxInBack;
|
bool mCheckSyntaxInBack;
|
||||||
|
|
|
@ -574,7 +574,7 @@
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QComboBox" name="comboBox">
|
<widget class="QComboBox" name="cbSearchHistory">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
|
@ -641,7 +641,7 @@
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QComboBox" name="comboBox_2">
|
<widget class="QComboBox" name="cbReplaceInHistory">
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>150</width>
|
<width>150</width>
|
||||||
|
@ -680,7 +680,11 @@
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QTreeView" name="searchView"/>
|
<widget class="QTreeView" name="searchView">
|
||||||
|
<attribute name="headerVisible">
|
||||||
|
<bool>false</bool>
|
||||||
|
</attribute>
|
||||||
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
@ -1304,7 +1308,7 @@
|
||||||
<customwidget>
|
<customwidget>
|
||||||
<class>IssuesTable</class>
|
<class>IssuesTable</class>
|
||||||
<extends>QTableView</extends>
|
<extends>QTableView</extends>
|
||||||
<header>widgets/issuestable.h</header>
|
<header location="global">widgets/issuestable.h</header>
|
||||||
</customwidget>
|
</customwidget>
|
||||||
<customwidget>
|
<customwidget>
|
||||||
<class>QConsole</class>
|
<class>QConsole</class>
|
||||||
|
|
|
@ -214,6 +214,10 @@ public:
|
||||||
void setCaretXY(const BufferCoord& value);
|
void setCaretXY(const BufferCoord& value);
|
||||||
void setCaretXYEx(bool CallEnsureCursorPos, BufferCoord value);
|
void setCaretXYEx(bool CallEnsureCursorPos, BufferCoord value);
|
||||||
void setCaretXYCentered(bool ForceToMiddle, const BufferCoord& value);
|
void setCaretXYCentered(bool ForceToMiddle, const BufferCoord& value);
|
||||||
|
void setCaretAndSelection(const BufferCoord& ptCaret,
|
||||||
|
const BufferCoord& ptBefore,
|
||||||
|
const BufferCoord& ptAfter);
|
||||||
|
|
||||||
void uncollapseAroundLine(int line);
|
void uncollapseAroundLine(int line);
|
||||||
PSynEditFoldRange foldHidesLine(int line);
|
PSynEditFoldRange foldHidesLine(int line);
|
||||||
void setSelText(const QString& Value);
|
void setSelText(const QString& Value);
|
||||||
|
@ -451,9 +455,7 @@ private:
|
||||||
void DeleteFromTo(const BufferCoord& start, const BufferCoord& end);
|
void DeleteFromTo(const BufferCoord& start, const BufferCoord& end);
|
||||||
void SetSelWord();
|
void SetSelWord();
|
||||||
void SetWordBlock(BufferCoord Value);
|
void SetWordBlock(BufferCoord Value);
|
||||||
void setCaretAndSelection(const BufferCoord& ptCaret,
|
|
||||||
const BufferCoord& ptBefore,
|
|
||||||
const BufferCoord& ptAfter);
|
|
||||||
|
|
||||||
void processGutterClick(QMouseEvent* event);
|
void processGutterClick(QMouseEvent* event);
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "../qsynedit/Search.h"
|
#include "../qsynedit/Search.h"
|
||||||
#include "../qsynedit/SearchRegex.h"
|
#include "../qsynedit/SearchRegex.h"
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
|
||||||
SearchDialog::SearchDialog(QWidget *parent) :
|
SearchDialog::SearchDialog(QWidget *parent) :
|
||||||
|
@ -122,7 +123,7 @@ void SearchDialog::on_btnCancel_clicked()
|
||||||
|
|
||||||
void SearchDialog::on_btnExecute_clicked()
|
void SearchDialog::on_btnExecute_clicked()
|
||||||
{
|
{
|
||||||
int findcount = 0;
|
int findCount = 0;
|
||||||
|
|
||||||
SearchAction actionType;
|
SearchAction actionType;
|
||||||
switch (mTabBar->currentIndex()) {
|
switch (mTabBar->currentIndex()) {
|
||||||
|
@ -187,13 +188,13 @@ void SearchDialog::on_btnExecute_clicked()
|
||||||
if (actionType == SearchAction::Find) {
|
if (actionType == SearchAction::Find) {
|
||||||
Editor *e = pMainWindow->editorList()->getEditor();
|
Editor *e = pMainWindow->editorList()->getEditor();
|
||||||
if (e!=nullptr) {
|
if (e!=nullptr) {
|
||||||
findcount+=execute(e,ui->cbFind->currentText(),"");
|
findCount+=execute(e,ui->cbFind->currentText(),"");
|
||||||
}
|
}
|
||||||
} else {
|
} else if (actionType == SearchAction::Replace) {
|
||||||
Editor *e = pMainWindow->editorList()->getEditor();
|
Editor *e = pMainWindow->editorList()->getEditor();
|
||||||
if (e!=nullptr) {
|
if (e!=nullptr) {
|
||||||
bool doPrompt = ui->chkPrompt->isChecked();
|
bool doPrompt = ui->chkPrompt->isChecked();
|
||||||
findcount+=execute(e,ui->cbFind->currentText(),ui->cbReplace->currentText(),
|
findCount+=execute(e,ui->cbFind->currentText(),ui->cbReplace->currentText(),
|
||||||
[&doPrompt](const QString& sSearch,
|
[&doPrompt](const QString& sSearch,
|
||||||
const QString& sReplace, int Line, int ch, int wordLen){
|
const QString& sReplace, int Line, int ch, int wordLen){
|
||||||
if (doPrompt) {
|
if (doPrompt) {
|
||||||
|
@ -219,43 +220,52 @@ void SearchDialog::on_btnExecute_clicked()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else if (actionType == SearchAction::FindFiles) {
|
||||||
|
int fileSearched = 0;
|
||||||
|
int fileHitted = 0;
|
||||||
|
QString keyword = ui->cbFind->currentText();
|
||||||
|
if (ui->rbOpenFiles->isChecked()) {
|
||||||
|
PSearchResults results = pMainWindow->searchResultModel()->addSearchResults(
|
||||||
|
keyword,
|
||||||
|
mSearchOptions,
|
||||||
|
SearchFileScope::openedFiles
|
||||||
|
);
|
||||||
|
// loop through editors, add results to message control
|
||||||
|
for (int i=0;i<pMainWindow->editorList()->pageCount();i++) {
|
||||||
|
Editor * e=pMainWindow->editorList()->operator[](i);
|
||||||
|
if (e!=nullptr) {
|
||||||
|
fileSearched++;
|
||||||
|
PSearchResultTreeItem parentItem = batchFindInEditor(e,
|
||||||
|
keyword);
|
||||||
|
int t = parentItem->results.size();
|
||||||
|
findCount+=t;
|
||||||
|
if (t>0) {
|
||||||
|
fileHitted++;
|
||||||
|
results->results.append(parentItem);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// // Replace first, find to next
|
}
|
||||||
//end else if actiontype = faReplace then begin
|
pMainWindow->searchResultModel()->notifySearchResultsUpdated();
|
||||||
// e := MainForm.EditorList.GetEditor;
|
} else if (ui->rbCurrentFile->isChecked()) {
|
||||||
|
PSearchResults results = pMainWindow->searchResultModel()->addSearchResults(
|
||||||
// if Assigned(e) then begin
|
keyword,
|
||||||
// Inc(findcount, Execute(e.Text, faReplace));
|
mSearchOptions,
|
||||||
// if findcount > 0 then begin
|
SearchFileScope::openedFiles
|
||||||
// Exclude(fSearchOptions, ssoReplace);
|
);
|
||||||
// Inc(findcount, Execute(e.Text, faFind));
|
Editor * e= pMainWindow->editorList()->getEditor();
|
||||||
// end;
|
if (e!=nullptr) {
|
||||||
// end;
|
fileSearched++;
|
||||||
// // Or find everything
|
PSearchResultTreeItem parentItem = batchFindInEditor(e,
|
||||||
//end else if actiontype = faFindFiles then begin
|
keyword);
|
||||||
// fileSearched:=0;
|
int t = parentItem->results.size();
|
||||||
// fileHitted:=0;
|
findCount+=t;
|
||||||
// MainForm.FindOutput.BeginFind(cboFindText.Text);
|
if (t>0) {
|
||||||
// try
|
fileHitted++;
|
||||||
|
results->results.append(parentItem);
|
||||||
// // loop through pagecontrol
|
}
|
||||||
// if rbOpenFiles.Checked then begin
|
}
|
||||||
|
pMainWindow->searchResultModel()->notifySearchResultsUpdated();
|
||||||
// // loop through editors, add results to message control
|
} else if (ui->rbProject->isChecked()) {
|
||||||
// for I := 0 to MainForm.EditorList.PageCount - 1 do begin
|
|
||||||
// e := MainForm.EditorList[i];
|
|
||||||
// if Assigned(e) then begin
|
|
||||||
// inc(fileSearched);
|
|
||||||
// fCurFile := e.FileName;
|
|
||||||
// t:=Execute(e.Text, actiontype);
|
|
||||||
// Inc(findcount, t);
|
|
||||||
// if t>0 then
|
|
||||||
// inc(filehitted);
|
|
||||||
// end;
|
|
||||||
// end;
|
|
||||||
|
|
||||||
// // loop through project
|
|
||||||
// end else if rbProjectFiles.Checked then begin
|
// end else if rbProjectFiles.Checked then begin
|
||||||
// for I := 0 to MainForm.Project.Units.Count - 1 do begin
|
// for I := 0 to MainForm.Project.Units.Count - 1 do begin
|
||||||
// e := MainForm.Project.Units[i].Editor;
|
// e := MainForm.Project.Units[i].Editor;
|
||||||
|
@ -269,115 +279,8 @@ void SearchDialog::on_btnExecute_clicked()
|
||||||
// if t>0 then
|
// if t>0 then
|
||||||
// inc(filehitted);
|
// inc(filehitted);
|
||||||
// end;
|
// end;
|
||||||
|
}
|
||||||
// // not open? load from disk
|
}
|
||||||
// end else if FileExists(fCurFile) then begin
|
|
||||||
// // Only finding...
|
|
||||||
// fTempSynEdit.Lines.LoadFromFile(fCurFile);
|
|
||||||
// inc(fileSearched);
|
|
||||||
// t:=Execute(fTempSynEdit, actiontype);
|
|
||||||
// Inc(findcount, t);
|
|
||||||
// if t>0 then
|
|
||||||
// inc(filehitted);
|
|
||||||
// end;
|
|
||||||
// end;
|
|
||||||
|
|
||||||
// // Don't loop, only pass single file
|
|
||||||
// end else if rbCurFile.Checked then begin
|
|
||||||
// e := MainForm.EditorList.GetEditor;
|
|
||||||
|
|
||||||
// if Assigned(e) then begin
|
|
||||||
|
|
||||||
// fCurFile := e.FileName;
|
|
||||||
|
|
||||||
// inc(fileSearched);
|
|
||||||
// t:=Execute(e.Text, actiontype);
|
|
||||||
// Inc(findcount, t);
|
|
||||||
// if t>0 then
|
|
||||||
// inc(filehitted);
|
|
||||||
// end;
|
|
||||||
// end;
|
|
||||||
// finally
|
|
||||||
// MainForm.FindOutput.EndFind(cboFindText.Text,findCount,
|
|
||||||
// filehitted,filesearched);
|
|
||||||
// end;
|
|
||||||
//end else if actiontype = faReplaceFiles then begin
|
|
||||||
// // loop through pagecontrol
|
|
||||||
// if rbOpenFiles.Checked then begin
|
|
||||||
|
|
||||||
// // loop through editors, add results to message control
|
|
||||||
// for I := 0 to MainForm.EditorList.PageCount - 1 do begin
|
|
||||||
// e := MainForm.EditorList[i];
|
|
||||||
// if Assigned(e) then begin
|
|
||||||
// fCurFile := e.FileName;
|
|
||||||
// if (ssoPrompt in fSearchOptions) then
|
|
||||||
// e.Activate;
|
|
||||||
// Inc(findcount, Execute(e.Text, actiontype));
|
|
||||||
// end;
|
|
||||||
// end;
|
|
||||||
|
|
||||||
// // loop through project
|
|
||||||
// end else if rbProjectFiles.Checked then begin
|
|
||||||
// for I := 0 to MainForm.Project.Units.Count - 1 do begin
|
|
||||||
// e := MainForm.Project.Units[i].Editor;
|
|
||||||
// fCurFile := MainForm.Project.Units[i].FileName;
|
|
||||||
|
|
||||||
// // file is already open, use memory
|
|
||||||
// if Assigned(e) then begin
|
|
||||||
// if (ssoPrompt in fSearchOptions) then
|
|
||||||
// e.Activate;
|
|
||||||
// Inc(findcount, Execute(e.Text, actiontype));
|
|
||||||
|
|
||||||
// // not open? load from disk
|
|
||||||
// end else if FileExists(fCurFile) then begin
|
|
||||||
// // we have to open an editor...
|
|
||||||
// if ssoPrompt in fSearchOptions then begin
|
|
||||||
// e := MainForm.EditorList.GetEditorFromFileName(fCurFile);
|
|
||||||
// if Assigned(e) then begin
|
|
||||||
// e.Activate;
|
|
||||||
|
|
||||||
// Inc(findcount, Execute(e.Text, actiontype));
|
|
||||||
|
|
||||||
// // Save and close
|
|
||||||
// e.Save;
|
|
||||||
// MainForm.Project.CloseUnit(MainForm.Project.Units.Indexof(e));
|
|
||||||
// end;
|
|
||||||
// end else begin
|
|
||||||
// // Stealth replace
|
|
||||||
// fTempSynEdit.Lines.LoadFromFile(fCurFile);
|
|
||||||
// Inc(findcount, Execute(fTempSynEdit, actiontype));
|
|
||||||
// fTempSynEdit.Lines.SaveToFile(fCurFile);
|
|
||||||
// end;
|
|
||||||
// end;
|
|
||||||
// end;
|
|
||||||
// // Don't loop, only pass single file
|
|
||||||
// end else if rbCurFile.Checked then begin
|
|
||||||
// e := MainForm.EditorList.GetEditor;
|
|
||||||
|
|
||||||
// if Assigned(e) then begin
|
|
||||||
// fCurFile := e.FileName;
|
|
||||||
// Inc(findcount, Execute(e.Text, actiontype));
|
|
||||||
// end;
|
|
||||||
// end;
|
|
||||||
//end;
|
|
||||||
|
|
||||||
//if actiontype = faFindFiles then begin
|
|
||||||
// MainForm.MessageControl.ActivePageIndex := 4; // Find Tab
|
|
||||||
// if findcount > 0 then
|
|
||||||
// MainForm.FindSheet.Caption := Lang[ID_SHEET_FIND];
|
|
||||||
// MainForm.OpenCloseMessageSheet(TRUE);
|
|
||||||
// self.Close;
|
|
||||||
//end else if findcount = 0 then begin
|
|
||||||
// MessageBox(
|
|
||||||
// Self.Handle,
|
|
||||||
// PAnsiChar(Format(Lang[ID_MSG_TEXTNOTFOUND], [cboFindText.Text])),
|
|
||||||
// PAnsiChar(Lang[ID_INFO]),
|
|
||||||
// MB_ICONINFORMATION or MB_TOPMOST);
|
|
||||||
// cboFindText.SetFocus;
|
|
||||||
//end;
|
|
||||||
//if actiontype = faFind then begin
|
|
||||||
// self.Close;
|
|
||||||
//end;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int SearchDialog::execute(Editor *editor, const QString &sSearch, const QString &sReplace, SynSearchMathedProc matchCallback)
|
int SearchDialog::execute(Editor *editor, const QString &sSearch, const QString &sReplace, SynSearchMathedProc matchCallback)
|
||||||
|
@ -403,30 +306,44 @@ int SearchDialog::execute(Editor *editor, const QString &sSearch, const QString
|
||||||
|
|
||||||
return editor->searchReplace(sSearch, sReplace, mSearchOptions,
|
return editor->searchReplace(sSearch, sReplace, mSearchOptions,
|
||||||
mSearchEngine, matchCallback);
|
mSearchEngine, matchCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<SearchResultTreeItem> SearchDialog::batchFindInEditor(Editor *e, const QString &keyword)
|
||||||
|
{
|
||||||
|
//backup
|
||||||
|
BufferCoord caretBackup = e->caretXY();
|
||||||
|
BufferCoord blockBeginBackup = e->blockBegin();
|
||||||
|
BufferCoord blockEndBackup = e->blockEnd();
|
||||||
|
int toplineBackup = e->topLine();
|
||||||
|
int leftCharBackup = e->leftChar();
|
||||||
|
|
||||||
// // When using find in files, report each find using OnReplaceText
|
PSearchResultTreeItem parentItem = std::make_shared<SearchResultTreeItem>();
|
||||||
// if action = faFindFiles then
|
parentItem->filename = e->filename();
|
||||||
// editor.OnReplaceText := FindAllAction;
|
parentItem->parent = nullptr;
|
||||||
|
execute(e,keyword,"",
|
||||||
|
[e,&parentItem](const QString&,
|
||||||
|
const QString&, int Line, int ch, int wordLen){
|
||||||
|
PSearchResultTreeItem item = std::make_shared<SearchResultTreeItem>();
|
||||||
|
item->filename = e->filename();
|
||||||
|
item->line = Line;
|
||||||
|
item->start = ch;
|
||||||
|
item->len = wordLen;
|
||||||
|
item->parent = parentItem.get();
|
||||||
|
item->text = e->lines()->getString(Line-1);
|
||||||
|
parentItem->results.append(item);
|
||||||
|
return SynSearchAction::Skip;
|
||||||
|
});
|
||||||
|
|
||||||
// // Swap search engire for ours
|
// restore
|
||||||
// if (ssoRegExp in fSearchOptions) then
|
e->setCaretXY(caretBackup);
|
||||||
// editor.SearchEngine := fRegExpSearchEngine
|
e->setTopLine(toplineBackup);
|
||||||
// else
|
e->setLeftChar(leftCharBackup);
|
||||||
// editor.SearchEngine := fSearchEngine;
|
e->setCaretAndSelection(
|
||||||
// result := editor.SearchReplace(cboFindText.Text, cboReplaceText.Text, fSearchOptions);
|
caretBackup,
|
||||||
|
blockBeginBackup,
|
||||||
// // Don't touch editors which we are only scanning
|
blockEndBackup
|
||||||
// if action in [faFindFiles] then begin
|
);
|
||||||
// // Put backup back into place
|
return parentItem;
|
||||||
// editor.CaretXY := caretbackup;
|
|
||||||
// editor.BlockBegin := blockbeginbackup;
|
|
||||||
// editor.BlockEnd := blockendbackup;
|
|
||||||
// editor.TopLine := toplinebackup;
|
|
||||||
// end;
|
|
||||||
|
|
||||||
// editor.OnReplaceText := onreplacebackup;
|
|
||||||
// editor.SearchEngine := enginebackup;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QTabBar *SearchDialog::tabBar() const
|
QTabBar *SearchDialog::tabBar() const
|
||||||
|
|
|
@ -8,6 +8,7 @@ namespace Ui {
|
||||||
class SearchDialog;
|
class SearchDialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct SearchResultTreeItem;
|
||||||
class QTabBar;
|
class QTabBar;
|
||||||
class Editor;
|
class Editor;
|
||||||
class SearchDialog : public QDialog
|
class SearchDialog : public QDialog
|
||||||
|
@ -43,6 +44,7 @@ private slots:
|
||||||
private:
|
private:
|
||||||
int execute(Editor* editor, const QString& sSearch,
|
int execute(Editor* editor, const QString& sSearch,
|
||||||
const QString& sReplace, SynSearchMathedProc matchCallback = nullptr);
|
const QString& sReplace, SynSearchMathedProc matchCallback = nullptr);
|
||||||
|
std::shared_ptr<SearchResultTreeItem> batchFindInEditor(Editor* editor,const QString& keyword);
|
||||||
private:
|
private:
|
||||||
Ui::SearchDialog *ui;
|
Ui::SearchDialog *ui;
|
||||||
QTabBar *mTabBar;
|
QTabBar *mTabBar;
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
#include "searchresultview.h"
|
#include "searchresultview.h"
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QStyledItemDelegate>
|
||||||
|
#include "mainwindow.h"
|
||||||
|
|
||||||
PSearchResults SearchResultModel::addSearchResults(const QString &keyword, SynSearchOptions options, SearchFileScope scope)
|
PSearchResults SearchResultModel::addSearchResults(const QString &keyword, SynSearchOptions options, SearchFileScope scope)
|
||||||
{
|
{
|
||||||
|
@ -10,7 +14,7 @@ PSearchResults SearchResultModel::addSearchResults(const QString &keyword, SynSe
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (index>0) {
|
if (index>=0) {
|
||||||
mSearchResults.removeAt(index);
|
mSearchResults.removeAt(index);
|
||||||
}
|
}
|
||||||
if (mSearchResults.size()>=MAX_SEARCH_RESULTS) {
|
if (mSearchResults.size()>=MAX_SEARCH_RESULTS) {
|
||||||
|
@ -21,7 +25,7 @@ PSearchResults SearchResultModel::addSearchResults(const QString &keyword, SynSe
|
||||||
results->options = options;
|
results->options = options;
|
||||||
results->scope = scope;
|
results->scope = scope;
|
||||||
mSearchResults.push_front(results);
|
mSearchResults.push_front(results);
|
||||||
emit modelChanged();
|
mCurrentIndex = 0;
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,6 +37,11 @@ PSearchResults SearchResultModel::results(int index)
|
||||||
return mSearchResults[index];
|
return mSearchResults[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SearchResultModel::notifySearchResultsUpdated()
|
||||||
|
{
|
||||||
|
emit modelChanged();
|
||||||
|
}
|
||||||
|
|
||||||
SearchResultModel::SearchResultModel(QObject* parent):
|
SearchResultModel::SearchResultModel(QObject* parent):
|
||||||
QObject(parent),
|
QObject(parent),
|
||||||
mCurrentIndex(-1)
|
mCurrentIndex(-1)
|
||||||
|
@ -75,7 +84,111 @@ SearchResultTreeModel::SearchResultTreeModel(SearchResultModel *model, QObject *
|
||||||
QAbstractItemModel(parent),
|
QAbstractItemModel(parent),
|
||||||
mSearchResultModel(model)
|
mSearchResultModel(model)
|
||||||
{
|
{
|
||||||
|
connect(mSearchResultModel,&SearchResultModel::currentChanged,
|
||||||
|
this,&SearchResultTreeModel::onResultModelChanged);
|
||||||
|
connect(mSearchResultModel,&SearchResultModel::modelChanged,
|
||||||
|
this,&SearchResultTreeModel::onResultModelChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex SearchResultTreeModel::index(int row, int column, const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
if (!hasIndex(row,column,parent))
|
||||||
|
return QModelIndex();
|
||||||
|
|
||||||
|
PSearchResults results = mSearchResultModel->currentResults();
|
||||||
|
if (!results)
|
||||||
|
return QModelIndex();
|
||||||
|
SearchResultTreeItem *parentItem=nullptr;
|
||||||
|
PSearchResultTreeItem childItem;
|
||||||
|
if (!parent.isValid()) {
|
||||||
|
parentItem = nullptr;
|
||||||
|
childItem = results->results[row];
|
||||||
|
} else {
|
||||||
|
parentItem = static_cast<SearchResultTreeItem *>(parent.internalPointer());
|
||||||
|
childItem = parentItem->results[row];
|
||||||
|
}
|
||||||
|
if (childItem)
|
||||||
|
return createIndex(row,column,childItem.get());
|
||||||
|
return QModelIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex SearchResultTreeModel::parent(const QModelIndex &child) const
|
||||||
|
{
|
||||||
|
if (!child.isValid())
|
||||||
|
return QModelIndex();
|
||||||
|
SearchResultTreeItem* item = static_cast<SearchResultTreeItem *>(child.internalPointer());
|
||||||
|
if (!item) {
|
||||||
|
return QModelIndex();
|
||||||
|
} else {
|
||||||
|
if (item->parent==nullptr)
|
||||||
|
return QModelIndex();
|
||||||
|
SearchResultTreeItem* parent = item->parent;
|
||||||
|
int row = -1;
|
||||||
|
for (int i=0;i<parent->results.count();i++) {
|
||||||
|
if (parent->results[i].get()==item) {
|
||||||
|
row = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return createIndex(row,0,parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int SearchResultTreeModel::rowCount(const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
if (!parent.isValid()){ //root
|
||||||
|
PSearchResults searchResults = mSearchResultModel->currentResults();
|
||||||
|
if (!searchResults)
|
||||||
|
return 0;
|
||||||
|
return searchResults->results.count();
|
||||||
|
}
|
||||||
|
SearchResultTreeItem* item = static_cast<SearchResultTreeItem *>(parent.internalPointer()); if (!item)
|
||||||
|
return 0;
|
||||||
|
return item->results.count();
|
||||||
|
}
|
||||||
|
|
||||||
|
int SearchResultTreeModel::columnCount(const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant SearchResultTreeModel::data(const QModelIndex &index, int role) const
|
||||||
|
{
|
||||||
|
if (!index.isValid()){
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
SearchResultTreeItem *item = static_cast<SearchResultTreeItem *>(index.internalPointer());
|
||||||
|
if (!item)
|
||||||
|
return QVariant();
|
||||||
|
if (role == Qt::DisplayRole) {
|
||||||
|
|
||||||
|
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 item->filename;
|
||||||
|
} else {
|
||||||
|
return QString("%1 %2: %3").arg(tr("Line")).arg(item->line)
|
||||||
|
.arg(item->text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchResultModel *SearchResultTreeModel::searchResultModel() const
|
||||||
|
{
|
||||||
|
return mSearchResultModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SearchResultTreeModel::onResultModelChanged()
|
||||||
|
{
|
||||||
|
beginResetModel();
|
||||||
|
endResetModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
SearchResultListModel::SearchResultListModel(SearchResultModel *model, QObject *parent):
|
SearchResultListModel::SearchResultListModel(SearchResultModel *model, QObject *parent):
|
||||||
|
@ -118,3 +231,53 @@ void SearchResultListModel::onResultModelChanged()
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
endResetModel();
|
endResetModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* see https://stackoverflow.com/questions/1956542/how-to-make-item-view-render-rich-html-text-in-qt/66412883#66412883
|
||||||
|
*/
|
||||||
|
SearchResultTreeViewDelegate::SearchResultTreeViewDelegate(PSearchResultTreeModel model, QObject *parent):
|
||||||
|
QStyledItemDelegate(parent),
|
||||||
|
mModel(model)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SearchResultTreeViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &optIn, const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
QStyleOptionViewItem option = optIn;
|
||||||
|
initStyleOption(&option,index);
|
||||||
|
PSearchResults results = mModel->searchResultModel()->currentResults();
|
||||||
|
|
||||||
|
if (!results || !index.isValid() ) {
|
||||||
|
// This is nothing this function is supposed to handle
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStyle *style = option.widget ? option.widget->style() : QApplication::style();
|
||||||
|
|
||||||
|
// Painting item without text (this takes care of painting e.g. the highlighted for selected
|
||||||
|
// or hovered over items in an ItemView)
|
||||||
|
option.text = QString();
|
||||||
|
style->drawControl(QStyle::CE_ItemViewItem, &option, painter, option.widget);
|
||||||
|
SearchResultTreeItem* item = static_cast<SearchResultTreeItem *>(index.internalPointer());
|
||||||
|
|
||||||
|
QString fullText;
|
||||||
|
if (item->parent==nullptr) { //is filename
|
||||||
|
fullText = item->filename;
|
||||||
|
} else {
|
||||||
|
fullText = QString("%1 %2: %3").arg(tr("Line")).arg(item->line)
|
||||||
|
.arg(item->text);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Figure out where to render the text in order to follow the requested alignment
|
||||||
|
option.text = fullText;
|
||||||
|
QRect textRect = style->subElementRect(QStyle::SE_ItemViewItemText, &option);
|
||||||
|
|
||||||
|
QFontMetrics metrics = option.fontMetrics;
|
||||||
|
int x=textRect.left();
|
||||||
|
int y=textRect.top() + metrics.ascent();
|
||||||
|
//painter->setClipRect(textRect);
|
||||||
|
painter->drawText(x,y,fullText);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -3,38 +3,45 @@
|
||||||
|
|
||||||
#include <QTreeView>
|
#include <QTreeView>
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
|
#include <QStyledItemDelegate>
|
||||||
#include "../qsynedit/SearchBase.h"
|
#include "../qsynedit/SearchBase.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
#define MAX_SEARCH_RESULTS 20
|
#define MAX_SEARCH_RESULTS 20
|
||||||
|
struct SearchResultTreeItem;
|
||||||
|
using PSearchResultTreeItem = std::shared_ptr<SearchResultTreeItem>;
|
||||||
|
using SearchResultTreeItemList = QList<PSearchResultTreeItem>;
|
||||||
|
using PSearchResultTreeItemList = std::shared_ptr<SearchResultTreeItemList>;
|
||||||
|
|
||||||
struct SearchResult {
|
struct SearchResultTreeItem {
|
||||||
QString filename;
|
QString filename;
|
||||||
int line;
|
int line;
|
||||||
int start;
|
int start;
|
||||||
int len;
|
int len;
|
||||||
|
QString text;
|
||||||
|
SearchResultTreeItem* parent;
|
||||||
|
SearchResultTreeItemList results;
|
||||||
};
|
};
|
||||||
|
|
||||||
using PSearchResult = std::shared_ptr<SearchResult>;
|
|
||||||
using SearchResultList = QList<PSearchResult>;
|
|
||||||
using PSearchResultList = std::shared_ptr<SearchResultList>;
|
|
||||||
|
|
||||||
struct SearchResults{
|
struct SearchResults{
|
||||||
SynSearchOptions options;
|
SynSearchOptions options;
|
||||||
QString keyword;
|
QString keyword;
|
||||||
SearchFileScope scope;
|
SearchFileScope scope;
|
||||||
QMap<QString, PSearchResultList> results;
|
QList<PSearchResultTreeItem> results;
|
||||||
};
|
};
|
||||||
|
|
||||||
using PSearchResults = std::shared_ptr<SearchResults>;
|
using PSearchResults = std::shared_ptr<SearchResults>;
|
||||||
|
|
||||||
class SearchResultModel : QObject {
|
class SearchResultModel : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit SearchResultModel(QObject* parent=nullptr);
|
explicit SearchResultModel(QObject* parent=nullptr);
|
||||||
PSearchResults addSearchResults(const QString& keyword,SynSearchOptions options,
|
PSearchResults addSearchResults(const QString& keyword,SynSearchOptions options,
|
||||||
SearchFileScope scope);
|
SearchFileScope scope);
|
||||||
PSearchResults results(int index);
|
PSearchResults results(int index);
|
||||||
|
void notifySearchResultsUpdated();
|
||||||
int currentIndex() const;
|
int currentIndex() const;
|
||||||
int resultsCount() const;
|
int resultsCount() const;
|
||||||
PSearchResults currentResults();
|
PSearchResults currentResults();
|
||||||
|
@ -62,6 +69,8 @@ private:
|
||||||
SearchResultModel *mSearchResultModel;
|
SearchResultModel *mSearchResultModel;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using PSearchResultListModel = std::shared_ptr<SearchResultListModel>;
|
||||||
|
|
||||||
class SearchResultTreeModel : public QAbstractItemModel {
|
class SearchResultTreeModel : public QAbstractItemModel {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
// QAbstractItemModel interface
|
// QAbstractItemModel interface
|
||||||
|
@ -72,15 +81,26 @@ public:
|
||||||
int rowCount(const QModelIndex &parent) const override;
|
int rowCount(const QModelIndex &parent) const override;
|
||||||
int columnCount(const QModelIndex &parent) const override;
|
int columnCount(const QModelIndex &parent) const override;
|
||||||
QVariant data(const QModelIndex &index, int role) const override;
|
QVariant data(const QModelIndex &index, int role) const override;
|
||||||
|
SearchResultModel *searchResultModel() const;
|
||||||
|
public slots:
|
||||||
|
void onResultModelChanged();
|
||||||
private:
|
private:
|
||||||
SearchResultModel *mSearchResultModel;
|
SearchResultModel *mSearchResultModel;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SearchResultView : public QTreeView
|
using PSearchResultTreeModel = std::shared_ptr<SearchResultTreeModel>;
|
||||||
{
|
|
||||||
|
class SearchResultTreeViewDelegate: public QStyledItemDelegate{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
// QAbstractItemDelegate interface
|
||||||
public:
|
public:
|
||||||
explicit SearchResultView(QWidget* parent=nullptr);
|
explicit SearchResultTreeViewDelegate(PSearchResultTreeModel model,
|
||||||
|
QObject* parent=nullptr);
|
||||||
|
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
|
||||||
|
private:
|
||||||
|
PSearchResultTreeModel mModel;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using PSearchResultTreeViewDelegate = std::shared_ptr<SearchResultTreeViewDelegate>;
|
||||||
|
|
||||||
#endif // SEARCHRESULTVIEW_H
|
#endif // SEARCHRESULTVIEW_H
|
||||||
|
|
Loading…
Reference in New Issue