Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 32 additions & 2 deletions src/common/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@
#include <QJsonDocument>
#include <QMimeDatabase>
#include <QJsonObject>
#include <QApplication>

Check warning on line 17 in src/common/utils.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QApplication> not found. Please note: Cppcheck does not need standard library headers to get proper results.

Check warning on line 17 in src/common/utils.cpp

View workflow job for this annotation

GitHub Actions / static-check / static-check

Include file: <QApplication> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QDebug>

Check warning on line 18 in src/common/utils.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QDebug> not found. Please note: Cppcheck does not need standard library headers to get proper results.

Check warning on line 18 in src/common/utils.cpp

View workflow job for this annotation

GitHub Actions / static-check / static-check

Include file: <QDebug> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QDir>

Check warning on line 19 in src/common/utils.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QDir> not found. Please note: Cppcheck does not need standard library headers to get proper results.

Check warning on line 19 in src/common/utils.cpp

View workflow job for this annotation

GitHub Actions / static-check / static-check

Include file: <QDir> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QHash>

Check warning on line 20 in src/common/utils.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QHash> not found. Please note: Cppcheck does not need standard library headers to get proper results.

Check warning on line 20 in src/common/utils.cpp

View workflow job for this annotation

GitHub Actions / static-check / static-check

Include file: <QHash> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QSet>

Check warning on line 21 in src/common/utils.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QSet> not found. Please note: Cppcheck does not need standard library headers to get proper results.

Check warning on line 21 in src/common/utils.cpp

View workflow job for this annotation

GitHub Actions / static-check / static-check

Include file: <QSet> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QFontMetrics>

Check warning on line 22 in src/common/utils.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QFontMetrics> not found. Please note: Cppcheck does not need standard library headers to get proper results.

Check warning on line 22 in src/common/utils.cpp

View workflow job for this annotation

GitHub Actions / static-check / static-check

Include file: <QFontMetrics> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QPainter>

Check warning on line 23 in src/common/utils.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QPainter> not found. Please note: Cppcheck does not need standard library headers to get proper results.

Check warning on line 23 in src/common/utils.cpp

View workflow job for this annotation

GitHub Actions / static-check / static-check

Include file: <QPainter> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QString>

Check warning on line 24 in src/common/utils.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QString> not found. Please note: Cppcheck does not need standard library headers to get proper results.

Check warning on line 24 in src/common/utils.cpp

View workflow job for this annotation

GitHub Actions / static-check / static-check

Include file: <QString> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QtMath>
#include <QWidget>
#include <QStandardPaths>
Expand Down Expand Up @@ -562,8 +564,36 @@

QString Utils::getKeyshortcutFromKeymap(Settings *settings, const QString &keyCategory, const QString &keyName)
{
qDebug() << "Enter getKeyshortcutFromKeymap, keyCategory:" << keyCategory << "keyName:" << keyName;
return settings->settings->option(QString("shortcuts.%1.%2").arg(keyCategory).arg(keyName))->value().toString();
if (settings == nullptr || settings->settings == nullptr) {
return QString();
}

static QHash<QString, QString> cache;
static QSet<Settings *> watchedSettings;
const QString cacheKey = QStringLiteral("shortcuts.%1.%2").arg(keyCategory).arg(keyName);

if (!watchedSettings.contains(settings)) {
watchedSettings.insert(settings);
QObject::connect(settings->settings, &Dtk::Core::DSettings::valueChanged, settings, [&cache](const QString &key) {
if (key.startsWith(QStringLiteral("shortcuts."))) {
cache.clear();
}
});
}

const auto it = cache.constFind(cacheKey);
if (it != cache.constEnd()) {
return it.value();
}

Dtk::Core::DSettingsOption *option = settings->settings->option(cacheKey);
if (option == nullptr) {
return QString();
}

const QString result = option->value().toString();
cache.insert(cacheKey, result);
return result;
}

QPixmap Utils::dropShadow(const QPixmap &source, qreal radius, const QColor &color, const QPoint &offset)
Expand Down
152 changes: 34 additions & 118 deletions src/editor/dtextedit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,16 +109,15 @@ TextEdit::TextEdit(QWidget *parent)
// Init widgets.
//左边栏控件 滑动条滚动跟新行号 折叠标记
connect(this->verticalScrollBar(), &QScrollBar::valueChanged, this, &TextEdit::slotValueChanged);
// 左侧栏更新节流:textChanged 每次按键都触发,50ms 合并连续按键
m_leftAreaUpdateTimer.setSingleShot(true);
m_leftAreaUpdateTimer.setInterval(50);
connect(&m_leftAreaUpdateTimer, &QTimer::timeout, this, &TextEdit::updateLeftAreaWidget);
connect(this, &QPlainTextEdit::textChanged, this, [this]() {
if (m_wrapper) {
m_wrapper->UpdateBottomBarWordCnt(characterCount());
}
// 仅行数变化时全量刷新左侧栏;同行编辑由 cursorPositionChanged 局部 update 负责
const int blockCountNow = blockCount();
if (blockCountNow != m_lastLeftAreaBlockCount) {
m_lastLeftAreaBlockCount = blockCountNow;
updateLeftAreaWidget();
}
m_leftAreaUpdateTimer.start();
});

