From aeaa61a4b8ad7339bd5d1a32374c05253ce971da Mon Sep 17 00:00:00 2001 From: mae Date: Wed, 7 Apr 2010 13:13:15 +0200 Subject: Fix QTextDocument::undo() cursor positioning When doing block undo operations, QTextDocument used the change position of the last undo command for positioning the cursor. This is incorrect if the last commands are of type QTextUndoCommand::Removed but split because of the text fragments. The bug is highly noticable in creator when inserting snippets and doing undo afterwards. The change adds an auto test. --- src/gui/text/qtextdocument_p.cpp | 32 ++++++++++++++++++++++------ tests/auto/qtextcursor/tst_qtextcursor.cpp | 34 ++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 7 deletions(-) diff --git a/src/gui/text/qtextdocument_p.cpp b/src/gui/text/qtextdocument_p.cpp index 969d5b4..646ef4c 100644 --- a/src/gui/text/qtextdocument_p.cpp +++ b/src/gui/text/qtextdocument_p.cpp @@ -870,6 +870,7 @@ int QTextDocumentPrivate::undoRedo(bool undo) undoEnabled = false; beginEditBlock(); int editPos = -1; + int editLength = -1; while (1) { if (undo) --undoState; @@ -882,12 +883,16 @@ int QTextDocumentPrivate::undoRedo(bool undo) PMDEBUG(" erase: from %d, length %d", c.pos, c.length); c.command = QTextUndoCommand::Removed; editPos = c.pos; + editLength = 0; break; case QTextUndoCommand::Removed: PMDEBUG(" insert: format %d (from %d, length %d, strpos=%d)", c.format, c.pos, c.length, c.strPos); insert_string(c.pos, c.strPos, c.length, c.format, (QTextUndoCommand::Operation)c.operation); c.command = QTextUndoCommand::Inserted; - editPos = c.pos + c.length; + if (editPos != (int)c.pos) + editLength = 0; + editPos = c.pos; + editLength += c.length; break; case QTextUndoCommand::BlockInserted: case QTextUndoCommand::BlockAdded: @@ -898,6 +903,7 @@ int QTextDocumentPrivate::undoRedo(bool undo) else c.command = QTextUndoCommand::BlockDeleted; editPos = c.pos; + editLength = 0; break; case QTextUndoCommand::BlockRemoved: case QTextUndoCommand::BlockDeleted: @@ -908,7 +914,10 @@ int QTextDocumentPrivate::undoRedo(bool undo) c.command = QTextUndoCommand::BlockInserted; else c.command = QTextUndoCommand::BlockAdded; - editPos = c.pos + 1; + if (editPos != (int)c.pos) + editLength = 0; + editPos = c.pos; + editLength += 1; break; case QTextUndoCommand::CharFormatChanged: { resetBlockRevision = -1; // ## TODO @@ -919,7 +928,10 @@ int QTextDocumentPrivate::undoRedo(bool undo) int oldFormat = it.value()->format; setCharFormat(c.pos, c.length, formats.charFormat(c.format)); c.format = oldFormat; - editPos = c.pos + c.length; + if (editPos != (int)c.pos) + editLength = 0; + editPos = c.pos; + editLength += c.length; break; } case QTextUndoCommand::BlockFormatChanged: { @@ -987,13 +999,19 @@ int QTextDocumentPrivate::undoRedo(bool undo) break; } undoEnabled = true; - if (editPos < 0 && docChangeFrom >= 0) { - editPos = qMin(docChangeFrom + docChangeLength, length() - 1); - } + + int newCursorPos = -1; + + if (editPos >=0) + newCursorPos = editPos + editLength; + else if (docChangeFrom >= 0) + newCursorPos= qMin(docChangeFrom + docChangeLength, length() - 1); + endEditBlock(); emitUndoAvailable(isUndoAvailable()); emitRedoAvailable(isRedoAvailable()); - return editPos; + + return newCursorPos; } /*! diff --git a/tests/auto/qtextcursor/tst_qtextcursor.cpp b/tests/auto/qtextcursor/tst_qtextcursor.cpp index f55b8db..d44ce72 100644 --- a/tests/auto/qtextcursor/tst_qtextcursor.cpp +++ b/tests/auto/qtextcursor/tst_qtextcursor.cpp @@ -150,6 +150,7 @@ private slots: void adjustCursorsOnInsert(); void cursorPositionWithBlockUndoAndRedo(); + void cursorPositionWithBlockUndoAndRedo2(); private: int blockCount(); @@ -1778,5 +1779,38 @@ void tst_QTextCursor::cursorPositionWithBlockUndoAndRedo() QCOMPARE(cursor.position(), cursorPositionAfter); } +void tst_QTextCursor::cursorPositionWithBlockUndoAndRedo2() +{ + cursor.insertText("AAAABBBB"); + int cursorPositionBefore = cursor.position(); + cursor.setPosition(0, QTextCursor::KeepAnchor); + cursor.beginEditBlock(); + cursor.removeSelectedText(); + cursor.insertText("AAAABBBBCCCCDDDD"); + cursor.endEditBlock(); + doc->undo(&cursor); + QVERIFY(doc->toPlainText() == "AAAABBBB"); + QCOMPARE(cursor.position(), cursorPositionBefore); + + cursor.insertText("CCCC"); + QVERIFY(doc->toPlainText() == "AAAABBBBCCCC"); + + cursorPositionBefore = cursor.position(); + cursor.setPosition(0, QTextCursor::KeepAnchor); + cursor.beginEditBlock(); + cursor.removeSelectedText(); + cursor.insertText("AAAABBBBCCCCDDDD"); + cursor.endEditBlock(); + + /* this undo now implicitely reinserts two segments, first "CCCCC", then + "AAAABBBB". The test ensures that the two are combined in order to + reconstruct the correct cursor position */ + doc->undo(&cursor); + + + QVERIFY(doc->toPlainText() == "AAAABBBBCCCC"); + QCOMPARE(cursor.position(), cursorPositionBefore); +} + QTEST_MAIN(tst_QTextCursor) #include "tst_qtextcursor.moc" -- cgit v0.12 From 3d3bff79216a24625ac7e5aa33b40c5363a228fc Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Tue, 13 Apr 2010 14:43:48 +0200 Subject: qdoc: Changed