implement Find/Replace logics

Supports Find/Replace in both edit and preview modes.

Signed-off-by: Le Tan <tamlokveer@gmail.com>
This commit is contained in:
Le Tan 2017-01-02 11:52:49 +08:00
parent 768c1632b0
commit 3005d9bf5c
17 changed files with 847 additions and 49 deletions

View File

@ -2,7 +2,7 @@
#include <QtWidgets> #include <QtWidgets>
VFindReplaceDialog::VFindReplaceDialog(QWidget *p_parent) VFindReplaceDialog::VFindReplaceDialog(QWidget *p_parent)
: QWidget(p_parent) : QWidget(p_parent), m_options(0), m_replaceAvailable(true)
{ {
setupUI(); setupUI();
} }
@ -24,25 +24,42 @@ void VFindReplaceDialog::setupUI()
// Find // Find
QLabel *findLabel = new QLabel(tr("&Find:")); QLabel *findLabel = new QLabel(tr("&Find:"));
m_findEdit = new QLineEdit(); m_findEdit = new QLineEdit();
m_findEdit->setPlaceholderText(tr("Enter text to search"));
findLabel->setBuddy(m_findEdit); findLabel->setBuddy(m_findEdit);
m_findNextBtn = new QPushButton(tr("Find Next")); m_findNextBtn = new QPushButton(tr("Find &Next"));
m_findNextBtn->setProperty("FlatBtn", true); m_findNextBtn->setProperty("FlatBtn", true);
m_findNextBtn->setDefault(true); m_findNextBtn->setDefault(true);
m_findPrevBtn = new QPushButton(tr("Find Previous")); m_findPrevBtn = new QPushButton(tr("Find &Previous"));
m_findPrevBtn->setProperty("FlatBtn", true); m_findPrevBtn->setProperty("FlatBtn", true);
// Replace // Replace
QLabel *replaceLabel = new QLabel(tr("&Replace with:")); QLabel *replaceLabel = new QLabel(tr("&Replace with:"));
m_replaceEdit = new QLineEdit(); m_replaceEdit = new QLineEdit();
m_replaceEdit->setPlaceholderText(tr("Enter text to replace with"));
replaceLabel->setBuddy(m_replaceEdit); replaceLabel->setBuddy(m_replaceEdit);
m_replaceBtn = new QPushButton(tr("Replace")); m_replaceBtn = new QPushButton(tr("R&eplace"));
m_replaceBtn->setProperty("FlatBtn", true); m_replaceBtn->setProperty("FlatBtn", true);
m_replaceFindBtn = new QPushButton(tr("Replace && Find")); m_replaceFindBtn = new QPushButton(tr("Replace && Fin&d"));
m_replaceFindBtn->setProperty("FlatBtn", true); m_replaceFindBtn->setProperty("FlatBtn", true);
m_replaceAllBtn = new QPushButton(tr("Replace All")); m_replaceAllBtn = new QPushButton(tr("Replace A&ll"));
m_replaceAllBtn->setProperty("FlatBtn", true); m_replaceAllBtn->setProperty("FlatBtn", true);
m_advancedBtn = new QPushButton(tr("Advanced")); m_advancedBtn = new QPushButton(tr("&Advanced >>"));
m_advancedBtn->setProperty("FlatBtn", true); m_advancedBtn->setProperty("FlatBtn", true);
m_advancedBtn->setCheckable(true);
// Options
m_caseSensitiveCheck = new QCheckBox(tr("&Case sensitive"), this);
connect(m_caseSensitiveCheck, &QCheckBox::stateChanged,
this, &VFindReplaceDialog::optionBoxToggled);
m_wholeWordOnlyCheck = new QCheckBox(tr("&Whole word only"), this);
connect(m_wholeWordOnlyCheck, &QCheckBox::stateChanged,
this, &VFindReplaceDialog::optionBoxToggled);
m_regularExpressionCheck = new QCheckBox(tr("Re&gular expression"), this);
connect(m_regularExpressionCheck, &QCheckBox::stateChanged,
this, &VFindReplaceDialog::optionBoxToggled);
m_incrementalSearchCheck = new QCheckBox(tr("&Incremental search"), this);
connect(m_incrementalSearchCheck, &QCheckBox::stateChanged,
this, &VFindReplaceDialog::optionBoxToggled);
QGridLayout *gridLayout = new QGridLayout(); QGridLayout *gridLayout = new QGridLayout();
gridLayout->addWidget(findLabel, 0, 0); gridLayout->addWidget(findLabel, 0, 0);
@ -55,6 +72,10 @@ void VFindReplaceDialog::setupUI()
gridLayout->addWidget(m_replaceFindBtn, 1, 3); gridLayout->addWidget(m_replaceFindBtn, 1, 3);
gridLayout->addWidget(m_replaceAllBtn, 1, 4); gridLayout->addWidget(m_replaceAllBtn, 1, 4);
gridLayout->addWidget(m_advancedBtn, 1, 5); gridLayout->addWidget(m_advancedBtn, 1, 5);
gridLayout->addWidget(m_caseSensitiveCheck, 2, 1);
gridLayout->addWidget(m_wholeWordOnlyCheck, 2, 2);
gridLayout->addWidget(m_regularExpressionCheck, 3, 1);
gridLayout->addWidget(m_incrementalSearchCheck, 3, 2);
gridLayout->setColumnStretch(0, 0); gridLayout->setColumnStretch(0, 0);
gridLayout->setColumnStretch(1, 4); gridLayout->setColumnStretch(1, 4);
gridLayout->setColumnStretch(2, 1); gridLayout->setColumnStretch(2, 1);
@ -62,6 +83,7 @@ void VFindReplaceDialog::setupUI()
gridLayout->setColumnStretch(4, 1); gridLayout->setColumnStretch(4, 1);
gridLayout->setColumnStretch(5, 1); gridLayout->setColumnStretch(5, 1);
gridLayout->setColumnStretch(6, 3); gridLayout->setColumnStretch(6, 3);
QMargins margin = gridLayout->contentsMargins(); QMargins margin = gridLayout->contentsMargins();
margin.setLeft(3); margin.setLeft(3);
gridLayout->setContentsMargins(margin); gridLayout->setContentsMargins(margin);
@ -73,31 +95,195 @@ void VFindReplaceDialog::setupUI()
setLayout(mainLayout); setLayout(mainLayout);
m_caseSensitiveCheck->hide();
m_wholeWordOnlyCheck->hide();
m_regularExpressionCheck->hide();
m_incrementalSearchCheck->hide();
// Signals // Signals
connect(m_closeBtn, &QPushButton::clicked, connect(m_closeBtn, &QPushButton::clicked,
this, &VFindReplaceDialog::closeDialog); this, &VFindReplaceDialog::closeDialog);
connect(m_findEdit, &QLineEdit::textChanged,
this, &VFindReplaceDialog::handleFindTextChanged);
connect(m_advancedBtn, &QPushButton::toggled,
this, &VFindReplaceDialog::advancedBtnToggled);
connect(m_findNextBtn, SIGNAL(clicked(bool)),
this, SLOT(findNext()));
connect(m_findPrevBtn, SIGNAL(clicked(bool)),
this, SLOT(findPrevious()));
connect(m_replaceBtn, SIGNAL(clicked(bool)),
this, SLOT(replace()));
connect(m_replaceFindBtn, SIGNAL(clicked(bool)),
this, SLOT(replaceFind()));
connect(m_replaceAllBtn, SIGNAL(clicked(bool)),
this, SLOT(replaceAll()));
} }
void VFindReplaceDialog::closeDialog() void VFindReplaceDialog::closeDialog()
{ {
if (this->isVisible()) { if (this->isVisible()) {
this->hide(); hide();
emit dialogClosed(); emit dialogClosed();
} }
} }
void VFindReplaceDialog::showEvent(QShowEvent *event)
{
m_findEdit->selectAll();
QWidget::showEvent(event);
}
void VFindReplaceDialog::keyPressEvent(QKeyEvent *event) void VFindReplaceDialog::keyPressEvent(QKeyEvent *event)
{ {
if (event->key() == Qt::Key_Escape) { switch (event->key()) {
case Qt::Key_Escape:
event->accept(); event->accept();
closeDialog(); closeDialog();
return; return;
case Qt::Key_Return:
{
int modifiers = event->modifiers();
bool shift = false;
if (modifiers == Qt::ShiftModifier) {
shift = true;
} else if (modifiers != Qt::NoModifier) {
break;
}
if (!m_findEdit->hasFocus() && !m_replaceEdit->hasFocus()) {
break;
}
event->accept();
if (shift) {
findPrevious();
} else {
findNext();
}
return;
}
default:
break;
} }
QWidget::keyPressEvent(event); QWidget::keyPressEvent(event);
} }
void VFindReplaceDialog::openDialog(QString p_text)
{
show();
if (!p_text.isEmpty()) {
m_findEdit->setText(p_text);
}
m_findEdit->setFocus();
m_findEdit->selectAll();
}
void VFindReplaceDialog::handleFindTextChanged(const QString &p_text)
{
emit findTextChanged(p_text, m_options);
}
void VFindReplaceDialog::advancedBtnToggled(bool p_checked)
{
if (p_checked) {
m_advancedBtn->setText("B&asic <<");
} else {
m_advancedBtn->setText("&Advanced <<");
}
m_caseSensitiveCheck->setVisible(p_checked);
m_wholeWordOnlyCheck->setVisible(p_checked);
m_regularExpressionCheck->setVisible(p_checked);
m_incrementalSearchCheck->setVisible(p_checked);
}
void VFindReplaceDialog::optionBoxToggled(int p_state)
{
QObject *obj = sender();
FindOption opt = FindOption::CaseSensitive;
if (obj == m_caseSensitiveCheck) {
opt = FindOption::CaseSensitive;
} else if (obj == m_wholeWordOnlyCheck) {
opt = FindOption::WholeWordOnly;
} else if (obj == m_regularExpressionCheck) {
opt = FindOption::RegularExpression;
} else {
opt = FindOption::IncrementalSearch;
}
if (p_state) {
m_options |= opt;
} else {
m_options &= ~opt;
}
emit findOptionChanged(m_options);
}
void VFindReplaceDialog::setOption(FindOption p_opt, bool p_enabled)
{
if (p_opt == FindOption::CaseSensitive) {
m_caseSensitiveCheck->setChecked(p_enabled);
} else if (p_opt == FindOption::WholeWordOnly) {
m_wholeWordOnlyCheck->setChecked(p_enabled);
} else if (p_opt == FindOption::RegularExpression) {
m_regularExpressionCheck->setChecked(p_enabled);
} else if (p_opt == FindOption::IncrementalSearch) {
m_incrementalSearchCheck->setChecked(p_enabled);
} else {
Q_ASSERT(false);
}
}
void VFindReplaceDialog::findNext()
{
QString text = m_findEdit->text();
if (text.isEmpty()) {
return;
}
emit findNext(text, m_options, true);
}
void VFindReplaceDialog::findPrevious()
{
QString text = m_findEdit->text();
if (text.isEmpty()) {
return;
}
emit findNext(text, m_options, false);
}
void VFindReplaceDialog::replace()
{
QString text = m_findEdit->text();
if (text.isEmpty() || !m_replaceAvailable) {
return;
}
QString replaceText = m_replaceEdit->text();
emit replace(text, m_options, replaceText, false);
}
void VFindReplaceDialog::replaceFind()
{
QString text = m_findEdit->text();
if (text.isEmpty() || !m_replaceAvailable) {
return;
}
QString replaceText = m_replaceEdit->text();
emit replace(text, m_options, replaceText, true);
}
void VFindReplaceDialog::replaceAll()
{
QString text = m_findEdit->text();
if (text.isEmpty() || !m_replaceAvailable) {
return;
}
QString replaceText = m_replaceEdit->text();
emit replaceAll(text, m_options, replaceText);
}
void VFindReplaceDialog::updateState(DocType p_docType, bool p_editMode)
{
if (p_editMode || p_docType == DocType::Html) {
m_wholeWordOnlyCheck->setEnabled(true);
m_regularExpressionCheck->setEnabled(true);
} else {
m_wholeWordOnlyCheck->setEnabled(false);
m_regularExpressionCheck->setEnabled(false);
}
m_replaceAvailable = p_editMode;
}

