/**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the either Technology Preview License Agreement or the ** Beta Release License Agreement. ** ** 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 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain ** additional rights. These rights are described in the Nokia Qt LGPL ** Exception version 1.0, 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. ** ** If you are unsure which license is appropriate for your use, please ** contact the sales department at http://www.qtsoftware.com/contact. ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "qplaintextedit.h" //Used in copyAvailable typedef QPair keyPairType; typedef QList pairListType; Q_DECLARE_METATYPE(pairListType); Q_DECLARE_METATYPE(keyPairType); Q_DECLARE_METATYPE(QList); #ifdef Q_WS_MAC #include #endif QT_FORWARD_DECLARE_CLASS(QPlainTextEdit) //TESTED_CLASS= //TESTED_FILES=gui/widgets/qtextedit.h gui/widgets/qtextedit.cpp class tst_QPlainTextEdit : public QObject { Q_OBJECT public: tst_QPlainTextEdit(); public slots: void initTestCase(); void init(); void cleanup(); private slots: void getSetCheck(); void clearMustNotChangeClipboard(); void clearMustNotResetRootFrameMarginToDefault(); void paragSeparatorOnPlaintextAppend(); void selectAllSetsNotSelection(); void asciiTab(); void setDocument(); void emptyAppend(); void appendOnEmptyDocumentShouldReuseInitialParagraph(); void cursorPositionChanged(); void setTextCursor(); void undoAvailableAfterPaste(); void undoRedoAvailableRepetition(); void appendShouldNotTouchTheSelection(); void backspace(); void shiftBackspace(); void undoRedo(); void preserveCharFormatInAppend(); void copyAndSelectAllInReadonly(); void ctrlAltInput(); void noPropertiesOnDefaultTextEditCharFormat(); void setPlainTextShouldEmitTextChangedOnce(); void overwriteMode(); void shiftDownInLineLastShouldSelectToEnd_data(); void shiftDownInLineLastShouldSelectToEnd(); void undoRedoShouldRepositionTextEditCursor(); void lineWrapModes(); void mouseCursorShape(); void implicitClear(); void undoRedoAfterSetContent(); void numPadKeyNavigation(); void moveCursor(); void mimeDataReimplementations(); void shiftEnterShouldInsertLineSeparator(); void selectWordsFromStringsContainingSeparators_data(); void selectWordsFromStringsContainingSeparators(); void canPaste(); void copyAvailable_data(); void copyAvailable(); void ensureCursorVisibleOnInitialShow(); void setTextInsideResizeEvent(); void colorfulAppend(); void ensureVisibleWithRtl(); void preserveCharFormatAfterSetPlainText(); void extraSelections(); void adjustScrollbars(); void textObscuredByScrollbars(); void setTextPreservesUndoRedoEnabled(); void wordWrapProperty(); void lineWrapProperty(); void selectionChanged(); void blockCountChanged(); private: void createSelection(); int blockCount() const; int lineCount() const; bool nativeClipboardWorking(); QPlainTextEdit *ed; qreal rootFrameMargin; }; bool tst_QPlainTextEdit::nativeClipboardWorking() { #ifdef Q_WS_MAC PasteboardRef pasteboard; OSStatus status = PasteboardCreate(0, &pasteboard); if (status == noErr) CFRelease(pasteboard); return status == noErr; #endif return true; } // Testing get/set functions void tst_QPlainTextEdit::getSetCheck() { QPlainTextEdit obj1; // QTextDocument * QPlainTextEdit::document() // void QPlainTextEdit::setDocument(QTextDocument *) QTextDocument *var1 = new QTextDocument; var1->setDocumentLayout(new QPlainTextDocumentLayout(var1)); obj1.setDocument(var1); QCOMPARE(var1, obj1.document()); obj1.setDocument((QTextDocument *)0); QVERIFY(var1 != obj1.document()); // QPlainTextEdit creates a new document when setting 0 QVERIFY((QTextDocument *)0 != obj1.document()); delete var1; // bool QPlainTextEdit::tabChangesFocus() // void QPlainTextEdit::setTabChangesFocus(bool) obj1.setTabChangesFocus(false); QCOMPARE(false, obj1.tabChangesFocus()); obj1.setTabChangesFocus(true); QCOMPARE(true, obj1.tabChangesFocus()); // LineWrapMode QPlainTextEdit::lineWrapMode() // void QPlainTextEdit::setLineWrapMode(LineWrapMode) obj1.setLineWrapMode(QPlainTextEdit::LineWrapMode(QPlainTextEdit::NoWrap)); QCOMPARE(QPlainTextEdit::LineWrapMode(QPlainTextEdit::NoWrap), obj1.lineWrapMode()); obj1.setLineWrapMode(QPlainTextEdit::LineWrapMode(QPlainTextEdit::WidgetWidth)); QCOMPARE(QPlainTextEdit::LineWrapMode(QPlainTextEdit::WidgetWidth), obj1.lineWrapMode()); // obj1.setLineWrapMode(QPlainTextEdit::LineWrapMode(QPlainTextEdit::FixedPixelWidth)); // QCOMPARE(QPlainTextEdit::LineWrapMode(QPlainTextEdit::FixedPixelWidth), obj1.lineWrapMode()); // obj1.setLineWrapMode(QPlainTextEdit::LineWrapMode(QPlainTextEdit::FixedColumnWidth)); // QCOMPARE(QPlainTextEdit::LineWrapMode(QPlainTextEdit::FixedColumnWidth), obj1.lineWrapMode()); // bool QPlainTextEdit::overwriteMode() // void QPlainTextEdit::setOverwriteMode(bool) obj1.setOverwriteMode(false); QCOMPARE(false, obj1.overwriteMode()); obj1.setOverwriteMode(true); QCOMPARE(true, obj1.overwriteMode()); // int QPlainTextEdit::tabStopWidth() // void QPlainTextEdit::setTabStopWidth(int) obj1.setTabStopWidth(0); QCOMPARE(0, obj1.tabStopWidth()); obj1.setTabStopWidth(INT_MIN); QCOMPARE(0, obj1.tabStopWidth()); // Makes no sense to set a negative tabstop value #if defined(QT_ARCH_WINDOWSCE) // due to rounding error in qRound when qreal==float // we cannot use INT_MAX for this check obj1.setTabStopWidth(SHRT_MAX*2); QCOMPARE(SHRT_MAX*2, obj1.tabStopWidth()); #else obj1.setTabStopWidth(INT_MAX); QCOMPARE(INT_MAX, obj1.tabStopWidth()); #endif } class QtTestDocumentLayout : public QAbstractTextDocumentLayout { Q_OBJECT public: inline QtTestDocumentLayout(QPlainTextEdit *edit, QTextDocument *doc, int &itCount) : QAbstractTextDocumentLayout(doc), useBiggerSize(false), ed(edit), iterationCounter(itCount) {} virtual void draw(QPainter *, const QAbstractTextDocumentLayout::PaintContext &) {} virtual int hitTest(const QPointF &, Qt::HitTestAccuracy ) const { return 0; } virtual void documentChanged(int, int, int) {} virtual int pageCount() const { return 1; } virtual QSizeF documentSize() const { return usedSize; } virtual QRectF frameBoundingRect(QTextFrame *) const { return QRectF(); } virtual QRectF blockBoundingRect(const QTextBlock &) const { return QRectF(); } bool useBiggerSize; QSize usedSize; QPlainTextEdit *ed; int &iterationCounter; }; tst_QPlainTextEdit::tst_QPlainTextEdit() {} void tst_QPlainTextEdit::initTestCase() { #ifdef Q_OS_WINCE //disable magic for WindowsCE qApp->setAutoMaximizeThreshold(-1); #endif } void tst_QPlainTextEdit::init() { ed = new QPlainTextEdit(0); rootFrameMargin = ed->document()->documentMargin(); } void tst_QPlainTextEdit::cleanup() { delete ed; ed = 0; } void tst_QPlainTextEdit::createSelection() { QTest::keyClicks(ed, "Hello World"); /* go to start */ #ifndef Q_WS_MAC QTest::keyClick(ed, Qt::Key_Home, Qt::ControlModifier); #else QTest::keyClick(ed, Qt::Key_Home); #endif QCOMPARE(ed->textCursor().position(), 0); /* select until end of text */ #ifndef Q_WS_MAC QTest::keyClick(ed, Qt::Key_End, Qt::ControlModifier | Qt::ShiftModifier); #else QTest::keyClick(ed, Qt::Key_End, Qt::ShiftModifier); #endif QCOMPARE(ed->textCursor().position(), 11); } void tst_QPlainTextEdit::clearMustNotChangeClipboard() { if (!nativeClipboardWorking()) QSKIP("Clipboard not working with cron-started unit tests", SkipAll); ed->textCursor().insertText("Hello World"); QString txt("This is different text"); QApplication::clipboard()->setText(txt); ed->clear(); QCOMPARE(QApplication::clipboard()->text(), txt); } void tst_QPlainTextEdit::clearMustNotResetRootFrameMarginToDefault() { QCOMPARE(ed->document()->rootFrame()->frameFormat().margin(), rootFrameMargin); ed->clear(); QCOMPARE(ed->document()->rootFrame()->frameFormat().margin(), rootFrameMargin); } void tst_QPlainTextEdit::paragSeparatorOnPlaintextAppend() { ed->appendPlainText("Hello\nWorld"); int cnt = 0; QTextBlock blk = ed->document()->begin(); while (blk.isValid()) { ++cnt; blk = blk.next(); } QCOMPARE(cnt, 2); } void tst_QPlainTextEdit::selectAllSetsNotSelection() { if (!QApplication::clipboard()->supportsSelection()) { QSKIP("Test only relevant for systems with selection", SkipAll); return; } QApplication::clipboard()->setText(QString("foobar"), QClipboard::Selection); QVERIFY(QApplication::clipboard()->text(QClipboard::Selection) == QString("foobar")); ed->insertPlainText("Hello World"); ed->selectAll(); QCOMPARE(QApplication::clipboard()->text(QClipboard::Selection), QString::fromAscii("foobar")); } void tst_QPlainTextEdit::asciiTab() { QPlainTextEdit edit; edit.setPlainText("\t"); edit.show(); qApp->processEvents(); QCOMPARE(edit.toPlainText().at(0), QChar('\t')); } void tst_QPlainTextEdit::setDocument() { QTextDocument *document = new QTextDocument(ed); document->setDocumentLayout(new QPlainTextDocumentLayout(document)); QTextCursor(document).insertText("Test"); ed->setDocument(document); QCOMPARE(ed->toPlainText(), QString("Test")); } int tst_QPlainTextEdit::blockCount() const { int blocks = 0; for (QTextBlock block = ed->document()->begin(); block.isValid(); block = block.next()) ++blocks; return blocks; } int tst_QPlainTextEdit::lineCount() const { int lines = 0; for (QTextBlock block = ed->document()->begin(); block.isValid(); block = block.next()) { ed->document()->documentLayout()->blockBoundingRect(block); lines += block.layout()->lineCount(); } return lines; } // Supporter issue #56783 void tst_QPlainTextEdit::emptyAppend() { ed->appendPlainText("Blah"); QCOMPARE(blockCount(), 1); ed->appendPlainText(QString::null); QCOMPARE(blockCount(), 2); ed->appendPlainText(QString(" ")); QCOMPARE(blockCount(), 3); } void tst_QPlainTextEdit::appendOnEmptyDocumentShouldReuseInitialParagraph() { QCOMPARE(blockCount(), 1); ed->appendPlainText("Blah"); QCOMPARE(blockCount(), 1); } class CursorPositionChangedRecorder : public QObject { Q_OBJECT public: inline CursorPositionChangedRecorder(QPlainTextEdit *ed) : editor(ed) { connect(editor, SIGNAL(cursorPositionChanged()), this, SLOT(recordCursorPos())); } QList cursorPositions; private slots: void recordCursorPos() { cursorPositions.append(editor->textCursor().position()); } private: QPlainTextEdit *editor; }; void tst_QPlainTextEdit::cursorPositionChanged() { QSignalSpy spy(ed, SIGNAL(cursorPositionChanged())); spy.clear(); QTest::keyClick(ed, Qt::Key_A); QCOMPARE(spy.count(), 1); QTextCursor cursor = ed->textCursor(); cursor.movePosition(QTextCursor::Start); ed->setTextCursor(cursor); cursor.movePosition(QTextCursor::End); spy.clear(); cursor.insertText("Test"); QCOMPARE(spy.count(), 0); cursor.movePosition(QTextCursor::End); ed->setTextCursor(cursor); cursor.movePosition(QTextCursor::Start); spy.clear(); cursor.insertText("Test"); QCOMPARE(spy.count(), 1); spy.clear(); QTest::keyClick(ed, Qt::Key_Left); QCOMPARE(spy.count(), 1); CursorPositionChangedRecorder spy2(ed); QVERIFY(ed->textCursor().position() > 0); ed->setPlainText("Hello World"); QCOMPARE(spy2.cursorPositions.count(), 1); QCOMPARE(spy2.cursorPositions.at(0), 0); QCOMPARE(ed->textCursor().position(), 0); } void tst_QPlainTextEdit::setTextCursor() { QSignalSpy spy(ed, SIGNAL(cursorPositionChanged())); ed->setPlainText("Test"); QTextCursor cursor = ed->textCursor(); cursor.movePosition(QTextCursor::Start); cursor.movePosition(QTextCursor::NextCharacter); spy.clear(); ed->setTextCursor(cursor); QCOMPARE(spy.count(), 1); } void tst_QPlainTextEdit::undoAvailableAfterPaste() { if (!nativeClipboardWorking()) QSKIP("Clipboard not working with cron-started unit tests", SkipAll); QSignalSpy spy(ed->document(), SIGNAL(undoAvailable(bool))); const QString txt("Test"); QApplication::clipboard()->setText(txt); ed->paste(); QVERIFY(spy.count() >= 1); QCOMPARE(ed->toPlainText(), txt); } class UndoRedoRecorder : public QObject { Q_OBJECT public: UndoRedoRecorder(QTextDocument *doc) : undoRepetitions(false) , redoRepetitions(false) , undoCount(0) , redoCount(0) { connect(doc, SIGNAL(undoAvailable(bool)), this, SLOT(undoAvailable(bool))); connect(doc, SIGNAL(redoAvailable(bool)), this, SLOT(redoAvailable(bool))); } bool undoRepetitions; bool redoRepetitions; private slots: void undoAvailable(bool enabled) { if (undoCount > 0 && enabled == lastUndoEnabled) undoRepetitions = true; ++undoCount; lastUndoEnabled = enabled; } void redoAvailable(bool enabled) { if (redoCount > 0 && enabled == lastRedoEnabled) redoRepetitions = true; ++redoCount; lastRedoEnabled = enabled; } private: bool lastUndoEnabled; bool lastRedoEnabled; int undoCount; int redoCount; }; void tst_QPlainTextEdit::undoRedoAvailableRepetition() { UndoRedoRecorder spy(ed->document()); ed->textCursor().insertText("ABC\n\nDEF\n\nGHI\n"); ed->textCursor().insertText("foo\n"); ed->textCursor().insertText("bar\n"); ed->undo(); ed->undo(); ed->undo(); ed->redo(); ed->redo(); ed->redo(); QVERIFY(!spy.undoRepetitions); QVERIFY(!spy.redoRepetitions); } void tst_QPlainTextEdit::appendShouldNotTouchTheSelection() { QTextCursor cursor(ed->document()); QTextCharFormat fmt; fmt.setForeground(Qt::blue); cursor.insertText("H", fmt); fmt.setForeground(Qt::red); cursor.insertText("ey", fmt); cursor.insertText("some random text inbetween"); cursor.movePosition(QTextCursor::Start); cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor); QCOMPARE(cursor.charFormat().foreground().color(), QColor(Qt::blue)); cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor); QCOMPARE(cursor.charFormat().foreground().color(), QColor(Qt::red)); cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor); QCOMPARE(cursor.charFormat().foreground().color(), QColor(Qt::red)); QCOMPARE(cursor.selectedText(), QString("Hey")); ed->setTextCursor(cursor); QVERIFY(ed->textCursor().hasSelection()); ed->appendHtml("Some Bold Text"); cursor.movePosition(QTextCursor::Start); cursor.movePosition(QTextCursor::NextCharacter); QCOMPARE(cursor.charFormat().foreground().color(), QColor(Qt::blue)); } void tst_QPlainTextEdit::backspace() { QTextCursor cursor = ed->textCursor(); QTextListFormat listFmt; listFmt.setStyle(QTextListFormat::ListDisc); listFmt.setIndent(1); cursor.insertList(listFmt); cursor.insertText("A"); ed->setTextCursor(cursor); // delete 'A' QTest::keyClick(ed, Qt::Key_Backspace); QVERIFY(ed->textCursor().currentList()); // delete list QTest::keyClick(ed, Qt::Key_Backspace); QVERIFY(!ed->textCursor().currentList()); QCOMPARE(ed->textCursor().blockFormat().indent(), 1); // outdent paragraph QTest::keyClick(ed, Qt::Key_Backspace); QCOMPARE(ed->textCursor().blockFormat().indent(), 0); } void tst_QPlainTextEdit::shiftBackspace() { QTextCursor cursor = ed->textCursor(); QTextListFormat listFmt; listFmt.setStyle(QTextListFormat::ListDisc); listFmt.setIndent(1); cursor.insertList(listFmt); cursor.insertText("A"); ed->setTextCursor(cursor); // delete 'A' QTest::keyClick(ed, Qt::Key_Backspace, Qt::ShiftModifier); QVERIFY(ed->textCursor().currentList()); // delete list QTest::keyClick(ed, Qt::Key_Backspace, Qt::ShiftModifier); QVERIFY(!ed->textCursor().currentList()); QCOMPARE(ed->textCursor().blockFormat().indent(), 1); // outdent paragraph QTest::keyClick(ed, Qt::Key_Backspace, Qt::ShiftModifier); QCOMPARE(ed->textCursor().blockFormat().indent(), 0); } void tst_QPlainTextEdit::undoRedo() { ed->clear(); QTest::keyClicks(ed, "abc d"); QCOMPARE(ed->toPlainText(), QString("abc d")); ed->undo(); QCOMPARE(ed->toPlainText(), QString()); ed->redo(); QCOMPARE(ed->toPlainText(), QString("abc d")); #ifdef Q_WS_WIN // shortcut for undo QTest::keyClick(ed, Qt::Key_Backspace, Qt::AltModifier); QCOMPARE(ed->toPlainText(), QString()); // shortcut for redo QTest::keyClick(ed, Qt::Key_Backspace, Qt::ShiftModifier|Qt::AltModifier); QCOMPARE(ed->toPlainText(), QString("abc d")); #endif } // Task #70465 void tst_QPlainTextEdit::preserveCharFormatInAppend() { ed->appendHtml("First para"); ed->appendHtml("Second para"); ed->appendHtml("third para"); QTextCursor cursor(ed->textCursor()); cursor.movePosition(QTextCursor::Start); cursor.movePosition(QTextCursor::NextCharacter); QCOMPARE(cursor.charFormat().fontWeight(), (int)QFont::Normal); QCOMPARE(cursor.block().text(), QString("First para")); cursor.movePosition(QTextCursor::NextBlock); cursor.movePosition(QTextCursor::NextCharacter); QCOMPARE(cursor.charFormat().fontWeight(), (int)QFont::Bold); QCOMPARE(cursor.block().text(), QString("Second para")); cursor.movePosition(QTextCursor::NextBlock); cursor.movePosition(QTextCursor::NextCharacter); QCOMPARE(cursor.charFormat().fontWeight(), (int)QFont::Normal); QCOMPARE(cursor.block().text(), QString("third para")); } void tst_QPlainTextEdit::copyAndSelectAllInReadonly() { if (!nativeClipboardWorking()) QSKIP("Clipboard not working with cron-started unit tests", SkipAll); ed->setReadOnly(true); ed->setPlainText("Hello World"); QTextCursor cursor = ed->textCursor(); cursor.clearSelection(); ed->setTextCursor(cursor); QVERIFY(!ed->textCursor().hasSelection()); QCOMPARE(ed->toPlainText(), QString("Hello World")); // shouldn't do anything QTest::keyClick(ed, Qt::Key_A); QCOMPARE(ed->toPlainText(), QString("Hello World")); QTest::keyClick(ed, Qt::Key_A, Qt::ControlModifier); QVERIFY(ed->textCursor().hasSelection()); QApplication::clipboard()->setText(QString()); QVERIFY(QApplication::clipboard()->text().isEmpty()); QTest::keyClick(ed, Qt::Key_C, Qt::ControlModifier); QCOMPARE(QApplication::clipboard()->text(), QString("Hello World")); } void tst_QPlainTextEdit::ctrlAltInput() { QTest::keyClick(ed, Qt::Key_At, Qt::ControlModifier | Qt::AltModifier); QCOMPARE(ed->toPlainText(), QString("@")); } void tst_QPlainTextEdit::noPropertiesOnDefaultTextEditCharFormat() { // there should be no properties set on the default/initial char format // on a text edit. Font properties instead should be taken from the // widget's font (in sync with defaultFont property in document) and the // foreground color should be taken from the palette. QCOMPARE(ed->textCursor().charFormat().properties().count(), 0); } void tst_QPlainTextEdit::setPlainTextShouldEmitTextChangedOnce() { QSignalSpy spy(ed, SIGNAL(textChanged())); ed->setPlainText("Yankee Doodle"); QCOMPARE(spy.count(), 1); ed->setPlainText(""); QCOMPARE(spy.count(), 2); } void tst_QPlainTextEdit::overwriteMode() { QVERIFY(!ed->overwriteMode()); QTest::keyClicks(ed, "Some first text"); QCOMPARE(ed->toPlainText(), QString("Some first text")); ed->setOverwriteMode(true); QTextCursor cursor = ed->textCursor(); cursor.setPosition(5); ed->setTextCursor(cursor); QTest::keyClicks(ed, "shiny"); QCOMPARE(ed->toPlainText(), QString("Some shiny text")); cursor.movePosition(QTextCursor::End); ed->setTextCursor(cursor); QTest::keyClick(ed, Qt::Key_Enter); ed->setOverwriteMode(false); QTest::keyClicks(ed, "Second paragraph"); QCOMPARE(blockCount(), 2); cursor.movePosition(QTextCursor::Start); cursor.movePosition(QTextCursor::EndOfBlock); QCOMPARE(cursor.position(), 15); ed->setTextCursor(cursor); ed->setOverwriteMode(true); QTest::keyClicks(ed, " blah"); QCOMPARE(blockCount(), 2); QTextBlock block = ed->document()->begin(); QCOMPARE(block.text(), QString("Some shiny text blah")); block = block.next(); QCOMPARE(block.text(), QString("Second paragraph")); } void tst_QPlainTextEdit::shiftDownInLineLastShouldSelectToEnd_data() { // shift cursor-down in the last line should select to the end of the document QTest::addColumn("input"); QTest::addColumn("totalLineCount"); QTest::newRow("1") << QString("Foo\nBar") << 2; QTest::newRow("2") << QString("Foo\nBar") + QChar(QChar::LineSeparator) + QString("Baz") << 3; } void tst_QPlainTextEdit::shiftDownInLineLastShouldSelectToEnd() { QFETCH(QString, input); QFETCH(int, totalLineCount); ed->setPlainText(input); ed->show(); // ensure we're layouted for (QTextBlock block = ed->document()->begin(); block.isValid(); block = block.next()) ed->document()->documentLayout()->blockBoundingRect(block); QCOMPARE(blockCount(), 2); int lineCount = 0; for (QTextBlock block = ed->document()->begin(); block.isValid(); block = block.next()) lineCount += block.layout()->lineCount(); QCOMPARE(lineCount, totalLineCount); QTextCursor cursor = ed->textCursor(); cursor.movePosition(QTextCursor::Start); ed->setTextCursor(cursor); for (int i = 0; i < lineCount; ++i) { QTest::keyClick(ed, Qt::Key_Down, Qt::ShiftModifier); } input.replace(QLatin1Char('\n'), QChar(QChar::ParagraphSeparator)); QCOMPARE(ed->textCursor().selectedText(), input); QVERIFY(ed->textCursor().atEnd()); // also test that without shift modifier the cursor does not move to the end // for Key_Down in the last line cursor.movePosition(QTextCursor::Start); ed->setTextCursor(cursor); for (int i = 0; i < lineCount; ++i) { QTest::keyClick(ed, Qt::Key_Down); } QVERIFY(!ed->textCursor().atEnd()); } void tst_QPlainTextEdit::undoRedoShouldRepositionTextEditCursor() { ed->setPlainText("five\nlines\nin\nthis\ntextedit"); QTextCursor cursor = ed->textCursor(); cursor.movePosition(QTextCursor::Start); ed->setUndoRedoEnabled(false); ed->setUndoRedoEnabled(true); QVERIFY(!ed->document()->isUndoAvailable()); QVERIFY(!ed->document()->isRedoAvailable()); cursor.insertText("Blah"); QVERIFY(ed->document()->isUndoAvailable()); QVERIFY(!ed->document()->isRedoAvailable()); cursor.movePosition(QTextCursor::End); ed->setTextCursor(cursor); QVERIFY(QMetaObject::invokeMethod(ed, "undo")); QVERIFY(!ed->document()->isUndoAvailable()); QVERIFY(ed->document()->isRedoAvailable()); QCOMPARE(ed->textCursor().position(), 0); cursor.movePosition(QTextCursor::End); ed->setTextCursor(cursor); QVERIFY(QMetaObject::invokeMethod(ed, "redo")); QVERIFY(ed->document()->isUndoAvailable()); QVERIFY(!ed->document()->isRedoAvailable()); QCOMPARE(ed->textCursor().position(), 4); } void tst_QPlainTextEdit::lineWrapModes() { QWidget *window = new QWidget; ed->setParent(window); window->show(); ed->show(); ed->setPlainText("a b c d e f g h i j k l m n o p q r s t u v w x y z"); ed->setLineWrapMode(QPlainTextEdit::NoWrap); QCOMPARE(lineCount(), 1); ed->setLineWrapMode(QPlainTextEdit::WidgetWidth); // QPlainTextEdit does lazy line layout on resize, only for the visible blocks. // We thus need to make it wide enough to show something visible. int minimumWidth = 2 * ed->document()->documentMargin(); minimumWidth += ed->fontMetrics().width(QLatin1Char('a')); ed->resize(minimumWidth, 1000); QCOMPARE(lineCount(), 26); ed->setParent(0); delete window; } void tst_QPlainTextEdit::mouseCursorShape() { #ifndef QT_NO_CURSOR // always show an IBeamCursor, see change 170146 QVERIFY(!ed->isReadOnly()); QVERIFY(ed->viewport()->cursor().shape() == Qt::IBeamCursor); ed->setReadOnly(true); QVERIFY(ed->viewport()->cursor().shape() == Qt::IBeamCursor); ed->setPlainText("Foo"); QVERIFY(ed->viewport()->cursor().shape() == Qt::IBeamCursor); #endif } void tst_QPlainTextEdit::implicitClear() { // test that QPlainTextEdit::setHtml, etc. avoid calling clear() but instead call // QTextDocument::setHtml/etc. instead, which also clear the contents and // cached resource but preserve manually added resources. setHtml on a textedit // should behave the same as on a document with respect to that. // see also clearResources() autotest in qtextdocument // regular resource for QTextDocument QUrl testUrl(":/foobar"); QVariant testResource("hello world"); ed->document()->addResource(QTextDocument::ImageResource, testUrl, testResource); QVERIFY(ed->document()->resource(QTextDocument::ImageResource, testUrl) == testResource); ed->setPlainText("Blah"); QVERIFY(ed->document()->resource(QTextDocument::ImageResource, testUrl) == testResource); ed->setPlainText("Blah"); QVERIFY(ed->document()->resource(QTextDocument::ImageResource, testUrl) == testResource); ed->clear(); QVERIFY(!ed->document()->resource(QTextDocument::ImageResource, testUrl).isValid()); QVERIFY(ed->toPlainText().isEmpty()); } void tst_QPlainTextEdit::copyAvailable_data() { QTest::addColumn("keystrokes"); QTest::addColumn >("copyAvailable"); QTest::addColumn("function"); pairListType keystrokes; QList copyAvailable; keystrokes << qMakePair(Qt::Key_B, Qt::NoModifier) << qMakePair(Qt::Key_B, Qt::NoModifier) << qMakePair(Qt::Key_Left, Qt::ShiftModifier); copyAvailable << true ; QTest::newRow(QString("Case1 B,B, <- + shift | signals: true").toLatin1()) << keystrokes << copyAvailable << QString(); keystrokes.clear(); copyAvailable.clear(); keystrokes << qMakePair(Qt::Key_T, Qt::NoModifier) << qMakePair(Qt::Key_A, Qt::NoModifier) << qMakePair(Qt::Key_A, Qt::NoModifier) << qMakePair(Qt::Key_Left, Qt::ShiftModifier); copyAvailable << true << false; QTest::newRow(QString("Case2 T,A,A, <- + shift, cut() | signals: true, false").toLatin1()) << keystrokes << copyAvailable << QString("cut"); keystrokes.clear(); copyAvailable.clear(); keystrokes << qMakePair(Qt::Key_T, Qt::NoModifier) << qMakePair(Qt::Key_A, Qt::NoModifier) << qMakePair(Qt::Key_A, Qt::NoModifier) << qMakePair(Qt::Key_Left, Qt::ShiftModifier) << qMakePair(Qt::Key_Left, Qt::ShiftModifier) << qMakePair(Qt::Key_Left, Qt::ShiftModifier); copyAvailable << true; QTest::newRow(QString("Case3 T,A,A, <- + shift, <- + shift, <- + shift, copy() | signals: true").toLatin1()) << keystrokes << copyAvailable << QString("copy"); keystrokes.clear(); copyAvailable.clear(); keystrokes << qMakePair(Qt::Key_T, Qt::NoModifier) << qMakePair(Qt::Key_A, Qt::NoModifier) << qMakePair(Qt::Key_A, Qt::NoModifier) << qMakePair(Qt::Key_Left, Qt::ShiftModifier) << qMakePair(Qt::Key_Left, Qt::ShiftModifier) << qMakePair(Qt::Key_Left, Qt::ShiftModifier) << qMakePair(Qt::Key_X, Qt::ControlModifier); copyAvailable << true << false; QTest::newRow(QString("Case4 T,A,A, <- + shift, <- + shift, <- + shift, ctrl + x, paste() | signals: true, false").toLatin1()) << keystrokes << copyAvailable << QString("paste"); keystrokes.clear(); copyAvailable.clear(); keystrokes << qMakePair(Qt::Key_B, Qt::NoModifier) << qMakePair(Qt::Key_B, Qt::NoModifier) << qMakePair(Qt::Key_Left, Qt::ShiftModifier) << qMakePair(Qt::Key_Left, Qt::NoModifier); copyAvailable << true << false; QTest::newRow(QString("Case5 B,B, <- + shift, <- | signals: true, false").toLatin1()) << keystrokes << copyAvailable << QString(); keystrokes.clear(); copyAvailable.clear(); keystrokes << qMakePair(Qt::Key_B, Qt::NoModifier) << qMakePair(Qt::Key_A, Qt::NoModifier) << qMakePair(Qt::Key_Left, Qt::ShiftModifier) << qMakePair(Qt::Key_Left, Qt::NoModifier) << qMakePair(Qt::Key_Right, Qt::ShiftModifier); copyAvailable << true << false << true << false; QTest::newRow(QString("Case6 B,A, <- + shift, ->, <- + shift | signals: true, false, true, false").toLatin1()) << keystrokes << copyAvailable << QString("cut"); keystrokes.clear(); copyAvailable.clear(); keystrokes << qMakePair(Qt::Key_T, Qt::NoModifier) << qMakePair(Qt::Key_A, Qt::NoModifier) << qMakePair(Qt::Key_A, Qt::NoModifier) << qMakePair(Qt::Key_Left, Qt::ShiftModifier) << qMakePair(Qt::Key_Left, Qt::ShiftModifier) << qMakePair(Qt::Key_Left, Qt::ShiftModifier) << qMakePair(Qt::Key_X, Qt::ControlModifier); copyAvailable << true << false << true; QTest::newRow(QString("Case7 T,A,A, <- + shift, <- + shift, <- + shift, ctrl + x, undo() | signals: true, false, true").toLatin1()) << keystrokes << copyAvailable << QString("undo"); } //Tests the copyAvailable slot for several cases void tst_QPlainTextEdit::copyAvailable() { QFETCH(pairListType,keystrokes); QFETCH(QList, copyAvailable); QFETCH(QString, function); #ifdef Q_WS_MAC QSKIP("copyAvailable has never passed on Mac, task to fix is 132482", SkipAll); #endif ed->clear(); QApplication::clipboard()->clear(); QVERIFY(!ed->canPaste()); QSignalSpy spyCopyAvailabe(ed, SIGNAL(copyAvailable(bool))); //Execute Keystrokes foreach(keyPairType keyPair, keystrokes) { QTest::keyClick(ed, keyPair.first, keyPair.second ); } //Execute ed->"function" if (function == "cut") ed->cut(); else if (function == "copy") ed->copy(); else if (function == "paste") ed->paste(); else if (function == "undo") ed->paste(); else if (function == "redo") ed->paste(); //Compare spied signals QEXPECT_FAIL("Case7 T,A,A, <- + shift, <- + shift, <- + shift, ctrl + x, undo() | signals: true, false, true", "Wrong undo selection behaviour. Should be fixed in some future release. (See task: 132482)", Abort); QCOMPARE(spyCopyAvailabe.count(), copyAvailable.count()); for (int i=0;idocument()->isUndoAvailable()); QVERIFY(!ed->document()->isRedoAvailable()); ed->setPlainText("Foobar"); QVERIFY(!ed->document()->isUndoAvailable()); QVERIFY(!ed->document()->isRedoAvailable()); ed->setPlainText("