connect(this, &QPlainTextEdit::cursorPositionChanged, this, &TextEdit::cursorPositionChanged);
Expand Down Expand Up @@ -170,11 +169,6 @@ TextEdit::TextEdit(QWidget *parent)
m_scrollAnimation->setEasingCurve(QEasingCurve::InOutExpo);
m_scrollAnimation->setDuration(300);

m_typingBurstFlushTimer = new QTimer(this);
m_typingBurstFlushTimer->setSingleShot(true);
m_typingBurstFlushTimer->setInterval(120);
connect(m_typingBurstFlushTimer, &QTimer::timeout, this, &TextEdit::flushDeferredCursorUpdate);

m_cursorMode = Insert;

connect(m_scrollAnimation, &QPropertyAnimation::finished, this, &TextEdit::handleScrollFinish, Qt::QueuedConnection);
Expand Down Expand Up @@ -309,7 +303,6 @@ void TextEdit::deleteSelectTextEx(QTextCursor cursor, QString text, bool currLin
void TextEdit::deleteTextEx(QTextCursor cursor)
{
qDebug() << "Deleting text at position:" << cursor.position();
flushDeferredCursorUpdate();
QUndoCommand *pDeleteStack = new DeleteTextUndoCommand(cursor, this);
m_pUndoStack->push(pDeleteStack);
qDebug() << "Text deleted successfully";
Expand Down Expand Up @@ -340,32 +333,15 @@ void TextEdit::deleteMultiTextEx(const QList<QTextCursor> &multiText)
void TextEdit::insertSelectTextEx(QTextCursor cursor, QString text)
{
qDebug() << "Inserting selected text at position:" << cursor.position() << "Length:" << text.length();

const bool deferHeavyUpdate = shouldDeferCursorHeavyUpdate(cursor, text);
if (!deferHeavyUpdate) {
flushDeferredCursorUpdate();
} else {
const int line = cursor.blockNumber();
if (m_deferCursorHeavyUpdate && line != m_deferCursorLastLine) {
flushDeferredCursorUpdate();
}
m_deferCursorHeavyUpdate = true;
m_deferCursorLastLine = line;
}

QUndoCommand *pInsertStack = new InsertTextUndoCommand(cursor, text, this);
m_pUndoStack->push(pInsertStack);
ensureCursorVisible();
if (deferHeavyUpdate) {
scheduleDeferredCursorUpdateBurst();
}
qDebug() << "Selected text inserted successfully";
}

void TextEdit::insertColumnEditTextEx(QString text)
{
qDebug() << "Inserting column text";
flushDeferredCursorUpdate();
if (m_isSelectAll) {
QPlainTextEdit::selectAll();
}
Expand Down Expand Up @@ -3016,63 +2992,7 @@ bool TextEdit::setCursorKeywordSeletoin(int position, bool findNext)
return false;
}

bool TextEdit::shouldDeferCursorHeavyUpdate(const QTextCursor &cursor, const QString &text) const
{
if (m_cursorMode != Insert
|| m_bIsAltMod
|| m_readOnlyMode
|| m_bReadOnlyPermission
|| m_bIsFileOpen
|| m_isPreeditBefore
|| m_bIsInputMethod) {
return false;
}

if (cursor.anchor() != cursor.position()) {
return false;
}

for (const QChar ch : text) {
if (ch == QLatin1Char('\n') || ch == QLatin1Char('\t') || ch == QChar::ParagraphSeparator) {
return false;
}
}

return true;
}

void TextEdit::scheduleDeferredCursorUpdateBurst()
{
m_deferCursorHeavyUpdate = true;
m_deferCursorLastLine = textCursor().blockNumber();
m_typingBurstFlushTimer->start();
}

void TextEdit::flushDeferredCursorUpdate()
{
if (m_typingBurstFlushTimer != nullptr) {
m_typingBurstFlushTimer->stop();
}

if (!m_deferCursorHeavyUpdate) {
return;
}

m_deferCursorHeavyUpdate = false;
m_deferCursorLastLine = -1;
applyCursorHeavyUpdate();
}

void TextEdit::updateCursorPositionStatusLightweight()
{
QTextCursor cursor = textCursor();
if (m_wrapper) {
m_wrapper->bottomBar()->updatePosition(cursor.blockNumber() + 1,
cursor.positionInBlock() + 1);
}
}

void TextEdit::applyCursorHeavyUpdate()
void TextEdit::cursorPositionChanged()
{
qDebug() << "Cursor position changed";
// 以赋值形式,清空 Bracket 括号的selection
Expand All @@ -3081,35 +3001,21 @@ void TextEdit::applyCursorHeavyUpdate()
m_endBracketSelection = QTextEdit::ExtraSelection();

updateHighlightLineSelection();
updateHighlightBrackets('(', ')');
updateHighlightBrackets('{', '}');
updateHighlightBrackets('[', ']');
updateHighlightBracketsAll();
renderAllSelections();

updateCursorPositionStatusLightweight();
QTextCursor cursor = textCursor();
if (m_wrapper) {
m_wrapper->bottomBar()->updatePosition(cursor.blockNumber() + 1,
cursor.positionInBlock() + 1);
}

m_pLeftAreaWidget->m_pLineNumberArea->update();
m_pLeftAreaWidget->m_pBookMarkArea->update();
m_pLeftAreaWidget->m_pFlodArea->update();
qDebug() << "Cursor position changed completed";
}

void TextEdit::cursorPositionChanged()
{
if (m_deferCursorHeavyUpdate) {
const int line = textCursor().blockNumber();
if (line != m_deferCursorLastLine) {
flushDeferredCursorUpdate();
return;
}

updateCursorPositionStatusLightweight();
return;
}

applyCursorHeavyUpdate();
}

/**
* @brief 剪切光标选中的文本
* @param ignoreCheck 是否忽略权限判断(外部已进行),默认false
Expand Down Expand Up @@ -3277,10 +3183,10 @@ void TextEdit::paste()

void TextEdit::highlight()
{
QTimer::singleShot(0, this, [&]() {
if (nullptr != m_wrapper) {
QTimer::singleShot(0, this, [this]() {
if (m_wrapper != nullptr) {
qDebug() << "Highlighting with wrapper";
m_wrapper->OnUpdateHighlighter();
m_wrapper->scheduleHighlight();
}
});
qDebug() << "Highlighting completed";
Expand Down Expand Up @@ -3635,7 +3541,6 @@ void TextEdit::slotRedoAvailable(bool redoIsAvailable)
void TextEdit::redo_()
{
qDebug() << "Starting redo operation";
flushDeferredCursorUpdate();
if (!m_pUndoStack->canRedo()) {
qDebug() << "Redo operation skipped - nothing to redo";
return;
Expand Down Expand Up @@ -3667,7 +3572,6 @@ void TextEdit::undo_()
{
qDebug() << "Starting undo operation";
qDebug() << "Starting undo operation";
flushDeferredCursorUpdate();
if (!m_pUndoStack->canUndo()) {
qDebug() << "Undo operation skipped - nothing to undo";
return;
Expand Down Expand Up @@ -4044,6 +3948,24 @@ void TextEdit::updateHighlightBrackets(const QChar &openChar, const QChar &close
qDebug() << "Updating highlight brackets completed";
}

void TextEdit::updateHighlightBracketsAll()
{
QTextDocument *doc = document();
QTextCursor cursor = textCursor();
const int position = cursor.position();

const QChar atPos = doc->characterAt(position);
const QChar atPrev = doc->characterAt(position - 1);
static const QString brackets = QStringLiteral("(){}[]");
if (!brackets.contains(atPos) && !brackets.contains(atPrev)) {
return;
}

updateHighlightBrackets('(', ')');
updateHighlightBrackets('{', '}');
updateHighlightBrackets('[', ']');
}

int TextEdit::getFirstVisibleBlockId() const
{
qDebug() << "Getting first visible block id";
Expand Down Expand Up @@ -5593,7 +5515,6 @@ void TextEdit::setTextFinished()
qDebug() << "Set text finished";
m_bIsFileOpen = false;
m_nLines = blockCount();
m_lastLeftAreaBlockCount = m_nLines;

if (!m_listBookmark.isEmpty()) {
qDebug() << "Set text finished, m_listBookmark is not empty";
Expand Down Expand Up @@ -6798,8 +6719,7 @@ void TextEdit::updateMark(int from, int charsRemoved, int charsAdded)
}
}

//渲染所有的指定字符格式
renderAllSelections();
// renderAllSelections 和 highlight 已在 cursorPositionChanged / highlight 防抖定时器中统一调度
qDebug() << "updateMark, completed";
}

Expand Down Expand Up @@ -7710,7 +7630,6 @@ void TextEdit::dropEvent(QDropEvent *event)

void TextEdit::inputMethodEvent(QInputMethodEvent *e)
{
flushDeferredCursorUpdate();
m_bIsInputMethod = true;

if (m_isSelectAll)
Expand Down Expand Up @@ -7781,7 +7700,6 @@ void TextEdit::inputMethodEvent(QInputMethodEvent *e)

void TextEdit::mousePressEvent(QMouseEvent *e)
{
flushDeferredCursorUpdate();
if (m_bIsFindClose)
{
m_bIsFindClose = false;
Expand Down Expand Up @@ -8301,7 +8219,6 @@ void TextEdit::keyPressEvent(QKeyEvent *e)

//列编辑 删除撤销重做
if (modifiers == Qt::NoModifier && (e->key() == Qt::Key_Backspace)) {
flushDeferredCursorUpdate();
if (m_isSelectAll)
QPlainTextEdit::selectAll();

Expand All @@ -8325,7 +8242,6 @@ void TextEdit::keyPressEvent(QKeyEvent *e)

//列编辑 向后删除撤销重做
if (modifiers == Qt::NoModifier && (e->key() == Qt::Key_Delete)) {
flushDeferredCursorUpdate();
if (m_isSelectAll)
QPlainTextEdit::selectAll();

Expand Down
12 changes: 2 additions & 10 deletions src/editor/dtextedit.h
Original file line number Diff line number Diff line change
Expand Up @@ -511,9 +511,6 @@ public slots:
void onSelectionArea();
void fingerZoom(QString name, QString direction, int fingers);
void cursorPositionChanged();
void flushDeferredCursorUpdate();
void applyCursorHeavyUpdate();
void updateCursorPositionStatusLightweight();

//剪切槽函数
void cut(bool ignoreCheck = false);
Expand Down Expand Up @@ -589,6 +586,7 @@ public slots:
void unCommentSelection();
void setComment();
void removeComment();
void updateHighlightBracketsAll();

//去除"*{*" "*}*" "*{*}*"跳过当做普通文本处理不折叠 梁卫东2020-09-01 17:16:41
bool blockContainStrBrackets(int line);
Expand Down Expand Up @@ -788,7 +786,6 @@ private slots:
QList<int> m_listBookmark;///< 存储书签的list
int m_nBookMarkHoverLine;///< 悬浮效果书签所在的行
int m_nLines;///< 文本总行数
int m_lastLeftAreaBlockCount = 0;///< 上次刷新左侧栏时的文档行数
bool m_bIsFileOpen;///< 是否在读取文件(导致文本变化)
bool m_bIsShortCut;///< 是否在使用书签快捷键

Expand Down Expand Up @@ -877,12 +874,7 @@ private slots:
bool m_isPreeditBefore = false; // 上一个输入法时间是否是 preedit
int m_preeditLengthBefore = 0;

bool shouldDeferCursorHeavyUpdate(const QTextCursor &cursor, const QString &text) const;
void scheduleDeferredCursorUpdateBurst();

bool m_deferCursorHeavyUpdate = false;
int m_deferCursorLastLine = -1;
QTimer *m_typingBurstFlushTimer = nullptr;
QTimer m_leftAreaUpdateTimer;

Qt::CaseSensitivity defaultCaseSensitive = Qt::CaseInsensitive; // 查找匹配时默认不区分大小写
};
Expand Down
10 changes: 10 additions & 0 deletions src/editor/editwrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,11 @@ EditWrapper::EditWrapper(Window *window, QWidget *parent)
connect(m_pTextEdit, &TextEdit::cursorModeChanged, this, &EditWrapper::handleCursorModeChanged);
connect(m_pWaringNotices, &WarningNotices::reloadBtnClicked, this, &EditWrapper::reloadModifyFile);
connect(m_pWaringNotices, &WarningNotices::saveAsBtnClicked, m_pWindow, &Window::saveAsFile);

m_highlightDebounceTimer.setSingleShot(true);
m_highlightDebounceTimer.setInterval(150);
connect(&m_highlightDebounceTimer, &QTimer::timeout, this, &EditWrapper::OnUpdateHighlighter);

// NOTE: 文本高亮会触发重新布局,与界面布局(拖拽、放大窗口)变更时的布局操作冲突,因此调整更新顺序,在布局后刷新高亮
connect(m_pTextEdit->verticalScrollBar(), &QScrollBar::valueChanged, this, [this](int) {
qDebug() << "EditWrapper connect verticalScrollBar valueChanged";
Expand Down Expand Up @@ -1150,6 +1155,11 @@ void EditWrapper::UpdateBottomBarWordCnt(int cnt)
m_pBottomBar->updateWordCount(cnt);
}

void EditWrapper::scheduleHighlight()
{
m_highlightDebounceTimer.start();
}

/**
* @brief 界面显示内容变更时触发,将查询当前显示的内容
* @param forceUpdate 是否强制重设高亮处理,部分高亮无需重复设置
Expand Down
Loading
Loading