QmlDesigner: Handle undo/redo/manual edits while editing subcomponent

Undo/redo stack is reset when changing between subcomponent and
document edit modes, so we can assume any undo/redo is contained within
the component. Manual edits can still happen outside the component
code, but we can assume they are always limited to either outside or
inside the component code, as the only way to make a manual edit
that spans both is to delete a block that includes both, which
invalidates the subcomponent anyway.

Fixes: QDS-5392
Change-Id: I820de73f519215a9cb3672abc55d5aa60cce078a
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Miikka Heikkinen
2021-11-11 13:23:23 +02:00
parent 25f1efc2b6
commit c2fb654681
2 changed files with 58 additions and 28 deletions

View File

@@ -279,6 +279,7 @@ bool DesignDocument::isDocumentLoaded() const
void DesignDocument::resetToDocumentModel()
{
plainTextEdit()->document()->clearUndoRedoStacks();
m_inFileComponentModel.reset();
}
@@ -310,6 +311,8 @@ void DesignDocument::changeToDocumentModel()
viewManager().detachRewriterView();
viewManager().detachViewsExceptRewriterAndComponetView();
plainTextEdit()->document()->clearUndoRedoStacks();
m_inFileComponentModel.reset();
m_inFileComponentTextModifier.reset();
@@ -345,6 +348,8 @@ void DesignDocument::changeToInFileComponentModel(ComponentTextModifier *textMod
viewManager().detachRewriterView();
viewManager().detachViewsExceptRewriterAndComponetView();
plainTextEdit()->document()->clearUndoRedoStacks();
m_inFileComponentModel.reset(createInFileComponentModel());
m_inFileComponentModel->setTextModifier(m_inFileComponentTextModifier.data());

View File

@@ -160,40 +160,65 @@ void ComponentTextModifier::handleOriginalTextChanged()
const QString currentText = m_originalModifier->text();
// Adjust for removal/addition of whitespace in the document
// Check that non-whitespace portion of the text is the same and count the whitespace diff
const int oldLen = m_originalText.size();
const int newLen = currentText.size();
int newSpace = 0;
int oldSpace = 0;
int newIdx = 0;
for (int oldIdx = 0; oldIdx < oldLen; ++oldIdx) {
const QChar oldChar = m_originalText[oldIdx];
if (oldIdx == m_componentStartOffset)
m_componentStartOffset += newSpace - oldSpace;
if (oldIdx == m_componentEndOffset) {
m_componentEndOffset += newSpace - oldSpace;
break;
if (oldLen != newLen) {
int newSpace = 0;
int oldSpace = 0;
int newIdx = 0;
int nonWhiteSpaceChangeIdx = -1;
int newStartOffset = m_componentStartOffset;
// Adjust for removal/addition of whitespace in the document.
// Whitespace changes that happen when document is saved can be spread around throughout
// the entire document in multiple places.
// Check that non-whitespace portion of the text is the same and count the whitespace diff
for (int oldIdx = 0; oldIdx < oldLen; ++oldIdx) {
const QChar oldChar = m_originalText[oldIdx];
if (oldIdx == m_componentStartOffset)
newStartOffset += newSpace - oldSpace;
if (oldIdx == m_componentEndOffset) {
m_componentEndOffset += newSpace - oldSpace;
m_componentStartOffset = newStartOffset;
m_originalText = currentText;
break;
}
while (newIdx < newLen && currentText[newIdx].isSpace()) {
++newSpace;
++newIdx;
}
if (oldChar.isSpace()) {
++oldSpace;
continue;
}
if (currentText[newIdx] != oldChar) {
nonWhiteSpaceChangeIdx = oldIdx;
// A non-whitespace change is a result of manual text edit or undo/redo operation.
// Assumption is that separate whitespace changes and a non-whitespace change can't
// both happen simultaneously, so break out of whitespace check loop.
break;
} else {
++newIdx;
}
}
while (newIdx < newLen && currentText[newIdx].isSpace()) {
++newSpace;
++newIdx;
if (nonWhiteSpaceChangeIdx >= 0) {
// For non-whitespace change, we assume the whole change is either before the component
// or inside the component. If the change spans both, it's likely the change is
// invalid anyway, and we don't care about trying to keep offsets up to date.
int diff = newLen - oldLen;
if (nonWhiteSpaceChangeIdx < m_componentEndOffset)
m_componentEndOffset += diff;
if (nonWhiteSpaceChangeIdx < m_componentStartOffset)
m_componentStartOffset += diff;
m_originalText = currentText;
}
if (oldChar.isSpace()) {
++oldSpace;
continue;
}
if (currentText[newIdx] != oldChar) {
// Non-whitespace difference, we can't determine a valid offset in this case
// TODO: Needs proper handling to deal with undo/redo/arbitrary edits somehow (QDS-5392)
break;
} else {
++newIdx;
}
}
m_originalText = currentText;
emit textChanged();
}