View File

@ -2,28 +2,64 @@
#define VFINDREPLACEDIALOG_H #define VFINDREPLACEDIALOG_H
#include <QWidget> #include <QWidget>
#include <QString>
#include "vconstants.h"
class QLineEdit; class QLineEdit;
class QPushButton; class QPushButton;
class QCheckBox;
enum FindOption
{
CaseSensitive = 0x1U,
WholeWordOnly = 0x2U,
RegularExpression = 0x4U,
IncrementalSearch = 0x8U
};
class VFindReplaceDialog : public QWidget class VFindReplaceDialog : public QWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit VFindReplaceDialog(QWidget *p_parent = 0); explicit VFindReplaceDialog(QWidget *p_parent = 0);
void setOption(FindOption p_opt, bool p_enabled);
// Update the options enabled/disabled state according to current
// edit tab.
void updateState(DocType p_docType, bool p_editMode);
signals: signals:
void dialogClosed(); void dialogClosed();
void findTextChanged(const QString &p_text, uint p_options);
void findOptionChanged(uint p_options);
void findNext(const QString &p_text, uint p_options, bool p_forward);
void replace(const QString &p_text, uint p_options,
const QString &p_replaceText, bool p_findNext);
void replaceAll(const QString &p_text, uint p_options,
const QString &p_replaceText);
protected: protected:
void showEvent(QShowEvent *event) Q_DECL_OVERRIDE;
void keyPressEvent(QKeyEvent *event) Q_DECL_OVERRIDE; void keyPressEvent(QKeyEvent *event) Q_DECL_OVERRIDE;
public slots: public slots:
void closeDialog(); void closeDialog();
void openDialog(QString p_text = "");
void findNext();
void findPrevious();
void replace();
void replaceFind();
void replaceAll();
private slots:
void handleFindTextChanged(const QString &p_text);
void advancedBtnToggled(bool p_checked);
void optionBoxToggled(int p_state);
private: private:
void setupUI(); void setupUI();
// Bit OR of FindOption
uint m_options;
bool m_replaceAvailable;
QLineEdit *m_findEdit; QLineEdit *m_findEdit;
QLineEdit *m_replaceEdit; QLineEdit *m_replaceEdit;
QPushButton *m_findNextBtn; QPushButton *m_findNextBtn;
@ -33,6 +69,10 @@ private:
QPushButton *m_replaceAllBtn; QPushButton *m_replaceAllBtn;
QPushButton *m_advancedBtn; QPushButton *m_advancedBtn;
QPushButton *m_closeBtn; QPushButton *m_closeBtn;
QCheckBox *m_caseSensitiveCheck;
QCheckBox *m_wholeWordOnlyCheck;
QCheckBox *m_regularExpressionCheck;
QCheckBox *m_incrementalSearchCheck;
}; };
#endif // VFINDREPLACEDIALOG_H #endif // VFINDREPLACEDIALOG_H

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="512px" height="512px" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<path d="M445,386.7l-84.8-85.9c13.8-24.1,21-50.9,21-77.9c0-87.6-71.2-158.9-158.6-158.9C135.2,64,64,135.3,64,222.9
c0,87.6,71.2,158.9,158.6,158.9c27.9,0,55.5-7.7,80.1-22.4l84.4,85.6c1.9,1.9,4.6,3.1,7.3,3.1c2.7,0,5.4-1.1,7.3-3.1l43.3-43.8
C449,397.1,449,390.7,445,386.7z M222.6,125.9c53.4,0,96.8,43.5,96.8,97c0,53.5-43.4,97-96.8,97c-53.4,0-96.8-43.5-96.8-97
C125.8,169.4,169.2,125.9,222.6,125.9z"/>
</svg>

