path: root/tests
diff options
authorEskil Abrahamsen Blomfeldt <>2014-09-22 15:50:29 +0200
committerEskil Abrahamsen Blomfeldt <>2014-09-30 10:21:39 +0200
commit27bc4c4ce5f1af8fd06b60c5d06e011001ea3613 (patch)
tree7d1fcb3155cf7c0b1a3b79a1e08fe6d06994d488 /tests
parentee6e9cbf36a189a4f59851ea3b069560e823b4ef (diff)
QPlainTextEdit: Fix crash on complex undo w/full width selection
Say you have a document of two blocks of text. When you select a block of text in the document and then replace this with a new empty block (by pressing enter) and then subsequently undo this action, the following three steps are performed as a chain of undo commands: 1. Remove the empty block at the beginning of the document 2. Insert a new empty block at the beginning of the document 3. Insert the text back into the first block Since a block is removed and inserted in the same go, both blocks require a relayout, since the accumulated change spans both blocks. However, in QPlainTextDocumentLayout we would only look at the max of either removed chars or added chars. This would match the text length of the first block at this point, so we would only relayout that block. However, since we are also removing characters, the actual accumulated change to the document is larger. We should relayout any block touched by the sum of the added and removed character counts. Missing this, the paint event would later query block.layout()->lineForTextPosition(0) which would give an invalid line despite the fact that the block.length() > 0. This caused a crash in the paint event when the full width selection was turned on. Note that the logic here was only recently updated to include the removed characters at all in the logic, by the SHA1: 2983cb9531d47e5826540ca79e3066a8ed0db30c. [ChangeLog][QPlainTextEdit] Fixed a crash when using full width selections and issuing a complex undo command chain which removes and inserts an empty block in one go. Task-number: QTBUG-36415 Change-Id: Iafe8a69e455e0c713a48714f10f0cace69c84f51 Reviewed-by: Axel Rasmussen <> Reviewed-by: Konstantin Ritt <> Reviewed-by: Simon Hausmann <>
Diffstat (limited to 'tests')
1 files changed, 25 insertions, 0 deletions
diff --git a/tests/auto/widgets/widgets/qplaintextedit/tst_qplaintextedit.cpp b/tests/auto/widgets/widgets/qplaintextedit/tst_qplaintextedit.cpp
index c47f7b1ff6..613d4fa28c 100644
--- a/tests/auto/widgets/widgets/qplaintextedit/tst_qplaintextedit.cpp
+++ b/tests/auto/widgets/widgets/qplaintextedit/tst_qplaintextedit.cpp
@@ -155,6 +155,7 @@ private slots:
void findWithRegExpReturnsFalseIfNoMoreResults();
void layoutAfterMultiLineRemove();
+ void undoCommandRemovesAndReinsertsBlock();
void createSelection();
@@ -1612,5 +1613,29 @@ void tst_QPlainTextEdit::layoutAfterMultiLineRemove()
QCOMPARE(curs.blockNumber(), 3);
+void tst_QPlainTextEdit::undoCommandRemovesAndReinsertsBlock()
+ ed->setVisible(true);
+ ed->setPlainText(QStringLiteral("line1\nline2"));
+ QCOMPARE(ed->document()->blockCount(), 2);
+ QTextCursor cursor = ed->textCursor();
+ cursor.movePosition(QTextCursor::Start);
+ cursor.movePosition(QTextCursor::NextBlock, QTextCursor::KeepAnchor);
+ cursor.insertText(QStringLiteral("\n"));
+ QCOMPARE(ed->document()->blockCount(), 2);
+ ed->undo();
+ QCOMPARE(ed->document()->blockCount(), 2);
+ QTextBlock block;
+ for (block = ed->document()->begin(); block != ed->document()->end(); block = {
+ QVERIFY(block.isValid());
+ QCOMPARE(block.length(), 6);
+ QVERIFY(block.layout()->lineForTextPosition(0).isValid());
+ }
#include "tst_qplaintextedit.moc"