From 5106baf62a741511ba414f0eb961731a558d3e9a Mon Sep 17 00:00:00 2001 From: Fozei Date: Mon, 6 May 2024 12:06:50 +0800 Subject: [PATCH] feat: add search status label on findbar and replacebar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit desc: 在查找和替换组件上,增加指示当前选中是第几个和总共有多少个查找结果的标签 --- src/controls/findbar.cpp | 7 ++ src/controls/findbar.h | 2 + src/controls/replacebar.cpp | 8 ++ src/controls/replacebar.h | 2 + src/editor/dtextedit.cpp | 145 ++++++++++++++++++++++-------------- src/editor/dtextedit.h | 5 ++ src/widgets/window.cpp | 29 ++++++++ src/widgets/window.h | 2 + 8 files changed, 146 insertions(+), 54 deletions(-) diff --git a/src/controls/findbar.cpp b/src/controls/findbar.cpp index 5c422046a..4af41e52b 100644 --- a/src/controls/findbar.cpp +++ b/src/controls/findbar.cpp @@ -31,6 +31,7 @@ FindBar::FindBar(QWidget *parent) m_layout->setAlignment(Qt::AlignVCenter); m_findLabel = new QLabel(tr("Find")); m_editLine = new LineBar(); + m_statusLabel = new QLabel(tr("")); m_findPrevButton = new QPushButton(tr("Previous")); m_findNextButton = new QPushButton(tr("Next")); m_closeButton = new DIconButton(DStyle::SP_CloseButton); @@ -49,6 +50,7 @@ FindBar::FindBar(QWidget *parent) lineBarLayout->addItem(new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding)); m_layout->addLayout(lineBarLayout); + m_layout->addWidget(m_statusLabel); m_layout->addWidget(m_findPrevButton); m_layout->addWidget(m_findNextButton); m_layout->addWidget(m_closeButton); @@ -216,3 +218,8 @@ void FindBar::findPreClicked() emit findPrev(m_editLine->lineEdit()->text()); } } + +void FindBar::setStatusText(QString statusStr) +{ + m_statusLabel->setText(statusStr); +} diff --git a/src/controls/findbar.h b/src/controls/findbar.h index a7185efad..3bcf3557e 100644 --- a/src/controls/findbar.h +++ b/src/controls/findbar.h @@ -41,6 +41,7 @@ class FindBar : public DFloatingWidget void receiveText(QString t); void setSearched(bool _); void findPreClicked(); + void setStatusText(QString str); Q_SIGNALS: void pressEsc(); @@ -74,6 +75,7 @@ public Q_SLOTS: LineBar *m_editLine; QHBoxLayout *m_layout; QLabel *m_findLabel; + QLabel *m_statusLabel; QString m_findFile; int m_findFileColumn; int m_findFileRow; diff --git a/src/controls/replacebar.cpp b/src/controls/replacebar.cpp index 898717ee5..58ff996ca 100644 --- a/src/controls/replacebar.cpp +++ b/src/controls/replacebar.cpp @@ -32,6 +32,7 @@ ReplaceBar::ReplaceBar(QWidget *parent) m_replaceLine = new LineBar(); m_withLabel = new QLabel(tr("Replace With")); m_withLine = new LineBar(); + m_statusLabel = new QLabel(tr("")); m_replaceButton = new QPushButton(tr("Replace")); m_replaceSkipButton = new QPushButton(tr("Skip")); m_replaceRestButton = new QPushButton(tr("Replace Rest")); @@ -46,6 +47,8 @@ ReplaceBar::ReplaceBar(QWidget *parent) m_layout->addLayout(createVerticalLine(m_replaceLine)); m_layout->addWidget(m_withLabel); m_layout->addLayout(createVerticalLine(m_withLine)); + + m_layout->addWidget(m_statusLabel); m_layout->addWidget(m_replaceButton); m_layout->addWidget(m_replaceSkipButton); m_layout->addWidget(m_replaceRestButton); @@ -260,3 +263,8 @@ void ReplaceBar::change() { searched = false; } + +void ReplaceBar::setStatusText(QString str) +{ + m_statusLabel->setText(str); +} diff --git a/src/controls/replacebar.h b/src/controls/replacebar.h index 724ecd8dc..c33afc0f9 100644 --- a/src/controls/replacebar.h +++ b/src/controls/replacebar.h @@ -32,6 +32,7 @@ class ReplaceBar : public DFloatingWidget void activeInput(QString text, QString file, int row, int column, int scrollOffset); void setMismatchAlert(bool isAlert); void setsearched(bool _); + void setStatusText(QString text); Q_SIGNALS: void pressEsc(); @@ -77,6 +78,7 @@ public Q_SLOTS: QHBoxLayout *m_layout; QLabel *m_replaceLabel; QLabel *m_withLabel; + QLabel *m_statusLabel; QString m_replaceFile; int m_replaceFileColumn; int m_replaceFileRow; diff --git a/src/editor/dtextedit.cpp b/src/editor/dtextedit.cpp index 17c65c4b7..aee575961 100644 --- a/src/editor/dtextedit.cpp +++ b/src/editor/dtextedit.cpp @@ -2014,72 +2014,76 @@ bool TextEdit::updateKeywordSelectionsInView(QString keyword, QTextCharFormat ch // Clear keyword selections first. listSelection->clear(); + if (keyword.isEmpty()) { + return false; + } + + this->updateSearchStatus(keyword); + // Update selections with keyword. - if (!keyword.isEmpty()) { - QTextCursor cursor(document()); - QTextEdit::ExtraSelection extra; - extra.format = charFormat; + QTextCursor cursor(document()); + QTextEdit::ExtraSelection extra; + extra.format = charFormat; + + QScrollBar *pScrollBar = verticalScrollBar(); + QPoint startPoint = QPointF(0, 0).toPoint(); + QTextBlock beginBlock = cursorForPosition(startPoint).block(); + int beginPos = beginBlock.position(); + QTextBlock endBlock; + + if (pScrollBar->maximum() > 0) { + QPoint endPoint = QPointF(0, 1.5 * height()).toPoint(); + endBlock = cursorForPosition(endPoint).block(); + } else { + endBlock = document()->lastBlock(); + } + int endPos = endBlock.position() + endBlock.length() - 1; - QScrollBar *pScrollBar = verticalScrollBar(); - QPoint startPoint = QPointF(0, 0).toPoint(); - QTextBlock beginBlock = cursorForPosition(startPoint).block(); - int beginPos = beginBlock.position(); - QTextBlock endBlock; + // 内部计算时,均视为 \n 结尾 + QLatin1Char endLine('\n'); + QString multiLineText; + QTextDocument::FindFlags flags; + flags |= QTextDocument::FindCaseSensitively; + if (keyword.contains(endLine)) { + auto temp = this->textCursor(); + temp.setPosition(beginPos); + while (temp.position() < endPos) { + temp.movePosition(QTextCursor::EndOfLine, QTextCursor::KeepAnchor); + multiLineText += temp.selectedText(); + multiLineText += endLine; + temp.setPosition(temp.position() + 1); + } + cursor = findCursor(keyword, multiLineText, 0, false, beginPos); + } else { + cursor = document()->find(keyword, beginPos, flags); + } - if (pScrollBar->maximum() > 0) { - QPoint endPoint = QPointF(0, 1.5 * height()).toPoint(); - endBlock = cursorForPosition(endPoint).block(); - } else { - endBlock = document()->lastBlock(); + if (cursor.isNull()) { + return false; + } + + + + while (!cursor.isNull()) { + extra.cursor = cursor; + /* 查找字符时,查找到完全相等的时候才高亮,如查找小写f时,大写的F不高亮 */ + if (!extra.cursor.selectedText().compare(keyword) || keyword.contains(endLine)) { + listSelection->append(extra); } - int endPos = endBlock.position() + endBlock.length() - 1; - // 内部计算时,均视为 \n 结尾 - QLatin1Char endLine('\n'); - QString multiLineText; - QTextDocument::FindFlags flags; - flags |= QTextDocument::FindCaseSensitively; if (keyword.contains(endLine)) { - auto temp = this->textCursor(); - temp.setPosition(beginPos); - while (temp.position() < endPos) { - temp.movePosition(QTextCursor::EndOfLine, QTextCursor::KeepAnchor); - multiLineText += temp.selectedText(); - multiLineText += endLine; - temp.setPosition(temp.position() + 1); - } - cursor = findCursor(keyword, multiLineText, 0, false, beginPos); + int pos = std::max(extra.cursor.position(), extra.cursor.anchor()); + cursor = findCursor(keyword, multiLineText, pos - beginPos, false, beginPos); } else { - cursor = document()->find(keyword, beginPos, flags); - } - - if (cursor.isNull()) { - return false; + cursor = document()->find(keyword, cursor, flags); } - while (!cursor.isNull()) { - extra.cursor = cursor; - /* 查找字符时,查找到完全相等的时候才高亮,如查找小写f时,大写的F不高亮 */ - if (!extra.cursor.selectedText().compare(keyword) || keyword.contains(endLine)) { - listSelection->append(extra); - } - - if (keyword.contains(endLine)) { - int pos = std::max(extra.cursor.position(), extra.cursor.anchor()); - cursor = findCursor(keyword, multiLineText, pos - beginPos, false, beginPos); - } else { - cursor = document()->find(keyword, cursor, flags); - } - - if (cursor.position() > endPos) { - break; - } + if (cursor.position() > endPos) { + break; } - - return true; } - return false; + return true; } bool TextEdit::searchKeywordSeletion(QString keyword, QTextCursor cursor, bool findNext) @@ -2195,6 +2199,10 @@ void TextEdit::renderAllSelections() // 设置到 QPlainText 中进行渲染 setExtraSelections(finalSelections); + + QString status = m_searchCount == 0 ? QString("No Reuslt") : QString("%1/%2").arg(m_searchStep).arg(m_searchCount); + // 发射信号,通知window更新状态文字 + Q_EMIT signal_renderAllFinish(this, status); } void TextEdit::updateMarkAllSelectColor() @@ -8071,3 +8079,32 @@ void TextEdit::onTextContentChanged(int from, int charsRemoved, int charsAdded) m_MidButtonPatse = false; } } + +void TextEdit::updateSearchStatus(const QString &keyword) +{ + QTextCursor currentCursor = textCursor(); + + if (currentCursor.isNull()) + { + return; + } + + // 记录当前cursor在结果列表中的位置 + int anchorPosition = currentCursor.anchor(); + m_searchCount = 0; + + QString plainText = this->toPlainText(); + m_searchCount = plainText.count(keyword); + + int searchStart = -1; + for (size_t i = 0; i < m_searchCount; i++) + { + int appearPosition = plainText.indexOf(keyword, searchStart + 1); + if (appearPosition >= anchorPosition) + { + m_searchStep = i + 1; + break; + } + searchStart = appearPosition; + } +} diff --git a/src/editor/dtextedit.h b/src/editor/dtextedit.h index 6fcbf50b7..d35a7e33f 100644 --- a/src/editor/dtextedit.h +++ b/src/editor/dtextedit.h @@ -476,6 +476,7 @@ class TextEdit : public DPlainTextEdit void popupNotify(QString notify); void signal_readingPath(); void signal_setTitleFocus(); + void signal_renderAllFinish(const TextEdit *editor, const QString &statusText); public slots: /** * @author liumaochuan ut000616 @@ -606,6 +607,8 @@ public slots: const QString &replaceText, const QString &withText, int offset = 0) const; // 查找行号line起始的折叠区域 bool findFoldBlock(int line, QTextBlock &beginBlock, QTextBlock &endBlock, QTextBlock &curBlock); + // 更新 查找/替换 时位置信息 + void updateSearchStatus(const QString &keyword); private slots: // 文档内容变更时触发 @@ -861,5 +864,7 @@ private slots: bool m_MidButtonPatse = false; // 鼠标中键黏贴处理 bool m_isPreeditBefore = false; // 上一个输入法时间是否是 preedit int m_preeditLengthBefore = 0; + size_t m_searchStep = 0; + size_t m_searchCount = 0; }; #endif diff --git a/src/widgets/window.cpp b/src/widgets/window.cpp index c5babbc42..230a430df 100644 --- a/src/widgets/window.cpp +++ b/src/widgets/window.cpp @@ -940,6 +940,9 @@ EditWrapper *Window::createEditor() updateJumpLineBar(wrapper->textEditor()); }, Qt::QueuedConnection); + // Editor renderAllSelections执行完毕后,调用onEditorRenderAllFinish更新状态文字 + connect(wrapper->textEditor(),&TextEdit::signal_renderAllFinish,this,&Window::onEditorRenderAllFinish,Qt::QueuedConnection); + bool wordWrap = m_settings->settings->option("base.font.wordwrap")->value().toBool(); wrapper->textEditor()->m_pIsShowCodeFoldArea = m_settings->settings->option("base.font.codeflod")->value().toBool(); wrapper->OnThemeChangeSlot(m_themePath); @@ -1547,6 +1550,10 @@ void Window::popupReplaceBar() m_replaceBar->activeInput(text, tabPath, row, column, scrollOffset); + wrapper->textEditor()->highlightKeywordInView(text); + // set keywords + m_keywordForSearchAll = m_keywordForSearch = text; + QTimer::singleShot(10, this, [ = ] { m_replaceBar->focus(); }); } @@ -3595,6 +3602,28 @@ void Window::setPrintEnabled(bool enabled) } } +void Window::onEditorRenderAllFinish(const TextEdit *editor, const QString &status) +{ + EditWrapper *wrapper = currentWrapper(); + + if (wrapper == nullptr) { + return; + } + // 如果当前TextEdit和发射信号的TextEdit不是同一个,则不处理 + // 实际上,只有切换tab时才会发生这种情况 + if (wrapper->textEditor() != editor) { + return; + } + + if (m_findBar->isVisible()) { + m_findBar->setStatusText(status); + } + + if (m_replaceBar->isVisible()) { + m_replaceBar->setStatusText(status); + } +} + QStackedWidget *Window::getStackedWgt() { return m_editorWidget; diff --git a/src/widgets/window.h b/src/widgets/window.h index 67cf028a7..1f708b1cb 100644 --- a/src/widgets/window.h +++ b/src/widgets/window.h @@ -242,6 +242,8 @@ public Q_SLOTS: // 接收布局模式变更信号,更新界面布局 Q_SLOT void updateSizeMode(); + Q_SLOT void onEditorRenderAllFinish(const TextEdit *editor, const QString &text); + protected: void resizeEvent(QResizeEvent *event) override; void closeEvent(QCloseEvent *event) override;