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->cbEvaluate->lineEdit(), &QLineEdit::returnPressed,
|
||||
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()
|
||||
|
@ -882,6 +889,11 @@ SearchDialog *MainWindow::searchDialog() const
|
|||
return mSearchDialog;
|
||||
}
|
||||
|
||||
SearchResultModel *MainWindow::searchResultModel()
|
||||
{
|
||||
return &mSearchResultModel;
|
||||
}
|
||||
|
||||
EditorList *MainWindow::editorList() const
|
||||
{
|
||||
return mEditorList;
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <QMainWindow>
|
||||
#include "common.h"
|
||||
#include "widgets/searchresultview.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui { class MainWindow; }
|
||||
|
@ -81,6 +82,8 @@ public:
|
|||
|
||||
SearchDialog *searchDialog() const;
|
||||
|
||||
SearchResultModel* searchResultModel();
|
||||
|
||||
protected:
|
||||
void openFiles(const QStringList& files);
|
||||
void openFile(const QString& filename);
|
||||
|
@ -213,6 +216,11 @@ private:
|
|||
SearchDialog *mSearchDialog;
|
||||
QList<QAction *> mRecentFileActions;
|
||||
|
||||
SearchResultModel mSearchResultModel;
|
||||
PSearchResultListModel mSearchResultListModel;
|
||||
PSearchResultTreeModel mSearchResultTreeModel;
|
||||
PSearchResultTreeViewDelegate mSearchViewDelegate;
|
||||
|
||||
bool mMessageControlChanged;
|
||||
bool mTabMessagesTogglingState;
|
||||
bool mCheckSyntaxInBack;
|
||||
|
|
|
@ -574,7 +574,7 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="comboBox">
|
||||
<widget class="QComboBox" name="cbSearchHistory">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
|
@ -641,7 +641,7 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="comboBox_2">
|
||||
<widget class="QComboBox" name="cbReplaceInHistory">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>150</width>
|
||||
|
@ -680,7 +680,11 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTreeView" name="searchView"/>
|
||||
<widget class="QTreeView" name="searchView">
|
||||
<attribute name="headerVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
@ -1304,7 +1308,7 @@
|
|||
<customwidget>
|
||||
<class>IssuesTable</class>
|
||||
<extends>QTableView</extends>
|
||||
<header>widgets/issuestable.h</header>
|
||||
<header location="global">widgets/issuestable.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>QConsole</class>
|
||||
|
|
|
@ -214,6 +214,10 @@ public:
|
|||
void setCaretXY(const BufferCoord& value);
|
||||
void setCaretXYEx(bool CallEnsureCursorPos, BufferCoord value);
|
||||
void setCaretXYCentered(bool ForceToMiddle, const BufferCoord& value);
|
||||
void setCaretAndSelection(const BufferCoord& ptCaret,
|
||||
const BufferCoord& ptBefore,
|
||||
const BufferCoord& ptAfter);
|
||||
|
||||
void uncollapseAroundLine(int line);
|
||||
PSynEditFoldRange foldHidesLine(int line);
|
||||
void setSelText(const QString& Value);
|
||||
|
@ -451,9 +455,7 @@ private:
|
|||
void DeleteFromTo(const BufferCoord& start, const BufferCoord& end);
|
||||
void SetSelWord();
|
||||
void SetWordBlock(BufferCoord Value);
|
||||
void setCaretAndSelection(const BufferCoord& ptCaret,
|
||||
const BufferCoord& ptBefore,
|
||||
const BufferCoord& ptAfter);
|
||||
|
||||
|
||||
void processGutterClick(QMouseEvent* event);
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "../qsynedit/Search.h"
|
||||
#include "../qsynedit/SearchRegex.h"
|
||||
#include <QMessageBox>
|
||||
#include <QDebug>
|
||||
|
||||
|
||||
SearchDialog::SearchDialog(QWidget *parent) :
|
||||
|
@ -122,7 +123,7 @@ void SearchDialog::on_btnCancel_clicked()
|
|||
|
||||
void SearchDialog::on_btnExecute_clicked()
|
||||
{
|
||||
int findcount = 0;
|
||||
int findCount = 0;
|
||||
|
||||
SearchAction actionType;
|
||||
switch (mTabBar->currentIndex()) {
|
||||
|
@ -187,13 +188,13 @@ void SearchDialog::on_btnExecute_clicked()
|
|||
if (actionType == SearchAction::Find) {
|
||||
Editor *e = pMainWindow->editorList()->getEditor();
|
||||
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();
|
||||
if (e!=nullptr) {
|
||||
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,
|
||||
const QString& sReplace, int Line, int ch, int wordLen){
|
||||
if (doPrompt) {
|
||||
|
@ -219,165 +220,67 @@ 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
pMainWindow->searchResultModel()->notifySearchResultsUpdated();
|
||||
} else if (ui->rbCurrentFile->isChecked()) {
|
||||
PSearchResults results = pMainWindow->searchResultModel()->addSearchResults(
|
||||
keyword,
|
||||
mSearchOptions,
|
||||
SearchFileScope::openedFiles
|
||||
);
|
||||
Editor * e= pMainWindow->editorList()->getEditor();
|
||||
if (e!=nullptr) {
|
||||
fileSearched++;
|
||||
PSearchResultTreeItem parentItem = batchFindInEditor(e,
|
||||
keyword);
|
||||
int t = parentItem->results.size();
|
||||
findCount+=t;
|
||||
if (t>0) {
|
||||
fileHitted++;
|
||||
results->results.append(parentItem);
|
||||
}
|
||||
}
|
||||
pMainWindow->searchResultModel()->notifySearchResultsUpdated();
|
||||
} else if (ui->rbProject->isChecked()) {
|
||||
// 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 begin
|
||||
// inc(fileSearched);
|
||||
// t:=Execute(e.Text, actiontype);
|
||||
// Inc(findcount, t);
|
||||
// if t>0 then
|
||||
// inc(filehitted);
|
||||
// end;
|
||||
}
|
||||
}
|
||||
|
||||
// // Replace first, find to next
|
||||
//end else if actiontype = faReplace then begin
|
||||
// e := MainForm.EditorList.GetEditor;
|
||||
|
||||
// if Assigned(e) then begin
|
||||
// Inc(findcount, Execute(e.Text, faReplace));
|
||||
// if findcount > 0 then begin
|
||||
// Exclude(fSearchOptions, ssoReplace);
|
||||
// Inc(findcount, Execute(e.Text, faFind));
|
||||
// end;
|
||||
// end;
|
||||
// // Or find everything
|
||||
//end else if actiontype = faFindFiles then begin
|
||||
// fileSearched:=0;
|
||||
// fileHitted:=0;
|
||||
// MainForm.FindOutput.BeginFind(cboFindText.Text);
|
||||
// try
|
||||
|
||||
// // 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
|
||||
// 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
|
||||
// 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 begin
|
||||
// inc(fileSearched);
|
||||
// t:=Execute(e.Text, actiontype);
|
||||
// Inc(findcount, t);
|
||||
// if t>0 then
|
||||
// inc(filehitted);
|
||||
// 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)
|
||||
|
@ -403,30 +306,44 @@ int SearchDialog::execute(Editor *editor, const QString &sSearch, const QString
|
|||
|
||||
return editor->searchReplace(sSearch, sReplace, mSearchOptions,
|
||||
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
|
||||
// if action = faFindFiles then
|
||||
// editor.OnReplaceText := FindAllAction;
|
||||
PSearchResultTreeItem parentItem = std::make_shared<SearchResultTreeItem>();
|
||||
parentItem->filename = e->filename();
|
||||
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
|
||||
// if (ssoRegExp in fSearchOptions) then
|
||||
// editor.SearchEngine := fRegExpSearchEngine
|
||||
// else
|
||||
// editor.SearchEngine := fSearchEngine;
|
||||
// result := editor.SearchReplace(cboFindText.Text, cboReplaceText.Text, fSearchOptions);
|
||||
|
||||
// // Don't touch editors which we are only scanning
|
||||
// if action in [faFindFiles] then begin
|
||||
// // Put backup back into place
|
||||
// editor.CaretXY := caretbackup;
|
||||
// editor.BlockBegin := blockbeginbackup;
|
||||
// editor.BlockEnd := blockendbackup;
|
||||
// editor.TopLine := toplinebackup;
|
||||
// end;
|
||||
|
||||
// editor.OnReplaceText := onreplacebackup;
|
||||
// editor.SearchEngine := enginebackup;
|
||||
// restore
|
||||
e->setCaretXY(caretBackup);
|
||||
e->setTopLine(toplineBackup);
|
||||
e->setLeftChar(leftCharBackup);
|
||||
e->setCaretAndSelection(
|
||||
caretBackup,
|
||||
blockBeginBackup,
|
||||
blockEndBackup
|
||||
);
|
||||
return parentItem;
|
||||
}
|
||||
|
||||
QTabBar *SearchDialog::tabBar() const
|
||||
|
|
|
@ -8,6 +8,7 @@ namespace Ui {
|
|||
class SearchDialog;
|
||||
}
|
||||
|
||||
struct SearchResultTreeItem;
|
||||
class QTabBar;
|
||||
class Editor;
|
||||
class SearchDialog : public QDialog
|
||||
|
@ -43,6 +44,7 @@ private slots:
|
|||
private:
|
||||
int execute(Editor* editor, const QString& sSearch,
|
||||
const QString& sReplace, SynSearchMathedProc matchCallback = nullptr);
|
||||
std::shared_ptr<SearchResultTreeItem> batchFindInEditor(Editor* editor,const QString& keyword);
|
||||
private:
|
||||
Ui::SearchDialog *ui;
|
||||
QTabBar *mTabBar;
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
#include "searchresultview.h"
|
||||
#include <QApplication>
|
||||
#include <QPainter>
|
||||
#include <QStyledItemDelegate>
|
||||
#include "mainwindow.h"
|
||||
|
||||
PSearchResults SearchResultModel::addSearchResults(const QString &keyword, SynSearchOptions options, SearchFileScope scope)
|
||||
{
|
||||
|
@ -10,7 +14,7 @@ PSearchResults SearchResultModel::addSearchResults(const QString &keyword, SynSe
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (index>0) {
|
||||
if (index>=0) {
|
||||
mSearchResults.removeAt(index);
|
||||
}
|
||||
if (mSearchResults.size()>=MAX_SEARCH_RESULTS) {
|
||||
|
@ -21,7 +25,7 @@ PSearchResults SearchResultModel::addSearchResults(const QString &keyword, SynSe
|
|||
results->options = options;
|
||||
results->scope = scope;
|
||||
mSearchResults.push_front(results);
|
||||
emit modelChanged();
|
||||
mCurrentIndex = 0;
|
||||
return results;
|
||||
}
|
||||
|
||||
|
@ -33,6 +37,11 @@ PSearchResults SearchResultModel::results(int index)
|
|||
return mSearchResults[index];
|
||||
}
|
||||
|
||||
void SearchResultModel::notifySearchResultsUpdated()
|
||||
{
|
||||
emit modelChanged();
|
||||
}
|
||||
|
||||
SearchResultModel::SearchResultModel(QObject* parent):
|
||||
QObject(parent),
|
||||
mCurrentIndex(-1)
|
||||
|
@ -75,7 +84,111 @@ SearchResultTreeModel::SearchResultTreeModel(SearchResultModel *model, QObject *
|
|||
QAbstractItemModel(parent),
|
||||
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):
|
||||
|
@ -118,3 +231,53 @@ void SearchResultListModel::onResultModelChanged()
|
|||
beginResetModel();
|
||||
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 <QMap>
|
||||
#include <QStyledItemDelegate>
|
||||
#include "../qsynedit/SearchBase.h"
|
||||
#include "utils.h"
|
||||
|
||||
#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;
|
||||
int line;
|
||||
int start;
|
||||
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{
|
||||
SynSearchOptions options;
|
||||
QString keyword;
|
||||
SearchFileScope scope;
|
||||
QMap<QString, PSearchResultList> results;
|
||||
QList<PSearchResultTreeItem> results;
|
||||
};
|
||||
|
||||
using PSearchResults = std::shared_ptr<SearchResults>;
|
||||
|
||||
class SearchResultModel : QObject {
|
||||
class SearchResultModel : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SearchResultModel(QObject* parent=nullptr);
|
||||
PSearchResults addSearchResults(const QString& keyword,SynSearchOptions options,
|
||||
SearchFileScope scope);
|
||||
PSearchResults results(int index);
|
||||
void notifySearchResultsUpdated();
|
||||
int currentIndex() const;
|
||||
int resultsCount() const;
|
||||
PSearchResults currentResults();
|
||||
|
@ -62,6 +69,8 @@ private:
|
|||
SearchResultModel *mSearchResultModel;
|
||||
};
|
||||
|
||||
using PSearchResultListModel = std::shared_ptr<SearchResultListModel>;
|
||||
|
||||
class SearchResultTreeModel : public QAbstractItemModel {
|
||||
Q_OBJECT
|
||||
// QAbstractItemModel interface
|
||||
|
@ -72,15 +81,26 @@ public:
|
|||
int rowCount(const QModelIndex &parent) const override;
|
||||
int columnCount(const QModelIndex &parent) const override;
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
SearchResultModel *searchResultModel() const;
|
||||
public slots:
|
||||
void onResultModelChanged();
|
||||
private:
|
||||
SearchResultModel *mSearchResultModel;
|
||||
};
|
||||
|
||||
class SearchResultView : public QTreeView
|
||||
{
|
||||
Q_OBJECT
|
||||
using PSearchResultTreeModel = std::shared_ptr<SearchResultTreeModel>;
|
||||
|
||||
class SearchResultTreeViewDelegate: public QStyledItemDelegate{
|
||||
Q_OBJECT
|
||||
// QAbstractItemDelegate interface
|
||||
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
|
||||
|
|
Loading…
Reference in New Issue