After

Width:  |  Height:  |  Size: 894 B

View File

@ -68,6 +68,15 @@ void VConfigManager::initialize()
m_mainSplitterState = getConfigFromSettings("session", "main_splitter_state").toByteArray(); m_mainSplitterState = getConfigFromSettings("session", "main_splitter_state").toByteArray();
updateMarkdownEditStyle(); updateMarkdownEditStyle();
m_findCaseSensitive = getConfigFromSettings("global",
"find_case_sensitive").toBool();
m_findWholeWordOnly = getConfigFromSettings("global",
"find_whole_word_only").toBool();
m_findRegularExpression = getConfigFromSettings("global",
"find_regular_expression").toBool();
m_findIncrementalSearch = getConfigFromSettings("global",
"find_incremental_search").toBool();
} }
void VConfigManager::readPredefinedColorsFromSettings() void VConfigManager::readPredefinedColorsFromSettings()

View File

@ -99,6 +99,18 @@ public:
inline const QByteArray &getMainSplitterState() const; inline const QByteArray &getMainSplitterState() const;
inline void setMainSplitterState(const QByteArray &p_state); inline void setMainSplitterState(const QByteArray &p_state);
inline bool getFindCaseSensitive() const;
inline void setFindCaseSensitive(bool p_enabled);
inline bool getFindWholeWordOnly() const;
inline void setFindWholeWordOnly(bool p_enabled);
inline bool getFindRegularExpression() const;
inline void setFindRegularExpression(bool p_enabled);
inline bool getFindIncrementalSearch() const;
inline void setFindIncrementalSearch(bool p_enabled);
private: private:
void updateMarkdownEditStyle(); void updateMarkdownEditStyle();
QVariant getConfigFromSettings(const QString &section, const QString &key); QVariant getConfigFromSettings(const QString &section, const QString &key);
@ -144,6 +156,12 @@ private:
QByteArray m_mainWindowState; QByteArray m_mainWindowState;
QByteArray m_mainSplitterState; QByteArray m_mainSplitterState;
// Find/Replace dialog options
bool m_findCaseSensitive;
bool m_findWholeWordOnly;
bool m_findRegularExpression;
bool m_findIncrementalSearch;
// The name of the config file in each directory // The name of the config file in each directory
static const QString dirConfigFileName; static const QString dirConfigFileName;
// The name of the default configuration file // The name of the default configuration file
@ -373,4 +391,62 @@ inline void VConfigManager::setMainSplitterState(const QByteArray &p_state)
setConfigToSettings("session", "main_splitter_state", m_mainSplitterState); setConfigToSettings("session", "main_splitter_state", m_mainSplitterState);
} }
inline bool VConfigManager::getFindCaseSensitive() const
{
return m_findCaseSensitive;
}
inline void VConfigManager::setFindCaseSensitive(bool p_enabled)
{
if (m_findCaseSensitive == p_enabled) {
return;
}
m_findCaseSensitive = p_enabled;
setConfigToSettings("global", "find_case_sensitive", m_findCaseSensitive);
}
inline bool VConfigManager::getFindWholeWordOnly() const
{
return m_findWholeWordOnly;
}
inline void VConfigManager::setFindWholeWordOnly(bool p_enabled)
{
if (m_findWholeWordOnly == p_enabled) {
return;
}
m_findWholeWordOnly = p_enabled;
setConfigToSettings("global", "find_whole_word_only", m_findWholeWordOnly);
}
inline bool VConfigManager::getFindRegularExpression() const
{
return m_findRegularExpression;
}
inline void VConfigManager::setFindRegularExpression(bool p_enabled)
{
if (m_findRegularExpression == p_enabled) {
return;
}
m_findRegularExpression = p_enabled;
setConfigToSettings("global", "find_regular_expression",
m_findRegularExpression);
}
inline bool VConfigManager::getFindIncrementalSearch() const
{
return m_findIncrementalSearch;
}
inline void VConfigManager::setFindIncrementalSearch(bool p_enabled)
{
if (m_findIncrementalSearch == p_enabled) {
return;
}
m_findIncrementalSearch = p_enabled;
setConfigToSettings("global", "find_incremental_search",
m_findIncrementalSearch);
}
#endif // VCONFIGMANAGER_H #endif // VCONFIGMANAGER_H

