diff options
author | mae <qt-info@nokia.com> | 2010-04-07 11:13:15 (GMT) |
---|---|---|
committer | mae <qt-info@nokia.com> | 2010-04-07 11:54:03 (GMT) |
commit | 054950602a6675d01a9815a567b69157ee8ceff6 (patch) | |
tree | 8208e5557ca6db761d8f6b44fd4210a155b0a59d | |
parent | 0dd9960cbc533e377c8cc38b9e81b14108fac9be (diff) | |
download | Qt-054950602a6675d01a9815a567b69157ee8ceff6.zip Qt-054950602a6675d01a9815a567b69157ee8ceff6.tar.gz Qt-054950602a6675d01a9815a567b69157ee8ceff6.tar.bz2 |
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.
-rw-r--r-- | src/gui/text/qtextdocument_p.cpp | 32 | ||||
-rw-r--r-- | 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 302a349..e2bca04 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" |