diff --git a/src/dialog/vfindreplacedialog.cpp b/src/dialog/vfindreplacedialog.cpp
index 937736bd..69b01eff 100644
--- a/src/dialog/vfindreplacedialog.cpp
+++ b/src/dialog/vfindreplacedialog.cpp
@@ -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);
diff --git a/src/resources/icons/search_wrap.svg b/src/resources/icons/search_wrap.svg
new file mode 100644
index 00000000..865781ed
--- /dev/null
+++ b/src/resources/icons/search_wrap.svg
@@ -0,0 +1,14 @@
+
+
+
+
diff --git a/src/vedit.cpp b/src/vedit.cpp
index 61811b56..f28ffecb 100644
--- a/src/vedit.cpp
+++ b/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();
+}
diff --git a/src/vedit.h b/src/vedit.h
index 18708360..4e2daa46 100644
--- a/src/vedit.h
+++ b/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 m_file;
VEditOperations *m_editOps;
+
+private:
+ QLabel *m_wrapLabel;
+ QTimer *m_labelTimer;
+
+ void showWrapLabel();
};
diff --git a/src/vedittab.cpp b/src/vedittab.cpp
index c899f5ca..4845f7f0 100644
--- a/src/vedittab.cpp
+++ b/src/vedittab.cpp
@@ -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;
diff --git a/src/vnote.qrc b/src/vnote.qrc
index 82cef341..b0d2d2b5 100644
--- a/src/vnote.qrc
+++ b/src/vnote.qrc
@@ -83,5 +83,6 @@
resources/icons/corner_tablist_cur.svg
resources/icons/close.svg
resources/icons/find_replace.svg
+ resources/icons/search_wrap.svg