View File

@ -1,11 +1,13 @@
#include <QtWidgets> #include <QtWidgets>
#include <QVector> #include <QVector>
#include <QDebug>
#include "vedit.h" #include "vedit.h"
#include "vnote.h" #include "vnote.h"
#include "vconfigmanager.h" #include "vconfigmanager.h"
#include "vtoc.h" #include "vtoc.h"
#include "utils/vutils.h" #include "utils/vutils.h"
#include "veditoperations.h" #include "veditoperations.h"
#include "dialog/vfindreplacedialog.h"
extern VConfigManager vconfig; extern VConfigManager vconfig;
@ -82,3 +84,165 @@ void VEdit::insertImage()
m_editOps->insertImage(); m_editOps->insertImage();
} }
} }
bool VEdit::findText(const QString &p_text, uint p_options, bool p_peek,
bool p_forward)
{
static int startPos = textCursor().selectionStart();
static int lastPos = startPos;
bool found = false;
if (p_text.isEmpty() && p_peek) {
// Clear previous selection
QTextCursor cursor = textCursor();
cursor.clearSelection();
cursor.setPosition(startPos);
setTextCursor(cursor);
} else {
QTextCursor cursor = textCursor();
if (p_peek) {
int curPos = cursor.selectionStart();
if (curPos != lastPos) {
// Cursor has been moved. Just start at current position.
startPos = curPos;
lastPos = curPos;
} else {
// Move cursor to startPos to search.
cursor.setPosition(startPos);
setTextCursor(cursor);
}
}
// Options
QTextDocument::FindFlags flags;
if (p_options & FindOption::CaseSensitive) {
flags |= QTextDocument::FindCaseSensitively;
}
if (p_options & FindOption::WholeWordOnly) {
flags |= QTextDocument::FindWholeWords;
}
if (!p_forward) {
flags |= QTextDocument::FindBackward;
}
// Use regular expression
if (p_options & FindOption::RegularExpression) {
QRegExp exp(p_text,
p_options & FindOption::CaseSensitive ?
Qt::CaseSensitive : Qt::CaseInsensitive);
found = find(exp, flags);
} else {
found = find(p_text, flags);
}
cursor = textCursor();
if (!p_peek) {
startPos = cursor.selectionStart();
}
lastPos = cursor.selectionStart();
}
return found;
}
void VEdit::replaceText(const QString &p_text, uint p_options,
const QString &p_replaceText, bool p_findNext)
{
// Options
QTextDocument::FindFlags flags;
if (p_options & FindOption::CaseSensitive) {
flags |= QTextDocument::FindCaseSensitively;
}
if (p_options & FindOption::WholeWordOnly) {
flags |= QTextDocument::FindWholeWords;
}
bool useRegExp = false;
QRegExp exp;
if (p_options & FindOption::RegularExpression) {
useRegExp = true;
exp = QRegExp(p_text,
p_options & FindOption::CaseSensitive ?
Qt::CaseSensitive : Qt::CaseInsensitive);
}
QTextCursor cursor = textCursor();
if (cursor.hasSelection()) {
// Replace occurs only if the selected text matches @p_text with @p_options.
QTextCursor matchCursor;
if (useRegExp) {
matchCursor = document()->find(exp, cursor.selectionStart(),
flags);
} else {
matchCursor = document()->find(p_text, cursor.selectionStart(),
flags);
}
bool matched = (cursor.selectionStart() == matchCursor.selectionStart())
&& (cursor.selectionEnd() == matchCursor.selectionEnd());
if (matched) {
cursor.beginEditBlock();
cursor.removeSelectedText();
cursor.insertText(p_replaceText);
cursor.endEditBlock();
setTextCursor(cursor);
}
}
if (p_findNext) {
findText(p_text, p_options, false, true);
}
}
void VEdit::replaceTextAll(const QString &p_text, uint p_options,
const QString &p_replaceText)
{
// Options
QTextDocument::FindFlags flags;
if (p_options & FindOption::CaseSensitive) {
flags |= QTextDocument::FindCaseSensitively;
}
if (p_options & FindOption::WholeWordOnly) {
flags |= QTextDocument::FindWholeWords;
}
bool useRegExp = false;
QRegExp exp;
if (p_options & FindOption::RegularExpression) {
useRegExp = true;
exp = QRegExp(p_text,
p_options & FindOption::CaseSensitive ?
Qt::CaseSensitive : Qt::CaseInsensitive);
}
QTextCursor cursor = textCursor();
int pos = cursor.position();
int nrReplaces = 0;
int startPos = 0;
int lastMatch = -1;
while (true) {
QTextCursor matchCursor;
if (useRegExp) {
matchCursor = document()->find(exp, startPos, flags);
} else {
matchCursor = document()->find(p_text, startPos, flags);
}
if (matchCursor.isNull()) {
break;
} else {
if (matchCursor.selectionStart() <= lastMatch) {
// Wrap back.
break;
} else {
lastMatch = matchCursor.selectionStart();
}
nrReplaces++;
matchCursor.beginEditBlock();
matchCursor.removeSelectedText();
matchCursor.insertText(p_replaceText);
matchCursor.endEditBlock();
setTextCursor(matchCursor);
startPos = matchCursor.position();
}
}
// Restore cursor position.
cursor.setPosition(pos);
setTextCursor(cursor);
qDebug() << "replace all" << nrReplaces << "occurencs";
}

View File

@ -26,6 +26,12 @@ public:
virtual void scrollToLine(int p_lineNumber); virtual void scrollToLine(int p_lineNumber);
// User requests to insert an image. // User requests to insert an image.
virtual void insertImage(); virtual void insertImage();
virtual bool findText(const QString &p_text, uint p_options, bool p_peek,
bool p_forward);
virtual void replaceText(const QString &p_text, uint p_options,
const QString &p_replaceText, bool p_findNext);
virtual void replaceTextAll(const QString &p_text, uint p_options,
const QString &p_replaceText);
protected: protected:
QPointer<VFile> m_file; QPointer<VFile> m_file;

View File

