/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see http://www.qt.io/terms-conditions. For further ** information use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** As a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include #include #include #include #include #include #include //TESTED_FILES=gui/text/qtextcursor.cpp gui/text/qtextcursor_p.h QT_FORWARD_DECLARE_CLASS(QTextDocument) class tst_QTextCursor : public QObject { Q_OBJECT public: tst_QTextCursor(); public slots: void init(); void cleanup(); private slots: void navigation1(); void navigation2_data(); void navigation2(); void navigation3(); void navigation4(); void navigation5(); void navigation6(); void navigation7(); void navigation8(); void navigation9(); void navigation10(); void movePositionEndOfLine(); void insertBlock(); void insertWithBlockSeparator1(); void insertWithBlockSeparator2(); void insertWithBlockSeparator3(); void insertWithBlockSeparator4(); void clearObjectType1(); void clearObjectType2(); void clearObjectType3(); void comparisonOperators1(); void comparisonOperators2(); void selection1(); void dontCopyTableAttributes(); void checkFrame1(); void checkFrame2(); void tableMovement(); void selectionsInTable(); void insertBlockToUseCharFormat(); void selectedText(); void insertBlockShouldRemoveSelection(); void insertBlockShouldRemoveSelection2(); void mergeCellShouldUpdateSelection(); void joinPreviousEditBlock(); void setBlockFormatInTable(); void blockCharFormat(); void blockCharFormat2(); void blockCharFormat3(); void blockCharFormatOnSelection(); void anchorInitialized1(); void anchorInitialized2(); void anchorInitialized3(); void selectWord(); void selectWordWithSeparators_data(); void selectWordWithSeparators(); void startOfWord(); void selectBlock(); void selectVisually(); void insertText(); void insertFragmentShouldUseCurrentCharFormat(); void endOfLine(); void editBlocksDuringRemove(); void selectAllDuringRemove(); void update_data(); void update(); void disallowSettingObjectIndicesOnCharFormats(); void blockAndColumnNumber(); void clearCells(); void task244408_wordUnderCursor_data(); void task244408_wordUnderCursor(); void adjustCursorsOnInsert(); void cursorPositionWithBlockUndoAndRedo(); void cursorPositionWithBlockUndoAndRedo2(); void cursorPositionWithBlockUndoAndRedo3(); void joinNonEmptyRemovedBlockUserState(); private: int blockCount(); QTextDocument *doc; QTextCursor cursor; }; Q_DECLARE_METATYPE(QList) tst_QTextCursor::tst_QTextCursor() {} void tst_QTextCursor::init() { doc = new QTextDocument; cursor = QTextCursor(doc); } void tst_QTextCursor::cleanup() { cursor = QTextCursor(); delete doc; doc = 0; } void tst_QTextCursor::navigation1() { cursor.insertText("Hello World"); QVERIFY(doc->toPlainText() == "Hello World"); cursor.movePosition(QTextCursor::End); QVERIFY(cursor.position() == 11); cursor.deletePreviousChar(); QVERIFY(cursor.position() == 10); cursor.deletePreviousChar(); cursor.deletePreviousChar(); cursor.deletePreviousChar(); cursor.deletePreviousChar(); cursor.deletePreviousChar(); QVERIFY(doc->toPlainText() == "Hello"); QTextCursor otherCursor(doc); otherCursor.movePosition(QTextCursor::Start); otherCursor.movePosition(QTextCursor::Right); cursor = otherCursor; cursor.movePosition(QTextCursor::Right); QVERIFY(cursor != otherCursor); otherCursor.insertText("Hey"); QVERIFY(cursor.position() == 5); doc->undo(); QVERIFY(cursor.position() == 2); doc->redo(); QVERIFY(cursor.position() == 5); doc->undo(); doc->undo(); QVERIFY(doc->toPlainText() == "Hello World"); cursor.movePosition(QTextCursor::Start); cursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, 6); QVERIFY(cursor.position() == 6); otherCursor = cursor; otherCursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, 2); otherCursor.deletePreviousChar(); otherCursor.deletePreviousChar(); otherCursor.deletePreviousChar(); QVERIFY(cursor.position() == 5); cursor.movePosition(QTextCursor::End); cursor.insertBlock(); { int oldPos = cursor.position(); cursor.movePosition(QTextCursor::End); QVERIFY(cursor.position() == oldPos); } QVERIFY(cursor.atBlockStart()); QVERIFY(cursor.position() == 9); QTextCharFormat fmt; fmt.setForeground(Qt::blue); cursor.insertText("Test", fmt); QVERIFY(fmt == cursor.charFormat()); QVERIFY(cursor.position() == 13); } void tst_QTextCursor::navigation2_data() { QTest::addColumn("sl"); QTest::addColumn >("movement"); QTest::addColumn("finalPos"); QTest::newRow("startBlock1") << QStringList("Happy happy happy joy joy joy") << (QList() << QVariant(QTextCursor::StartOfBlock)) << 0; QTest::newRow("endBlock1") << QStringList("Happy happy happy joy joy joy") << (QList() << QVariant(QTextCursor::StartOfBlock) << QVariant(QTextCursor::EndOfBlock)) << 29; QTest::newRow("startBlock2") << QStringList("Happy happy happy joy joy joy") << (QList() << QVariant(QTextCursor::StartOfBlock) << QVariant(QTextCursor::EndOfBlock) << QVariant(QTextCursor::StartOfBlock)) << 0; QTest::newRow("endBlock2") << QStringList("Happy happy happy joy joy joy") << (QList() << QVariant(QTextCursor::StartOfBlock) << QVariant(QTextCursor::EndOfBlock) << QVariant(QTextCursor::StartOfBlock) << QVariant(QTextCursor::EndOfBlock) ) << 29; QTest::newRow("multiBlock1") << (QStringList() << QString("Happy happy happy") << QString("Joy Joy Joy")) << (QList() << QVariant(QTextCursor::StartOfBlock)) << 18; QTest::newRow("multiBlock2") << (QStringList() << QString("Happy happy happy") << QString("Joy Joy Joy")) << (QList() << QVariant(QTextCursor::StartOfBlock) << QVariant(QTextCursor::EndOfBlock)) << 29; QTest::newRow("multiBlock3") << (QStringList() << QString("Happy happy happy") << QString("Joy Joy Joy")) << (QList() << QVariant(QTextCursor::StartOfBlock) << QVariant(QTextCursor::StartOfBlock)) << 18; QTest::newRow("multiBlock4") << (QStringList() << QString("Happy happy happy") << QString("Joy Joy Joy")) << (QList() << QVariant(QTextCursor::Start) << QVariant(QTextCursor::EndOfBlock)) << 17; QTest::newRow("multiBlock5") << (QStringList() << QString("Happy happy happy") << QString("Joy Joy Joy")) << (QList() << QVariant(QTextCursor::Start) << QVariant(QTextCursor::EndOfBlock) << QVariant(QTextCursor::EndOfBlock)) << 17; QTest::newRow("multiBlock6") << (QStringList() << QString("Happy happy happy") << QString("Joy Joy Joy")) << (QList() << QVariant(QTextCursor::End) << QVariant(QTextCursor::StartOfBlock)) << 18; QTest::newRow("multiBlock7") << (QStringList() << QString("Happy happy happy") << QString("Joy Joy Joy")) << (QList() << QVariant(QTextCursor::PreviousBlock)) << 0; QTest::newRow("multiBlock8") << (QStringList() << QString("Happy happy happy") << QString("Joy Joy Joy")) << (QList() << QVariant(QTextCursor::PreviousBlock) << QVariant(QTextCursor::EndOfBlock)) << 17; QTest::newRow("multiBlock9") << (QStringList() << QString("Happy happy happy") << QString("Joy Joy Joy")) << (QList() << QVariant(QTextCursor::PreviousBlock) << QVariant(QTextCursor::NextBlock)) << 18; QTest::newRow("multiBlock10") << (QStringList() << QString("Happy happy happy") << QString("Joy Joy Joy")) << (QList() << QVariant(QTextCursor::PreviousBlock) << QVariant(QTextCursor::NextBlock) << QVariant(QTextCursor::NextBlock)) << 18; QTest::newRow("multiBlock11") << (QStringList() << QString("Happy happy happy") << QString("Joy Joy Joy")) << (QList() << QVariant(QTextCursor::PreviousBlock) << QVariant(QTextCursor::NextBlock) << QVariant(QTextCursor::EndOfBlock)) << 29; QTest::newRow("PreviousWord1") << (QStringList() << QString("Happy happy happy Joy Joy Joy")) << (QList() << QVariant(QTextCursor::PreviousWord)) << 26; QTest::newRow("PreviousWord2") << (QStringList() << QString("Happy happy happy Joy Joy Joy")) << (QList() << QVariant(QTextCursor::PreviousWord) << QVariant(QTextCursor::PreviousWord)) << 22; QTest::newRow("EndWord1") << (QStringList() << QString("Happy happy happy Joy Joy Joy")) << (QList() << QVariant(QTextCursor::PreviousWord) << QVariant(QTextCursor::PreviousWord) << QVariant(QTextCursor::EndOfWord)) << 25; QTest::newRow("NextWord1") << (QStringList() << QString("Happy happy happy Joy Joy Joy")) << (QList() << QVariant(QTextCursor::PreviousWord) << QVariant(QTextCursor::PreviousWord) << QVariant(QTextCursor::NextWord)) << 26; QTest::newRow("NextWord2") << (QStringList() << QString("Happy happy happy Joy Joy Joy")) << (QList() << QVariant(QTextCursor::Start) << QVariant(QTextCursor::NextWord) << QVariant(QTextCursor::EndOfWord)) << 11; QTest::newRow("StartWord1") << (QStringList() << QString("Happy happy happy Joy Joy Joy")) << (QList() << QVariant(QTextCursor::PreviousWord) << QVariant(QTextCursor::PreviousWord) << QVariant(QTextCursor::StartOfWord)) << 22; QTest::newRow("StartWord3") << (QStringList() << QString("Happy happy happy Joy Joy Joy")) << (QList() << QVariant(QTextCursor::Start) << QVariant(QTextCursor::NextWord) << QVariant(QTextCursor::EndOfWord) << QVariant(QTextCursor::StartOfWord)) << 6; QTest::newRow("PreviousCharacter") << (QStringList() << QString("Happy happy Joy Joy")) << (QList() << QVariant(QTextCursor::PreviousCharacter) << QVariant(QTextCursor::PreviousCharacter)) << 17; } void tst_QTextCursor::navigation2() { QFETCH(QStringList, sl); QFETCH(QList, movement); int i; for (i = 0; i < sl.size(); ++i) { cursor.insertText(sl.at(i)); if (i < sl.size() - 1) cursor.insertBlock(); } for (i = 0; i < movement.size(); ++i) cursor.movePosition(QTextCursor::MoveOperation(movement.at(i).toInt())); QTEST(cursor.position(), "finalPos"); } void tst_QTextCursor::navigation3() { cursor.insertText("a"); cursor.deletePreviousChar(); QCOMPARE(cursor.position(), 0); QVERIFY(doc->toPlainText().isEmpty()); } void tst_QTextCursor::navigation4() { cursor.insertText(" Test "); cursor.setPosition(4); cursor.movePosition(QTextCursor::EndOfWord); QCOMPARE(cursor.position(), 6); } void tst_QTextCursor::navigation5() { cursor.insertText("Test"); cursor.insertBlock(); cursor.insertText("Test"); cursor.setPosition(0); cursor.movePosition(QTextCursor::EndOfBlock); QCOMPARE(cursor.position(), 4); } void tst_QTextCursor::navigation6() { // triger creation of document layout, so that QTextLines are there doc->documentLayout(); doc->setTextWidth(1000); cursor.insertText("Test "); cursor.movePosition(QTextCursor::Start); cursor.movePosition(QTextCursor::EndOfLine); QCOMPARE(cursor.position(), 8); } void tst_QTextCursor::navigation7() { QVERIFY(doc->isEmpty()); for (int i = QTextCursor::Start; i <= QTextCursor::WordRight; ++i) QVERIFY(!cursor.movePosition(QTextCursor::MoveOperation(i))); doc->setPlainText("Hello World"); cursor.movePosition(QTextCursor::Start); do { } while (cursor.movePosition(QTextCursor::NextCharacter)); QVERIFY(true /*reached*/); } void tst_QTextCursor::navigation8() { cursor.insertList(QTextListFormat::ListDecimal); QCOMPARE(cursor.position(), 1); cursor.insertText("foo"); QCOMPARE(cursor.position(), 4); cursor.insertList(QTextListFormat::ListCircle); QCOMPARE(cursor.position(), 5); cursor.insertText("something"); QCOMPARE(cursor.position(), 14); cursor.movePosition(QTextCursor::PreviousCharacter); QCOMPARE(cursor.position(), 13); cursor.setPosition(2); cursor.movePosition(QTextCursor::NextCharacter); QCOMPARE(cursor.position(), 3); } void tst_QTextCursor::navigation9() { cursor.insertText("Hello &-=+\t World"); cursor.movePosition(QTextCursor::PreviousWord); QCOMPARE(cursor.position(), 15); cursor.movePosition(QTextCursor::PreviousWord); QCOMPARE(cursor.position(), 7); cursor.movePosition(QTextCursor::PreviousWord); QCOMPARE(cursor.position(), 0); cursor.movePosition(QTextCursor::NextWord); QCOMPARE(cursor.position(), 7); cursor.movePosition(QTextCursor::NextWord); QCOMPARE(cursor.position(), 15); } void tst_QTextCursor::navigation10() { doc->setHtml("