bleh

"); QVERIFY(!ed->document()->isUndoAvailable()); QVERIFY(!ed->document()->isRedoAvailable()); } void tst_QPlainTextEdit::numPadKeyNavigation() { ed->setPlainText("Hello World"); QCOMPARE(ed->textCursor().position(), 0); QTest::keyClick(ed, Qt::Key_Right, Qt::KeypadModifier); QCOMPARE(ed->textCursor().position(), 1); } void tst_QPlainTextEdit::moveCursor() { ed->setPlainText("Test"); QSignalSpy cursorMovedSpy(ed, SIGNAL(cursorPositionChanged())); QCOMPARE(ed->textCursor().position(), 0); ed->moveCursor(QTextCursor::NextCharacter); QCOMPARE(ed->textCursor().position(), 1); QCOMPARE(cursorMovedSpy.count(), 1); ed->moveCursor(QTextCursor::NextCharacter, QTextCursor::KeepAnchor); QCOMPARE(ed->textCursor().position(), 2); QCOMPARE(cursorMovedSpy.count(), 2); QCOMPARE(ed->textCursor().selectedText(), QString("e")); } class MyTextEdit : public QPlainTextEdit { public: inline MyTextEdit() : createMimeDataCallCount(0), canInsertCallCount(0), insertCallCount(0) {} mutable int createMimeDataCallCount; mutable int canInsertCallCount; mutable int insertCallCount; virtual QMimeData *createMimeDataFromSelection() const { createMimeDataCallCount++; return QPlainTextEdit::createMimeDataFromSelection(); } virtual bool canInsertFromMimeData(const QMimeData *source) const { canInsertCallCount++; return QPlainTextEdit::canInsertFromMimeData(source); } virtual void insertFromMimeData(const QMimeData *source) { insertCallCount++; QPlainTextEdit::insertFromMimeData(source); } }; void tst_QPlainTextEdit::mimeDataReimplementations() { MyTextEdit ed; ed.setPlainText("Hello World"); QCOMPARE(ed.createMimeDataCallCount, 0); QCOMPARE(ed.canInsertCallCount, 0); QCOMPARE(ed.insertCallCount, 0); ed.selectAll(); QCOMPARE(ed.createMimeDataCallCount, 0); QCOMPARE(ed.canInsertCallCount, 0); QCOMPARE(ed.insertCallCount, 0); ed.copy(); QCOMPARE(ed.createMimeDataCallCount, 1); QCOMPARE(ed.canInsertCallCount, 0); QCOMPARE(ed.insertCallCount, 0); #ifdef QT_BUILD_INTERNAL QTextControl *control = qFindChild(&ed); QVERIFY(control); control->canInsertFromMimeData(QApplication::clipboard()->mimeData()); QCOMPARE(ed.createMimeDataCallCount, 1); QCOMPARE(ed.canInsertCallCount, 1); QCOMPARE(ed.insertCallCount, 0); ed.paste(); QCOMPARE(ed.createMimeDataCallCount, 1); QCOMPARE(ed.canInsertCallCount, 1); QCOMPARE(ed.insertCallCount, 1); #endif } void tst_QPlainTextEdit::shiftEnterShouldInsertLineSeparator() { QTest::keyClick(ed, Qt::Key_A); QTest::keyClick(ed, Qt::Key_Enter, Qt::ShiftModifier); QTest::keyClick(ed, Qt::Key_B); QString expected; expected += 'a'; expected += QChar::LineSeparator; expected += 'b'; QCOMPARE(ed->textCursor().block().text(), expected); } void tst_QPlainTextEdit::selectWordsFromStringsContainingSeparators_data() { QTest::addColumn("testString"); QTest::addColumn("selectedWord"); QStringList wordSeparators; wordSeparators << "." << "," << "?" << "!" << ":" << ";" << "-" << "<" << ">" << "[" << "]" << "(" << ")" << "{" << "}" << "=" << "\t"<< QString(QChar::Nbsp); foreach (QString s, wordSeparators) QTest::newRow(QString("separator: " + s).toLocal8Bit()) << QString("foo") + s + QString("bar") << QString("foo"); } void tst_QPlainTextEdit::selectWordsFromStringsContainingSeparators() { QFETCH(QString, testString); QFETCH(QString, selectedWord); ed->setPlainText(testString); QTextCursor cursor = ed->textCursor(); cursor.movePosition(QTextCursor::StartOfLine); cursor.select(QTextCursor::WordUnderCursor); QVERIFY(cursor.hasSelection()); QCOMPARE(cursor.selection().toPlainText(), selectedWord); cursor.clearSelection(); } void tst_QPlainTextEdit::canPaste() { if (!nativeClipboardWorking()) QSKIP("Clipboard not working with cron-started unit tests", SkipAll); QApplication::clipboard()->setText(QString()); QVERIFY(!ed->canPaste()); QApplication::clipboard()->setText("Test"); QVERIFY(ed->canPaste()); ed->setTextInteractionFlags(Qt::NoTextInteraction); QVERIFY(!ed->canPaste()); } void tst_QPlainTextEdit::ensureCursorVisibleOnInitialShow() { QString manyPagesOfPlainText; for (int i = 0; i < 800; ++i) manyPagesOfPlainText += QLatin1String("Blah blah blah blah blah blah\n"); ed->setPlainText(manyPagesOfPlainText); QCOMPARE(ed->textCursor().position(), 0); ed->moveCursor(QTextCursor::End); ed->show(); QVERIFY(ed->verticalScrollBar()->value() > 10); ed->moveCursor(QTextCursor::Start); QVERIFY(ed->verticalScrollBar()->value() < 10); ed->hide(); ed->verticalScrollBar()->setValue(ed->verticalScrollBar()->maximum()); ed->show(); QCOMPARE(ed->verticalScrollBar()->value(), ed->verticalScrollBar()->maximum()); } class TestEdit : public QPlainTextEdit { public: TestEdit() : resizeEventCalled(false) {} bool resizeEventCalled; protected: virtual void resizeEvent(QResizeEvent *e) { QPlainTextEdit::resizeEvent(e); setPlainText("
Size is " + QString::number(size().width()) + " x " + QString::number(size().height())); resizeEventCalled = true; } }; void tst_QPlainTextEdit::setTextInsideResizeEvent() { TestEdit edit; edit.show(); edit.resize(800, 600); QVERIFY(edit.resizeEventCalled); } void tst_QPlainTextEdit::colorfulAppend() { QTextCharFormat fmt; fmt.setForeground(QBrush(Qt::red)); ed->mergeCurrentCharFormat(fmt); ed->appendPlainText("Red"); fmt.setForeground(QBrush(Qt::blue)); ed->mergeCurrentCharFormat(fmt); ed->appendPlainText("Blue"); fmt.setForeground(QBrush(Qt::green)); ed->mergeCurrentCharFormat(fmt); ed->appendPlainText("Green"); QCOMPARE(ed->document()->blockCount(), 3); QTextBlock block = ed->document()->begin(); QCOMPARE(block.begin().fragment().text(), QString("Red")); QVERIFY(block.begin().fragment().charFormat().foreground().color() == Qt::red); block = block.next(); QCOMPARE(block.begin().fragment().text(), QString("Blue")); QVERIFY(block.begin().fragment().charFormat().foreground().color() == Qt::blue); block = block.next(); QCOMPARE(block.begin().fragment().text(), QString("Green")); QVERIFY(block.begin().fragment().charFormat().foreground().color() == Qt::green); } void tst_QPlainTextEdit::ensureVisibleWithRtl() { ed->setLayoutDirection(Qt::RightToLeft); ed->setLineWrapMode(QPlainTextEdit::NoWrap); QString txt(500, QChar(QLatin1Char('a'))); QCOMPARE(txt.length(), 500); ed->setPlainText(txt); ed->resize(100, 100); ed->show(); qApp->processEvents(); QVERIFY(ed->horizontalScrollBar()->maximum() > 0); ed->moveCursor(QTextCursor::Start); QCOMPARE(ed->horizontalScrollBar()->value(), ed->horizontalScrollBar()->maximum()); ed->moveCursor(QTextCursor::End); QCOMPARE(ed->horizontalScrollBar()->value(), 0); ed->moveCursor(QTextCursor::Start); QCOMPARE(ed->horizontalScrollBar()->value(), ed->horizontalScrollBar()->maximum()); ed->moveCursor(QTextCursor::End); QCOMPARE(ed->horizontalScrollBar()->value(), 0); } void tst_QPlainTextEdit::preserveCharFormatAfterSetPlainText() { QTextCharFormat fmt; fmt.setForeground(QBrush(Qt::blue)); ed->mergeCurrentCharFormat(fmt); ed->setPlainText("This is blue"); ed->appendPlainText("This should still be blue"); QTextBlock block = ed->document()->begin(); block = block.next(); QCOMPARE(block.text(), QString("This should still be blue")); QVERIFY(block.begin().fragment().charFormat().foreground().color() == QColor(Qt::blue)); } void tst_QPlainTextEdit::extraSelections() { ed->setPlainText("Hello World"); QTextCursor c = ed->textCursor(); c.movePosition(QTextCursor::Start); c.movePosition(QTextCursor::End, QTextCursor::KeepAnchor); const int endPos = c.position(); QTextEdit::ExtraSelection sel; sel.cursor = c; ed->setExtraSelections(QList() << sel); c.movePosition(QTextCursor::Start); c.movePosition(QTextCursor::NextWord); const int wordPos = c.position(); c.movePosition(QTextCursor::End, QTextCursor::KeepAnchor); sel.cursor = c; ed->setExtraSelections(QList() << sel); QList selections = ed->extraSelections(); QCOMPARE(selections.count(), 1); QCOMPARE(selections.at(0).cursor.position(), endPos); QCOMPARE(selections.at(0).cursor.anchor(), wordPos); } void tst_QPlainTextEdit::adjustScrollbars() { // For some reason ff is defined to be << on Mac Panther / gcc 3.3 #undef ff QFont ff(ed->font()); ff.setFamily("Tahoma"); ff.setPointSize(11); ed->setFont(ff); ed->setMinimumSize(140, 100); ed->setMaximumSize(140, 100); ed->show(); QLatin1String txt("\nabc def ghi jkl mno pqr stu vwx"); ed->setPlainText(txt + txt + txt + txt); QVERIFY(ed->verticalScrollBar()->maximum() > 0); ed->moveCursor(QTextCursor::End); int oldMaximum = ed->verticalScrollBar()->maximum(); QTextCursor cursor = ed->textCursor(); cursor.insertText(QLatin1String("\n")); cursor.deletePreviousChar(); QCOMPARE(ed->verticalScrollBar()->maximum(), oldMaximum); } class SignalReceiver : public QObject { Q_OBJECT public: SignalReceiver() : received(0) {} int receivedSignals() const { return received; } QTextCharFormat charFormat() const { return format; } public slots: void charFormatChanged(const QTextCharFormat &tcf) { ++received; format = tcf; } private: QTextCharFormat format; int received; }; void tst_QPlainTextEdit::textObscuredByScrollbars() { ed->textCursor().insertText( "ab cab cab c abca kjsdf lka sjd lfk jsal df j kasdf abc ab abc " "a b c d e f g h i j k l m n o p q r s t u v w x y z " "abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc " "ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab" "abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc " "ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab" "abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc " "ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab" "abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc " "ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab" "abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc " "ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab" ); ed->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); ed->show(); QSize documentSize = ed->document()->documentLayout()->documentSize().toSize(); QSize viewportSize = ed->viewport()->size(); QVERIFY(documentSize.width() <= viewportSize.width()); } void tst_QPlainTextEdit::setTextPreservesUndoRedoEnabled() { QVERIFY(ed->isUndoRedoEnabled()); ed->setPlainText("Test"); QVERIFY(ed->isUndoRedoEnabled()); ed->setUndoRedoEnabled(false); QVERIFY(!ed->isUndoRedoEnabled()); ed->setPlainText("Test2"); QVERIFY(!ed->isUndoRedoEnabled()); ed->setPlainText("