@ -7,6 +7,8 @@
#include "vfile.h" #include "vfile.h"
#include "dialog/vfindreplacedialog.h" #include "dialog/vfindreplacedialog.h"
extern VConfigManager vconfig;
VEditArea::VEditArea(VNote *vnote, QWidget *parent) VEditArea::VEditArea(VNote *vnote, QWidget *parent)
: QWidget(parent), vnote(vnote), curWindowIndex(-1) : QWidget(parent), vnote(vnote), curWindowIndex(-1)
{ {
@ -20,6 +22,14 @@ void VEditArea::setupUI()
{ {
splitter = new QSplitter(this); splitter = new QSplitter(this);
m_findReplace = new VFindReplaceDialog(this); m_findReplace = new VFindReplaceDialog(this);
m_findReplace->setOption(FindOption::CaseSensitive,
vconfig.getFindCaseSensitive());
m_findReplace->setOption(FindOption::WholeWordOnly,
vconfig.getFindWholeWordOnly());
m_findReplace->setOption(FindOption::RegularExpression,
vconfig.getFindRegularExpression());
m_findReplace->setOption(FindOption::IncrementalSearch,
vconfig.getFindIncrementalSearch());
QVBoxLayout *mainLayout = new QVBoxLayout(); QVBoxLayout *mainLayout = new QVBoxLayout();
mainLayout->addWidget(splitter); mainLayout->addWidget(splitter);
@ -31,6 +41,22 @@ void VEditArea::setupUI()
setLayout(mainLayout); setLayout(mainLayout);
connect(m_findReplace, &VFindReplaceDialog::findTextChanged,
this, &VEditArea::handleFindTextChanged);
connect(m_findReplace, &VFindReplaceDialog::findOptionChanged,
this, &VEditArea::handleFindOptionChanged);
connect(m_findReplace, SIGNAL(findNext(const QString &, uint, bool)),
this, SLOT(handleFindNext(const QString &, uint, bool)));
connect(m_findReplace,
SIGNAL(replace(const QString &, uint, const QString &, bool)),
this,
SLOT(handleReplace(const QString &, uint, const QString &, bool)));
connect(m_findReplace,
SIGNAL(replaceAll(const QString &, uint, const QString &)),
this,
SLOT(handleReplaceAll(const QString &, uint, const QString &)));
connect(m_findReplace, &VFindReplaceDialog::dialogClosed,
this, &VEditArea::handleFindDialogClosed);
m_findReplace->hide(); m_findReplace->hide();
} }
@ -422,3 +448,80 @@ void VEditArea::moveTab(QWidget *p_widget, int p_fromIdx, int p_toIdx)
delete p_widget; delete p_widget;
} }
} }
// Only propogate the search in the IncrementalSearch case.
void VEditArea::handleFindTextChanged(const QString &p_text, uint p_options)
{
VEditTab *tab = currentEditTab();
if (tab) {
if (p_options & FindOption::IncrementalSearch) {
tab->findText(p_text, p_options, true);
}
}
}
void VEditArea::handleFindOptionChanged(uint p_options)
{
qDebug() << "find option changed" << p_options;
vconfig.setFindCaseSensitive(p_options & FindOption::CaseSensitive);
vconfig.setFindWholeWordOnly(p_options & FindOption::WholeWordOnly);
vconfig.setFindRegularExpression(p_options & FindOption::RegularExpression);
vconfig.setFindIncrementalSearch(p_options & FindOption::IncrementalSearch);
}
void VEditArea::handleFindNext(const QString &p_text, uint p_options,
bool p_forward)
{
qDebug() << "find next" << p_text << p_options << p_forward;
VEditTab *tab = currentEditTab();
if (tab) {
tab->findText(p_text, p_options, false, p_forward);
}
}
void VEditArea::handleReplace(const QString &p_text, uint p_options,
const QString &p_replaceText, bool p_findNext)
{
qDebug() << "replace" << p_text << p_options << "with" << p_replaceText
<< p_findNext;
VEditTab *tab = currentEditTab();
if (tab) {
tab->replaceText(p_text, p_options, p_replaceText, p_findNext);
}
}
void VEditArea::handleReplaceAll(const QString &p_text, uint p_options,
const QString &p_replaceText)
{
qDebug() << "replace all" << p_text << p_options << "with" << p_replaceText;
VEditTab *tab = currentEditTab();
if (tab) {
tab->replaceTextAll(p_text, p_options, p_replaceText);
}
}
// Let VEditArea get focus after VFindReplaceDialog is closed.
void VEditArea::handleFindDialogClosed()
{
if (curWindowIndex == -1) {
setFocus();
} else {
getWindow(curWindowIndex)->focusWindow();
}
// Clear all the selection in Web view.
int nrWin = splitter->count();
for (int i = 0; i < nrWin; ++i) {
getWindow(i)->clearFindSelectionInWebView();
}
}
QString VEditArea::getSelectedText()
{
VEditTab *tab = currentEditTab();
if (tab) {
return tab->getSelectedText();
} else {
return QString();
}
}

View File

@ -40,6 +40,8 @@ public:
// If fail, just delete the p_widget. // If fail, just delete the p_widget.
void moveTab(QWidget *p_widget, int p_fromIdx, int p_toIdx); void moveTab(QWidget *p_widget, int p_fromIdx, int p_toIdx);
inline VFindReplaceDialog *getFindReplaceDialog() const; inline VFindReplaceDialog *getFindReplaceDialog() const;
// Return selected text of current edit tab.
QString getSelectedText();
signals: signals:
void curTabStatusChanged(const VFile *p_file, const VEditTab *p_editTab, bool p_editMode); void curTabStatusChanged(const VFile *p_file, const VEditTab *p_editTab, bool p_editMode);
@ -66,6 +68,14 @@ private slots:
void handleWindowFocused(); void handleWindowFocused();
void handleOutlineChanged(const VToc &toc); void handleOutlineChanged(const VToc &toc);
void handleCurHeaderChanged(const VAnchor &anchor); void handleCurHeaderChanged(const VAnchor &anchor);
void handleFindTextChanged(const QString &p_text, uint p_options);
void handleFindOptionChanged(uint p_options);
void handleFindNext(const QString &p_text, uint p_options, bool p_forward);
void handleReplace(const QString &p_text, uint p_options,
const QString &p_replaceText, bool p_findNext);
void handleReplaceAll(const QString &p_text, uint p_options,
const QString &p_replaceText);
void handleFindDialogClosed();
private: private:
void setupUI(); void setupUI();

View File

