mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 13:59:52 +08:00
Editor: refine find logics
This commit is contained in:
parent
f3e4f370dd
commit
647807a918
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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`
|
||||
|
@ -25,6 +25,8 @@
|
||||
编辑当前笔记或保存更改并退出编辑模式。
|
||||
- `Ctrl+G`
|
||||
激活通用入口。
|
||||
- `Ctrl+8`/`Ctrl+9`
|
||||
跳转到最近一次查找的下一个/上一个匹配。
|
||||
|
||||
### 阅读模式
|
||||
- `H`/`J`/`K`/`L`
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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<QPair<int, int> > 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);
|
||||
|
315
src/veditor.cpp
315
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<QTextCursor> VEditor::findTextAll(const QString &p_text, uint p_options)
|
||||
QList<QTextCursor> VEditor::findTextAll(const QString &p_text,
|
||||
uint p_options,
|
||||
int p_start,
|
||||
int p_end)
|
||||
{
|
||||
QList<QTextCursor> results;
|
||||
if (p_text.isEmpty()) {
|
||||
@ -355,35 +360,37 @@ QList<QTextCursor> 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,
|
||||
if (p_options & FindOption::RegularExpression) {
|
||||
QRegExp exp(p_text,
|
||||
caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive);
|
||||
}
|
||||
|
||||
int startPos = 0;
|
||||
QTextCursor cursor;
|
||||
while (true) {
|
||||
if (useRegExp) {
|
||||
cursor = m_document->find(exp, startPos, findFlags);
|
||||
results = findTextAllInRange(m_document, exp, findFlags, p_start, p_end);
|
||||
} else {
|
||||
cursor = m_document->find(p_text, startPos, findFlags);
|
||||
}
|
||||
|
||||
if (cursor.isNull()) {
|
||||
break;
|
||||
} else {
|
||||
results.append(cursor);
|
||||
startPos = cursor.selectionEnd();
|
||||
}
|
||||
results = findTextAllInRange(m_document, p_text, findFlags, p_start, p_end);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
const QList<QTextCursor> &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<QTextCursor> 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<QTextEdit::ExtraSelection> &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<QTextCursor> &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<QTextCursor> &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 (result.isEmpty()) {
|
||||
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;
|
||||
}
|
||||
|
||||
bool wrapped = false;
|
||||
int idx = selectCursor(result, pos, p_forward, wrapped);
|
||||
const QTextCursor &tcursor = result.at(idx);
|
||||
if (wrapped) {
|
||||
showWrapLabel();
|
||||
}
|
||||
|
||||
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);
|
||||
p_cursor->setPosition(tcursor.selectionStart(), p_moveMode);
|
||||
} else {
|
||||
cursor.setPosition(retCursor.selectionStart(), p_moveMode);
|
||||
cursor.setPosition(tcursor.selectionStart(), p_moveMode);
|
||||
setTextCursorW(cursor);
|
||||
}
|
||||
|
||||
highlightSearchedWord(p_text, p_options);
|
||||
highlightSearchedWordUnderCursor(retCursor);
|
||||
matches = m_extraSelections[(int)SelectionId::SearchedKeyword].size();
|
||||
} else {
|
||||
clearSearchedWordHighlight();
|
||||
highlightSearchedWord(result);
|
||||
|
||||
highlightSearchedWordUnderCursor(tcursor);
|
||||
|
||||
emit m_object->statusMessage(QObject::tr("Match found: %2 of %3")
|
||||
.arg(idx + 1)
|
||||
.arg(result.size()));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
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<QTextCursor> &p_matches)
|
||||
{
|
||||
QList<QTextEdit::ExtraSelection> &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<QTextCursor> VEditor::findTextAllInRange(const QTextDocument *p_doc,
|
||||
const QString &p_text,
|
||||
QTextDocument::FindFlags p_flags,
|
||||
int p_start,
|
||||
int p_end)
|
||||
{
|
||||
QList<QTextCursor> 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<QTextCursor> VEditor::findTextAllInRange(const QTextDocument *p_doc,
|
||||
const QRegExp &p_reg,
|
||||
QTextDocument::FindFlags p_flags,
|
||||
int p_start,
|
||||
int p_end)
|
||||
{
|
||||
QList<QTextCursor> 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);
|
||||
}
|
||||
}
|
||||
|
141
src/veditor.h
141
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<QTextCursor> &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<QTextCursor> m_result;
|
||||
};
|
||||
|
||||
// Filter out the trailing space right before cursor.
|
||||
void filterTrailingSpace(QList<QTextEdit::ExtraSelection> &p_selects,
|
||||
const QList<QTextEdit::ExtraSelection> &p_src);
|
||||
@ -293,7 +391,15 @@ private:
|
||||
QList<QTextEdit::ExtraSelection> &) = NULL);
|
||||
|
||||
// Find all the occurences of @p_text.
|
||||
QList<QTextCursor> findTextAll(const QString &p_text, uint p_options);
|
||||
QList<QTextCursor> findTextAll(const QString &p_text,
|
||||
uint p_options,
|
||||
int p_start = 0,
|
||||
int p_end = -1);
|
||||
|
||||
const QList<QTextCursor> &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<QTextCursor> &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<QTextCursor> findTextAllInRange(const QTextDocument *p_doc,
|
||||
const QString &p_text,
|
||||
QTextDocument::FindFlags p_flags,
|
||||
int p_start = 0,
|
||||
int p_end = -1);
|
||||
|
||||
static QList<QTextCursor> 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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user