mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 13:59:52 +08:00
refine find/replace logics
Do not select the found target. Use highlight instead.
This commit is contained in:
parent
0d0f6d4e47
commit
c53950fe77
@ -339,7 +339,7 @@ void VEditUtils::scrollBlockInPage(QTextEdit *p_edit,
|
||||
QScrollBar *vsbar = p_edit->verticalScrollBar();
|
||||
|
||||
if (!vsbar || !vsbar->isVisible()) {
|
||||
// No vertical scrollbar. No need to scrool.
|
||||
// No vertical scrollbar. No need to scroll.
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -104,6 +104,7 @@ public:
|
||||
// Scroll block @p_blockNum into the visual window.
|
||||
// @p_dest is the position of the window: 0 for top, 1 for center, 2 for bottom.
|
||||
// @p_blockNum is based on 0.
|
||||
// Will set the cursor to the block.
|
||||
static void scrollBlockInPage(QTextEdit *p_edit,
|
||||
int p_blockNum,
|
||||
int p_dest);
|
||||
|
@ -94,7 +94,7 @@ VVim::VVim(VEdit *p_editor)
|
||||
|
||||
initRegisters();
|
||||
|
||||
connect(m_editor, &VEdit::copyAvailable,
|
||||
connect(m_editor, &VEdit::selectionChangedByMouse,
|
||||
this, &VVim::selectionToVisualMode);
|
||||
}
|
||||
|
||||
@ -4328,9 +4328,13 @@ int VVim::blockCountOfPageStep() const
|
||||
|
||||
void VVim::selectionToVisualMode(bool p_hasText)
|
||||
{
|
||||
if (p_hasText && m_mode == VimMode::Normal) {
|
||||
// Enter visual mode without clearing the selection.
|
||||
setMode(VimMode::Visual, false);
|
||||
if (p_hasText) {
|
||||
if (m_mode == VimMode::Normal) {
|
||||
// Enter visual mode without clearing the selection.
|
||||
setMode(VimMode::Visual, false);
|
||||
}
|
||||
} else if (m_mode == VimMode::Visual || m_mode == VimMode::VisualLine) {
|
||||
setMode(VimMode::Normal);
|
||||
}
|
||||
}
|
||||
|
||||
|
295
src/vedit.cpp
295
src/vedit.cpp
@ -51,6 +51,8 @@ VEdit::VEdit(VFile *p_file, QWidget *p_parent)
|
||||
|
||||
m_selectedWordColor = QColor("Yellow");
|
||||
m_searchedWordColor = QColor(g_vnote->getColorFromPalette("Green4"));
|
||||
m_searchedWordCursorColor = QColor("#64B5F6");
|
||||
m_incrementalSearchedWordColor = QColor(g_vnote->getColorFromPalette("Purple2"));
|
||||
m_trailingSpaceColor = QColor(vconfig.getEditorTrailingSpaceBackground());
|
||||
|
||||
QPixmap wrapPixmap(":/resources/icons/search_wrap.svg");
|
||||
@ -178,41 +180,29 @@ void VEdit::insertImage()
|
||||
|
||||
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()) {
|
||||
// Clear previous selection
|
||||
QTextCursor cursor = textCursor();
|
||||
cursor.clearSelection();
|
||||
cursor.setPosition(startPos);
|
||||
setTextCursor(cursor);
|
||||
} else {
|
||||
QTextCursor cursor = textCursor();
|
||||
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);
|
||||
}
|
||||
makeBlockVisible(document()->findBlock(textCursor().selectionStart()));
|
||||
highlightIncrementalSearchedWord(QTextCursor());
|
||||
return false;
|
||||
}
|
||||
|
||||
bool wrapped = false;
|
||||
found = findTextHelper(p_text, p_options, true, wrapped);
|
||||
QTextCursor retCursor;
|
||||
bool found = findTextHelper(p_text, p_options, true,
|
||||
textCursor().position() + 1, wrapped, retCursor);
|
||||
if (found) {
|
||||
lastPos = textCursor().selectionStart();
|
||||
found = true;
|
||||
makeBlockVisible(document()->findBlock(retCursor.selectionStart()));
|
||||
highlightIncrementalSearchedWord(retCursor);
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
// Use QTextEdit::find() instead of QTextDocument::find() because the later has
|
||||
// bugs in searching backward.
|
||||
bool VEdit::findTextHelper(const QString &p_text, uint p_options,
|
||||
bool p_forward, bool &p_wrapped)
|
||||
bool p_forward, int p_start,
|
||||
bool &p_wrapped, QTextCursor &p_cursor)
|
||||
{
|
||||
p_wrapped = false;
|
||||
bool found = false;
|
||||
@ -224,12 +214,15 @@ bool VEdit::findTextHelper(const QString &p_text, uint p_options,
|
||||
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;
|
||||
@ -238,32 +231,53 @@ bool VEdit::findTextHelper(const QString &p_text, uint p_options,
|
||||
exp = QRegExp(p_text,
|
||||
caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive);
|
||||
}
|
||||
|
||||
// Store current state of the cursor.
|
||||
QTextCursor cursor = textCursor();
|
||||
if (cursor.position() != p_start) {
|
||||
if (p_start < 0) {
|
||||
p_start = 0;
|
||||
} else if (p_start > document()->characterCount()) {
|
||||
p_start = document()->characterCount();
|
||||
}
|
||||
|
||||
QTextCursor startCursor = cursor;
|
||||
startCursor.setPosition(p_start);
|
||||
setTextCursor(startCursor);
|
||||
}
|
||||
|
||||
while (!found) {
|
||||
if (useRegExp) {
|
||||
found = find(exp, findFlags);
|
||||
} else {
|
||||
found = find(p_text, findFlags);
|
||||
}
|
||||
|
||||
if (p_wrapped) {
|
||||
if (!found) {
|
||||
setTextCursor(cursor);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
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 (found) {
|
||||
p_cursor = textCursor();
|
||||
}
|
||||
|
||||
// Restore the original cursor.
|
||||
setTextCursor(cursor);
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
@ -312,26 +326,44 @@ QList<QTextCursor> VEdit::findTextAll(const QString &p_text, uint p_options)
|
||||
|
||||
bool VEdit::findText(const QString &p_text, uint p_options, bool p_forward)
|
||||
{
|
||||
bool found = false;
|
||||
clearIncrementalSearchedWordHighlight();
|
||||
|
||||
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) {
|
||||
if (wrapped) {
|
||||
showWrapLabel();
|
||||
}
|
||||
highlightSearchedWord(p_text, p_options);
|
||||
} else {
|
||||
// Simply clear previous highlight.
|
||||
highlightSearchedWord("", p_options);
|
||||
}
|
||||
clearSearchedWordHighlight();
|
||||
return false;
|
||||
}
|
||||
qDebug() << "findText" << p_text << p_options << p_forward
|
||||
<< (found ? "Found" : "NotFound");
|
||||
|
||||
bool wrapped = false;
|
||||
QTextCursor retCursor;
|
||||
int matches = 0;
|
||||
bool found = findTextHelper(p_text, p_options, p_forward,
|
||||
p_forward ? textCursor().position() + 1
|
||||
: textCursor().position(),
|
||||
wrapped, retCursor);
|
||||
if (found) {
|
||||
Q_ASSERT(!retCursor.isNull());
|
||||
if (wrapped) {
|
||||
showWrapLabel();
|
||||
}
|
||||
|
||||
QTextCursor cursor = textCursor();
|
||||
cursor.setPosition(retCursor.selectionStart());
|
||||
setTextCursor(cursor);
|
||||
|
||||
highlightSearchedWord(p_text, p_options);
|
||||
highlightSearchedWordUnderCursor(retCursor);
|
||||
matches = m_extraSelections[(int)SelectionId::SearchedKeyword].size();
|
||||
} else {
|
||||
clearSearchedWordHighlight();
|
||||
}
|
||||
|
||||
if (matches == 0) {
|
||||
statusMessage(tr("Found no match"));
|
||||
} else {
|
||||
statusMessage(tr("Found %1 %2").arg(matches)
|
||||
.arg(matches > 1 ? tr("matches") : tr("match")));
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
@ -339,47 +371,40 @@ void VEdit::replaceText(const QString &p_text, uint p_options,
|
||||
const QString &p_replaceText, bool p_findNext)
|
||||
{
|
||||
QTextCursor cursor = textCursor();
|
||||
if (cursor.hasSelection()) {
|
||||
// Replace occurs only if the selected text matches @p_text with @p_options.
|
||||
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 wrapped = false;
|
||||
QTextCursor retCursor;
|
||||
bool found = findTextHelper(p_text, p_options, true,
|
||||
cursor.position(), wrapped, retCursor);
|
||||
if (found) {
|
||||
if (retCursor.selectionStart() == cursor.position()) {
|
||||
// Matched.
|
||||
retCursor.beginEditBlock();
|
||||
retCursor.insertText(p_replaceText);
|
||||
retCursor.endEditBlock();
|
||||
setTextCursor(retCursor);
|
||||
}
|
||||
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, true);
|
||||
}
|
||||
}
|
||||
if (p_findNext) {
|
||||
findText(p_text, p_options, true);
|
||||
}
|
||||
}
|
||||
|
||||
void VEdit::replaceTextAll(const QString &p_text, uint p_options,
|
||||
const QString &p_replaceText)
|
||||
{
|
||||
// Replace from the start to the end and resotre the cursor.
|
||||
// Replace from the start to the end and restore the cursor.
|
||||
QTextCursor cursor = textCursor();
|
||||
int nrReplaces = 0;
|
||||
QTextCursor tmpCursor = cursor;
|
||||
tmpCursor.setPosition(0);
|
||||
setTextCursor(tmpCursor);
|
||||
int start = tmpCursor.position();
|
||||
while (true) {
|
||||
bool wrapped = false;
|
||||
bool found = findTextHelper(p_text, p_options, true, wrapped);
|
||||
QTextCursor retCursor;
|
||||
bool found = findTextHelper(p_text, p_options, true,
|
||||
start, wrapped, retCursor);
|
||||
if (!found) {
|
||||
break;
|
||||
} else {
|
||||
@ -387,19 +412,24 @@ void VEdit::replaceTextAll(const QString &p_text, uint p_options,
|
||||
// Wrap back.
|
||||
break;
|
||||
}
|
||||
|
||||
nrReplaces++;
|
||||
tmpCursor = textCursor();
|
||||
tmpCursor.beginEditBlock();
|
||||
tmpCursor.removeSelectedText();
|
||||
tmpCursor.insertText(p_replaceText);
|
||||
tmpCursor.endEditBlock();
|
||||
setTextCursor(tmpCursor);
|
||||
retCursor.beginEditBlock();
|
||||
retCursor.insertText(p_replaceText);
|
||||
retCursor.endEditBlock();
|
||||
setTextCursor(retCursor);
|
||||
start = retCursor.position();
|
||||
}
|
||||
}
|
||||
|
||||
// Restore cursor position.
|
||||
cursor.clearSelection();
|
||||
setTextCursor(cursor);
|
||||
qDebug() << "replace all" << nrReplaces << "occurences";
|
||||
|
||||
emit statusMessage(tr("Replace %1 %2").arg(nrReplaces)
|
||||
.arg(nrReplaces > 1 ? tr("occurences")
|
||||
: tr("occurence")));
|
||||
}
|
||||
|
||||
void VEdit::showWrapLabel()
|
||||
@ -624,13 +654,84 @@ void VEdit::highlightSearchedWord(const QString &p_text, uint p_options)
|
||||
highlightTextAll(p_text, p_options, SelectionId::SearchedKeyword, format);
|
||||
}
|
||||
|
||||
void VEdit::highlightSearchedWordUnderCursor(const QTextCursor &p_cursor)
|
||||
{
|
||||
QList<QTextEdit::ExtraSelection> &selects = m_extraSelections[(int)SelectionId::SearchedKeywordUnderCursor];
|
||||
if (!p_cursor.hasSelection()) {
|
||||
if (!selects.isEmpty()) {
|
||||
selects.clear();
|
||||
highlightExtraSelections(true);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
selects.clear();
|
||||
QTextEdit::ExtraSelection select;
|
||||
select.format.setBackground(m_searchedWordCursorColor);
|
||||
select.cursor = p_cursor;
|
||||
selects.append(select);
|
||||
|
||||
highlightExtraSelections(true);
|
||||
}
|
||||
|
||||
void VEdit::highlightIncrementalSearchedWord(const QTextCursor &p_cursor)
|
||||
{
|
||||
QList<QTextEdit::ExtraSelection> &selects = m_extraSelections[(int)SelectionId::IncrementalSearchedKeyword];
|
||||
if (!vconfig.getHighlightSearchedWord() || !p_cursor.hasSelection()) {
|
||||
if (!selects.isEmpty()) {
|
||||
selects.clear();
|
||||
highlightExtraSelections(true);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
selects.clear();
|
||||
QTextEdit::ExtraSelection select;
|
||||
select.format.setBackground(m_incrementalSearchedWordColor);
|
||||
select.cursor = p_cursor;
|
||||
selects.append(select);
|
||||
|
||||
highlightExtraSelections(true);
|
||||
}
|
||||
|
||||
void VEdit::clearSearchedWordHighlight()
|
||||
{
|
||||
clearIncrementalSearchedWordHighlight(false);
|
||||
clearSearchedWordUnderCursorHighlight(false);
|
||||
|
||||
QList<QTextEdit::ExtraSelection> &selects = m_extraSelections[(int)SelectionId::SearchedKeyword];
|
||||
if (selects.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
selects.clear();
|
||||
highlightExtraSelections(true);
|
||||
}
|
||||
|
||||
void VEdit::clearSearchedWordUnderCursorHighlight(bool p_now)
|
||||
{
|
||||
QList<QTextEdit::ExtraSelection> &selects = m_extraSelections[(int)SelectionId::SearchedKeywordUnderCursor];
|
||||
if (selects.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
selects.clear();
|
||||
highlightExtraSelections(p_now);
|
||||
}
|
||||
|
||||
void VEdit::clearIncrementalSearchedWordHighlight(bool p_now)
|
||||
{
|
||||
QList<QTextEdit::ExtraSelection> &selects = m_extraSelections[(int)SelectionId::IncrementalSearchedKeyword];
|
||||
if (selects.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
selects.clear();
|
||||
highlightExtraSelections(p_now);
|
||||
}
|
||||
|
||||
void VEdit::contextMenuEvent(QContextMenuEvent *p_event)
|
||||
{
|
||||
QMenu *menu = createStandardContextMenu();
|
||||
@ -746,6 +847,8 @@ void VEdit::mousePressEvent(QMouseEvent *p_event)
|
||||
m_mouseMoveScrolled = false;
|
||||
|
||||
QTextEdit::mousePressEvent(p_event);
|
||||
|
||||
emit selectionChangedByMouse(textCursor().hasSelection());
|
||||
}
|
||||
|
||||
void VEdit::mouseReleaseEvent(QMouseEvent *p_event)
|
||||
@ -797,6 +900,8 @@ void VEdit::mouseMoveEvent(QMouseEvent *p_event)
|
||||
}
|
||||
|
||||
QTextEdit::mouseMoveEvent(p_event);
|
||||
|
||||
emit selectionChangedByMouse(textCursor().hasSelection());
|
||||
}
|
||||
|
||||
void VEdit::requestUpdateVimStatus()
|
||||
@ -1033,3 +1138,37 @@ int LineNumberArea::calculateWidth() const
|
||||
|
||||
return m_width;
|
||||
}
|
||||
|
||||
void VEdit::makeBlockVisible(const QTextBlock &p_block)
|
||||
{
|
||||
if (!p_block.isValid() || !p_block.isVisible()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QScrollBar *vbar = verticalScrollBar();
|
||||
if (!vbar || !vbar->isVisible()) {
|
||||
// No vertical scrollbar. No need to scroll.
|
||||
return;
|
||||
}
|
||||
|
||||
QAbstractTextDocumentLayout *layout = document()->documentLayout();
|
||||
int height = rect().height();
|
||||
QScrollBar *hbar = horizontalScrollBar();
|
||||
if (hbar && hbar->isVisible()) {
|
||||
height -= hbar->height();
|
||||
}
|
||||
|
||||
QRectF rect = layout->blockBoundingRect(p_block);
|
||||
int y = contentOffsetY() + (int)rect.y();
|
||||
while (y < 0 && vbar->value() > vbar->minimum()) {
|
||||
vbar->setValue(vbar->value() - vbar->singleStep());
|
||||
rect = layout->blockBoundingRect(p_block);
|
||||
y = contentOffsetY() + (int)rect.y();
|
||||
}
|
||||
|
||||
while (y + (int)rect.height() > height && vbar->value() < vbar->maximum()) {
|
||||
vbar->setValue(vbar->value() + vbar->singleStep());
|
||||
rect = layout->blockBoundingRect(p_block);
|
||||
y = contentOffsetY() + (int)rect.y();
|
||||
}
|
||||
}
|
||||
|
41
src/vedit.h
41
src/vedit.h
@ -26,6 +26,8 @@ enum class SelectionId {
|
||||
CurrentLine = 0,
|
||||
SelectedWord,
|
||||
SearchedKeyword,
|
||||
SearchedKeywordUnderCursor,
|
||||
IncrementalSearchedKeyword,
|
||||
TrailingSapce,
|
||||
MaxSelection
|
||||
};
|
||||
@ -78,16 +80,27 @@ public:
|
||||
virtual void scrollToLine(int p_lineNumber);
|
||||
// User requests to insert an image.
|
||||
virtual void insertImage();
|
||||
bool findTextHelper(const QString &p_text, uint p_options,
|
||||
bool p_forward, bool &p_wrapped);
|
||||
|
||||
// Used for incremental search.
|
||||
// User has enter the content to search, but does not enter the "find" button yet.
|
||||
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);
|
||||
void setReadOnly(bool p_ro);
|
||||
|
||||
// Clear SearchedKeyword highlight.
|
||||
void clearSearchedWordHighlight();
|
||||
|
||||
// Clear SearchedKeywordUnderCursor Highlight.
|
||||
void clearSearchedWordUnderCursorHighlight(bool p_now = true);
|
||||
|
||||
// Clear IncrementalSearchedKeyword highlight.
|
||||
void clearIncrementalSearchedWordHighlight(bool p_now = true);
|
||||
|
||||
VFile *getFile() const;
|
||||
|
||||
VEditConfig &getConfig();
|
||||
@ -127,6 +140,9 @@ signals:
|
||||
// Emit when Vim status updated.
|
||||
void vimStatusUpdated(const VVim *p_vim);
|
||||
|
||||
// Selection changed by mouse.
|
||||
void selectionChangedByMouse(bool p_hasSelection);
|
||||
|
||||
public slots:
|
||||
virtual void highlightCurrentLine();
|
||||
|
||||
@ -181,6 +197,8 @@ private:
|
||||
|
||||
QColor m_selectedWordColor;
|
||||
QColor m_searchedWordColor;
|
||||
QColor m_searchedWordCursorColor;
|
||||
QColor m_incrementalSearchedWordColor;
|
||||
QColor m_trailingSpaceColor;
|
||||
|
||||
// Timer for extra selections highlight.
|
||||
@ -214,6 +232,13 @@ private:
|
||||
void (*p_filter)(VEdit *, QList<QTextEdit::ExtraSelection> &) = NULL);
|
||||
|
||||
void highlightSearchedWord(const QString &p_text, uint p_options);
|
||||
|
||||
// Highlight @p_cursor as the searched keyword under cursor.
|
||||
void highlightSearchedWordUnderCursor(const QTextCursor &p_cursor);
|
||||
|
||||
// Highlight @p_cursor as the incremental searched keyword.
|
||||
void highlightIncrementalSearchedWord(const QTextCursor &p_cursor);
|
||||
|
||||
bool wordInSearchedSelection(const QString &p_text);
|
||||
|
||||
// Return the first visible block.
|
||||
@ -221,6 +246,18 @@ private:
|
||||
|
||||
// Return the y offset of the content.
|
||||
int contentOffsetY();
|
||||
|
||||
// Find @p_text in the document starting from @p_start.
|
||||
// Returns true if @p_text is found and set @p_cursor to indicate
|
||||
// the position.
|
||||
// Will NOT change current cursor.
|
||||
bool findTextHelper(const QString &p_text, uint p_options,
|
||||
bool p_forward, int p_start,
|
||||
bool &p_wrapped, QTextCursor &p_cursor);
|
||||
|
||||
// Scroll the content to make @p_block visible.
|
||||
// Will not change current cursor.
|
||||
void makeBlockVisible(const QTextBlock &p_block);
|
||||
};
|
||||
|
||||
class LineNumberArea : public QWidget
|
||||
|
Loading…
x
Reference in New Issue
Block a user