@ -15,6 +15,7 @@
#include "vnotebook.h" #include "vnotebook.h"
#include "vtoc.h" #include "vtoc.h"
#include "vmdedit.h" #include "vmdedit.h"
#include "dialog/vfindreplacedialog.h"
extern VConfigManager vconfig; extern VConfigManager vconfig;
@ -107,6 +108,7 @@ void VEditTab::showFileReadMode()
previewByConverter(); previewByConverter();
} }
setCurrentWidget(webPreviewer); setCurrentWidget(webPreviewer);
clearFindSelectionInWebView();
scrollPreviewToHeader(outlineIndex); scrollPreviewToHeader(outlineIndex);
break; break;
default: default:
@ -276,6 +278,7 @@ void VEditTab::setupMarkdownPreview()
void VEditTab::focusTab() void VEditTab::focusTab()
{ {
currentWidget()->setFocus(); currentWidget()->setFocus();
emit getFocused();
} }
void VEditTab::handleFocusChanged(QWidget * /* old */, QWidget *now) void VEditTab::handleFocusChanged(QWidget * /* old */, QWidget *now)
@ -455,3 +458,60 @@ void VEditTab::insertImage()
} }
m_textEditor->insertImage(); m_textEditor->insertImage();
} }
void VEditTab::findText(const QString &p_text, uint p_options, bool p_peek,
bool p_forward)
{
if (isEditMode || !webPreviewer) {
m_textEditor->findText(p_text, p_options, p_peek, p_forward);
} else {
findTextInWebView(p_text, p_options, p_peek, p_forward);
}
}
void VEditTab::replaceText(const QString &p_text, uint p_options,
const QString &p_replaceText, bool p_findNext)
{
if (isEditMode) {
m_textEditor->replaceText(p_text, p_options, p_replaceText, p_findNext);
}
}
void VEditTab::replaceTextAll(const QString &p_text, uint p_options,
const QString &p_replaceText)
{
if (isEditMode) {
m_textEditor->replaceTextAll(p_text, p_options, p_replaceText);
}
}
void VEditTab::findTextInWebView(const QString &p_text, uint p_options,
bool p_peek, bool p_forward)
{
Q_ASSERT(webPreviewer);
QWebEnginePage::FindFlags flags;
if (p_options & FindOption::CaseSensitive) {
flags |= QWebEnginePage::FindCaseSensitively;
}
if (!p_forward) {
flags |= QWebEnginePage::FindBackward;
}
webPreviewer->findText(p_text, flags);
}
QString VEditTab::getSelectedText() const
{
if (isEditMode || !webPreviewer) {
QTextCursor cursor = m_textEditor->textCursor();
return cursor.selectedText();
} else {
return webPreviewer->selectedText();
}
}
void VEditTab::clearFindSelectionInWebView()
{
if (webPreviewer) {
webPreviewer->findText("");
}
}

View File

@ -38,6 +38,16 @@ public:
void scrollToAnchor(const VAnchor& anchor); void scrollToAnchor(const VAnchor& anchor);
inline VFile *getFile(); inline VFile *getFile();
void insertImage(); void insertImage();
// Search @p_text in current note.
void findText(const QString &p_text, uint p_options, bool p_peek,
bool p_forward = true);
// Replace @p_text with @p_replaceText in current note.
void replaceText(const QString &p_text, uint p_options,
const QString &p_replaceText, bool p_findNext);
void replaceTextAll(const QString &p_text, uint p_options,
const QString &p_replaceText);
QString getSelectedText() const;
void clearFindSelectionInWebView();
signals: signals:
void getFocused(); void getFocused();
@ -65,6 +75,8 @@ private:
void parseTocUl(QXmlStreamReader &xml, QVector<VHeader> &headers, int level); void parseTocUl(QXmlStreamReader &xml, QVector<VHeader> &headers, int level);
void parseTocLi(QXmlStreamReader &xml, QVector<VHeader> &headers, int level); void parseTocLi(QXmlStreamReader &xml, QVector<VHeader> &headers, int level);
void scrollPreviewToHeader(int p_outlineIndex); void scrollPreviewToHeader(int p_outlineIndex);
void findTextInWebView(const QString &p_text, uint p_options, bool p_peek,
bool p_forward);
QPointer<VFile> m_file; QPointer<VFile> m_file;
bool isEditMode; bool isEditMode;

View File

@ -362,6 +362,7 @@ void VEditWindow::focusWindow()
int idx = currentIndex(); int idx = currentIndex();
if (idx == -1) { if (idx == -1) {
setFocus(); setFocus();
emit getFocused();
return; return;
} }
getTab(idx)->focusTab(); getTab(idx)->focusTab();
@ -375,7 +376,7 @@ void VEditWindow::handleTabbarClicked(int /* index */)
void VEditWindow::mousePressEvent(QMouseEvent *event) void VEditWindow::mousePressEvent(QMouseEvent *event)
{ {
emit getFocused(); focusWindow();
QTabWidget::mousePressEvent(event); QTabWidget::mousePressEvent(event);
} }
@ -705,3 +706,11 @@ void VEditWindow::setCurrentWindow(bool p_current)
leftBtn->setIcon(QIcon(":/resources/icons/corner_tablist.svg")); leftBtn->setIcon(QIcon(":/resources/icons/corner_tablist.svg"));
} }
} }
void VEditWindow::clearFindSelectionInWebView()
{
int nrTab = count();
for (int i = 0; i < nrTab; ++i) {
getTab(i)->clearFindSelectionInWebView();
}
}

View File

@ -45,6 +45,7 @@ public:
bool addEditTab(QWidget *p_widget); bool addEditTab(QWidget *p_widget);
// Set whether it is the current window. // Set whether it is the current window.
void setCurrentWindow(bool p_current); void setCurrentWindow(bool p_current);
void clearFindSelectionInWebView();
protected: protected:
void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE; void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;

View File