just a simple paragraph.

" "" "" "" "" "
Cell number 1another cellprevious
is
empty
row 2foo barlast cell
row 3a
clear(); doc->setHtml("tr>
ab
c
"); cursor.setPosition(1); // a ok = cursor.movePosition(QTextCursor::NextCell); QVERIFY(ok); QCOMPARE(cursor.position(), 3); // b ok = cursor.movePosition(QTextCursor::NextCell); QVERIFY(ok); QCOMPARE(cursor.position(), 5); // c ok = cursor.movePosition(QTextCursor::PreviousCell); QVERIFY(ok); QCOMPARE(cursor.position(), 3); // b ok = cursor.movePosition(QTextCursor::PreviousCell); QVERIFY(ok); QCOMPARE(cursor.position(), 1); // a } void tst_QTextCursor::insertBlock() { QTextBlockFormat fmt; fmt.setTopMargin(100); cursor.insertBlock(fmt); QVERIFY(cursor.position() == 1); QVERIFY(cursor.blockFormat() == fmt); } void tst_QTextCursor::insertWithBlockSeparator1() { QString text = "Hello" + QString(QChar::ParagraphSeparator) + "World"; cursor.insertText(text); cursor.movePosition(QTextCursor::PreviousBlock); QVERIFY(cursor.position() == 0); cursor.movePosition(QTextCursor::NextBlock); QVERIFY(cursor.position() == 6); } void tst_QTextCursor::insertWithBlockSeparator2() { cursor.insertText(QString(QChar::ParagraphSeparator)); QVERIFY(cursor.position() == 1); } void tst_QTextCursor::insertWithBlockSeparator3() { cursor.insertText(QString(QChar::ParagraphSeparator) + "Hi" + QString(QChar::ParagraphSeparator)); QVERIFY(cursor.position() == 4); } void tst_QTextCursor::insertWithBlockSeparator4() { cursor.insertText(QString(QChar::ParagraphSeparator) + QString(QChar::ParagraphSeparator)); QVERIFY(cursor.position() == 2); } void tst_QTextCursor::clearObjectType1() { cursor.insertImage("test.png"); QVERIFY(cursor.charFormat().isValid()); QVERIFY(cursor.charFormat().isImageFormat()); cursor.insertText("Hey"); QVERIFY(cursor.charFormat().isValid()); QVERIFY(!cursor.charFormat().isImageFormat()); } void tst_QTextCursor::clearObjectType2() { cursor.insertImage("test.png"); QVERIFY(cursor.charFormat().isValid()); QVERIFY(cursor.charFormat().isImageFormat()); cursor.insertBlock(); QVERIFY(cursor.charFormat().isValid()); QVERIFY(!cursor.charFormat().isImageFormat()); } void tst_QTextCursor::clearObjectType3() { // like clearObjectType2 but tests different insertBlock overload cursor.insertImage("test.png"); QVERIFY(cursor.charFormat().isValid()); QVERIFY(cursor.charFormat().isImageFormat()); QTextBlockFormat bfmt; bfmt.setAlignment(Qt::AlignRight); cursor.insertBlock(bfmt); QVERIFY(cursor.charFormat().isValid()); QVERIFY(!cursor.charFormat().isImageFormat()); } void tst_QTextCursor::comparisonOperators1() { cursor.insertText("Hello World"); cursor.movePosition(QTextCursor::PreviousWord); QTextCursor startCursor = cursor; startCursor.movePosition(QTextCursor::Start); QVERIFY(startCursor < cursor); QTextCursor midCursor = startCursor; midCursor.movePosition(QTextCursor::NextWord); QVERIFY(midCursor <= cursor); QVERIFY(midCursor == cursor); QVERIFY(midCursor >= cursor); QVERIFY(midCursor > startCursor); QVERIFY(midCursor != startCursor); QVERIFY(!(midCursor == startCursor)); QTextCursor nullCursor; QVERIFY(!(startCursor < nullCursor)); QVERIFY(!(nullCursor < nullCursor)); QVERIFY(nullCursor < startCursor); QVERIFY(nullCursor <= startCursor); QVERIFY(!(startCursor <= nullCursor)); QVERIFY(!(nullCursor >= startCursor)); QVERIFY(startCursor >= nullCursor); QVERIFY(!(nullCursor > startCursor)); QVERIFY(!(nullCursor > nullCursor)); QVERIFY(startCursor > nullCursor); } void tst_QTextCursor::comparisonOperators2() { QTextDocument doc1; QTextDocument doc2; QTextCursor cursor1(&doc1); QTextCursor cursor2(&doc2); QVERIFY(cursor1 != cursor2); QVERIFY(cursor1 == QTextCursor(&doc1)); } void tst_QTextCursor::selection1() { cursor.insertText("Hello World"); cursor.setPosition(0); cursor.clearSelection(); cursor.setPosition(4, QTextCursor::KeepAnchor); QCOMPARE(cursor.selectionStart(), 0); QCOMPARE(cursor.selectionEnd(), 4); } void tst_QTextCursor::dontCopyTableAttributes() { /* when pressing 'enter' inside a cell it shouldn't * enlarge the table by adding another cell but just * extend the cell */ QTextTable *table = cursor.insertTable(2, 2); QVERIFY(cursor == table->cellAt(0, 0).firstCursorPosition()); cursor.insertBlock(); QCOMPARE(table->columns(), 2); } void tst_QTextCursor::checkFrame1() { QVERIFY(cursor.position() == 0); QPointer frame = cursor.insertFrame(QTextFrameFormat()); QVERIFY(frame != 0); QTextFrame *root = frame->parentFrame(); QVERIFY(root != 0); QVERIFY(frame->firstPosition() == 1); QVERIFY(frame->lastPosition() == 1); QVERIFY(frame->parentFrame() != 0); QVERIFY(root->childFrames().size() == 1); QVERIFY(cursor.position() == 1); QVERIFY(cursor.selectionStart() == 1); QVERIFY(cursor.selectionEnd() == 1); doc->undo(); QVERIFY(!frame); QVERIFY(root->childFrames().size() == 0); QVERIFY(cursor.position() == 0); QVERIFY(cursor.selectionStart() == 0); QVERIFY(cursor.selectionEnd() == 0); doc->redo(); frame = doc->frameAt(1); QVERIFY(frame); QVERIFY(frame->firstPosition() == 1); QVERIFY(frame->lastPosition() == 1); QVERIFY(frame->parentFrame() != 0); QVERIFY(root->childFrames().size() == 1); QVERIFY(cursor.position() == 1); QVERIFY(cursor.selectionStart() == 1); QVERIFY(cursor.selectionEnd() == 1); // cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor); // QVERIFY(cursor.position() == 2); // QVERIFY(cursor.selectionStart() == 0); // QVERIFY(cursor.selectionEnd() == 2); } void tst_QTextCursor::checkFrame2() { QVERIFY(cursor.position() == 0); cursor.insertText("A"); QVERIFY(cursor.position() == 1); cursor.movePosition(QTextCursor::Start, QTextCursor::KeepAnchor); QPointer frame = cursor.insertFrame(QTextFrameFormat()); QTextFrame *root = frame->parentFrame(); QVERIFY(frame->firstPosition() == 1); QVERIFY(frame->lastPosition() == 2); QVERIFY(frame->parentFrame() != 0); QVERIFY(root->childFrames().size() == 1); QVERIFY(cursor.position() == 1); QVERIFY(cursor.selectionStart() == 1); QVERIFY(cursor.selectionEnd() == 2); doc->undo(); QVERIFY(!frame); QVERIFY(root->childFrames().size() == 0); QVERIFY(cursor.position() == 0); QVERIFY(cursor.selectionStart() == 0); QVERIFY(cursor.selectionEnd() == 1); doc->redo(); frame = doc->frameAt(1); QVERIFY(frame); QVERIFY(frame->firstPosition() == 1); QVERIFY(frame->lastPosition() == 2); QVERIFY(frame->parentFrame() != 0); QVERIFY(root->childFrames().size() == 1); QVERIFY(cursor.position() == 1); QVERIFY(cursor.selectionStart() == 1); QVERIFY(cursor.selectionEnd() == 2); cursor.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor); QVERIFY(cursor.position() == 0); QVERIFY(cursor.selectionStart() == 0); QVERIFY(cursor.selectionEnd() == 3); } void tst_QTextCursor::insertBlockToUseCharFormat() { QTextCharFormat fmt; fmt.setForeground(Qt::blue); cursor.insertText("Hello", fmt); QCOMPARE(cursor.charFormat().foreground().color(), QColor(Qt::blue)); cursor.insertBlock(); QCOMPARE(cursor.charFormat().foreground().color(), QColor(Qt::blue)); fmt.setForeground(Qt::red); cursor.insertText("Hello\nWorld", fmt); cursor.insertText("Blah"); QCOMPARE(cursor.charFormat().foreground().color(), QColor(Qt::red)); // ### we might want a testcase for createTable, too, as it calls insertBlock, too, // and we might want to have the char format copied (the one that gets inserted // as table separators, that are undeletable) } void tst_QTextCursor::tableMovement() { QVERIFY(cursor.position() == 0); cursor.insertText("AA"); QVERIFY(cursor.position() == 2); cursor.movePosition(QTextCursor::Left); cursor.insertTable(3, 3); QCOMPARE(cursor.position(), 2); cursor.movePosition(QTextCursor::Down); QCOMPARE(cursor.position(), 5); cursor.movePosition(QTextCursor::Right); QCOMPARE(cursor.position(), 6); cursor.movePosition(QTextCursor::Up); QCOMPARE(cursor.position(), 3); cursor.movePosition(QTextCursor::Right); QCOMPARE(cursor.position(), 4); cursor.movePosition(QTextCursor::Right); QCOMPARE(cursor.position(), 5); cursor.movePosition(QTextCursor::Up); QCOMPARE(cursor.position(), 2); cursor.movePosition(QTextCursor::Up); QCOMPARE(cursor.position(), 0); } void tst_QTextCursor::selectionsInTable() { QTextTable *table = cursor.insertTable(2, 2); table->cellAt(0, 0).firstCursorPosition().insertText("First"); table->cellAt(0, 1).firstCursorPosition().insertText("Second"); table->cellAt(1, 0).firstCursorPosition().insertText("Third"); table->cellAt(1, 1).firstCursorPosition().insertText("Fourth"); cursor = table->cellAt(0, 0).lastCursorPosition(); QVERIFY(cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::KeepAnchor)); QVERIFY(cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::KeepAnchor) == false); cursor = table->cellAt(1, 0).lastCursorPosition(); QVERIFY(cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::KeepAnchor)); QVERIFY(cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::KeepAnchor) == false); cursor = table->cellAt(0, 1).firstCursorPosition(); QVERIFY(cursor.movePosition(QTextCursor::NextWord, QTextCursor::KeepAnchor)); QVERIFY(cursor.movePosition(QTextCursor::NextWord, QTextCursor::KeepAnchor) == false); cursor = table->cellAt(1, 1).firstCursorPosition(); QVERIFY(cursor.movePosition(QTextCursor::NextWord, QTextCursor::KeepAnchor)); QVERIFY(cursor.movePosition(QTextCursor::NextWord, QTextCursor::KeepAnchor) == false); } void tst_QTextCursor::selectedText() { cursor.insertText("Hello World"); cursor.movePosition(QTextCursor::Start); cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor); QCOMPARE(cursor.selectedText(), QString("Hello World")); } void tst_QTextCursor::insertBlockShouldRemoveSelection() { cursor.insertText("Hello World"); cursor.movePosition(QTextCursor::Start); cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor); QVERIFY(cursor.hasSelection()); QCOMPARE(cursor.selectedText(), QString("Hello")); cursor.insertBlock(); QVERIFY(!cursor.hasSelection()); QVERIFY(doc->toPlainText().indexOf("Hello") == -1); } void tst_QTextCursor::insertBlockShouldRemoveSelection2() { cursor.insertText("Hello World"); cursor.movePosition(QTextCursor::Start); cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor); QVERIFY(cursor.hasSelection()); QCOMPARE(cursor.selectedText(), QString("Hello")); QTextBlockFormat fmt = cursor.blockFormat(); cursor.insertBlock(fmt); QVERIFY(!cursor.hasSelection()); QVERIFY(doc->toPlainText().indexOf("Hello") == -1); } void tst_QTextCursor::mergeCellShouldUpdateSelection() { QTextTable *table = cursor.insertTable(4, 4); cursor.setPosition(table->cellAt(0, 0).firstPosition()); cursor.setPosition(table->cellAt(3, 0).firstPosition(), QTextCursor::KeepAnchor); // aka bottom left int firstRow, numRows, firstColumn, numColumns; cursor.selectedTableCells(&firstRow, &numRows, &firstColumn, &numColumns); QCOMPARE(firstRow, 0); QCOMPARE(numRows, 4); QCOMPARE(firstColumn, 0); QCOMPARE(numColumns, 1); table->removeColumns(firstColumn, numColumns); QCOMPARE(cursor.anchor(), table->cellAt(0, 0).firstPosition()); QCOMPARE(cursor.position(), table->cellAt(0, 0).firstPosition()); QCOMPARE(cursor.position(), cursor.anchor()); // empty. I don't really care where it ends up. // prepare for another test with multiple cursors. // note we have a 4 rows, 3 cols table now. cursor.setPosition(table->cellAt(0, 0).firstPosition()); cursor.setPosition(table->cellAt(0, 2).firstPosition(), QTextCursor::KeepAnchor); // now create a selection of a whole row. QTextCursor c2 = table->cellAt(2, 0).firstCursorPosition(); c2.setPosition(table->cellAt(2, 2).firstPosition(), QTextCursor::KeepAnchor); // just for good measure, another one for a block of cells. QTextCursor c3 = table->cellAt(2, 1).firstCursorPosition(); c3.setPosition(table->cellAt(3, 2).firstPosition(), QTextCursor::KeepAnchor); table->removeRows(2, 1); QCOMPARE(cursor.anchor(), table->cellAt(0, 0).firstPosition()); QCOMPARE(cursor.position(), table->cellAt(0, 2).firstPosition()); QCOMPARE(c2.position(), c2.anchor()); // empty. I don't really care where it ends up. QCOMPARE(c3.anchor(), table->cellAt(2, 1).firstPosition()); QCOMPARE(c3.position(), table->cellAt(2, 2).firstPosition()); // prepare for another test where we remove a column // note we have a 3 rows, 3 cols table now. cursor.setPosition(table->cellAt(0, 0).firstPosition()); cursor.setPosition(table->cellAt(2, 1).firstPosition(), QTextCursor::KeepAnchor); c2.setPosition(table->cellAt(0, 1).firstPosition()); c2.setPosition(table->cellAt(2, 2).firstPosition(), QTextCursor::KeepAnchor); table->removeColumns(1, 1); QCOMPARE(cursor.anchor(), table->cellAt(0, 0).firstPosition()); QCOMPARE(cursor.position(), table->cellAt(2, 0).firstPosition()); QCOMPARE(c2.anchor(), table->cellAt(0, 1).firstPosition()); QCOMPARE(c2.position(), table->cellAt(2, 1).firstPosition()); // test for illegal cursor positions. // note we have a 3 rows, 2 cols table now. cursor.setPosition(table->cellAt(2, 0).firstPosition()); cursor.setPosition(table->cellAt(2, 1).firstPosition(), QTextCursor::KeepAnchor); c2.setPosition(table->cellAt(0, 0).firstPosition()); c2.setPosition(table->cellAt(2, 1).firstPosition(), QTextCursor::KeepAnchor); c3.setPosition(table->cellAt(2, 1).firstPosition()); table->removeRows(2, 1); QCOMPARE(cursor.anchor(), table->cellAt(1, 1).lastPosition()+1); QCOMPARE(cursor.position(), cursor.anchor()); QCOMPARE(c2.anchor(), table->cellAt(0, 0).firstPosition()); QCOMPARE(c2.position(), table->cellAt(1, 1).firstPosition()); QCOMPARE(c3.anchor(), table->cellAt(1, 1).firstPosition()); QCOMPARE(c3.position(), table->cellAt(1, 1).firstPosition()); } void tst_QTextCursor::joinPreviousEditBlock() { cursor.beginEditBlock(); cursor.insertText("Hello"); cursor.insertText("World"); cursor.endEditBlock(); QVERIFY(doc->toPlainText().startsWith("HelloWorld")); cursor.joinPreviousEditBlock(); cursor.insertText("Hey"); cursor.endEditBlock(); QVERIFY(doc->toPlainText().startsWith("HelloWorldHey")); doc->undo(); QVERIFY(!doc->toPlainText().contains("HelloWorldHey")); } void tst_QTextCursor::setBlockFormatInTable() { // someone reported this on qt4-preview-feedback QTextBlockFormat fmt; fmt.setBackground(Qt::blue); cursor.setBlockFormat(fmt); QTextTable *table = cursor.insertTable(2, 2); cursor = table->cellAt(0, 0).firstCursorPosition(); fmt.setBackground(Qt::red); cursor.setBlockFormat(fmt); cursor.movePosition(QTextCursor::Start); QVERIFY(cursor.blockFormat().background().color() == Qt::blue); } void tst_QTextCursor::blockCharFormat2() { QTextCharFormat fmt; fmt.setForeground(Qt::green); cursor.mergeBlockCharFormat(fmt); fmt.setForeground(Qt::red); cursor.insertText("Test", fmt); cursor.movePosition(QTextCursor::Start); cursor.insertText("Red"); cursor.movePosition(QTextCursor::PreviousCharacter); QVERIFY(cursor.charFormat().foreground().color() == Qt::red); } void tst_QTextCursor::blockCharFormat3() { QVERIFY(cursor.atBlockStart()); QVERIFY(cursor.atBlockEnd()); QVERIFY(cursor.atStart()); QTextCharFormat fmt; fmt.setForeground(Qt::green); cursor.setBlockCharFormat(fmt); cursor.insertText("Test"); cursor.movePosition(QTextCursor::Start); cursor.movePosition(QTextCursor::NextCharacter); QVERIFY(cursor.charFormat().foreground().color() == Qt::green); cursor.movePosition(QTextCursor::Start); QVERIFY(cursor.charFormat().foreground().color() == Qt::green); fmt.setForeground(Qt::red); cursor.setBlockCharFormat(fmt); QVERIFY(cursor.blockCharFormat().foreground().color() == Qt::red); cursor.movePosition(QTextCursor::End); cursor.movePosition(QTextCursor::Start); QVERIFY(cursor.charFormat().foreground().color() == Qt::green); cursor.insertText("Test"); QVERIFY(cursor.charFormat().foreground().color() == Qt::green); cursor.select(QTextCursor::Document); cursor.removeSelectedText(); QVERIFY(cursor.atBlockStart()); QVERIFY(cursor.atBlockEnd()); QVERIFY(cursor.atStart()); cursor.insertText("Test"); QVERIFY(cursor.charFormat().foreground().color() == Qt::red); } void tst_QTextCursor::blockCharFormat() { QTextCharFormat fmt; fmt.setForeground(Qt::blue); cursor.insertBlock(QTextBlockFormat(), fmt); cursor.insertText("Hm"); QVERIFY(cursor.blockCharFormat().foreground().color() == Qt::blue); fmt.setForeground(Qt::red); cursor.setBlockCharFormat(fmt); QVERIFY(cursor.blockCharFormat().foreground().color() == Qt::red); } void tst_QTextCursor::blockCharFormatOnSelection() { QTextCharFormat fmt; fmt.setForeground(Qt::blue); cursor.insertBlock(QTextBlockFormat(), fmt); fmt.setForeground(Qt::green); cursor.insertText("Hm", fmt); fmt.setForeground(Qt::red); cursor.insertBlock(QTextBlockFormat(), fmt); cursor.insertText("Ah"); fmt.setForeground(Qt::white); cursor.insertBlock(QTextBlockFormat(), fmt); cursor.insertText("bleh"); cursor.movePosition(QTextCursor::Start); cursor.movePosition(QTextCursor::NextBlock); QVERIFY(cursor.blockCharFormat().foreground().color() == Qt::blue); cursor.movePosition(QTextCursor::NextBlock); QVERIFY(cursor.blockCharFormat().foreground().color() == Qt::red); cursor.movePosition(QTextCursor::NextBlock); QVERIFY(cursor.blockCharFormat().foreground().color() == Qt::white); cursor.movePosition(QTextCursor::Start); cursor.movePosition(QTextCursor::NextBlock); cursor.movePosition(QTextCursor::NextBlock, QTextCursor::KeepAnchor); fmt.setForeground(Qt::cyan); cursor.setBlockCharFormat(fmt); cursor.movePosition(QTextCursor::Start); cursor.movePosition(QTextCursor::NextBlock); QVERIFY(cursor.blockCharFormat().foreground().color() == Qt::cyan); cursor.movePosition(QTextCursor::Right); cursor.movePosition(QTextCursor::Right); QVERIFY(cursor.charFormat().foreground().color() == Qt::green); cursor.movePosition(QTextCursor::NextBlock); QVERIFY(cursor.blockCharFormat().foreground().color() == Qt::cyan); cursor.movePosition(QTextCursor::NextBlock); QVERIFY(cursor.blockCharFormat().foreground().color() == Qt::white); } void tst_QTextCursor::anchorInitialized1() { cursor.insertBlock(); cursor = QTextCursor(cursor.block()); QCOMPARE(cursor.position(), 1); QCOMPARE(cursor.anchor(), 1); QCOMPARE(cursor.selectionStart(), 1); QCOMPARE(cursor.selectionEnd(), 1); } void tst_QTextCursor::anchorInitialized2() { cursor.insertBlock(); cursor = QTextCursor(cursor.block().docHandle(), 1); QCOMPARE(cursor.position(), 1); QCOMPARE(cursor.anchor(), 1); QCOMPARE(cursor.selectionStart(), 1); QCOMPARE(cursor.selectionEnd(), 1); } void tst_QTextCursor::anchorInitialized3() { QTextFrame *frame = cursor.insertFrame(QTextFrameFormat()); cursor = QTextCursor(frame); QCOMPARE(cursor.position(), 1); QCOMPARE(cursor.anchor(), 1); QCOMPARE(cursor.selectionStart(), 1); QCOMPARE(cursor.selectionEnd(), 1); } void tst_QTextCursor::selectWord() { cursor.insertText("first second third"); cursor.insertBlock(); cursor.insertText("words in second paragraph"); cursor.setPosition(9); cursor.select(QTextCursor::WordUnderCursor); QVERIFY(cursor.hasSelection()); QCOMPARE(cursor.selectionStart(), 6); QCOMPARE(cursor.selectionEnd(), 12); cursor.setPosition(5); cursor.select(QTextCursor::WordUnderCursor); QVERIFY(cursor.hasSelection()); QCOMPARE(cursor.selectionStart(), 0); QCOMPARE(cursor.selectionEnd(), 5); cursor.setPosition(6); cursor.select(QTextCursor::WordUnderCursor); QVERIFY(cursor.hasSelection()); QCOMPARE(cursor.selectionStart(), 6); QCOMPARE(cursor.selectionEnd(), 12); cursor.setPosition(14); cursor.select(QTextCursor::WordUnderCursor); QVERIFY(cursor.hasSelection()); QCOMPARE(cursor.selectionStart(), 6); QCOMPARE(cursor.selectionEnd(), 12); cursor.movePosition(QTextCursor::Start); cursor.select(QTextCursor::WordUnderCursor); QVERIFY(cursor.hasSelection()); QCOMPARE(cursor.selectionStart(), 0); QCOMPARE(cursor.selectionEnd(), 5); cursor.movePosition(QTextCursor::EndOfBlock); cursor.select(QTextCursor::WordUnderCursor); QVERIFY(cursor.hasSelection()); QCOMPARE(cursor.selectionStart(), 17); QCOMPARE(cursor.selectionEnd(), 22); } void tst_QTextCursor::selectWordWithSeparators_data() { QTest::addColumn("text"); QTest::addColumn("initialPosition"); QTest::addColumn("expectedSelectedText"); QTest::newRow("dereference") << QString::fromLatin1("foo->bar()") << 1 << QString::fromLatin1("foo"); QTest::newRow("funcsignature") << QString::fromLatin1("bar(int x);") << 1 << QString::fromLatin1("bar"); QTest::newRow("def") << QString::fromLatin1("foo *f;") << 1 << QString::fromLatin1("foo"); } void tst_QTextCursor::selectWordWithSeparators() { QFETCH(QString, text); QFETCH(int, initialPosition); QFETCH(QString, expectedSelectedText); cursor.insertText(text); cursor.setPosition(initialPosition); cursor.select(QTextCursor::WordUnderCursor); QCOMPARE(cursor.selectedText(), expectedSelectedText); } void tst_QTextCursor::startOfWord() { cursor.insertText("first second"); cursor.setPosition(7); cursor.movePosition(QTextCursor::StartOfWord); QCOMPARE(cursor.position(), 0); } void tst_QTextCursor::selectBlock() { cursor.insertText("foobar"); QTextBlockFormat blockFmt; blockFmt.setAlignment(Qt::AlignHCenter); cursor.insertBlock(blockFmt); cursor.insertText("blah"); cursor.insertBlock(QTextBlockFormat()); cursor.movePosition(QTextCursor::PreviousBlock); QCOMPARE(cursor.block().text(), QString("blah")); cursor.select(QTextCursor::BlockUnderCursor); QVERIFY(cursor.hasSelection()); QTextDocumentFragment fragment(cursor); doc->clear(); cursor.insertFragment(fragment); QCOMPARE(blockCount(), 2); cursor.movePosition(QTextCursor::Start); cursor.movePosition(QTextCursor::NextBlock); QVERIFY(cursor.blockFormat().alignment() == Qt::AlignHCenter); QCOMPARE(cursor.block().text(), QString("blah")); } void tst_QTextCursor::selectVisually() { cursor.insertText("Foo\nlong line which is probably going to be cut in two when shown in a widget\nparagraph 3\n"); cursor.setPosition(6); // somewhere in the long paragraph. cursor.select(QTextCursor::LineUnderCursor); // since we are not yet laid-out, we expect the whole paragraph to be selected. QCOMPARE(cursor.position(), 77); QCOMPARE(cursor.anchor(), 4); } void tst_QTextCursor::insertText() { QString txt = "Foo\nBar\r\nMeep"; txt += QChar::LineSeparator; txt += "Baz"; txt += QChar::ParagraphSeparator; txt += "yoyodyne"; cursor.insertText(txt); QCOMPARE(blockCount(), 4); cursor.movePosition(QTextCursor::Start); QCOMPARE(cursor.block().text(), QString("Foo")); cursor.movePosition(QTextCursor::NextBlock); QCOMPARE(cursor.block().text(), QString("Bar")); cursor.movePosition(QTextCursor::NextBlock); QCOMPARE(cursor.block().text(), QString(QString("Meep") + QChar(QChar::LineSeparator) + QString("Baz"))); cursor.movePosition(QTextCursor::NextBlock); QCOMPARE(cursor.block().text(), QString("yoyodyne")); } void tst_QTextCursor::insertFragmentShouldUseCurrentCharFormat() { QTextDocumentFragment fragment = QTextDocumentFragment::fromPlainText("Hello World"); QTextCharFormat fmt; fmt.setFontUnderline(true); cursor.clearSelection(); cursor.setCharFormat(fmt); cursor.insertFragment(fragment); cursor.movePosition(QTextCursor::Start); cursor.movePosition(QTextCursor::NextCharacter); QVERIFY(cursor.charFormat() == fmt); } int tst_QTextCursor::blockCount() { int cnt = 0; for (QTextBlock blk = doc->begin(); blk.isValid(); blk = blk.next()) ++cnt; return cnt; } void tst_QTextCursor::endOfLine() { doc->setPageSize(QSizeF(100000, INT_MAX)); QString text("First Line \nSecond Line "); text.replace(QLatin1Char('\n'), QChar(QChar::LineSeparator)); cursor.insertText(text); // ensure layouted doc->documentLayout()->documentSize(); cursor.movePosition(QTextCursor::Start); QCOMPARE(cursor.block().layout()->lineCount(), 2); cursor.movePosition(QTextCursor::EndOfLine); QCOMPARE(cursor.position(), 14); cursor.movePosition(QTextCursor::NextCharacter); QCOMPARE(cursor.position(), 15); cursor.movePosition(QTextCursor::EndOfLine); QCOMPARE(cursor.position(), 28); } class CursorListener : public QObject { Q_OBJECT public: CursorListener(QTextCursor *_cursor) : lastRecordedPosition(-1), lastRecordedAnchor(-1), recordingCount(0), cursor(_cursor) {} int lastRecordedPosition; int lastRecordedAnchor; int recordingCount; public slots: void recordCursorPosition() { lastRecordedPosition = cursor->position(); lastRecordedAnchor = cursor->anchor(); ++recordingCount; } void selectAllContents() { // Only test the first time if (!recordingCount) { recordingCount++; cursor->select(QTextCursor::Document); lastRecordedPosition = cursor->position(); lastRecordedAnchor = cursor->anchor(); } } private: QTextCursor *cursor; }; void tst_QTextCursor::editBlocksDuringRemove() { CursorListener listener(&cursor); cursor.insertText("Hello World"); cursor.movePosition(QTextCursor::Start, QTextCursor::KeepAnchor); QCOMPARE(cursor.selectedText(), QString("Hello World")); connect(doc, SIGNAL(contentsChanged()), &listener, SLOT(recordCursorPosition())); listener.recordingCount = 0; cursor.deleteChar(); QCOMPARE(listener.recordingCount, 1); QCOMPARE(listener.lastRecordedPosition, 0); QCOMPARE(listener.lastRecordedAnchor, 0); QVERIFY(doc->toPlainText().isEmpty()); } void tst_QTextCursor::selectAllDuringRemove() { CursorListener listener(&cursor); cursor.insertText("Hello World"); cursor.movePosition(QTextCursor::End); connect(doc, SIGNAL(contentsChanged()), &listener, SLOT(selectAllContents())); listener.recordingCount = 0; QTextCursor localCursor = cursor; localCursor.deletePreviousChar(); QCOMPARE(listener.lastRecordedPosition, 10); QCOMPARE(listener.lastRecordedAnchor, 0); } void tst_QTextCursor::update_data() { QTest::addColumn("text"); QTest::addColumn("position"); QTest::addColumn("anchor"); QTest::addColumn("modifyPosition"); QTest::addColumn("modifyAnchor"); QTest::addColumn("insertText"); QTest::addColumn("expectedPosition"); QTest::addColumn("expectedAnchor"); QString text("Hello big world"); int charsToDelete = 3; QTest::newRow("removeInsideSelection") << text << /*position*/ 0 << /*anchor*/ text.length() // delete 'big' << 6 << 6 + charsToDelete << QString() // don't insert anything, just remove << /*expectedPosition*/ 0 << /*expectedAnchor*/ text.length() - charsToDelete ; text = "Hello big world"; charsToDelete = 3; QTest::newRow("removeInsideSelectionWithSwappedAnchorAndPosition") << text << /*position*/ text.length() << /*anchor*/ 0 // delete 'big' << 6 << 6 + charsToDelete << QString() // don't insert anything, just remove << /*expectedPosition*/ text.length() - charsToDelete << /*expectedAnchor*/ 0 ; text = "Hello big world"; charsToDelete = 3; QString textToInsert("small"); QTest::newRow("replaceInsideSelection") << text << /*position*/ 0 << /*anchor*/ text.length() // delete 'big' ... << 6 << 6 + charsToDelete << textToInsert // ... and replace 'big' with 'small' << /*expectedPosition*/ 0 << /*expectedAnchor*/ text.length() - charsToDelete + textToInsert.length() ; text = "Hello big world"; charsToDelete = 3; textToInsert = "small"; QTest::newRow("replaceInsideSelectionWithSwappedAnchorAndPosition") << text << /*position*/ text.length() << /*anchor*/ 0 // delete 'big' ... << 6 << 6 + charsToDelete << textToInsert // ... and replace 'big' with 'small' << /*expectedPosition*/ text.length() - charsToDelete + textToInsert.length() << /*expectedAnchor*/ 0 ; text = "Hello big world"; charsToDelete = 3; QTest::newRow("removeBeforeSelection") << text << /*position*/ text.length() - 5 << /*anchor*/ text.length() // delete 'big' << 6 << 6 + charsToDelete << QString() // don't insert anything, just remove << /*expectedPosition*/ text.length() - 5 - charsToDelete << /*expectedAnchor*/ text.length() - charsToDelete ; text = "Hello big world"; charsToDelete = 3; QTest::newRow("removeAfterSelection") << text << /*position*/ 0 << /*anchor*/ 4 // delete 'big' << 6 << 6 + charsToDelete << QString() // don't insert anything, just remove << /*expectedPosition*/ 0 << /*expectedAnchor*/ 4 ; } void tst_QTextCursor::update() { QFETCH(QString, text); doc->setPlainText(text); QFETCH(int, position); QFETCH(int, anchor); cursor.setPosition(anchor); cursor.setPosition(position, QTextCursor::KeepAnchor); QCOMPARE(cursor.position(), position); QCOMPARE(cursor.anchor(), anchor); QFETCH(int, modifyPosition); QFETCH(int, modifyAnchor); QTextCursor modifyCursor = cursor; modifyCursor.setPosition(modifyAnchor); modifyCursor.setPosition(modifyPosition, QTextCursor::KeepAnchor); QCOMPARE(modifyCursor.position(), modifyPosition); QCOMPARE(modifyCursor.anchor(), modifyAnchor); QFETCH(QString, insertText); modifyCursor.insertText(insertText); QFETCH(int, expectedPosition); QFETCH(int, expectedAnchor); QCOMPARE(cursor.position(), expectedPosition); QCOMPARE(cursor.anchor(), expectedAnchor); } void tst_QTextCursor::disallowSettingObjectIndicesOnCharFormats() { QTextCharFormat fmt; fmt.setObjectIndex(42); cursor.insertText("Hey", fmt); QCOMPARE(cursor.charFormat().objectIndex(), -1); cursor.select(QTextCursor::Document); cursor.mergeCharFormat(fmt); QCOMPARE(doc->begin().begin().fragment().charFormat().objectIndex(), -1); cursor.select(QTextCursor::Document); cursor.setCharFormat(fmt); QCOMPARE(doc->begin().begin().fragment().charFormat().objectIndex(), -1); cursor.setBlockCharFormat(fmt); QCOMPARE(cursor.blockCharFormat().objectIndex(), -1); cursor.movePosition(QTextCursor::End); cursor.insertBlock(QTextBlockFormat(), fmt); QCOMPARE(cursor.blockCharFormat().objectIndex(), -1); doc->clear(); QTextTable *table = cursor.insertTable(1, 1); cursor.select(QTextCursor::Document); cursor.setCharFormat(fmt); cursor = table->cellAt(0, 0).firstCursorPosition(); QVERIFY(!cursor.isNull()); QCOMPARE(cursor.blockCharFormat().objectIndex(), table->objectIndex()); } void tst_QTextCursor::blockAndColumnNumber() { QCOMPARE(QTextCursor().columnNumber(), 0); QCOMPARE(QTextCursor().blockNumber(), 0); QCOMPARE(cursor.columnNumber(), 0); QCOMPARE(cursor.blockNumber(), 0); cursor.insertText("Hello"); QCOMPARE(cursor.columnNumber(), 5); QCOMPARE(cursor.blockNumber(), 0); cursor.insertBlock(); QCOMPARE(cursor.columnNumber(), 0); QCOMPARE(cursor.blockNumber(), 1); cursor.insertText("Blah"); QCOMPARE(cursor.blockNumber(), 1); // trigger a layout doc->documentLayout(); cursor.insertBlock(); QCOMPARE(cursor.columnNumber(), 0); QCOMPARE(cursor.blockNumber(), 2); cursor.insertText("Test"); QCOMPARE(cursor.columnNumber(), 4); QCOMPARE(cursor.blockNumber(), 2); cursor.insertText(QString(QChar(QChar::LineSeparator))); QCOMPARE(cursor.columnNumber(), 0); QCOMPARE(cursor.blockNumber(), 2); cursor.insertText("A"); QCOMPARE(cursor.columnNumber(), 1); QCOMPARE(cursor.blockNumber(), 2); } void tst_QTextCursor::movePositionEndOfLine() { cursor.insertText("blah\nblah\n"); // Select part of the second line ("la") cursor.setPosition(6); cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, 2); QCOMPARE(cursor.selectedText(), QLatin1String("la")); // trigger a layout doc->documentLayout(); // Remove "la" and append "something" to the end in one undo operation cursor.beginEditBlock(); cursor.removeSelectedText(); QTextCursor c2(doc); c2.setPosition(7); c2.insertText("foo"); // append to doc without touching the cursor. QCOMPARE(cursor.position(), 6); cursor.movePosition(QTextCursor::EndOfLine); // in an edit block visual movement is moved to the end of the paragraph QCOMPARE(cursor.position(), 10); cursor.endEditBlock(); } void tst_QTextCursor::clearCells() { QTextTable *table = cursor.insertTable(3, 5); cursor.setPosition(table->cellAt(0,0).firstPosition()); // select cell 1 and cell 2 cursor.setPosition(table->cellAt(0,1).firstPosition(), QTextCursor::KeepAnchor); cursor.deleteChar(); // should clear the cells, and not crash ;) } void tst_QTextCursor::task244408_wordUnderCursor_data() { QTest::addColumn("input"); QTest::addColumn("expected"); QTest::newRow("trailingSpace") << QString::fromLatin1("foo ") << QString::fromLatin1(""); QTest::newRow("noTrailingSpace") << QString::fromLatin1("foo") << QString::fromLatin1("foo"); } void tst_QTextCursor::task244408_wordUnderCursor() { QFETCH(QString, input); QFETCH(QString, expected); cursor.insertText(input); cursor.movePosition(QTextCursor::End); cursor.select(QTextCursor::WordUnderCursor); QCOMPARE(cursor.selectedText(), expected); } void tst_QTextCursor::adjustCursorsOnInsert() { cursor.insertText("Some text before "); int posBefore = cursor.position(); cursor.insertText("selected text"); int posAfter = cursor.position(); cursor.insertText(" some text afterwards"); QTextCursor selection = cursor; selection.setPosition(posBefore); selection.setPosition(posAfter, QTextCursor::KeepAnchor); cursor.setPosition(posBefore-1); cursor.insertText(QLatin1String("x")); QCOMPARE(selection.anchor(), posBefore+1); QCOMPARE(selection.position(), posAfter+1); doc->undo(); cursor.setPosition(posBefore); cursor.insertText(QLatin1String("x")); QCOMPARE(selection.anchor(), posBefore+1); QCOMPARE(selection.position(), posAfter+1); doc->undo(); cursor.setPosition(posBefore+1); cursor.insertText(QLatin1String("x")); QCOMPARE(selection.anchor(), posBefore); QCOMPARE(selection.position(), posAfter+1); doc->undo(); cursor.setPosition(posAfter-1); cursor.insertText(QLatin1String("x")); QCOMPARE(selection.anchor(), posBefore); QCOMPARE(selection.position(), posAfter+1); doc->undo(); selection.setKeepPositionOnInsert(true); cursor.setPosition(posAfter); cursor.insertText(QLatin1String("x")); selection.setKeepPositionOnInsert(false); QCOMPARE(selection.anchor(), posBefore); QCOMPARE(selection.position(), posAfter); doc->undo(); cursor.setPosition(posAfter+1); cursor.insertText(QLatin1String("x")); QCOMPARE(selection.anchor(), posBefore); QCOMPARE(selection.position(), posAfter); doc->undo(); selection.setPosition(posAfter); selection.setPosition(posBefore, QTextCursor::KeepAnchor); cursor.setPosition(posBefore-1); cursor.insertText(QLatin1String("x")); QCOMPARE(selection.position(), posBefore+1); QCOMPARE(selection.anchor(), posAfter+1); doc->undo(); cursor.setPosition(posBefore); cursor.insertText(QLatin1String("x")); QCOMPARE(selection.position(), posBefore+1); QCOMPARE(selection.anchor(), posAfter+1); doc->undo(); cursor.setPosition(posBefore+1); cursor.insertText(QLatin1String("x")); QCOMPARE(selection.position(), posBefore); QCOMPARE(selection.anchor(), posAfter+1); doc->undo(); cursor.setPosition(posAfter-1); cursor.insertText(QLatin1String("x")); QCOMPARE(selection.position(), posBefore); QCOMPARE(selection.anchor(), posAfter+1); doc->undo(); cursor.setPosition(posAfter); cursor.insertText(QLatin1String("x")); QCOMPARE(selection.position(), posBefore); QCOMPARE(selection.anchor(), posAfter+1); doc->undo(); cursor.setPosition(posAfter+1); cursor.insertText(QLatin1String("x")); QCOMPARE(selection.position(), posBefore); QCOMPARE(selection.anchor(), posAfter); doc->undo(); } void tst_QTextCursor::cursorPositionWithBlockUndoAndRedo() { cursor.insertText("AAAABBBBCCCCDDDD"); cursor.setPosition(12); int cursorPositionBefore = cursor.position(); cursor.beginEditBlock(); cursor.insertText("*"); cursor.setPosition(8); cursor.insertText("*"); cursor.setPosition(4); cursor.insertText("*"); cursor.setPosition(0); cursor.insertText("*"); int cursorPositionAfter = cursor.position(); cursor.endEditBlock(); QVERIFY(doc->toPlainText() == "*AAAA*BBBB*CCCC*DDDD"); QCOMPARE(12, cursorPositionBefore); QCOMPARE(1, cursorPositionAfter); doc->undo(&cursor); QVERIFY(doc->toPlainText() == "AAAABBBBCCCCDDDD"); QCOMPARE(cursor.position(), cursorPositionBefore); doc->redo(&cursor); QVERIFY(doc->toPlainText() == "*AAAA*BBBB*CCCC*DDDD"); 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); } void tst_QTextCursor::cursorPositionWithBlockUndoAndRedo3() { // verify that it's the position of the beginEditBlock that counts, and not the last edit position cursor.insertText("AAAABBBB"); int cursorPositionBefore = cursor.position(); cursor.beginEditBlock(); cursor.setPosition(4); QVERIFY(cursor.position() != cursorPositionBefore); cursor.insertText("*"); cursor.endEditBlock(); QCOMPARE(cursor.position(), 5); doc->undo(&cursor); QCOMPARE(cursor.position(), cursorPositionBefore); } void tst_QTextCursor::joinNonEmptyRemovedBlockUserState() { cursor.insertText("Hello"); cursor.insertBlock(); cursor.insertText("World"); cursor.block().setUserState(10); cursor.movePosition(QTextCursor::EndOfBlock); cursor.movePosition(QTextCursor::PreviousBlock, QTextCursor::KeepAnchor); cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor); cursor.removeSelectedText(); QCOMPARE(cursor.block().userState(), 10); } QTEST_MAIN(tst_QTextCursor) #include "tst_qtextcursor.moc"