mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 05:49:53 +08:00
support search wrap
Signed-off-by: Le Tan <tamlokveer@gmail.com>
This commit is contained in:
parent
7ed92ed7eb
commit
3769ac5311
@ -22,7 +22,7 @@ void VFindReplaceDialog::setupUI()
|
||||
titleLayout->setSpacing(0);
|
||||
|
||||
// Find
|
||||
QLabel *findLabel = new QLabel(tr("&Find:"));
|
||||
QLabel *findLabel = new QLabel(tr("Find:"));
|
||||
m_findEdit = new QLineEdit();
|
||||
m_findEdit->setPlaceholderText(tr("Enter text to search"));
|
||||
findLabel->setBuddy(m_findEdit);
|
||||
@ -37,7 +37,7 @@ void VFindReplaceDialog::setupUI()
|
||||
m_replaceEdit = new QLineEdit();
|
||||
m_replaceEdit->setPlaceholderText(tr("Enter text to replace with"));
|
||||
replaceLabel->setBuddy(m_replaceEdit);
|
||||
m_replaceBtn = new QPushButton(tr("R&eplace"));
|
||||
m_replaceBtn = new QPushButton(tr("Replace"));
|
||||
m_replaceBtn->setProperty("FlatBtn", true);
|
||||
m_replaceFindBtn = new QPushButton(tr("Replace && Fin&d"));
|
||||
m_replaceFindBtn->setProperty("FlatBtn", true);
|
||||
|
14
src/resources/icons/search_wrap.svg
Normal file
14
src/resources/icons/search_wrap.svg
Normal file
@ -0,0 +1,14 @@
|
||||
<?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">
|
||||
<g>
|
||||
<path d="M273.4,300.5l-0.3,58c48.9-8.2,86.3-51,86.3-102.5c0-15.9-3.6-31-10-44.5c-2.8-5.8-6-11.3-9.8-16.5l47.1-43.5
|
||||
c1.1,1.3,2.1,2.7,3.1,4c20.9,28,33.2,62.8,33.2,100.5c0,1.2,0,2.5,0,3.7c-1.5,71.5-47.6,132-111.4,154.6
|
||||
c-12.3,4.3-25.2,7.3-38.5,8.7l-0.1,57l-76.2-67L170.6,390l44.4-38.7L273.4,300.5z"/>
|
||||
<path d="M89,252.3c1.6-72.1,48.3-133,112.9-155.2c11.7-4,24-6.8,36.8-8.1l0.1-57l76.1,66.9l26.2,23.1l-44.3,38.6l-58.4,50.9
|
||||
l0.2-57.9c-48.8,8.3-86,51.1-86,102.4c0,16,3.6,31.1,10.1,44.7c2.7,5.8,6,11.2,9.7,16.3l-47,43.6c-1.3-1.6-2.6-3.3-3.8-5
|
||||
C101.1,327.7,89,293.3,89,256C89,254.8,89,253.5,89,252.3z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
256
src/vedit.cpp
256
src/vedit.cpp
@ -14,6 +14,18 @@ extern VConfigManager vconfig;
|
||||
VEdit::VEdit(VFile *p_file, QWidget *p_parent)
|
||||
: QTextEdit(p_parent), m_file(p_file), m_editOps(NULL)
|
||||
{
|
||||
const int labelTimerInterval = 500;
|
||||
const int labelSize = 64;
|
||||
|
||||
QPixmap wrapPixmap(":/resources/icons/search_wrap.svg");
|
||||
m_wrapLabel = new QLabel(this);
|
||||
m_wrapLabel->setPixmap(wrapPixmap.scaled(labelSize, labelSize));
|
||||
m_wrapLabel->hide();
|
||||
m_labelTimer = new QTimer(this);
|
||||
m_labelTimer->setSingleShot(true);
|
||||
m_labelTimer->setInterval(labelTimerInterval);
|
||||
connect(m_labelTimer, &QTimer::timeout,
|
||||
this, &VEdit::labelTimerTimeout);
|
||||
connect(document(), &QTextDocument::modificationChanged,
|
||||
(VFile *)m_file, &VFile::setModified);
|
||||
}
|
||||
@ -85,14 +97,13 @@ void VEdit::insertImage()
|
||||
}
|
||||
}
|
||||
|
||||
bool VEdit::findText(const QString &p_text, uint p_options, bool p_peek,
|
||||
bool p_forward)
|
||||
bool VEdit::peekText(const QString &p_text, uint p_options)
|
||||
{
|
||||
static int startPos = textCursor().selectionStart();
|
||||
static int lastPos = startPos;
|
||||
bool found = false;
|
||||
|
||||
if (p_text.isEmpty() && p_peek) {
|
||||
if (p_text.isEmpty()) {
|
||||
// Clear previous selection
|
||||
QTextCursor cursor = textCursor();
|
||||
cursor.clearSelection();
|
||||
@ -100,149 +111,186 @@ bool VEdit::findText(const QString &p_text, uint p_options, bool p_peek,
|
||||
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);
|
||||
int curPos = cursor.selectionStart();
|
||||
if (curPos != lastPos) {
|
||||
// Cursor has been moved. Just start at current potition.
|
||||
startPos = curPos;
|
||||
lastPos = curPos;
|
||||
} else {
|
||||
cursor.setPosition(startPos);
|
||||
setTextCursor(cursor);
|
||||
}
|
||||
}
|
||||
bool wrapped = false;
|
||||
found = findTextHelper(p_text, p_options, true, wrapped);
|
||||
if (found) {
|
||||
lastPos = textCursor().selectionStart();
|
||||
found = true;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
bool VEdit::findTextHelper(const QString &p_text, uint p_options,
|
||||
bool p_forward, bool &p_wrapped)
|
||||
{
|
||||
p_wrapped = false;
|
||||
bool found = false;
|
||||
|
||||
// Options
|
||||
QTextDocument::FindFlags findFlags;
|
||||
bool caseSensitive = false;
|
||||
if (p_options & FindOption::CaseSensitive) {
|
||||
findFlags |= QTextDocument::FindCaseSensitively;
|
||||
caseSensitive = true;
|
||||
}
|
||||
if (p_options & FindOption::WholeWordOnly) {
|
||||
findFlags |= QTextDocument::FindWholeWords;
|
||||
}
|
||||
if (!p_forward) {
|
||||
findFlags |= QTextDocument::FindBackward;
|
||||
}
|
||||
// Use regular expression
|
||||
bool useRegExp = false;
|
||||
QRegExp exp;
|
||||
if (p_options & FindOption::RegularExpression) {
|
||||
useRegExp = true;
|
||||
exp = QRegExp(p_text,
|
||||
caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive);
|
||||
}
|
||||
QTextCursor cursor = textCursor();
|
||||
while (!found) {
|
||||
if (useRegExp) {
|
||||
found = find(exp, findFlags);
|
||||
} else {
|
||||
found = find(p_text, findFlags);
|
||||
}
|
||||
if (p_wrapped) {
|
||||
if (!found) {
|
||||
setTextCursor(cursor);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Options
|
||||
QTextDocument::FindFlags flags;
|
||||
if (p_options & FindOption::CaseSensitive) {
|
||||
flags |= QTextDocument::FindCaseSensitively;
|
||||
if (!found) {
|
||||
// Wrap to the other end of the document to search again.
|
||||
p_wrapped = true;
|
||||
QTextCursor wrapCursor = textCursor();
|
||||
wrapCursor.clearSelection();
|
||||
if (p_forward) {
|
||||
wrapCursor.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor);
|
||||
} else {
|
||||
wrapCursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor);
|
||||
}
|
||||
setTextCursor(wrapCursor);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
bool VEdit::findText(const QString &p_text, uint p_options, bool p_forward)
|
||||
{
|
||||
bool found = false;
|
||||
if (p_text.isEmpty()) {
|
||||
QTextCursor cursor = textCursor();
|
||||
cursor.clearSelection();
|
||||
setTextCursor(cursor);
|
||||
} else {
|
||||
bool wrapped = false;
|
||||
found = findTextHelper(p_text, p_options, p_forward, wrapped);
|
||||
if (found && wrapped) {
|
||||
showWrapLabel();
|
||||
}
|
||||
}
|
||||
qDebug() << "findText" << p_text << p_options << p_forward
|
||||
<< (found ? "Found" : "NotFound");
|
||||
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);
|
||||
QTextCursor tmpCursor = cursor;
|
||||
tmpCursor.setPosition(tmpCursor.selectionStart());
|
||||
tmpCursor.clearSelection();
|
||||
setTextCursor(tmpCursor);
|
||||
bool wrapped = false;
|
||||
bool found = findTextHelper(p_text, p_options, true, wrapped);
|
||||
bool matched = false;
|
||||
if (found) {
|
||||
tmpCursor = textCursor();
|
||||
matched = (cursor.selectionStart() == tmpCursor.selectionStart())
|
||||
&& (cursor.selectionEnd() == tmpCursor.selectionEnd());
|
||||
}
|
||||
bool matched = (cursor.selectionStart() == matchCursor.selectionStart())
|
||||
&& (cursor.selectionEnd() == matchCursor.selectionEnd());
|
||||
if (matched) {
|
||||
cursor.beginEditBlock();
|
||||
cursor.removeSelectedText();
|
||||
cursor.insertText(p_replaceText);
|
||||
cursor.endEditBlock();
|
||||
setTextCursor(cursor);
|
||||
} else {
|
||||
setTextCursor(cursor);
|
||||
}
|
||||
}
|
||||
if (p_findNext) {
|
||||
findText(p_text, p_options, false, true);
|
||||
findText(p_text, p_options, 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);
|
||||
}
|
||||
|
||||
// Replace from the start to the end and resotre the cursor.
|
||||
QTextCursor cursor = textCursor();
|
||||
int pos = cursor.position();
|
||||
int nrReplaces = 0;
|
||||
int startPos = 0;
|
||||
int lastMatch = -1;
|
||||
QTextCursor tmpCursor = cursor;
|
||||
tmpCursor.setPosition(0);
|
||||
setTextCursor(tmpCursor);
|
||||
while (true) {
|
||||
QTextCursor matchCursor;
|
||||
if (useRegExp) {
|
||||
matchCursor = document()->find(exp, startPos, flags);
|
||||
} else {
|
||||
matchCursor = document()->find(p_text, startPos, flags);
|
||||
}
|
||||
if (matchCursor.isNull()) {
|
||||
bool wrapped = false;
|
||||
bool found = findTextHelper(p_text, p_options, true, wrapped);
|
||||
if (!found) {
|
||||
break;
|
||||
} else {
|
||||
if (matchCursor.selectionStart() <= lastMatch) {
|
||||
if (wrapped) {
|
||||
// Wrap back.
|
||||
break;
|
||||
} else {
|
||||
lastMatch = matchCursor.selectionStart();
|
||||
}
|
||||
nrReplaces++;
|
||||
matchCursor.beginEditBlock();
|
||||
matchCursor.removeSelectedText();
|
||||
matchCursor.insertText(p_replaceText);
|
||||
matchCursor.endEditBlock();
|
||||
setTextCursor(matchCursor);
|
||||
startPos = matchCursor.position();
|
||||
tmpCursor = textCursor();
|
||||
tmpCursor.beginEditBlock();
|
||||
tmpCursor.removeSelectedText();
|
||||
tmpCursor.insertText(p_replaceText);
|
||||
tmpCursor.endEditBlock();
|
||||
setTextCursor(tmpCursor);
|
||||
}
|
||||
}
|
||||
// Restore cursor position.
|
||||
cursor.setPosition(pos);
|
||||
cursor.clearSelection();
|
||||
setTextCursor(cursor);
|
||||
qDebug() << "replace all" << nrReplaces << "occurencs";
|
||||
qDebug() << "replace all" << nrReplaces << "occurences";
|
||||
}
|
||||
|
||||
void VEdit::showWrapLabel()
|
||||
{
|
||||
int labelW = m_wrapLabel->width();
|
||||
int labelH = m_wrapLabel->height();
|
||||
int x = (width() - labelW) / 2;
|
||||
int y = (height() - labelH) / 2;
|
||||
if (x < 0) {
|
||||
x = 0;
|
||||
}
|
||||
if (y < 0) {
|
||||
y = 0;
|
||||
}
|
||||
m_wrapLabel->move(x, y);
|
||||
m_wrapLabel->show();
|
||||
m_labelTimer->stop();
|
||||
m_labelTimer->start();
|
||||
}
|
||||
|
||||
void VEdit::labelTimerTimeout()
|
||||
{
|
||||
m_wrapLabel->hide();
|
||||
}
|
||||
|
25
src/vedit.h
25
src/vedit.h
@ -9,6 +9,8 @@
|
||||
#include "vfile.h"
|
||||
|
||||
class VEditOperations;
|
||||
class QLabel;
|
||||
class QTimer;
|
||||
|
||||
class VEdit : public QTextEdit
|
||||
{
|
||||
@ -26,16 +28,27 @@ public:
|
||||
virtual void scrollToLine(int p_lineNumber);
|
||||
// User requests to insert an image.
|
||||
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);
|
||||
bool findTextHelper(const QString &p_text, uint p_options,
|
||||
bool p_forward, bool &p_wrapped);
|
||||
bool peekText(const QString &p_text, uint p_options);
|
||||
bool findText(const QString &p_text, uint p_options, bool p_forward);
|
||||
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);
|
||||
|
||||
private slots:
|
||||
void labelTimerTimeout();
|
||||
|
||||
protected:
|
||||
QPointer<VFile> m_file;
|
||||
VEditOperations *m_editOps;
|
||||
|
||||
private:
|
||||
QLabel *m_wrapLabel;
|
||||
QTimer *m_labelTimer;
|
||||
|
||||
void showWrapLabel();
|
||||
};
|
||||
|
||||
|
||||
|
@ -463,7 +463,11 @@ 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);
|
||||
if (p_peek) {
|
||||
m_textEditor->peekText(p_text, p_options);
|
||||
} else {
|
||||
m_textEditor->findText(p_text, p_options, p_forward);
|
||||
}
|
||||
} else {
|
||||
findTextInWebView(p_text, p_options, p_peek, p_forward);
|
||||
}
|
||||
@ -486,7 +490,7 @@ void VEditTab::replaceTextAll(const QString &p_text, uint p_options,
|
||||
}
|
||||
|
||||
void VEditTab::findTextInWebView(const QString &p_text, uint p_options,
|
||||
bool p_peek, bool p_forward)
|
||||
bool /* p_peek */, bool p_forward)
|
||||
{
|
||||
Q_ASSERT(webPreviewer);
|
||||
QWebEnginePage::FindFlags flags;
|
||||
|
@ -83,5 +83,6 @@
|
||||
<file>resources/icons/corner_tablist_cur.svg</file>
|
||||
<file>resources/icons/close.svg</file>
|
||||
<file>resources/icons/find_replace.svg</file>
|
||||
<file>resources/icons/search_wrap.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
Loading…
x
Reference in New Issue
Block a user