@ -48,6 +48,7 @@ void VMainWindow::setupUI()
editArea = new VEditArea(vnote); editArea = new VEditArea(vnote);
editArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); editArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
m_findReplaceDialog = editArea->getFindReplaceDialog();
fileList->setEditArea(editArea); fileList->setEditArea(editArea);
directoryTree->setEditArea(editArea); directoryTree->setEditArea(editArea);
notebookSelector->setEditArea(editArea); notebookSelector->setEditArea(editArea);
@ -79,10 +80,12 @@ void VMainWindow::setupUI()
editArea, &VEditArea::handleFileUpdated); editArea, &VEditArea::handleFileUpdated);
connect(editArea, &VEditArea::curTabStatusChanged, connect(editArea, &VEditArea::curTabStatusChanged,
this, &VMainWindow::handleCurTabStatusChanged); this, &VMainWindow::handleCurTabStatusChanged);
connect(m_findReplaceDialog, &VFindReplaceDialog::findTextChanged,
this, &VMainWindow::handleFindDialogTextChanged);
setCentralWidget(mainSplitter); setCentralWidget(mainSplitter);
// TODO: Create and show the status bar // Create and show the status bar
// statusBar(); statusBar();
} }
QWidget *VMainWindow::setupDirectoryPanel() QWidget *VMainWindow::setupDirectoryPanel()
@ -179,7 +182,7 @@ void VMainWindow::initFileToolBar()
newNoteAct = new QAction(QIcon(":/resources/icons/create_note_tb.svg"), newNoteAct = new QAction(QIcon(":/resources/icons/create_note_tb.svg"),
tr("New &Note"), this); tr("New &Note"), this);
newNoteAct->setStatusTip(tr("Create a note in current directory")); newNoteAct->setStatusTip(tr("Create a note in current directory"));
newNoteAct->setShortcut(QKeySequence("Ctrl+N")); newNoteAct->setShortcut(QKeySequence::New);
connect(newNoteAct, &QAction::triggered, connect(newNoteAct, &QAction::triggered,
fileList, &VFileList::newFile); fileList, &VFileList::newFile);
@ -325,13 +328,49 @@ void VMainWindow::initEditMenu()
{ {
QMenu *editMenu = menuBar()->addMenu(tr("&Edit")); QMenu *editMenu = menuBar()->addMenu(tr("&Edit"));
// Inser image. // Insert image.
QAction *insertImageAct = new QAction(QIcon(":/resources/icons/insert_image.svg"), m_insertImageAct = new QAction(QIcon(":/resources/icons/insert_image.svg"),
tr("Insert &Image"), this); tr("Insert &Image"), this);
insertImageAct->setStatusTip(tr("Insert an image from file in current note")); m_insertImageAct->setStatusTip(tr("Insert an image from file in current note"));
connect(insertImageAct, &QAction::triggered, connect(m_insertImageAct, &QAction::triggered,
this, &VMainWindow::insertImage); this, &VMainWindow::insertImage);
// Find/Replace.
m_findReplaceAct = new QAction(QIcon(":/resources/icons/find_replace.svg"),
tr("Find/Replace"), this);
m_findReplaceAct->setStatusTip(tr("Open Find/Replace dialog to search in current note"));
m_findReplaceAct->setShortcut(QKeySequence::Find);
connect(m_findReplaceAct, &QAction::triggered,
this, &VMainWindow::openFindDialog);
m_findNextAct = new QAction(tr("Find Next"), this);
m_findNextAct->setStatusTip(tr("Find next occurence"));
m_findNextAct->setShortcut(QKeySequence::FindNext);
connect(m_findNextAct, SIGNAL(triggered(bool)),
m_findReplaceDialog, SLOT(findNext()));
m_findPreviousAct = new QAction(tr("Find Previous"), this);
m_findPreviousAct->setStatusTip(tr("Find previous occurence"));
m_findPreviousAct->setShortcut(QKeySequence::FindPrevious);
connect(m_findPreviousAct, SIGNAL(triggered(bool)),
m_findReplaceDialog, SLOT(findPrevious()));
m_replaceAct = new QAction(tr("Replace"), this);
m_replaceAct->setStatusTip(tr("Replace current occurence"));
m_replaceAct->setShortcut(QKeySequence::Replace);
connect(m_replaceAct, SIGNAL(triggered(bool)),
m_findReplaceDialog, SLOT(replace()));
m_replaceFindAct = new QAction(tr("Replace && Find"), this);
m_replaceFindAct->setStatusTip(tr("Replace current occurence and find the next one"));
connect(m_replaceFindAct, SIGNAL(triggered(bool)),
m_findReplaceDialog, SLOT(replaceFind()));
m_replaceAllAct = new QAction(tr("Replace All"), this);
m_replaceAllAct->setStatusTip(tr("Replace all occurences in current note"));
connect(m_replaceAllAct, SIGNAL(triggered(bool)),
m_findReplaceDialog, SLOT(replaceAll()));
// Expand Tab into spaces. // Expand Tab into spaces.
QAction *expandTabAct = new QAction(tr("&Expand Tab"), this); QAction *expandTabAct = new QAction(tr("&Expand Tab"), this);
expandTabAct->setStatusTip(tr("Expand entered tab to spaces")); expandTabAct->setStatusTip(tr("Expand entered tab to spaces"));
@ -364,8 +403,25 @@ void VMainWindow::initEditMenu()
this, &VMainWindow::changeHighlightCursorLine); this, &VMainWindow::changeHighlightCursorLine);
editMenu->addAction(insertImageAct); editMenu->addAction(m_insertImageAct);
editMenu->addSeparator(); editMenu->addSeparator();
m_insertImageAct->setEnabled(false);
QMenu *findReplaceMenu = editMenu->addMenu(tr("Find/Replace"));
findReplaceMenu->addAction(m_findReplaceAct);
findReplaceMenu->addAction(m_findNextAct);
findReplaceMenu->addAction(m_findPreviousAct);
findReplaceMenu->addAction(m_replaceAct);
findReplaceMenu->addAction(m_replaceFindAct);
findReplaceMenu->addAction(m_replaceAllAct);
editMenu->addSeparator();
m_findReplaceAct->setEnabled(false);
m_findNextAct->setEnabled(false);
m_findPreviousAct->setEnabled(false);
m_replaceAct->setEnabled(false);
m_replaceFindAct->setEnabled(false);
m_replaceAllAct->setEnabled(false);
editMenu->addAction(expandTabAct); editMenu->addAction(expandTabAct);
if (vconfig.getIsExpandTab()) { if (vconfig.getIsExpandTab()) {
expandTabAct->setChecked(true); expandTabAct->setChecked(true);
@ -588,36 +644,56 @@ void VMainWindow::setRenderBackgroundColor(QAction *action)
vnote->updateTemplate(); vnote->updateTemplate();
} }
void VMainWindow::updateToolbarFromTabChage(const VFile *p_file, bool p_editMode) void VMainWindow::updateActionStateFromTabStatusChange(const VFile *p_file,
bool p_editMode)
{ {
qDebug() << "update toolbar"; if (p_file) {
if (!p_file) { if (p_editMode) {
editNoteAct->setVisible(false);
saveExitAct->setVisible(true);
saveNoteAct->setVisible(true);
deleteNoteAct->setEnabled(true);
m_insertImageAct->setEnabled(true);
} else {
editNoteAct->setVisible(true);
saveExitAct->setVisible(false);
saveNoteAct->setVisible(false);
deleteNoteAct->setEnabled(true);
m_insertImageAct->setEnabled(false);
m_replaceAct->setEnabled(false);
m_replaceFindAct->setEnabled(false);
m_replaceAllAct->setEnabled(false);
}
noteInfoAct->setEnabled(true);
m_findReplaceAct->setEnabled(true);
} else {
editNoteAct->setVisible(false); editNoteAct->setVisible(false);
saveExitAct->setVisible(false); saveExitAct->setVisible(false);
saveNoteAct->setVisible(false); saveNoteAct->setVisible(false);
deleteNoteAct->setEnabled(false); deleteNoteAct->setEnabled(false);
} else if (p_editMode) {
editNoteAct->setVisible(false);
saveExitAct->setVisible(true);
saveNoteAct->setVisible(true);
deleteNoteAct->setEnabled(true);
} else {
editNoteAct->setVisible(true);
saveExitAct->setVisible(false);
saveNoteAct->setVisible(false);
deleteNoteAct->setEnabled(true);
}
if (p_file) {
noteInfoAct->setEnabled(true);
} else {
noteInfoAct->setEnabled(false); noteInfoAct->setEnabled(false);
m_insertImageAct->setEnabled(false);
// Find/Replace
m_findReplaceAct->setEnabled(false);
m_findNextAct->setEnabled(false);
m_findPreviousAct->setEnabled(false);
m_replaceAct->setEnabled(false);
m_replaceFindAct->setEnabled(false);
m_replaceAllAct->setEnabled(false);
m_findReplaceDialog->closeDialog();
} }
} }
void VMainWindow::handleCurTabStatusChanged(const VFile *p_file, const VEditTab *p_editTab, bool p_editMode) void VMainWindow::handleCurTabStatusChanged(const VFile *p_file, const VEditTab *p_editTab, bool p_editMode)
{ {
updateToolbarFromTabChage(p_file, p_editMode); updateActionStateFromTabStatusChange(p_file, p_editMode);
if (p_file) {
m_findReplaceDialog->updateState(p_file->getDocType(), p_editMode);
}
QString title; QString title;
if (p_file) { if (p_file) {
@ -761,7 +837,7 @@ void VMainWindow::resizeEvent(QResizeEvent *event)
void VMainWindow::keyPressEvent(QKeyEvent *event) void VMainWindow::keyPressEvent(QKeyEvent *event)
{ {
if (event->key() == Qt::Key_Escape) { if (event->key() == Qt::Key_Escape) {
editArea->getFindReplaceDialog()->closeDialog(); m_findReplaceDialog->closeDialog();
event->accept(); event->accept();
return; return;
} }
@ -809,3 +885,21 @@ void VMainWindow::locateFile(VFile *p_file) const
} }
} }
void VMainWindow::handleFindDialogTextChanged(const QString &p_text, uint /* p_options */)
{
bool enabled = true;
if (p_text.isEmpty()) {
enabled = false;
}
m_findNextAct->setEnabled(enabled);
m_findPreviousAct->setEnabled(enabled);
m_replaceAct->setEnabled(enabled);
m_replaceFindAct->setEnabled(enabled);
m_replaceAllAct->setEnabled(enabled);
}
void VMainWindow::openFindDialog()
{
m_findReplaceDialog->openDialog(editArea->getSelectedText());
}

View File

@ -27,6 +27,7 @@ class QToolBox;
class VOutline; class VOutline;
class VNotebookSelector; class VNotebookSelector;
class VAvatar; class VAvatar;
class VFindReplaceDialog;
class VMainWindow : public QMainWindow class VMainWindow : public QMainWindow
{ {
@ -55,6 +56,8 @@ private slots:
void handleCurrentDirectoryChanged(const VDirectory *p_dir); void handleCurrentDirectoryChanged(const VDirectory *p_dir);
void handleCurrentNotebookChanged(const VNotebook *p_notebook); void handleCurrentNotebookChanged(const VNotebook *p_notebook);
void insertImage(); void insertImage();
void handleFindDialogTextChanged(const QString &p_text, uint p_options);
void openFindDialog();
protected: protected:
void closeEvent(QCloseEvent *event) Q_DECL_OVERRIDE; void closeEvent(QCloseEvent *event) Q_DECL_OVERRIDE;
@ -83,7 +86,8 @@ private:
void initEditorBackgroundMenu(QMenu *menu); void initEditorBackgroundMenu(QMenu *menu);
void changeSplitterView(int nrPanel); void changeSplitterView(int nrPanel);
void updateWindowTitle(const QString &str); void updateWindowTitle(const QString &str);
void updateToolbarFromTabChage(const VFile *p_file, bool p_editMode); void updateActionStateFromTabStatusChange(const VFile *p_file,
bool p_editMode);
void saveStateAndGeometry(); void saveStateAndGeometry();
void restoreStateAndGeometry(); void restoreStateAndGeometry();
void repositionAvatar(); void repositionAvatar();
@ -103,6 +107,7 @@ private:
QToolBox *toolBox; QToolBox *toolBox;
VOutline *outline; VOutline *outline;
VAvatar *m_avatar; VAvatar *m_avatar;
VFindReplaceDialog *m_findReplaceDialog;
// Actions // Actions
QAction *newRootDirAct; QAction *newRootDirAct;
@ -115,6 +120,14 @@ private:
QAction *discardExitAct; QAction *discardExitAct;
QAction *expandViewAct; QAction *expandViewAct;
QAction *m_insertImageAct;
QAction *m_findReplaceAct;
QAction *m_findNextAct;
QAction *m_findPreviousAct;
QAction *m_replaceAct;
QAction *m_replaceFindAct;
QAction *m_replaceAllAct;
// Menus // Menus
QMenu *viewMenu; QMenu *viewMenu;

View File

@ -287,6 +287,7 @@ bool VMdEditOperations::handleKeyBracketLeft(QKeyEvent *p_event)
// 1. If it is not in Normal state, just go back to Normal state; // 1. If it is not in Normal state, just go back to Normal state;
// 2. If it is already Normal state, try to clear selection; // 2. If it is already Normal state, try to clear selection;
// 3. Anyway, we accept this event. // 3. Anyway, we accept this event.
bool accept = false;
if (p_event->modifiers() == Qt::ControlModifier) { if (p_event->modifiers() == Qt::ControlModifier) {
if (m_keyState != KeyState::Normal) { if (m_keyState != KeyState::Normal) {
m_pendingTimer->stop(); m_pendingTimer->stop();
@ -299,9 +300,12 @@ bool VMdEditOperations::handleKeyBracketLeft(QKeyEvent *p_event)
m_editor->setTextCursor(cursor); m_editor->setTextCursor(cursor);
} }
} }
accept = true;
} }
p_event->accept(); if (accept) {
return true; p_event->accept();
}
return accept;
} }
bool VMdEditOperations::handleKeyTab(QKeyEvent *p_event) bool VMdEditOperations::handleKeyTab(QKeyEvent *p_event)

View File

@ -82,5 +82,6 @@
<file>resources/icons/corner_menu_cur.svg</file> <file>resources/icons/corner_menu_cur.svg</file>
<file>resources/icons/corner_tablist_cur.svg</file> <file>resources/icons/corner_tablist_cur.svg</file>
<file>resources/icons/close.svg</file> <file>resources/icons/close.svg</file>
<file>resources/icons/find_replace.svg</file>
</qresource> </qresource>
</RCC> </RCC>