diff --git a/src/dialog/vfindreplacedialog.cpp b/src/dialog/vfindreplacedialog.cpp index 11a3f763..2e713448 100644 --- a/src/dialog/vfindreplacedialog.cpp +++ b/src/dialog/vfindreplacedialog.cpp @@ -307,3 +307,8 @@ void VFindReplaceDialog::updateState(DocType p_docType, bool p_editMode) m_replaceAvailable = p_editMode; } + +QString VFindReplaceDialog::textToFind() const +{ + return m_findEdit->text(); +} diff --git a/src/dialog/vfindreplacedialog.h b/src/dialog/vfindreplacedialog.h index 8b6d09b3..740839c2 100644 --- a/src/dialog/vfindreplacedialog.h +++ b/src/dialog/vfindreplacedialog.h @@ -14,11 +14,17 @@ class VFindReplaceDialog : public QWidget Q_OBJECT public: explicit VFindReplaceDialog(QWidget *p_parent = 0); + + uint options() const; + 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); + QString textToFind() const; + signals: void dialogClosed(); void findTextChanged(const QString &p_text, uint p_options); @@ -68,4 +74,8 @@ private: QCheckBox *m_incrementalSearchCheck; }; +inline uint VFindReplaceDialog::options() const +{ + return m_options; +} #endif // VFINDREPLACEDIALOG_H diff --git a/src/resources/docs/shortcuts_en.md b/src/resources/docs/shortcuts_en.md index 53a4d353..ce7d4e0e 100644 --- a/src/resources/docs/shortcuts_en.md +++ b/src/resources/docs/shortcuts_en.md @@ -25,6 +25,8 @@ Open Flash Page. Edit current note or save changes and exit edit mode. - `Ctrl+G` Activate Universal Entry. +- `Ctrl+8`/`Ctrl+9` +Jump to the next/previous match in last find action. ### Read Mode - `H`/`J`/`K`/`L` diff --git a/src/resources/docs/shortcuts_zh.md b/src/resources/docs/shortcuts_zh.md index b786a0f8..35e0a5c0 100644 --- a/src/resources/docs/shortcuts_zh.md +++ b/src/resources/docs/shortcuts_zh.md @@ -25,6 +25,8 @@ 编辑当前笔记或保存更改并退出编辑模式。 - `Ctrl+G` 激活通用入口。 +- `Ctrl+8`/`Ctrl+9` +跳转到最近一次查找的下一个/上一个匹配。 ### 阅读模式 - `H`/`J`/`K`/`L` diff --git a/src/resources/vnote.ini b/src/resources/vnote.ini index cb6e4b30..8537acc3 100644 --- a/src/resources/vnote.ini +++ b/src/resources/vnote.ini @@ -391,6 +391,10 @@ Find=Ctrl+F FindNext=F3 ; Find previous occurence FindPrevious=Shift+F3 +; Jump to next match of last find +NextMatch=Ctrl+8 +; Jump to previous match of last find +PreviousMatch=Ctrl+9 ; Advanced find AdvancedFind=Ctrl+Alt+F ; Recover last closed file diff --git a/src/veditarea.cpp b/src/veditarea.cpp index b002d148..c8a240fa 100644 --- a/src/veditarea.cpp +++ b/src/veditarea.cpp @@ -35,29 +35,7 @@ VEditArea::VEditArea(QWidget *parent) registerCaptainTargets(); - QString keySeq = g_config->getShortcutKeySequence("ActivateNextTab"); - qDebug() << "set ActivateNextTab shortcut to" << keySeq; - QShortcut *activateNextTab = new QShortcut(QKeySequence(keySeq), this); - activateNextTab->setContext(Qt::ApplicationShortcut); - connect(activateNextTab, &QShortcut::activated, - this, [this]() { - VEditWindow *win = getCurrentWindow(); - if (win) { - win->focusNextTab(true); - } - }); - - keySeq = g_config->getShortcutKeySequence("ActivatePreviousTab"); - qDebug() << "set ActivatePreviousTab shortcut to" << keySeq; - QShortcut *activatePreviousTab = new QShortcut(QKeySequence(keySeq), this); - activatePreviousTab->setContext(Qt::ApplicationShortcut); - connect(activatePreviousTab, &QShortcut::activated, - this, [this]() { - VEditWindow *win = getCurrentWindow(); - if (win) { - win->focusNextTab(false); - } - }); + initShortcuts(); QTimer *timer = new QTimer(this); timer->setSingleShot(false); @@ -130,6 +108,49 @@ void VEditArea::setupUI() }); } +void VEditArea::initShortcuts() +{ + QString keySeq = g_config->getShortcutKeySequence("ActivateNextTab"); + qDebug() << "set ActivateNextTab shortcut to" << keySeq; + QShortcut *activateNextTab = new QShortcut(QKeySequence(keySeq), this); + activateNextTab->setContext(Qt::ApplicationShortcut); + connect(activateNextTab, &QShortcut::activated, + this, [this]() { + VEditWindow *win = getCurrentWindow(); + if (win) { + win->focusNextTab(true); + } + }); + + keySeq = g_config->getShortcutKeySequence("ActivatePreviousTab"); + qDebug() << "set ActivatePreviousTab shortcut to" << keySeq; + QShortcut *activatePreviousTab = new QShortcut(QKeySequence(keySeq), this); + activatePreviousTab->setContext(Qt::ApplicationShortcut); + connect(activatePreviousTab, &QShortcut::activated, + this, [this]() { + VEditWindow *win = getCurrentWindow(); + if (win) { + win->focusNextTab(false); + } + }); + + keySeq = g_config->getShortcutKeySequence("NextMatch"); + qDebug() << "set NextMatch shortcut to" << keySeq; + QShortcut *nextMatchSC = new QShortcut(QKeySequence(keySeq), this); + connect(nextMatchSC, &QShortcut::activated, + this, [this]() { + nextMatch(true); + }); + + keySeq = g_config->getShortcutKeySequence("PreviousMatch"); + qDebug() << "set PreviousMatch shortcut to" << keySeq; + QShortcut *previousMatchSC = new QShortcut(QKeySequence(keySeq), this); + connect(previousMatchSC, &QShortcut::activated, + this, [this]() { + nextMatch(false); + }); +} + void VEditArea::insertSplitWindow(int idx) { VEditWindow *win = new VEditWindow(this); @@ -1277,3 +1298,17 @@ void VEditArea::distributeSplits() splitter->setSizes(sizes); } + +void VEditArea::nextMatch(bool p_forward) +{ + VEditTab *tab = getCurrentTab(); + if (!tab) { + return; + } + + Q_ASSERT(m_findReplace); + + tab->nextMatch(m_findReplace->textToFind(), + m_findReplace->options(), + p_forward); +} diff --git a/src/veditarea.h b/src/veditarea.h index 157dd46a..383e48c8 100644 --- a/src/veditarea.h +++ b/src/veditarea.h @@ -179,9 +179,16 @@ private slots: // Handle the timeout signal of file timer. void handleFileTimerTimeout(); + // Jump to next match of last find. + void nextMatch(bool p_forward); + private: void setupUI(); + + void initShortcuts(); + QVector > findTabsByFile(const VFile *p_file); + int openFileInWindow(int windowIndex, VFile *p_file, OpenFileMode p_mode); void setCurrentTab(int windowIndex, int tabIndex, bool setFocus); void setCurrentWindow(int windowIndex, bool setFocus); diff --git a/src/veditor.cpp b/src/veditor.cpp index 24358c5c..9c30da7a 100644 --- a/src/veditor.cpp +++ b/src/veditor.cpp @@ -56,6 +56,8 @@ void VEditor::init() const int labelSize = 64; m_document = documentW(); + QObject::connect(m_document, &QTextDocument::contentsChanged, + m_object, &VEditorObject::clearFindCache); m_selectedWordFg = QColor(g_config->getEditorSelectedWordFg()); m_selectedWordBg = QColor(g_config->getEditorSelectedWordBg()); @@ -344,7 +346,10 @@ static QTextDocument::FindFlags findOptionsToFlags(uint p_options, bool p_forwar return findFlags; } -QList VEditor::findTextAll(const QString &p_text, uint p_options) +QList VEditor::findTextAll(const QString &p_text, + uint p_options, + int p_start, + int p_end) { QList results; if (p_text.isEmpty()) { @@ -355,35 +360,37 @@ QList VEditor::findTextAll(const QString &p_text, uint p_options) bool caseSensitive = p_options & FindOption::CaseSensitive; QTextDocument::FindFlags findFlags = findOptionsToFlags(p_options, true); - // Use regular expression - bool useRegExp = p_options & FindOption::RegularExpression; - QRegExp exp; - if (useRegExp) { - useRegExp = true; - exp = QRegExp(p_text, - caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive); - } - - int startPos = 0; - QTextCursor cursor; - while (true) { - if (useRegExp) { - cursor = m_document->find(exp, startPos, findFlags); - } else { - cursor = m_document->find(p_text, startPos, findFlags); - } - - if (cursor.isNull()) { - break; - } else { - results.append(cursor); - startPos = cursor.selectionEnd(); - } + if (p_options & FindOption::RegularExpression) { + QRegExp exp(p_text, + caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive); + results = findTextAllInRange(m_document, exp, findFlags, p_start, p_end); + } else { + results = findTextAllInRange(m_document, p_text, findFlags, p_start, p_end); } return results; } +const QList &VEditor::findTextAllCached(const QString &p_text, + uint p_options, + int p_start, + int p_end) +{ + if (p_text.isEmpty()) { + m_findInfo.clear(); + return m_findInfo.m_result; + } + + if (m_findInfo.isCached(p_text, p_options, p_start, p_end)) { + return m_findInfo.m_result; + } + + QList result = findTextAll(p_text, p_options, p_start, p_end); + m_findInfo.update(p_text, p_options, p_start, p_end, result); + + return m_findInfo.m_result; +} + void VEditor::highlightSelectedWord() { QList &selects = m_extraSelections[(int)SelectionId::SelectedWord]; @@ -521,72 +528,146 @@ bool VEditor::peekText(const QString &p_text, uint p_options, bool p_forward) return found; } +// @p_cursors is in ascending order. +// If @p_forward is true, find the smallest cursor whose selection start is greater +// than @p_pos or the first cursor if wrapped. +// Otherwise, find the largest cursor whose selection start is smaller than @p_pos +// or the last cursor if wrapped. +static int selectCursor(const QList &p_cursors, + int p_pos, + bool p_forward, + bool &p_wrapped) +{ + Q_ASSERT(!p_cursors.isEmpty()); + + p_wrapped = false; + + int first = 0, last = p_cursors.size() - 1; + int lastMatch = -1; + while (first <= last) { + int mid = (first + last) / 2; + const QTextCursor &cur = p_cursors.at(mid); + if (p_forward) { + if (cur.selectionStart() < p_pos) { + first = mid + 1; + } else if (cur.selectionStart() == p_pos) { + // Next one is the right one. + if (mid < p_cursors.size() - 1) { + lastMatch = mid + 1; + } else { + lastMatch = 0; + p_wrapped = true; + } + break; + } else { + // It is a match. + if (lastMatch == -1 || mid < lastMatch) { + lastMatch = mid; + } + + last = mid - 1; + } + } else { + if (cur.selectionStart() > p_pos) { + last = mid - 1; + } else if (cur.selectionStart() == p_pos) { + // Previous one is the right one. + if (mid > 0) { + lastMatch = mid - 1; + } else { + lastMatch = p_cursors.size() - 1; + p_wrapped = true; + } + break; + } else { + // It is a match. + if (lastMatch == -1 || mid > lastMatch) { + lastMatch = mid; + } + + first = mid + 1; + } + } + } + + if (lastMatch == -1) { + p_wrapped = true; + lastMatch = p_forward ? 0 : (p_cursors.size() - 1); + } + + return lastMatch; +} + bool VEditor::findText(const QString &p_text, uint p_options, bool p_forward, QTextCursor *p_cursor, QTextCursor::MoveMode p_moveMode, bool p_useLeftSideOfCursor) +{ + return findTextInRange(p_text, + p_options, + p_forward, + p_cursor, + p_moveMode, + p_useLeftSideOfCursor); +} + +bool VEditor::findTextInRange(const QString &p_text, + uint p_options, + bool p_forward, + QTextCursor *p_cursor, + QTextCursor::MoveMode p_moveMode, + bool p_useLeftSideOfCursor, + int p_start, + int p_end) { clearIncrementalSearchedWordHighlight(); if (p_text.isEmpty()) { + m_findInfo.clear(); clearSearchedWordHighlight(); return false; } - QTextCursor cursor = textCursorW(); - bool wrapped = false; - QTextCursor retCursor; - int matches = 0; - int start = p_cursor ? p_cursor->position() : cursor.position(); - if (p_useLeftSideOfCursor) { - --start; - } - int skipPosition = start; + const QList &result = findTextAllCached(p_text, p_options, p_start, p_end); - bool found = false; - while (true) { - found = findTextHelper(p_text, p_options, p_forward, start, wrapped, retCursor); - if (found) { - Q_ASSERT(!retCursor.isNull()); - if (wrapped) { - showWrapLabel(); - } + if (result.isEmpty()) { + clearSearchedWordHighlight(); - if (p_forward && retCursor.selectionStart() == skipPosition) { - // Skip the first match. - skipPosition = -1; - start = retCursor.selectionEnd(); - continue; - } - - if (p_cursor) { - p_cursor->setPosition(retCursor.selectionStart(), p_moveMode); - } else { - cursor.setPosition(retCursor.selectionStart(), p_moveMode); - setTextCursorW(cursor); - } - - highlightSearchedWord(p_text, p_options); - highlightSearchedWordUnderCursor(retCursor); - matches = m_extraSelections[(int)SelectionId::SearchedKeyword].size(); - } else { - clearSearchedWordHighlight(); + emit m_object->statusMessage(QObject::tr("No match found")); + } else { + // Locate to the right match and update current cursor. + QTextCursor cursor = textCursorW(); + int pos = p_cursor ? p_cursor->position() : cursor.position(); + if (p_useLeftSideOfCursor) { + --pos; } - break; + bool wrapped = false; + int idx = selectCursor(result, pos, p_forward, wrapped); + const QTextCursor &tcursor = result.at(idx); + if (wrapped) { + showWrapLabel(); + } + + if (p_cursor) { + p_cursor->setPosition(tcursor.selectionStart(), p_moveMode); + } else { + cursor.setPosition(tcursor.selectionStart(), p_moveMode); + setTextCursorW(cursor); + } + + highlightSearchedWord(result); + + highlightSearchedWordUnderCursor(tcursor); + + emit m_object->statusMessage(QObject::tr("Match found: %2 of %3") + .arg(idx + 1) + .arg(result.size())); } - if (matches == 0) { - emit m_object->statusMessage(QObject::tr("Found no match")); - } else { - emit m_object->statusMessage(QObject::tr("Found %1 %2").arg(matches) - .arg(matches > 1 ? QObject::tr("matches") - : QObject::tr("match"))); - } - - return found; + return !result.isEmpty(); } bool VEditor::findTextOne(const QString &p_text, uint p_options, bool p_forward) @@ -626,10 +707,14 @@ bool VEditor::findTextInRange(const QString &p_text, int p_start, int p_end) { - Q_UNUSED(p_start); - Q_UNUSED(p_end); - // TODO - return findText(p_text, p_options, p_forward); + return findTextInRange(p_text, + p_options, + p_forward, + nullptr, + QTextCursor::MoveAnchor, + false, + p_start, + p_end); } void VEditor::highlightIncrementalSearchedWord(const QTextCursor &p_cursor) @@ -791,10 +876,10 @@ void VEditor::showWrapLabel() m_labelTimer->start(); } -void VEditor::highlightSearchedWord(const QString &p_text, uint p_options) +void VEditor::highlightSearchedWord(const QList &p_matches) { QList &selects = m_extraSelections[(int)SelectionId::SearchedKeyword]; - if (!g_config->getHighlightSearchedWord() || p_text.isEmpty()) { + if (!g_config->getHighlightSearchedWord() || p_matches.isEmpty()) { if (!selects.isEmpty()) { selects.clear(); highlightExtraSelections(true); @@ -803,10 +888,20 @@ void VEditor::highlightSearchedWord(const QString &p_text, uint p_options) return; } + selects.clear(); + QTextCharFormat format; format.setForeground(m_searchedWordFg); format.setBackground(m_searchedWordBg); - highlightTextAll(p_text, p_options, SelectionId::SearchedKeyword, format); + + for (int i = 0; i < p_matches.size(); ++i) { + QTextEdit::ExtraSelection select; + select.format = format; + select.cursor = p_matches[i]; + selects.append(select); + } + + highlightExtraSelections(); } void VEditor::highlightSearchedWordUnderCursor(const QTextCursor &p_cursor) @@ -1297,3 +1392,83 @@ void VEditor::insertCompletion(const QString &p_prefix, const QString &p_complet setTextCursorW(cursor); } + +QList VEditor::findTextAllInRange(const QTextDocument *p_doc, + const QString &p_text, + QTextDocument::FindFlags p_flags, + int p_start, + int p_end) +{ + QList results; + if (p_text.isEmpty()) { + return results; + } + + int start = p_start; + int end = p_end == -1 ? p_doc->characterCount() + 1 : p_end; + + while (start < end) { + QTextCursor cursor = p_doc->find(p_text, start, p_flags); + if (cursor.isNull()) { + break; + } else { + start = cursor.selectionEnd(); + if (start <= end) { + results.append(cursor); + } + } + } + + return results; +} + +QList VEditor::findTextAllInRange(const QTextDocument *p_doc, + const QRegExp &p_reg, + QTextDocument::FindFlags p_flags, + int p_start, + int p_end) +{ + QList results; + if (!p_reg.isValid()) { + return results; + } + + int start = p_start; + int end = p_end == -1 ? p_doc->characterCount() + 1 : p_end; + + while (start < end) { + QTextCursor cursor = p_doc->find(p_reg, start, p_flags); + if (cursor.isNull()) { + break; + } else { + start = cursor.selectionEnd(); + if (start <= end) { + results.append(cursor); + } + } + } + + return results; +} + +void VEditor::clearFindCache() +{ + m_findInfo.clearResult(); +} + +void VEditor::nextMatch(bool p_forward) +{ + if (m_findInfo.isNull()) { + return; + } + + if (m_findInfo.m_useToken) { + // TODO + } else { + findTextInRange(m_findInfo.m_text, + m_findInfo.m_options, + p_forward, + m_findInfo.m_start, + m_findInfo.m_end); + } +} diff --git a/src/veditor.h b/src/veditor.h index 30981f45..5651e92a 100644 --- a/src/veditor.h +++ b/src/veditor.h @@ -13,6 +13,7 @@ #include "vfile.h" #include "vwordcountinfo.h" #include "vtexteditcompleter.h" +#include "vsearchconfig.h" class QWidget; class VEditorObject; @@ -99,6 +100,9 @@ public: uint p_options, const QString &p_replaceText); + // Use m_findInfo to find next match. + void nextMatch(bool p_forward = false); + // Scroll the content to make @p_block visible. // If the @p_block is too long to hold in one page, just let it occupy the // whole page. @@ -276,6 +280,100 @@ protected: private: friend class VEditorObject; + // Info about one find-in-page. + struct FindInfo + { + FindInfo() + : m_start(0), + m_end(-1), + m_useToken(false), + m_options(0), + m_cacheValid(false) + { + } + + void clear() + { + m_start = 0; + m_end = -1; + + m_useToken = false; + + m_text.clear(); + m_options = 0; + + m_token.clear(); + + m_cacheValid = false; + m_result.clear(); + } + + void clearResult() + { + m_cacheValid = false; + m_result.clear(); + } + + bool isCached(const QString &p_text, + uint p_options, + int p_start = 0, + int p_end = -1) const + { + return m_cacheValid + && !m_useToken + && m_text == p_text + && m_options == p_options + && m_start == p_start + && m_end == p_end; + } + + void update(const QString &p_text, + uint p_options, + int p_start, + int p_end, + const QList &p_result) + { + m_start = p_start; + m_end = p_end; + + m_useToken = false; + + m_text = p_text; + m_options = p_options; + + m_cacheValid = true; + m_result = p_result; + + m_token.clear(); + } + + bool isNull() const + { + if (m_useToken) { + return m_token.tokenSize() == 0; + } else { + return m_text.isEmpty(); + } + } + + // Find in [m_start, m_end). + int m_start; + int m_end; + + bool m_useToken; + + // Use text and options to search. + QString m_text; + uint m_options; + + // Use token to search. + VSearchToken m_token; + + bool m_cacheValid; + + QList m_result; + }; + // Filter out the trailing space right before cursor. void filterTrailingSpace(QList &p_selects, const QList &p_src); @@ -293,7 +391,15 @@ private: QList &) = NULL); // Find all the occurences of @p_text. - QList findTextAll(const QString &p_text, uint p_options); + QList findTextAll(const QString &p_text, + uint p_options, + int p_start = 0, + int p_end = -1); + + const QList &findTextAllCached(const QString &p_text, + uint p_options, + int p_start = 0, + int p_end = -1); // Highlight @p_cursor as the incremental searched keyword. void highlightIncrementalSearchedWord(const QTextCursor &p_cursor); @@ -311,7 +417,7 @@ private: void showWrapLabel(); - void highlightSearchedWord(const QString &p_text, uint p_options); + void highlightSearchedWord(const QList &p_matches); // Highlight @p_cursor as the searched keyword under cursor. void highlightSearchedWordUnderCursor(const QTextCursor &p_cursor); @@ -322,6 +428,28 @@ private: bool findTextOne(const QString &p_text, uint p_options, bool p_forward); + // @p_end, -1 indicates the end of doc. + static QList findTextAllInRange(const QTextDocument *p_doc, + const QString &p_text, + QTextDocument::FindFlags p_flags, + int p_start = 0, + int p_end = -1); + + static QList findTextAllInRange(const QTextDocument *p_doc, + const QRegExp &p_reg, + QTextDocument::FindFlags p_flags, + int p_start = 0, + int p_end = -1); + + bool findTextInRange(const QString &p_text, + uint p_options, + bool p_forward, + QTextCursor *p_cursor = nullptr, + QTextCursor::MoveMode p_moveMode = QTextCursor::MoveAnchor, + bool p_useLeftSideOfCursor = false, + int p_start = 0, + int p_end = -1); + QLabel *m_wrapLabel; QTimer *m_labelTimer; @@ -368,6 +496,8 @@ private: // Temp files needed to be delete. QStringList m_tempFiles; + FindInfo m_findInfo; + // Functions for private slots. private: void labelTimerTimeout(); @@ -378,6 +508,8 @@ private: void updateTrailingSpaceHighlights(); void doUpdateTrailingSpaceHighlights(); + + void clearFindCache(); }; @@ -446,6 +578,11 @@ private slots: m_editor->doUpdateTrailingSpaceHighlights(); } + void clearFindCache() + { + m_editor->clearFindCache(); + } + private: friend class VEditor; diff --git a/src/vedittab.h b/src/vedittab.h index f9db4cd1..21d79a4c 100644 --- a/src/vedittab.h +++ b/src/vedittab.h @@ -66,6 +66,8 @@ public: virtual void replaceTextAll(const QString &p_text, uint p_options, const QString &p_replaceText) = 0; + virtual void nextMatch(const QString &p_text, uint p_options, bool p_forward) = 0; + // Return selected text. virtual QString getSelectedText() const = 0; diff --git a/src/vhtmltab.cpp b/src/vhtmltab.cpp index 4bbd68f6..890038c3 100644 --- a/src/vhtmltab.cpp +++ b/src/vhtmltab.cpp @@ -240,6 +240,11 @@ void VHtmlTab::replaceTextAll(const QString &p_text, uint p_options, } } +void VHtmlTab::nextMatch(const QString &p_text, uint p_options, bool p_forward) +{ + findText(p_text, p_options, false, p_forward); +} + QString VHtmlTab::getSelectedText() const { QTextCursor cursor = m_editor->textCursor(); diff --git a/src/vhtmltab.h b/src/vhtmltab.h index c4292247..9f9470ef 100644 --- a/src/vhtmltab.h +++ b/src/vhtmltab.h @@ -41,6 +41,8 @@ public: void replaceTextAll(const QString &p_text, uint p_options, const QString &p_replaceText) Q_DECL_OVERRIDE; + void nextMatch(const QString &p_text, uint p_options, bool p_forward) Q_DECL_OVERRIDE; + QString getSelectedText() const Q_DECL_OVERRIDE; void clearSearchedWordHighlight() Q_DECL_OVERRIDE; diff --git a/src/vmdtab.cpp b/src/vmdtab.cpp index f50ef87b..9206e563 100644 --- a/src/vmdtab.cpp +++ b/src/vmdtab.cpp @@ -719,6 +719,16 @@ void VMdTab::replaceTextAll(const QString &p_text, uint p_options, } } +void VMdTab::nextMatch(const QString &p_text, uint p_options, bool p_forward) +{ + if (m_isEditMode) { + Q_ASSERT(m_editor); + m_editor->nextMatch(p_forward); + } else { + findTextInWebView(p_text, p_options, false, p_forward); + } +} + void VMdTab::findTextInWebView(const QString &p_text, uint p_options, bool /* p_peek */, bool p_forward) { diff --git a/src/vmdtab.h b/src/vmdtab.h index 2f73a22f..c6a4fc2b 100644 --- a/src/vmdtab.h +++ b/src/vmdtab.h @@ -57,6 +57,8 @@ public: void replaceTextAll(const QString &p_text, uint p_options, const QString &p_replaceText) Q_DECL_OVERRIDE; + void nextMatch(const QString &p_text, uint p_options, bool p_forward) Q_DECL_OVERRIDE; + QString getSelectedText() const Q_DECL_OVERRIDE; void clearSearchedWordHighlight() Q_DECL_OVERRIDE;