find and replace dialog
This commit is contained in:
@@ -37,11 +37,13 @@ target_sources(pineapple-notepad
|
|||||||
PRIVATE
|
PRIVATE
|
||||||
main.cpp
|
main.cpp
|
||||||
mainwindow.cpp mainwindow.h
|
mainwindow.cpp mainwindow.h
|
||||||
|
findreplacedialog.cpp findreplacedialog.h
|
||||||
sciedit.cpp sciedit.h
|
sciedit.cpp sciedit.h
|
||||||
tabwidget.cpp tabwidget.h
|
tabwidget.cpp tabwidget.h
|
||||||
documentmanager.cpp documentmanager.h
|
documentmanager.cpp documentmanager.h
|
||||||
editorviewhelper.cpp editorviewhelper.h
|
editorviewhelper.cpp editorviewhelper.h
|
||||||
generalsettings.ui
|
generalsettings.ui
|
||||||
|
findreplacedialog.ui
|
||||||
|
|
||||||
appsettings.kcfg
|
appsettings.kcfg
|
||||||
)
|
)
|
||||||
|
|||||||
325
findreplacedialog.cpp
Normal file
325
findreplacedialog.cpp
Normal file
@@ -0,0 +1,325 @@
|
|||||||
|
#include "findreplacedialog.h"
|
||||||
|
|
||||||
|
#include "ui_findreplacedialog.h"
|
||||||
|
|
||||||
|
#include <QCheckBox>
|
||||||
|
#include <QCloseEvent>
|
||||||
|
#include <QComboBox>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QTabWidget>
|
||||||
|
|
||||||
|
static QString decodeExtended(const QString &s)
|
||||||
|
{
|
||||||
|
QString out;
|
||||||
|
out.reserve(s.size());
|
||||||
|
|
||||||
|
for (int i = 0; i < s.size(); ++i) {
|
||||||
|
const QChar c = s.at(i);
|
||||||
|
if (c != QLatin1Char('\\') || i + 1 >= s.size()) {
|
||||||
|
out.append(c);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QChar n = s.at(i + 1);
|
||||||
|
if (n == QLatin1Char('n')) {
|
||||||
|
out.append(QLatin1Char('\n'));
|
||||||
|
++i;
|
||||||
|
} else if (n == QLatin1Char('r')) {
|
||||||
|
out.append(QLatin1Char('\r'));
|
||||||
|
++i;
|
||||||
|
} else if (n == QLatin1Char('t')) {
|
||||||
|
out.append(QLatin1Char('\t'));
|
||||||
|
++i;
|
||||||
|
} else if (n == QLatin1Char('\\')) {
|
||||||
|
out.append(QLatin1Char('\\'));
|
||||||
|
++i;
|
||||||
|
} else if (n == QLatin1Char('0')) {
|
||||||
|
out.append(QChar(0));
|
||||||
|
++i;
|
||||||
|
} else if (n == QLatin1Char('x') && i + 3 < s.size()) {
|
||||||
|
bool ok = false;
|
||||||
|
const QString hex = s.mid(i + 2, 2);
|
||||||
|
const int code = hex.toInt(&ok, 16);
|
||||||
|
if (ok) {
|
||||||
|
out.append(QChar(code));
|
||||||
|
i += 3;
|
||||||
|
} else {
|
||||||
|
out.append(c);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out.append(n);
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
FindReplaceDialog::FindReplaceDialog(QWidget *parent)
|
||||||
|
: QDialog(parent)
|
||||||
|
, ui(new Ui::FindReplaceDialog)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
setModal(false);
|
||||||
|
setWindowFlags(windowFlags() | Qt::Tool);
|
||||||
|
|
||||||
|
initCombos();
|
||||||
|
initModeCombos();
|
||||||
|
initSync();
|
||||||
|
|
||||||
|
connect(ui->tabWidget, &QTabWidget::currentChanged, this, [this](int index) {
|
||||||
|
Q_UNUSED(index)
|
||||||
|
if (ui->tabWidget->currentWidget() == ui->findTab) {
|
||||||
|
syncFromReplaceTab();
|
||||||
|
} else {
|
||||||
|
syncFromFindTab();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(ui->findNextBtnFind, &QPushButton::clicked, this, [this]() {
|
||||||
|
commitHistory();
|
||||||
|
emit findRequested(true);
|
||||||
|
});
|
||||||
|
connect(ui->findPrevBtnFind, &QPushButton::clicked, this, [this]() {
|
||||||
|
commitHistory();
|
||||||
|
emit findRequested(false);
|
||||||
|
});
|
||||||
|
connect(ui->closeBtnFind, &QPushButton::clicked, this, &QDialog::hide);
|
||||||
|
|
||||||
|
connect(ui->findNextBtnReplace, &QPushButton::clicked, this, [this]() {
|
||||||
|
commitHistory();
|
||||||
|
emit findRequested(true);
|
||||||
|
});
|
||||||
|
connect(ui->replaceBtn, &QPushButton::clicked, this, [this]() {
|
||||||
|
commitHistory();
|
||||||
|
emit replaceRequested();
|
||||||
|
});
|
||||||
|
connect(ui->replaceAllBtn, &QPushButton::clicked, this, [this]() {
|
||||||
|
commitHistory();
|
||||||
|
emit replaceAllRequested();
|
||||||
|
});
|
||||||
|
connect(ui->closeBtnReplace, &QPushButton::clicked, this, &QDialog::hide);
|
||||||
|
|
||||||
|
resize(520, sizeHint().height());
|
||||||
|
}
|
||||||
|
|
||||||
|
FindReplaceDialog::~FindReplaceDialog()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FindReplaceDialog::initCombos()
|
||||||
|
{
|
||||||
|
ui->findWhatComboFind->setInsertPolicy(QComboBox::NoInsert);
|
||||||
|
ui->findWhatComboReplace->setInsertPolicy(QComboBox::NoInsert);
|
||||||
|
ui->replaceWithComboReplace->setInsertPolicy(QComboBox::NoInsert);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FindReplaceDialog::initModeCombos()
|
||||||
|
{
|
||||||
|
ui->modeComboFind->addItem(QStringLiteral("Normal"), QVariant::fromValue(static_cast<int>(SearchMode::Normal)));
|
||||||
|
ui->modeComboFind->addItem(QStringLiteral("Extended (\\n, \\r, \\t, \\0, \\xNN)"), QVariant::fromValue(static_cast<int>(SearchMode::Extended)));
|
||||||
|
ui->modeComboFind->addItem(QStringLiteral("Regular expression"), QVariant::fromValue(static_cast<int>(SearchMode::Regex)));
|
||||||
|
|
||||||
|
ui->modeComboReplace->addItem(QStringLiteral("Normal"), QVariant::fromValue(static_cast<int>(SearchMode::Normal)));
|
||||||
|
ui->modeComboReplace->addItem(QStringLiteral("Extended (\\n, \\r, \\t, \\0, \\xNN)"), QVariant::fromValue(static_cast<int>(SearchMode::Extended)));
|
||||||
|
ui->modeComboReplace->addItem(QStringLiteral("Regular expression"), QVariant::fromValue(static_cast<int>(SearchMode::Regex)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void FindReplaceDialog::initSync()
|
||||||
|
{
|
||||||
|
if (ui->findWhatComboFind->lineEdit()) {
|
||||||
|
connect(ui->findWhatComboFind->lineEdit(), &QLineEdit::textEdited, this, [this]() { syncFromFindTab(); });
|
||||||
|
}
|
||||||
|
connect(ui->matchCaseCheckFind, &QCheckBox::toggled, this, [this]() { syncFromFindTab(); });
|
||||||
|
connect(ui->wholeWordCheckFind, &QCheckBox::toggled, this, [this]() { syncFromFindTab(); });
|
||||||
|
connect(ui->wrapAroundCheckFind, &QCheckBox::toggled, this, [this]() { syncFromFindTab(); });
|
||||||
|
connect(ui->inSelectionCheckFind, &QCheckBox::toggled, this, [this]() { syncFromFindTab(); });
|
||||||
|
connect(ui->modeComboFind, &QComboBox::currentIndexChanged, this, [this](int) { syncFromFindTab(); });
|
||||||
|
|
||||||
|
if (ui->findWhatComboReplace->lineEdit()) {
|
||||||
|
connect(ui->findWhatComboReplace->lineEdit(), &QLineEdit::textEdited, this, [this]() { syncFromReplaceTab(); });
|
||||||
|
}
|
||||||
|
if (ui->replaceWithComboReplace->lineEdit()) {
|
||||||
|
connect(ui->replaceWithComboReplace->lineEdit(), &QLineEdit::textEdited, this, [this]() { syncFromReplaceTab(); });
|
||||||
|
}
|
||||||
|
connect(ui->matchCaseCheckReplace, &QCheckBox::toggled, this, [this]() { syncFromReplaceTab(); });
|
||||||
|
connect(ui->wholeWordCheckReplace, &QCheckBox::toggled, this, [this]() { syncFromReplaceTab(); });
|
||||||
|
connect(ui->wrapAroundCheckReplace, &QCheckBox::toggled, this, [this]() { syncFromReplaceTab(); });
|
||||||
|
connect(ui->inSelectionCheckReplace, &QCheckBox::toggled, this, [this]() { syncFromReplaceTab(); });
|
||||||
|
connect(ui->modeComboReplace, &QComboBox::currentIndexChanged, this, [this](int) { syncFromReplaceTab(); });
|
||||||
|
|
||||||
|
syncFromFindTab();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FindReplaceDialog::syncFromFindTab()
|
||||||
|
{
|
||||||
|
if (m_syncing) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_syncing = true;
|
||||||
|
ui->findWhatComboReplace->setCurrentText(ui->findWhatComboFind->currentText());
|
||||||
|
ui->matchCaseCheckReplace->setChecked(ui->matchCaseCheckFind->isChecked());
|
||||||
|
ui->wholeWordCheckReplace->setChecked(ui->wholeWordCheckFind->isChecked());
|
||||||
|
ui->wrapAroundCheckReplace->setChecked(ui->wrapAroundCheckFind->isChecked());
|
||||||
|
ui->inSelectionCheckReplace->setChecked(ui->inSelectionCheckFind->isChecked());
|
||||||
|
ui->modeComboReplace->setCurrentIndex(ui->modeComboFind->currentIndex());
|
||||||
|
m_syncing = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FindReplaceDialog::syncFromReplaceTab()
|
||||||
|
{
|
||||||
|
if (m_syncing) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_syncing = true;
|
||||||
|
ui->findWhatComboFind->setCurrentText(ui->findWhatComboReplace->currentText());
|
||||||
|
ui->matchCaseCheckFind->setChecked(ui->matchCaseCheckReplace->isChecked());
|
||||||
|
ui->wholeWordCheckFind->setChecked(ui->wholeWordCheckReplace->isChecked());
|
||||||
|
ui->wrapAroundCheckFind->setChecked(ui->wrapAroundCheckReplace->isChecked());
|
||||||
|
ui->inSelectionCheckFind->setChecked(ui->inSelectionCheckReplace->isChecked());
|
||||||
|
ui->modeComboFind->setCurrentIndex(ui->modeComboReplace->currentIndex());
|
||||||
|
m_syncing = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FindReplaceDialog::openFind()
|
||||||
|
{
|
||||||
|
ui->tabWidget->setCurrentWidget(ui->findTab);
|
||||||
|
show();
|
||||||
|
raise();
|
||||||
|
activateWindow();
|
||||||
|
ui->findWhatComboFind->setFocus();
|
||||||
|
if (ui->findWhatComboFind->lineEdit()) {
|
||||||
|
ui->findWhatComboFind->lineEdit()->selectAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FindReplaceDialog::openReplace()
|
||||||
|
{
|
||||||
|
ui->tabWidget->setCurrentWidget(ui->replaceTab);
|
||||||
|
show();
|
||||||
|
raise();
|
||||||
|
activateWindow();
|
||||||
|
ui->findWhatComboReplace->setFocus();
|
||||||
|
if (ui->findWhatComboReplace->lineEdit()) {
|
||||||
|
ui->findWhatComboReplace->lineEdit()->selectAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString FindReplaceDialog::findText() const
|
||||||
|
{
|
||||||
|
if (ui->tabWidget->currentWidget() == ui->replaceTab) {
|
||||||
|
return ui->findWhatComboReplace->currentText();
|
||||||
|
}
|
||||||
|
return ui->findWhatComboFind->currentText();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString FindReplaceDialog::replaceText() const
|
||||||
|
{
|
||||||
|
return ui->replaceWithComboReplace->currentText();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString FindReplaceDialog::findTextForSearch() const
|
||||||
|
{
|
||||||
|
const QString raw = findText();
|
||||||
|
if (searchMode() == SearchMode::Extended) {
|
||||||
|
return decodeExtended(raw);
|
||||||
|
}
|
||||||
|
return raw;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString FindReplaceDialog::replaceTextForReplace() const
|
||||||
|
{
|
||||||
|
const QString raw = replaceText();
|
||||||
|
if (searchMode() == SearchMode::Extended) {
|
||||||
|
return decodeExtended(raw);
|
||||||
|
}
|
||||||
|
return raw;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FindReplaceDialog::matchCase() const
|
||||||
|
{
|
||||||
|
if (ui->tabWidget->currentWidget() == ui->replaceTab) {
|
||||||
|
return ui->matchCaseCheckReplace->isChecked();
|
||||||
|
}
|
||||||
|
return ui->matchCaseCheckFind->isChecked();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FindReplaceDialog::wholeWord() const
|
||||||
|
{
|
||||||
|
if (ui->tabWidget->currentWidget() == ui->replaceTab) {
|
||||||
|
return ui->wholeWordCheckReplace->isChecked();
|
||||||
|
}
|
||||||
|
return ui->wholeWordCheckFind->isChecked();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FindReplaceDialog::wrapAround() const
|
||||||
|
{
|
||||||
|
if (ui->tabWidget->currentWidget() == ui->replaceTab) {
|
||||||
|
return ui->wrapAroundCheckReplace->isChecked();
|
||||||
|
}
|
||||||
|
return ui->wrapAroundCheckFind->isChecked();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FindReplaceDialog::inSelection() const
|
||||||
|
{
|
||||||
|
if (ui->tabWidget->currentWidget() == ui->replaceTab) {
|
||||||
|
return ui->inSelectionCheckReplace->isChecked();
|
||||||
|
}
|
||||||
|
return ui->inSelectionCheckFind->isChecked();
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchMode FindReplaceDialog::searchMode() const
|
||||||
|
{
|
||||||
|
const int v = (ui->tabWidget->currentWidget() == ui->replaceTab) ? ui->modeComboReplace->currentData().toInt()
|
||||||
|
: ui->modeComboFind->currentData().toInt();
|
||||||
|
return static_cast<SearchMode>(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FindReplaceDialog::setFindTextIfNotEmpty(const QString &text)
|
||||||
|
{
|
||||||
|
if (text.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ui->findWhatComboFind->setCurrentText(text);
|
||||||
|
ui->findWhatComboReplace->setCurrentText(text);
|
||||||
|
if (ui->tabWidget->currentWidget() == ui->replaceTab) {
|
||||||
|
if (ui->findWhatComboReplace->lineEdit()) {
|
||||||
|
ui->findWhatComboReplace->lineEdit()->selectAll();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (ui->findWhatComboFind->lineEdit()) {
|
||||||
|
ui->findWhatComboFind->lineEdit()->selectAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FindReplaceDialog::commitHistory()
|
||||||
|
{
|
||||||
|
const auto commit = [](QComboBox *combo) {
|
||||||
|
const QString v = combo->currentText();
|
||||||
|
if (v.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const int idx = combo->findText(v);
|
||||||
|
if (idx >= 0) {
|
||||||
|
combo->removeItem(idx);
|
||||||
|
}
|
||||||
|
combo->insertItem(0, v);
|
||||||
|
combo->setCurrentIndex(0);
|
||||||
|
while (combo->count() > 20) {
|
||||||
|
combo->removeItem(combo->count() - 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
commit(ui->findWhatComboFind);
|
||||||
|
commit(ui->findWhatComboReplace);
|
||||||
|
commit(ui->replaceWithComboReplace);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FindReplaceDialog::closeEvent(QCloseEvent *event)
|
||||||
|
{
|
||||||
|
hide();
|
||||||
|
event->ignore();
|
||||||
|
}
|
||||||
57
findreplacedialog.h
Normal file
57
findreplacedialog.h
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class FindReplaceDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class SearchMode {
|
||||||
|
Normal,
|
||||||
|
Extended,
|
||||||
|
Regex,
|
||||||
|
};
|
||||||
|
|
||||||
|
class FindReplaceDialog final : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit FindReplaceDialog(QWidget *parent = nullptr);
|
||||||
|
~FindReplaceDialog() override;
|
||||||
|
|
||||||
|
void openFind();
|
||||||
|
void openReplace();
|
||||||
|
|
||||||
|
QString findText() const;
|
||||||
|
QString replaceText() const;
|
||||||
|
QString findTextForSearch() const;
|
||||||
|
QString replaceTextForReplace() const;
|
||||||
|
|
||||||
|
bool matchCase() const;
|
||||||
|
bool wholeWord() const;
|
||||||
|
bool wrapAround() const;
|
||||||
|
bool inSelection() const;
|
||||||
|
SearchMode searchMode() const;
|
||||||
|
|
||||||
|
void setFindTextIfNotEmpty(const QString &text);
|
||||||
|
void commitHistory();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void findRequested(bool forward);
|
||||||
|
void replaceRequested();
|
||||||
|
void replaceAllRequested();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void closeEvent(QCloseEvent *event) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void initCombos();
|
||||||
|
void initModeCombos();
|
||||||
|
void initSync();
|
||||||
|
void syncFromFindTab();
|
||||||
|
void syncFromReplaceTab();
|
||||||
|
|
||||||
|
Ui::FindReplaceDialog *ui = nullptr;
|
||||||
|
bool m_syncing = false;
|
||||||
|
};
|
||||||
317
findreplacedialog.ui
Normal file
317
findreplacedialog.ui
Normal file
@@ -0,0 +1,317 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>FindReplaceDialog</class>
|
||||||
|
<widget class="QDialog" name="FindReplaceDialog">
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Find / Replace</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QTabWidget" name="tabWidget">
|
||||||
|
<property name="currentIndex">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="findTab">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Find</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QHBoxLayout" name="findTabLayout">
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="findLeftLayout">
|
||||||
|
<item>
|
||||||
|
<layout class="QFormLayout" name="findFormLayout">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="findWhatLabelFind">
|
||||||
|
<property name="text">
|
||||||
|
<string>Find what:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QComboBox" name="findWhatComboFind">
|
||||||
|
<property name="editable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="optionsGroupFind">
|
||||||
|
<property name="title">
|
||||||
|
<string>Search options</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="optionsLayoutFind">
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="matchCaseCheckFind">
|
||||||
|
<property name="text">
|
||||||
|
<string>Match case</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="wholeWordCheckFind">
|
||||||
|
<property name="text">
|
||||||
|
<string>Match whole word only</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="wrapAroundCheckFind">
|
||||||
|
<property name="text">
|
||||||
|
<string>Wrap around</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="inSelectionCheckFind">
|
||||||
|
<property name="text">
|
||||||
|
<string>In selection</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="modeLabelFind">
|
||||||
|
<property name="text">
|
||||||
|
<string>Search mode:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="modeComboFind"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacerFind">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QWidget" name="findButtonsWidget">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="findButtonsLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="findNextBtnFind">
|
||||||
|
<property name="text">
|
||||||
|
<string>Find Next</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="findPrevBtnFind">
|
||||||
|
<property name="text">
|
||||||
|
<string>Find Previous</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacerFindButtons">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="closeBtnFind">
|
||||||
|
<property name="text">
|
||||||
|
<string>Close</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="replaceTab">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Replace</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QHBoxLayout" name="replaceTabLayout">
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="replaceLeftLayout">
|
||||||
|
<item>
|
||||||
|
<layout class="QFormLayout" name="replaceFormLayout">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="findWhatLabelReplace">
|
||||||
|
<property name="text">
|
||||||
|
<string>Find what:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QComboBox" name="findWhatComboReplace">
|
||||||
|
<property name="editable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="replaceWithLabelReplace">
|
||||||
|
<property name="text">
|
||||||
|
<string>Replace with:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QComboBox" name="replaceWithComboReplace">
|
||||||
|
<property name="editable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="optionsGroupReplace">
|
||||||
|
<property name="title">
|
||||||
|
<string>Search options</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="optionsLayoutReplace">
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="matchCaseCheckReplace">
|
||||||
|
<property name="text">
|
||||||
|
<string>Match case</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="wholeWordCheckReplace">
|
||||||
|
<property name="text">
|
||||||
|
<string>Match whole word only</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="wrapAroundCheckReplace">
|
||||||
|
<property name="text">
|
||||||
|
<string>Wrap around</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="inSelectionCheckReplace">
|
||||||
|
<property name="text">
|
||||||
|
<string>In selection</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="modeLabelReplace">
|
||||||
|
<property name="text">
|
||||||
|
<string>Search mode:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="modeComboReplace"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacerReplace">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QWidget" name="replaceButtonsWidget">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="replaceButtonsLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="findNextBtnReplace">
|
||||||
|
<property name="text">
|
||||||
|
<string>Find Next</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="replaceBtn">
|
||||||
|
<property name="text">
|
||||||
|
<string>Replace</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="replaceAllBtn">
|
||||||
|
<property name="text">
|
||||||
|
<string>Replace All</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacerReplaceButtons">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="closeBtnReplace">
|
||||||
|
<property name="text">
|
||||||
|
<string>Close</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
353
mainwindow.cpp
353
mainwindow.cpp
@@ -5,12 +5,25 @@
|
|||||||
#include "documentmanager.h"
|
#include "documentmanager.h"
|
||||||
#include "appsettings.h"
|
#include "appsettings.h"
|
||||||
#include "editorviewhelper.h"
|
#include "editorviewhelper.h"
|
||||||
|
#include "findreplacedialog.h"
|
||||||
|
|
||||||
#include <QActionGroup>
|
#include <QActionGroup>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
#include <QCheckBox>
|
||||||
|
#include <QCloseEvent>
|
||||||
|
#include <QComboBox>
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QFormLayout>
|
||||||
|
#include <QGroupBox>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QLineEdit>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
|
#include <QPushButton>
|
||||||
#include <QStringBuilder>
|
#include <QStringBuilder>
|
||||||
#include <QStatusBar>
|
#include <QStatusBar>
|
||||||
|
#include <QTabWidget>
|
||||||
|
#include <QVBoxLayout>
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
|
||||||
@@ -98,11 +111,18 @@ void MainWindow::setupActions()
|
|||||||
}, actionCollection());
|
}, actionCollection());
|
||||||
|
|
||||||
// "Search" menu
|
// "Search" menu
|
||||||
KStandardAction::find(this, [](){}, actionCollection());
|
KStandardAction::find(this, [this](){
|
||||||
KStandardAction::findNext(this, [](){}, actionCollection());
|
showFindReplaceDialog(false);
|
||||||
KStandardAction::findPrev(this, [](){}, actionCollection());
|
}, actionCollection());
|
||||||
KStandardAction::replace(this, [](){}, actionCollection());
|
KStandardAction::findNext(this, [this](){
|
||||||
qDebug() << KStandardAction::name(KStandardAction::Replace);
|
findNextInCurrentEditor(true, true);
|
||||||
|
}, actionCollection());
|
||||||
|
KStandardAction::findPrev(this, [this](){
|
||||||
|
findNextInCurrentEditor(false, true);
|
||||||
|
}, actionCollection());
|
||||||
|
KStandardAction::replace(this, [this](){
|
||||||
|
showFindReplaceDialog(true);
|
||||||
|
}, actionCollection());
|
||||||
|
|
||||||
// "Language" menu
|
// "Language" menu
|
||||||
QAction *lexerNoneAction = new QAction(this);
|
QAction *lexerNoneAction = new QAction(this);
|
||||||
@@ -378,3 +398,326 @@ void MainWindow::updateActions()
|
|||||||
indentGuideAction->setChecked(m_indentGuidesEnabled);
|
indentGuideAction->setChecked(m_indentGuidesEnabled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::showFindReplaceDialog(bool showReplace)
|
||||||
|
{
|
||||||
|
if (!m_findReplaceDialog) {
|
||||||
|
m_findReplaceDialog = new FindReplaceDialog(this);
|
||||||
|
connect(m_findReplaceDialog, &FindReplaceDialog::findRequested, this, [this](bool forward) {
|
||||||
|
findNextInCurrentEditor(forward, true);
|
||||||
|
});
|
||||||
|
connect(m_findReplaceDialog, &FindReplaceDialog::replaceRequested, this, [this]() {
|
||||||
|
replaceOneInCurrentEditor(true);
|
||||||
|
});
|
||||||
|
connect(m_findReplaceDialog, &FindReplaceDialog::replaceAllRequested, this, [this]() {
|
||||||
|
replaceAllInCurrentEditor(true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SciEdit *editor = m_tabWidget->currentEditor()) {
|
||||||
|
const int selStart = static_cast<int>(editor->selectionStart());
|
||||||
|
const int selEnd = static_cast<int>(editor->selectionEnd());
|
||||||
|
if (selStart != selEnd) {
|
||||||
|
const int start = qMin(selStart, selEnd);
|
||||||
|
const int end = qMax(selStart, selEnd);
|
||||||
|
const QByteArray selected = editor->textRange(start, end);
|
||||||
|
m_findReplaceDialog->setFindTextIfNotEmpty(QString::fromUtf8(selected));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (showReplace) {
|
||||||
|
m_findReplaceDialog->openReplace();
|
||||||
|
} else {
|
||||||
|
m_findReplaceDialog->openFind();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static sptr_t buildSearchFlags(const FindReplaceDialog *dialog)
|
||||||
|
{
|
||||||
|
sptr_t flags = 0;
|
||||||
|
if (dialog->matchCase()) {
|
||||||
|
flags |= SCFIND_MATCHCASE;
|
||||||
|
}
|
||||||
|
if (dialog->wholeWord()) {
|
||||||
|
flags |= SCFIND_WHOLEWORD;
|
||||||
|
}
|
||||||
|
if (dialog->searchMode() == SearchMode::Regex) {
|
||||||
|
flags |= SCFIND_REGEXP;
|
||||||
|
}
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString buildFindPattern(const FindReplaceDialog *dialog)
|
||||||
|
{
|
||||||
|
return dialog->findTextForSearch();
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString buildReplacementText(const FindReplaceDialog *dialog)
|
||||||
|
{
|
||||||
|
return dialog->replaceTextForReplace();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MainWindow::findNextInCurrentEditor(bool forward, bool showNotFoundMessage)
|
||||||
|
{
|
||||||
|
SciEdit *editor = m_tabWidget->currentEditor();
|
||||||
|
if (!editor) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_findReplaceDialog) {
|
||||||
|
m_findReplaceDialog = new FindReplaceDialog(this);
|
||||||
|
connect(m_findReplaceDialog, &FindReplaceDialog::findRequested, this, [this](bool forward) {
|
||||||
|
findNextInCurrentEditor(forward, true);
|
||||||
|
});
|
||||||
|
connect(m_findReplaceDialog, &FindReplaceDialog::replaceRequested, this, [this]() {
|
||||||
|
replaceOneInCurrentEditor(true);
|
||||||
|
});
|
||||||
|
connect(m_findReplaceDialog, &FindReplaceDialog::replaceAllRequested, this, [this]() {
|
||||||
|
replaceAllInCurrentEditor(true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString needle = buildFindPattern(m_findReplaceDialog);
|
||||||
|
if (needle.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QByteArray needleBytes = needle.toUtf8();
|
||||||
|
const sptr_t flags = buildSearchFlags(m_findReplaceDialog);
|
||||||
|
|
||||||
|
const int docLen = static_cast<int>(editor->textLength());
|
||||||
|
int rangeStart = 0;
|
||||||
|
int rangeEnd = docLen;
|
||||||
|
|
||||||
|
if (m_findReplaceDialog->inSelection()) {
|
||||||
|
if (!m_findInSelectionEnabled) {
|
||||||
|
const int selStart = static_cast<int>(editor->selectionStart());
|
||||||
|
const int selEnd = static_cast<int>(editor->selectionEnd());
|
||||||
|
if (selStart != selEnd) {
|
||||||
|
m_findSelectionStart = qMin(selStart, selEnd);
|
||||||
|
m_findSelectionEnd = qMax(selStart, selEnd);
|
||||||
|
m_findInSelectionEnabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
m_findInSelectionEnabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_findInSelectionEnabled) {
|
||||||
|
rangeStart = qBound(0, m_findSelectionStart, docLen);
|
||||||
|
rangeEnd = qBound(0, m_findSelectionEnd, docLen);
|
||||||
|
if (rangeStart >= rangeEnd) {
|
||||||
|
m_findInSelectionEnabled = false;
|
||||||
|
rangeStart = 0;
|
||||||
|
rangeEnd = docLen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const int selStartNow = static_cast<int>(editor->selectionStart());
|
||||||
|
const int selEndNow = static_cast<int>(editor->selectionEnd());
|
||||||
|
int caretBase = static_cast<int>(editor->currentPos());
|
||||||
|
if (forward && selStartNow != selEndNow) {
|
||||||
|
caretBase = qMax(selStartNow, selEndNow);
|
||||||
|
}
|
||||||
|
caretBase = qBound(rangeStart, caretBase, rangeEnd);
|
||||||
|
|
||||||
|
auto selectMatch = [&](int start, int end) {
|
||||||
|
editor->setSel(start, end);
|
||||||
|
editor->scrollCaret();
|
||||||
|
};
|
||||||
|
|
||||||
|
auto showNotFound = [&]() {
|
||||||
|
if (!showNotFoundMessage) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QMessageBox::information(this, QStringLiteral("Find"), QStringLiteral("Text not found."));
|
||||||
|
};
|
||||||
|
|
||||||
|
if (forward) {
|
||||||
|
const QPair<int, int> found = editor->findText(static_cast<int>(flags), needleBytes.constData(), caretBase, rangeEnd);
|
||||||
|
if (found.first >= 0) {
|
||||||
|
selectMatch(found.first, found.second);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (m_findReplaceDialog->wrapAround()) {
|
||||||
|
const QPair<int, int> wrapped = editor->findText(static_cast<int>(flags), needleBytes.constData(), rangeStart, rangeEnd);
|
||||||
|
if (wrapped.first >= 0) {
|
||||||
|
selectMatch(wrapped.first, wrapped.second);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
showNotFound();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto findLastBefore = [&](int endExclusive) -> QPair<int, int> {
|
||||||
|
int bestStart = -1;
|
||||||
|
int bestEnd = -1;
|
||||||
|
int scanPos = rangeStart;
|
||||||
|
while (scanPos < endExclusive) {
|
||||||
|
const QPair<int, int> found = editor->findText(static_cast<int>(flags), needleBytes.constData(), scanPos, endExclusive);
|
||||||
|
if (found.first < 0 || found.first >= endExclusive) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bestStart = found.first;
|
||||||
|
bestEnd = found.second;
|
||||||
|
scanPos = found.first + 1;
|
||||||
|
}
|
||||||
|
return QPair<int, int>(bestStart, bestEnd);
|
||||||
|
};
|
||||||
|
|
||||||
|
QPair<int, int> found = findLastBefore(caretBase);
|
||||||
|
if (found.first >= 0) {
|
||||||
|
selectMatch(found.first, found.second);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_findReplaceDialog->wrapAround()) {
|
||||||
|
found = findLastBefore(rangeEnd);
|
||||||
|
if (found.first >= 0) {
|
||||||
|
selectMatch(found.first, found.second);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
showNotFound();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MainWindow::replaceOneInCurrentEditor(bool showNotFoundMessage)
|
||||||
|
{
|
||||||
|
SciEdit *editor = m_tabWidget->currentEditor();
|
||||||
|
if (!editor) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!m_findReplaceDialog) {
|
||||||
|
m_findReplaceDialog = new FindReplaceDialog(this);
|
||||||
|
connect(m_findReplaceDialog, &FindReplaceDialog::findRequested, this, [this](bool forward) {
|
||||||
|
findNextInCurrentEditor(forward, true);
|
||||||
|
});
|
||||||
|
connect(m_findReplaceDialog, &FindReplaceDialog::replaceRequested, this, [this]() {
|
||||||
|
replaceOneInCurrentEditor(true);
|
||||||
|
});
|
||||||
|
connect(m_findReplaceDialog, &FindReplaceDialog::replaceAllRequested, this, [this]() {
|
||||||
|
replaceAllInCurrentEditor(true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString needle = buildFindPattern(m_findReplaceDialog);
|
||||||
|
if (needle.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!findNextInCurrentEditor(true, showNotFoundMessage)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString replacement = buildReplacementText(m_findReplaceDialog);
|
||||||
|
const QByteArray replacementBytes = replacement.toUtf8();
|
||||||
|
|
||||||
|
editor->targetFromSelection();
|
||||||
|
if (m_findReplaceDialog->searchMode() == SearchMode::Regex) {
|
||||||
|
editor->replaceTargetRE(replacementBytes.size(), replacementBytes.constData());
|
||||||
|
} else {
|
||||||
|
editor->replaceTarget(replacementBytes.size(), replacementBytes.constData());
|
||||||
|
}
|
||||||
|
|
||||||
|
findNextInCurrentEditor(true, false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int MainWindow::replaceAllInCurrentEditor(bool showNotFoundMessage)
|
||||||
|
{
|
||||||
|
SciEdit *editor = m_tabWidget->currentEditor();
|
||||||
|
if (!editor) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!m_findReplaceDialog) {
|
||||||
|
m_findReplaceDialog = new FindReplaceDialog(this);
|
||||||
|
connect(m_findReplaceDialog, &FindReplaceDialog::findRequested, this, [this](bool forward) {
|
||||||
|
findNextInCurrentEditor(forward, true);
|
||||||
|
});
|
||||||
|
connect(m_findReplaceDialog, &FindReplaceDialog::replaceRequested, this, [this]() {
|
||||||
|
replaceOneInCurrentEditor(true);
|
||||||
|
});
|
||||||
|
connect(m_findReplaceDialog, &FindReplaceDialog::replaceAllRequested, this, [this]() {
|
||||||
|
replaceAllInCurrentEditor(true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString needle = buildFindPattern(m_findReplaceDialog);
|
||||||
|
if (needle.isEmpty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QByteArray needleBytes = needle.toUtf8();
|
||||||
|
const QString replacement = buildReplacementText(m_findReplaceDialog);
|
||||||
|
const QByteArray replacementBytes = replacement.toUtf8();
|
||||||
|
const sptr_t flags = buildSearchFlags(m_findReplaceDialog);
|
||||||
|
|
||||||
|
const int docLen = static_cast<int>(editor->textLength());
|
||||||
|
int rangeStart = 0;
|
||||||
|
int rangeEnd = docLen;
|
||||||
|
|
||||||
|
if (m_findReplaceDialog->inSelection()) {
|
||||||
|
if (!m_findInSelectionEnabled) {
|
||||||
|
const int selStart = static_cast<int>(editor->selectionStart());
|
||||||
|
const int selEnd = static_cast<int>(editor->selectionEnd());
|
||||||
|
if (selStart != selEnd) {
|
||||||
|
m_findSelectionStart = qMin(selStart, selEnd);
|
||||||
|
m_findSelectionEnd = qMax(selStart, selEnd);
|
||||||
|
m_findInSelectionEnabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
m_findInSelectionEnabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_findInSelectionEnabled) {
|
||||||
|
rangeStart = qBound(0, m_findSelectionStart, docLen);
|
||||||
|
rangeEnd = qBound(0, m_findSelectionEnd, docLen);
|
||||||
|
if (rangeStart >= rangeEnd) {
|
||||||
|
m_findInSelectionEnabled = false;
|
||||||
|
rangeStart = 0;
|
||||||
|
rangeEnd = docLen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
editor->setSearchFlags(flags);
|
||||||
|
|
||||||
|
int replacedCount = 0;
|
||||||
|
int start = rangeStart;
|
||||||
|
int end = rangeEnd;
|
||||||
|
|
||||||
|
editor->beginUndoAction();
|
||||||
|
while (start <= end) {
|
||||||
|
editor->setTargetRange(start, end);
|
||||||
|
const sptr_t pos = editor->searchInTarget(needleBytes.size(), needleBytes.constData());
|
||||||
|
if (pos < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int matchStart = static_cast<int>(editor->targetStart());
|
||||||
|
const int matchEnd = static_cast<int>(editor->targetEnd());
|
||||||
|
const int matchLen = matchEnd - matchStart;
|
||||||
|
|
||||||
|
sptr_t replacedLen = 0;
|
||||||
|
if (m_findReplaceDialog->searchMode() == SearchMode::Regex) {
|
||||||
|
replacedLen = editor->replaceTargetRE(replacementBytes.size(), replacementBytes.constData());
|
||||||
|
} else {
|
||||||
|
replacedLen = editor->replaceTarget(replacementBytes.size(), replacementBytes.constData());
|
||||||
|
}
|
||||||
|
|
||||||
|
++replacedCount;
|
||||||
|
const int delta = static_cast<int>(replacedLen) - matchLen;
|
||||||
|
end += delta;
|
||||||
|
start = matchStart + static_cast<int>(replacedLen);
|
||||||
|
}
|
||||||
|
editor->endUndoAction();
|
||||||
|
|
||||||
|
if (replacedCount == 0 && showNotFoundMessage) {
|
||||||
|
QMessageBox::information(this, QStringLiteral("Replace"), QStringLiteral("Text not found."));
|
||||||
|
}
|
||||||
|
|
||||||
|
return replacedCount;
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ class QLabel;
|
|||||||
class SciEdit;
|
class SciEdit;
|
||||||
class TabWidget;
|
class TabWidget;
|
||||||
class DocumentManager;
|
class DocumentManager;
|
||||||
|
class FindReplaceDialog;
|
||||||
|
|
||||||
class MainWindow : public KXmlGuiWindow
|
class MainWindow : public KXmlGuiWindow
|
||||||
{
|
{
|
||||||
@@ -36,6 +37,10 @@ private:
|
|||||||
void updateWindowTitle();
|
void updateWindowTitle();
|
||||||
void updateStatusBar();
|
void updateStatusBar();
|
||||||
void updateActions();
|
void updateActions();
|
||||||
|
void showFindReplaceDialog(bool showReplace);
|
||||||
|
bool findNextInCurrentEditor(bool forward, bool showNotFoundMessage);
|
||||||
|
bool replaceOneInCurrentEditor(bool showNotFoundMessage);
|
||||||
|
int replaceAllInCurrentEditor(bool showNotFoundMessage);
|
||||||
|
|
||||||
DocumentManager *m_documentManager;
|
DocumentManager *m_documentManager;
|
||||||
TabWidget *m_tabWidget;
|
TabWidget *m_tabWidget;
|
||||||
@@ -43,6 +48,10 @@ private:
|
|||||||
QLabel *m_encodingStatusLabel;
|
QLabel *m_encodingStatusLabel;
|
||||||
QLabel *m_languageStatusLabel;
|
QLabel *m_languageStatusLabel;
|
||||||
bool m_indentGuidesEnabled = false;
|
bool m_indentGuidesEnabled = false;
|
||||||
|
FindReplaceDialog *m_findReplaceDialog = nullptr;
|
||||||
|
bool m_findInSelectionEnabled = false;
|
||||||
|
int m_findSelectionStart = 0;
|
||||||
|
int m_findSelectionEnd = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// plainly for KConfigDialog
|
// plainly for KConfigDialog
|
||||||
|
|||||||
Reference in New Issue
Block a user