hello"); QVERIFY(!ed->isUndoRedoEnabled()); } void tst_QPlainTextEdit::wordWrapProperty() { { QPlainTextEdit edit; QTextDocument *doc = new QTextDocument(&edit); doc->setDocumentLayout(new QPlainTextDocumentLayout(doc)); edit.setDocument(doc); edit.setWordWrapMode(QTextOption::NoWrap); QVERIFY(doc->defaultTextOption().wrapMode() == QTextOption::NoWrap); } { QPlainTextEdit edit; QTextDocument *doc = new QTextDocument(&edit); doc->setDocumentLayout(new QPlainTextDocumentLayout(doc)); edit.setWordWrapMode(QTextOption::NoWrap); edit.setDocument(doc); QVERIFY(doc->defaultTextOption().wrapMode() == QTextOption::NoWrap); } } void tst_QPlainTextEdit::lineWrapProperty() { QVERIFY(ed->wordWrapMode() == QTextOption::WrapAtWordBoundaryOrAnywhere); QVERIFY(ed->lineWrapMode() == QPlainTextEdit::WidgetWidth); ed->setLineWrapMode(QPlainTextEdit::NoWrap); QVERIFY(ed->lineWrapMode() == QPlainTextEdit::NoWrap); QVERIFY(ed->wordWrapMode() == QTextOption::WrapAtWordBoundaryOrAnywhere); QVERIFY(ed->document()->defaultTextOption().wrapMode() == QTextOption::NoWrap); } void tst_QPlainTextEdit::selectionChanged() { ed->setPlainText("Hello World"); ed->moveCursor(QTextCursor::Start); QSignalSpy selectionChangedSpy(ed, SIGNAL(selectionChanged())); QTest::keyClick(ed, Qt::Key_Right); QCOMPARE(ed->textCursor().position(), 1); QCOMPARE(selectionChangedSpy.count(), 0); QTest::keyClick(ed, Qt::Key_Right, Qt::ShiftModifier); QCOMPARE(ed->textCursor().position(), 2); QCOMPARE(selectionChangedSpy.count(), 1); QTest::keyClick(ed, Qt::Key_Right, Qt::ShiftModifier); QCOMPARE(ed->textCursor().position(), 3); QCOMPARE(selectionChangedSpy.count(), 2); QTest::keyClick(ed, Qt::Key_Right, Qt::ShiftModifier); QCOMPARE(ed->textCursor().position(), 4); QCOMPARE(selectionChangedSpy.count(), 3); QTest::keyClick(ed, Qt::Key_Right); QCOMPARE(ed->textCursor().position(), 5); QCOMPARE(selectionChangedSpy.count(), 4); QTest::keyClick(ed, Qt::Key_Right); QCOMPARE(ed->textCursor().position(), 6); QCOMPARE(selectionChangedSpy.count(), 4); } void tst_QPlainTextEdit::blockCountChanged() { QSignalSpy blockCountCpangedSpy(ed, SIGNAL(blockCountChanged(int))); ed->setPlainText("Hello"); QCOMPARE(blockCountCpangedSpy.count(), 0); ed->setPlainText("Hello World"); QCOMPARE(blockCountCpangedSpy.count(), 0); ed->setPlainText("Hello \n World \n this \n has \n more \n blocks \n than \n just \n one"); QCOMPARE(blockCountCpangedSpy.count(), 1); ed->setPlainText("One"); QCOMPARE(blockCountCpangedSpy.count(), 2); ed->setPlainText("One \n Two"); QCOMPARE(blockCountCpangedSpy.count(), 3); ed->setPlainText("Three \n Four"); QCOMPARE(blockCountCpangedSpy.count(), 3); } QTEST_MAIN(tst_QPlainTextEdit) #include "tst_qplaintextedit.moc"