From dc9dc6b00204a5fef3542dc9a1f56f533353e058 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Thu, 28 Oct 2021 15:50:11 +0300 Subject: [PATCH] QmlDesigner: Adjust ComponentTextModifier offsets on doc text change ComponentTextModifier offsets were set at modifier creation time, and were not adjusted for changes on the document before the subcomponent code. Added rudimentary change detection logic for code additions and removals before subcomponent code and adjust offsets accordingly. Fixes: QDS-5305 Change-Id: I816adc1fc867b7135b992fb50a5d96e2cfd3f0d2 Reviewed-by: Mahmoud Badri Reviewed-by: Qt CI Bot Reviewed-by: Thomas Hartmann --- .../include/componenttextmodifier.h | 3 ++ .../model/componenttextmodifier.cpp | 47 ++++++++++++++++++- 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/designercore/include/componenttextmodifier.h b/src/plugins/qmldesigner/designercore/include/componenttextmodifier.h index d870f29622a..d35a4c149ee 100644 --- a/src/plugins/qmldesigner/designercore/include/componenttextmodifier.h +++ b/src/plugins/qmldesigner/designercore/include/componenttextmodifier.h @@ -62,11 +62,14 @@ public: { return false; } private: + void handleOriginalTextChanged(); + TextModifier *m_originalModifier; int m_componentStartOffset; int m_componentEndOffset; int m_rootStartOffset; int m_startLength; + QString m_originalText; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/model/componenttextmodifier.cpp b/src/plugins/qmldesigner/designercore/model/componenttextmodifier.cpp index 5f984a1f348..42dbbdd2a0e 100644 --- a/src/plugins/qmldesigner/designercore/model/componenttextmodifier.cpp +++ b/src/plugins/qmldesigner/designercore/model/componenttextmodifier.cpp @@ -33,10 +33,13 @@ ComponentTextModifier::ComponentTextModifier(TextModifier *originalModifier, int m_componentEndOffset(componentEndOffset), m_rootStartOffset(rootStartOffset) { - connect(m_originalModifier, &TextModifier::textChanged, this, &TextModifier::textChanged); + connect(m_originalModifier, &TextModifier::textChanged, + this, &ComponentTextModifier::handleOriginalTextChanged); connect(m_originalModifier, &TextModifier::replaced, this, &TextModifier::replaced); connect(m_originalModifier, &TextModifier::moved, this, &TextModifier::moved); + + m_originalText = m_originalModifier->text(); } ComponentTextModifier::~ComponentTextModifier() = default; @@ -146,3 +149,45 @@ void ComponentTextModifier::reactivateChangeSignals() { m_originalModifier->reactivateChangeSignals(); } + +void ComponentTextModifier::handleOriginalTextChanged() +{ + // Update offsets when original text changes, if necessary + + // Detect and adjust for removal/addition of unrelated text before the subcomponent code, + // as that can happen even without user editing the text (e.g. whitespace removal at save time) + + const QString currentText = m_originalModifier->text(); + + if (m_originalText.left(m_componentStartOffset) != currentText.left(m_componentStartOffset)) { + // Subcomponent item id is the only reliable indicator for adjustment + const int idIndex = m_originalText.indexOf("id:", m_componentStartOffset); + if (idIndex != -1 && idIndex < m_componentEndOffset) { + int newLineIndex = m_originalText.indexOf('\n', idIndex); + if (newLineIndex != -1) { + const QString checkLine = m_originalText.mid(idIndex, newLineIndex - idIndex); + int lineIndex = currentText.indexOf(checkLine); + if (lineIndex != -1) { + // Paranoia check - This shouldn't happen except when modifying text manually, + // but it's possible something was inserted between id and start + // of the component, which would throw off the calculation, so check that + // the first line is still correct even with new offset. + const int diff = idIndex - lineIndex; + newLineIndex = m_originalText.indexOf('\n', m_componentStartOffset); + if (newLineIndex != -1) { + const QString firstLine = m_originalText.mid(m_componentStartOffset, + newLineIndex - m_componentStartOffset); + const int newStart = m_componentStartOffset - diff; + if (firstLine == currentText.mid(newStart, firstLine.size())) { + m_componentEndOffset -= diff; + m_componentStartOffset = newStart; + m_originalText = currentText; + } + } + } + } + } + } + + emit textChanged(); +}