/**************************************************************************** ** ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** 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 Technology Preview License Agreement accompanying ** this package. ** ** 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.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** ** ** ** ** ** ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include <QtTest/QtTest> #include <qtextdocument.h> #include <qdebug.h> #include <qtextcursor.h> #include <qtextdocumentfragment.h> #include <qtextformat.h> #include <qtextobject.h> #include <qtexttable.h> #include <qabstracttextdocumentlayout.h> #include <qtextlist.h> #include <qtextcodec.h> #include <qurl.h> #include <qpainter.h> #include <qfontmetrics.h> #include <qimage.h> #include <qtextlayout.h> #include <QDomDocument> #include "common.h" QT_FORWARD_DECLARE_CLASS(QTextDocument) //TESTED_CLASS= //TESTED_FILES= class tst_QTextDocument : public QObject { Q_OBJECT public: tst_QTextDocument(); virtual ~tst_QTextDocument(); public slots: void init(); void cleanup(); private slots: void getSetCheck(); void isEmpty(); void find_data(); void find(); void find2(); void findWithRegExp_data(); void findWithRegExp(); void findMultiple(); void basicIsModifiedChecks(); void moreIsModified(); void isModified2(); void isModified3(); void isModified4(); void noundo_basicIsModifiedChecks(); void noundo_moreIsModified(); void noundo_isModified2(); void noundo_isModified3(); void mightBeRichText(); void mightBeRichText_data(); void task240325(); void stylesheetFont_data(); void stylesheetFont(); void toHtml_data(); void toHtml(); void toHtml2(); void setFragmentMarkersInHtmlExport(); void toHtmlBodyBgColor(); void toHtmlRootFrameProperties(); void capitalizationHtmlInExport(); void wordspacingHtmlExport(); void cursorPositionChanged(); void cursorPositionChangedOnSetText(); void textFrameIterator(); void codecForHtml(); void markContentsDirty(); void clonePreservesMetaInformation(); void clonePreservesPageSize(); void clonePreservesPageBreakPolicies(); void clonePreservesDefaultFont(); void clonePreservesRootFrameFormat(); void clonePreservesResources(); void clonePreservesUserStates(); void clonePreservesIndentWidth(); void blockCount(); void defaultStyleSheet(); void resolvedFontInEmptyFormat(); void defaultRootFrameMargin(); void clearResources(); void setPlainText(); void toPlainText(); void deleteTextObjectsOnClear(); void maximumBlockCount(); void adjustSize(); void initialUserData(); void html_defaultFont(); void blockCountChanged(); void nonZeroDocumentLengthOnClear(); void setTextPreservesUndoRedoEnabled(); void firstLast(); void backgroundImage_toHtml(); void backgroundImage_toHtml2(); void backgroundImage_clone(); void backgroundImage_copy(); void documentCleanup(); void characterAt(); void revisions(); void revisionWithUndoCompressionAndUndo(); void testUndoCommandAdded(); void testUndoBlocks(); void receiveCursorPositionChangedAfterContentsChange(); void escape_data(); void escape(); private: void backgroundImage_checkExpectedHtml(const QTextDocument &doc); QTextDocument *doc; QTextCursor cursor; QFont defaultFont; QString htmlHead; QString htmlTail; }; class MyAbstractTextDocumentLayout : public QAbstractTextDocumentLayout { public: MyAbstractTextDocumentLayout(QTextDocument *doc) : QAbstractTextDocumentLayout(doc) {} void draw(QPainter *, const PaintContext &) {} int hitTest(const QPointF &, Qt::HitTestAccuracy) const { return 0; } int pageCount() const { return 0; } QSizeF documentSize() const { return QSizeF(); } QRectF frameBoundingRect(QTextFrame *) const { return QRectF(); } QRectF blockBoundingRect(const QTextBlock &) const { return QRectF(); } void documentChanged(int, int, int) {} }; // Testing get/set functions void tst_QTextDocument::getSetCheck() { QTextDocument obj1; // QAbstractTextDocumentLayout * QTextDocument::documentLayout() // void QTextDocument::setDocumentLayout(QAbstractTextDocumentLayout *) QPointer<MyAbstractTextDocumentLayout> var1 = new MyAbstractTextDocumentLayout(0); obj1.setDocumentLayout(var1); QCOMPARE(static_cast<QAbstractTextDocumentLayout *>(var1), obj1.documentLayout()); obj1.setDocumentLayout((QAbstractTextDocumentLayout *)0); QVERIFY(var1.isNull()); QVERIFY(obj1.documentLayout()); // bool QTextDocument::useDesignMetrics() // void QTextDocument::setUseDesignMetrics(bool) obj1.setUseDesignMetrics(false); QCOMPARE(false, obj1.useDesignMetrics()); obj1.setUseDesignMetrics(true); QCOMPARE(true, obj1.useDesignMetrics()); } tst_QTextDocument::tst_QTextDocument() { QImage img(16, 16, QImage::Format_ARGB32_Premultiplied); img.save("foo.png"); } tst_QTextDocument::~tst_QTextDocument() { QFile::remove(QLatin1String("foo.png")); } void tst_QTextDocument::init() { doc = new QTextDocument; cursor = QTextCursor(doc); defaultFont = QFont(); htmlHead = QString("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" " "\"http://www.w3.org/TR/REC-html40/strict.dtd\">\n" "<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n" "p, li { white-space: pre-wrap; }\n" "</style></head>" "<body style=\" font-family:'%1'; font-size:%2pt; font-weight:%3; font-style:%4;\">\n"); htmlHead = htmlHead.arg(defaultFont.family()).arg(defaultFont.pointSizeF()).arg(defaultFont.weight() * 8).arg((defaultFont.italic() ? "italic" : "normal")); htmlTail = QString("</body></html>"); } void tst_QTextDocument::cleanup() { cursor = QTextCursor(); delete doc; doc = 0; } void tst_QTextDocument::isEmpty() { QVERIFY(doc->isEmpty()); } void tst_QTextDocument::find_data() { QTest::addColumn<QString>("haystack"); QTest::addColumn<QString>("needle"); QTest::addColumn<int>("flags"); QTest::addColumn<int>("from"); QTest::addColumn<int>("anchor"); QTest::addColumn<int>("position"); QTest::newRow("1") << "Hello World" << "World" << int(QTextDocument::FindCaseSensitively) << 0 << 6 << 11; QTest::newRow("2") << QString::fromAscii("Hello") + QString(QChar::ParagraphSeparator) + QString::fromAscii("World") << "World" << int(QTextDocument::FindCaseSensitively) << 1 << 6 << 11; QTest::newRow("3") << QString::fromAscii("Hello") + QString(QChar::ParagraphSeparator) + QString::fromAscii("World") << "Hello" << int(QTextDocument::FindCaseSensitively | QTextDocument::FindBackward) << 10 << 0 << 5; QTest::newRow("4wholewords") << QString::fromAscii("Hello Blah World") << "Blah" << int(QTextDocument::FindWholeWords) << 0 << 6 << 10; QTest::newRow("5wholewords") << QString::fromAscii("HelloBlahWorld") << "Blah" << int(QTextDocument::FindWholeWords) << 0 << -1 << -1; QTest::newRow("6wholewords") << QString::fromAscii("HelloBlahWorld Blah Hah") << "Blah" << int(QTextDocument::FindWholeWords) << 0 << 15 << 19; QTest::newRow("7wholewords") << QString::fromAscii("HelloBlahWorld Blah Hah") << "Blah" << int(QTextDocument::FindWholeWords | QTextDocument::FindBackward) << 23 << 15 << 19; QTest::newRow("8wholewords") << QString::fromAscii("Hello: World\n") << "orld" << int(QTextDocument::FindWholeWords) << 0 << -1 << -1; QTest::newRow("across-paragraphs") << QString::fromAscii("First Parag\nSecond Parag with a lot more text") << "Parag" << int(QTextDocument::FindBackward) << 15 << 6 << 11; QTest::newRow("nbsp") << "Hello" + QString(QChar(QChar::Nbsp)) +"World" << " " << int(QTextDocument::FindCaseSensitively) << 0 << 5 << 6; } void tst_QTextDocument::find() { QFETCH(QString, haystack); QFETCH(QString, needle); QFETCH(int, flags); QFETCH(int, from); QFETCH(int, anchor); QFETCH(int, position); cursor.insertText(haystack); cursor = doc->find(needle, from, QTextDocument::FindFlags(flags)); if (anchor != -1) { QCOMPARE(cursor.anchor(), anchor); QCOMPARE(cursor.position(), position); } else { QVERIFY(cursor.isNull()); } //search using a regular expression QRegExp expr(needle); expr.setPatternSyntax(QRegExp::FixedString); QTextDocument::FindFlags flg(flags); expr.setCaseSensitivity((flg & QTextDocument::FindCaseSensitively) ? Qt::CaseSensitive : Qt::CaseInsensitive); cursor = doc->find(expr, from, flg); if (anchor != -1) { QCOMPARE(cursor.anchor(), anchor); QCOMPARE(cursor.position(), position); } else { QVERIFY(cursor.isNull()); } } void tst_QTextDocument::findWithRegExp_data() { QTest::addColumn<QString>("haystack"); QTest::addColumn<QString>("needle"); QTest::addColumn<int>("flags"); QTest::addColumn<int>("from"); QTest::addColumn<int>("anchor"); QTest::addColumn<int>("position"); // match integers 0 to 99 QTest::newRow("1") << "23" << "^\\d\\d?$" << int(QTextDocument::FindCaseSensitively) << 0 << 0 << 2; // match ampersands but not & QTest::newRow("2") << "His & hers & theirs" << "&(?!amp;)"<< int(QTextDocument::FindCaseSensitively) << 0 << 15 << 16; //backward search QTest::newRow("3") << QString::fromAscii("HelloBlahWorld Blah Hah") << "h" << int(QTextDocument::FindBackward) << 18 << 8 << 9; } void tst_QTextDocument::findWithRegExp() { QFETCH(QString, haystack); QFETCH(QString, needle); QFETCH(int, flags); QFETCH(int, from); QFETCH(int, anchor); QFETCH(int, position); cursor.insertText(haystack); //search using a regular expression QRegExp expr(needle); QTextDocument::FindFlags flg(flags); expr.setCaseSensitivity((flg & QTextDocument::FindCaseSensitively) ? Qt::CaseSensitive : Qt::CaseInsensitive); cursor = doc->find(expr, from, flg); if (anchor != -1) { QCOMPARE(cursor.anchor(), anchor); QCOMPARE(cursor.position(), position); } else { QVERIFY(cursor.isNull()); } } void tst_QTextDocument::find2() { doc->setPlainText("aaa"); cursor.movePosition(QTextCursor::Start); cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor); QTextCursor hit = doc->find("a", cursor); QCOMPARE(hit.position(), 2); QCOMPARE(hit.anchor(), 1); } void tst_QTextDocument::findMultiple() { const QString text("foo bar baz foo bar baz"); doc->setPlainText(text); cursor.movePosition(QTextCursor::Start); cursor = doc->find("bar", cursor); QCOMPARE(cursor.selectionStart(), text.indexOf("bar")); QCOMPARE(cursor.selectionEnd(), cursor.selectionStart() + 3); cursor = doc->find("bar", cursor); QCOMPARE(cursor.selectionStart(), text.lastIndexOf("bar")); QCOMPARE(cursor.selectionEnd(), cursor.selectionStart() + 3); cursor.movePosition(QTextCursor::End); cursor = doc->find("bar", cursor, QTextDocument::FindBackward); QCOMPARE(cursor.selectionStart(), text.lastIndexOf("bar")); QCOMPARE(cursor.selectionEnd(), cursor.selectionStart() + 3); cursor = doc->find("bar", cursor, QTextDocument::FindBackward); QCOMPARE(cursor.selectionStart(), text.indexOf("bar")); QCOMPARE(cursor.selectionEnd(), cursor.selectionStart() + 3); QRegExp expr("bar"); expr.setPatternSyntax(QRegExp::FixedString); cursor.movePosition(QTextCursor::End); cursor = doc->find(expr, cursor, QTextDocument::FindBackward); QCOMPARE(cursor.selectionStart(), text.lastIndexOf("bar")); QCOMPARE(cursor.selectionEnd(), cursor.selectionStart() + 3); cursor = doc->find(expr, cursor, QTextDocument::FindBackward); QCOMPARE(cursor.selectionStart(), text.indexOf("bar")); QCOMPARE(cursor.selectionEnd(), cursor.selectionStart() + 3); cursor.movePosition(QTextCursor::Start); cursor = doc->find(expr, cursor); QCOMPARE(cursor.selectionStart(), text.indexOf("bar")); QCOMPARE(cursor.selectionEnd(), cursor.selectionStart() + 3); cursor = doc->find(expr, cursor); QCOMPARE(cursor.selectionStart(), text.lastIndexOf("bar")); QCOMPARE(cursor.selectionEnd(), cursor.selectionStart() + 3); } void tst_QTextDocument::basicIsModifiedChecks() { QSignalSpy spy(doc, SIGNAL(modificationChanged(bool))); QVERIFY(!doc->isModified()); cursor.insertText("Hello World"); QVERIFY(doc->isModified()); QCOMPARE(spy.count(), 1); QVERIFY(spy.takeFirst().at(0).toBool()); doc->undo(); QVERIFY(!doc->isModified()); QCOMPARE(spy.count(), 1); QVERIFY(!spy.takeFirst().at(0).toBool()); doc->redo(); QVERIFY(doc->isModified()); QCOMPARE(spy.count(), 1); QVERIFY(spy.takeFirst().at(0).toBool()); } void tst_QTextDocument::moreIsModified() { QVERIFY(!doc->isModified()); cursor.insertText("Hello"); QVERIFY(doc->isModified()); doc->undo(); QVERIFY(!doc->isModified()); cursor.insertText("Hello"); doc->undo(); QVERIFY(!doc->isModified()); } void tst_QTextDocument::isModified2() { // reported on qt4-preview-feedback QVERIFY(!doc->isModified()); cursor.insertText("Hello"); QVERIFY(doc->isModified()); doc->setModified(false); QVERIFY(!doc->isModified()); cursor.insertText("Hello"); QVERIFY(doc->isModified()); } void tst_QTextDocument::isModified3() { QVERIFY(!doc->isModified()); doc->setUndoRedoEnabled(false); doc->setUndoRedoEnabled(true); cursor.insertText("Hello"); QVERIFY(doc->isModified()); doc->undo(); QVERIFY(!doc->isModified()); } void tst_QTextDocument::isModified4() { QVERIFY(!doc->isModified()); cursor.insertText("Hello"); cursor.insertText("World"); doc->setModified(false); QVERIFY(!doc->isModified()); cursor.insertText("Again"); QVERIFY(doc->isModified()); doc->undo(); QVERIFY(!doc->isModified()); doc->undo(); QVERIFY(doc->isModified()); doc->redo(); QVERIFY(!doc->isModified()); doc->redo(); QVERIFY(doc->isModified()); doc->undo(); QVERIFY(!doc->isModified()); doc->undo(); QVERIFY(doc->isModified()); //task 197769 cursor.insertText("Hello"); QVERIFY(doc->isModified()); } void tst_QTextDocument::noundo_basicIsModifiedChecks() { doc->setUndoRedoEnabled(false); QSignalSpy spy(doc, SIGNAL(modificationChanged(bool))); QVERIFY(!doc->isModified()); cursor.insertText("Hello World"); QVERIFY(doc->isModified()); QCOMPARE(spy.count(), 1); QVERIFY(spy.takeFirst().at(0).toBool()); doc->undo(); QVERIFY(doc->isModified()); QCOMPARE(spy.count(), 0); doc->redo(); QVERIFY(doc->isModified()); QCOMPARE(spy.count(), 0); } void tst_QTextDocument::task240325() { doc->setHtml("<html><img width=\"100\" height=\"100\" align=\"right\"/>Foobar Foobar Foobar Foobar</html>"); QImage img(1000, 7000, QImage::Format_ARGB32_Premultiplied); QPainter p(&img); QFontMetrics fm(p.font()); // Set page size to contain image and one "Foobar" doc->setPageSize(QSize(100 + fm.width("Foobar")*2, 1000)); // Force layout doc->drawContents(&p); QCOMPARE(doc->blockCount(), 1); for (QTextBlock block = doc->begin() ; block!=doc->end() ; block = block.next()) { QTextLayout *layout = block.layout(); QCOMPARE(layout->lineCount(), 4); for (int lineIdx=0;lineIdx<layout->lineCount();++lineIdx) { QTextLine line = layout->lineAt(lineIdx); QString text = block.text().mid(line.textStart(), line.textLength()).trimmed(); // Remove start token if (lineIdx == 0) text = text.mid(1); QCOMPARE(text, QString::fromLatin1("Foobar")); } } } void tst_QTextDocument::stylesheetFont_data() { QTest::addColumn<QString>("stylesheet"); QTest::addColumn<QFont>("font"); { QFont font; font.setBold(true); font.setPixelSize(64); QTest::newRow("Regular font specification") << "font-size: 64px; font-weight: bold;" << font; } { QFont font; font.setBold(true); font.setPixelSize(64); QTest::newRow("Shorthand font specification") << "font: normal bold 64px Arial;" << font; } } void tst_QTextDocument::stylesheetFont() { QFETCH(QString, stylesheet); QFETCH(QFont, font); QString html = QString::fromLatin1("<html>" "<body>" "<div style=\"%1\" >" "Foobar" "</div>" "</body>" "</html>").arg(stylesheet); qDebug() << html; doc->setHtml(html); QCOMPARE(doc->blockCount(), 1); // First and only block QTextBlock block = doc->firstBlock(); QString text = block.text(); QCOMPARE(text, QString::fromLatin1("Foobar")); QFont actualFont = block.charFormat().font(); QCOMPARE(actualFont.bold(), font.bold()); QCOMPARE(actualFont.pixelSize(), font.pixelSize()); } void tst_QTextDocument::noundo_moreIsModified() { doc->setUndoRedoEnabled(false); QVERIFY(!doc->isModified()); cursor.insertText("Hello"); QVERIFY(doc->isModified()); doc->undo(); QVERIFY(doc->isModified()); cursor.insertText("Hello"); doc->undo(); QVERIFY(doc->isModified()); } void tst_QTextDocument::noundo_isModified2() { // reported on qt4-preview-feedback QVERIFY(!doc->isModified()); cursor.insertText("Hello"); QVERIFY(doc->isModified()); doc->setModified(false); QVERIFY(!doc->isModified()); cursor.insertText("Hello"); QVERIFY(doc->isModified()); } void tst_QTextDocument::noundo_isModified3() { doc->setUndoRedoEnabled(false); QVERIFY(!doc->isModified()); cursor.insertText("Hello"); QVERIFY(doc->isModified()); doc->undo(); QVERIFY(doc->isModified()); } void tst_QTextDocument::mightBeRichText_data() { const char qtDocuHeader[] = "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n" "<!DOCTYPE html\n" " PUBLIC ""-//W3C//DTD XHTML 1.0 Strict//EN\" \"DTD/xhtml1-strict.dtd\">\n" "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">"; QVERIFY(Qt::mightBeRichText(QString::fromLatin1(qtDocuHeader))); QTest::addColumn<QString>("input"); QTest::addColumn<bool>("result"); QTest::newRow("documentation-header") << QString("<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n" "<!DOCTYPE html\n" " PUBLIC ""-//W3C//DTD XHTML 1.0 Strict//EN\" \"DTD/xhtml1-strict.dtd\">\n" "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">") << true; QTest::newRow("br-nospace") << QString("Test <br/> new line") << true; QTest::newRow("br-space") << QString("Test <br /> new line") << true; QTest::newRow("br-invalidspace") << QString("Test <br/ > new line") << false; QTest::newRow("invalid closing tag") << QString("Test <br/ line") << false; } void tst_QTextDocument::mightBeRichText() { QFETCH(QString, input); QFETCH(bool, result); QVERIFY(result == Qt::mightBeRichText(input)); } Q_DECLARE_METATYPE(QTextDocumentFragment) #define CREATE_DOC_AND_CURSOR() \ QTextDocument doc; \ doc.setDefaultFont(defaultFont); \ QTextCursor cursor(&doc); void tst_QTextDocument::toHtml_data() { QTest::addColumn<QTextDocumentFragment>("input"); QTest::addColumn<QString>("expectedOutput"); { CREATE_DOC_AND_CURSOR(); cursor.insertText("Blah"); QTest::newRow("simple") << QTextDocumentFragment(&doc) << QString("<p DEFAULTBLOCKSTYLE>Blah</p>"); } { CREATE_DOC_AND_CURSOR(); cursor.insertText("&<>"); QTest::newRow("entities") << QTextDocumentFragment(&doc) << QString("<p DEFAULTBLOCKSTYLE>&<></p>"); } { CREATE_DOC_AND_CURSOR(); QTextCharFormat fmt; fmt.setFontFamily("Times"); cursor.insertText("Blah", fmt); QTest::newRow("font-family") << QTextDocumentFragment(&doc) << QString("<p DEFAULTBLOCKSTYLE><span style=\" font-family:'Times';\">Blah</span></p>"); } { CREATE_DOC_AND_CURSOR(); QTextCharFormat fmt; fmt.setFontFamily("Foo's Family"); cursor.insertText("Blah", fmt); QTest::newRow("font-family-with-quotes1") << QTextDocumentFragment(&doc) << QString("<p DEFAULTBLOCKSTYLE><span style=\" font-family:"Foo's Family";\">Blah</span></p>"); } { CREATE_DOC_AND_CURSOR(); QTextCharFormat fmt; fmt.setFontFamily("Foo\"s Family"); cursor.insertText("Blah", fmt); QTest::newRow("font-family-with-quotes2") << QTextDocumentFragment(&doc) << QString("<p DEFAULTBLOCKSTYLE><span style=\" font-family:'Foo"s Family';\">Blah</span></p>"); } { CREATE_DOC_AND_CURSOR(); QTextBlockFormat fmt; fmt.setNonBreakableLines(true); cursor.insertBlock(fmt); cursor.insertText("Blah"); QTest::newRow("pre") << QTextDocumentFragment(&doc) << QString("EMPTYBLOCK") + QString("<pre DEFAULTBLOCKSTYLE>Blah</pre>"); } { CREATE_DOC_AND_CURSOR(); QTextCharFormat fmt; fmt.setFontPointSize(40); cursor.insertText("Blah", fmt); QTest::newRow("font-size") << QTextDocumentFragment(&doc) << QString("<p DEFAULTBLOCKSTYLE><span style=\" font-size:40pt;\">Blah</span></p>"); } { CREATE_DOC_AND_CURSOR(); QTextCharFormat fmt; fmt.setProperty(QTextFormat::FontSizeIncrement, 2); cursor.insertText("Blah", fmt); QTest::newRow("logical-font-size") << QTextDocumentFragment(&doc) << QString("<p DEFAULTBLOCKSTYLE><span style=\" font-size:x-large;\">Blah</span></p>"); } { CREATE_DOC_AND_CURSOR(); cursor.insertText("Foo"); QTextCharFormat fmt; fmt.setFontPointSize(40); cursor.insertBlock(QTextBlockFormat(), fmt); fmt.clearProperty(QTextFormat::FontPointSize); cursor.insertText("Blub", fmt); QTest::newRow("no-font-size") << QTextDocumentFragment(&doc) << QString("<p DEFAULTBLOCKSTYLE>Foo</p>\n<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Blub</p>"); } { CREATE_DOC_AND_CURSOR(); QTextBlockFormat fmt; fmt.setLayoutDirection(Qt::RightToLeft); cursor.insertBlock(fmt); cursor.insertText("Blah"); QTest::newRow("rtl") << QTextDocumentFragment(&doc) << QString("EMPTYBLOCK") + QString("<p dir='rtl' DEFAULTBLOCKSTYLE>Blah</p>"); } { CREATE_DOC_AND_CURSOR(); QTextBlockFormat fmt; fmt.setAlignment(Qt::AlignJustify); cursor.insertBlock(fmt); cursor.insertText("Blah"); QTest::newRow("blockalign") << QTextDocumentFragment(&doc) << QString("EMPTYBLOCK") + QString("<p align=\"justify\" DEFAULTBLOCKSTYLE>Blah</p>"); } { CREATE_DOC_AND_CURSOR(); QTextBlockFormat fmt; fmt.setAlignment(Qt::AlignCenter); cursor.insertBlock(fmt); cursor.insertText("Blah"); QTest::newRow("blockalign2") << QTextDocumentFragment(&doc) << QString("EMPTYBLOCK") + QString("<p align=\"center\" DEFAULTBLOCKSTYLE>Blah</p>"); } { CREATE_DOC_AND_CURSOR(); QTextBlockFormat fmt; fmt.setAlignment(Qt::AlignRight | Qt::AlignAbsolute); cursor.insertBlock(fmt); cursor.insertText("Blah"); QTest::newRow("blockalign3") << QTextDocumentFragment(&doc) << QString("EMPTYBLOCK") + QString("<p align=\"right\" DEFAULTBLOCKSTYLE>Blah</p>"); } { CREATE_DOC_AND_CURSOR(); QTextBlockFormat fmt; fmt.setBackground(QColor("#0000ff")); cursor.insertBlock(fmt); cursor.insertText("Blah"); QTest::newRow("bgcolor") << QTextDocumentFragment(&doc) << QString("EMPTYBLOCK") + QString("<p OPENDEFAULTBLOCKSTYLE background-color:#0000ff;\">Blah</p>"); } { CREATE_DOC_AND_CURSOR(); QTextCharFormat fmt; fmt.setFontWeight(40); cursor.insertText("Blah", fmt); QTest::newRow("font-weight") << QTextDocumentFragment(&doc) << QString("<p DEFAULTBLOCKSTYLE><span style=\" font-weight:320;\">Blah</span></p>"); } { CREATE_DOC_AND_CURSOR(); QTextCharFormat fmt; fmt.setFontItalic(true); cursor.insertText("Blah", fmt); QTest::newRow("font-italic") << QTextDocumentFragment(&doc) << QString("<p DEFAULTBLOCKSTYLE><span style=\" font-style:italic;\">Blah</span></p>"); } { CREATE_DOC_AND_CURSOR(); QTextCharFormat fmt; fmt.setFontUnderline(true); fmt.setFontOverline(false); cursor.insertText("Blah", fmt); QTest::newRow("text-decoration-1") << QTextDocumentFragment(&doc) << QString("<p DEFAULTBLOCKSTYLE><span style=\" text-decoration: underline;\">Blah</span></p>"); } { CREATE_DOC_AND_CURSOR(); QTextCharFormat fmt; fmt.setForeground(QColor("#00ff00")); cursor.insertText("Blah", fmt); QTest::newRow("color") << QTextDocumentFragment(&doc) << QString("<p DEFAULTBLOCKSTYLE><span style=\" color:#00ff00;\">Blah</span></p>"); } { CREATE_DOC_AND_CURSOR(); QTextCharFormat fmt; fmt.setBackground(QColor("#00ff00")); cursor.insertText("Blah", fmt); QTest::newRow("span-bgcolor") << QTextDocumentFragment(&doc) << QString("<p DEFAULTBLOCKSTYLE><span style=\" background-color:#00ff00;\">Blah</span></p>"); } { CREATE_DOC_AND_CURSOR(); QTextCharFormat fmt; fmt.setVerticalAlignment(QTextCharFormat::AlignSubScript); cursor.insertText("Blah", fmt); QTest::newRow("valign-sub") << QTextDocumentFragment(&doc) << QString("<p DEFAULTBLOCKSTYLE><span style=\" vertical-align:sub;\">Blah</span></p>"); } { CREATE_DOC_AND_CURSOR(); QTextCharFormat fmt; fmt.setVerticalAlignment(QTextCharFormat::AlignSuperScript); cursor.insertText("Blah", fmt); QTest::newRow("valign-super") << QTextDocumentFragment(&doc) << QString("<p DEFAULTBLOCKSTYLE><span style=\" vertical-align:super;\">Blah</span></p>"); } { CREATE_DOC_AND_CURSOR(); QTextCharFormat fmt; fmt.setAnchor(true); fmt.setAnchorName("blub"); cursor.insertText("Blah", fmt); QTest::newRow("named anchor") << QTextDocumentFragment(&doc) << QString("<p DEFAULTBLOCKSTYLE><a name=\"blub\"></a>Blah</p>"); } { CREATE_DOC_AND_CURSOR(); QTextCharFormat fmt; fmt.setAnchor(true); fmt.setAnchorHref("http://www.kde.org/"); cursor.insertText("Blah", fmt); QTest::newRow("href anchor") << QTextDocumentFragment(&doc) << QString("<p DEFAULTBLOCKSTYLE><a href=\"http://www.kde.org/\">Blah</a></p>"); } { CREATE_DOC_AND_CURSOR(); QTextCharFormat fmt; fmt.setAnchor(true); fmt.setAnchorHref("http://www.kde.org/?a=1&b=2"); cursor.insertText("Blah", fmt); QTest::newRow("href anchor with &") << QTextDocumentFragment(&doc) << QString("<p DEFAULTBLOCKSTYLE><a href=\"http://www.kde.org/?a=1&b=2\">Blah</a></p>"); } { CREATE_DOC_AND_CURSOR(); QTextCharFormat fmt; fmt.setAnchor(true); fmt.setAnchorHref("http://www.kde.org/?a='&b=\""); cursor.insertText("Blah", fmt); QTest::newRow("href anchor with ' and \"") << QTextDocumentFragment(&doc) << QString("<p DEFAULTBLOCKSTYLE><a href=\"http://www.kde.org/?a='&b="\">Blah</a></p>"); } { CREATE_DOC_AND_CURSOR(); cursor.insertTable(2, 2); QTest::newRow("simpletable") << QTextDocumentFragment(&doc) << QString("<table border=\"1\" cellspacing=\"2\">" "\n<tr>\n<td></td>\n<td></td></tr>" "\n<tr>\n<td></td>\n<td></td></tr>" "</table>"); } { CREATE_DOC_AND_CURSOR(); QTextTable *table = cursor.insertTable(1, 4); table->mergeCells(0, 0, 1, 2); table->mergeCells(0, 2, 1, 2); QTest::newRow("tablespans") << QTextDocumentFragment(&doc) << QString("<table border=\"1\" cellspacing=\"2\">" "\n<tr>\n<td colspan=\"2\"></td>\n<td colspan=\"2\"></td></tr>" "</table>"); } { CREATE_DOC_AND_CURSOR(); QTextTableFormat fmt; fmt.setBorder(1); fmt.setCellSpacing(3); fmt.setCellPadding(3); fmt.setBackground(QColor("#ff00ff")); fmt.setWidth(QTextLength(QTextLength::PercentageLength, 50)); fmt.setAlignment(Qt::AlignHCenter); fmt.setPosition(QTextFrameFormat::FloatRight); cursor.insertTable(2, 2, fmt); QTest::newRow("tableattrs") << QTextDocumentFragment(&doc) << QString("<table border=\"1\" style=\" float: right;\" align=\"center\" width=\"50%\" cellspacing=\"3\" cellpadding=\"3\" bgcolor=\"#ff00ff\">" "\n<tr>\n<td></td>\n<td></td></tr>" "\n<tr>\n<td></td>\n<td></td></tr>" "</table>"); } { CREATE_DOC_AND_CURSOR(); QTextTableFormat fmt; fmt.setBorder(1); fmt.setCellSpacing(3); fmt.setCellPadding(3); fmt.setBackground(QColor("#ff00ff")); fmt.setWidth(QTextLength(QTextLength::PercentageLength, 50)); fmt.setAlignment(Qt::AlignHCenter); fmt.setPosition(QTextFrameFormat::FloatRight); fmt.setLeftMargin(25); fmt.setBottomMargin(35); cursor.insertTable(2, 2, fmt); QTest::newRow("tableattrs2") << QTextDocumentFragment(&doc) << QString("<table border=\"1\" style=\" float: right; margin-top:0px; margin-bottom:35px; margin-left:25px; margin-right:0px;\" align=\"center\" width=\"50%\" cellspacing=\"3\" cellpadding=\"3\" bgcolor=\"#ff00ff\">" "\n<tr>\n<td></td>\n<td></td></tr>" "\n<tr>\n<td></td>\n<td></td></tr>" "</table>"); } { CREATE_DOC_AND_CURSOR(); QTextTableFormat fmt; fmt.setHeaderRowCount(2); cursor.insertTable(4, 2, fmt); QTest::newRow("tableheader") << QTextDocumentFragment(&doc) << QString("<table border=\"1\" cellspacing=\"2\">" "<thead>\n<tr>\n<td></td>\n<td></td></tr>" "\n<tr>\n<td></td>\n<td></td></tr></thead>" "\n<tr>\n<td></td>\n<td></td></tr>" "\n<tr>\n<td></td>\n<td></td></tr>" "</table>"); } { CREATE_DOC_AND_CURSOR(); QTextTable *table = cursor.insertTable(2, 2); QTextTable *subTable = table->cellAt(0, 1).firstCursorPosition().insertTable(1, 1); subTable->cellAt(0, 0).firstCursorPosition().insertText("Hey"); QTest::newRow("nestedtable") << QTextDocumentFragment(&doc) << QString("<table border=\"1\" cellspacing=\"2\">" "\n<tr>\n<td></td>\n<td>\n<table border=\"1\" cellspacing=\"2\">\n<tr>\n<td>\n<p DEFAULTBLOCKSTYLE>Hey</p></td></tr></table></td></tr>" "\n<tr>\n<td></td>\n<td></td></tr>" "</table>"); } { CREATE_DOC_AND_CURSOR(); QTextTableFormat fmt; QVector<QTextLength> widths; widths.append(QTextLength()); widths.append(QTextLength(QTextLength::PercentageLength, 30)); widths.append(QTextLength(QTextLength::FixedLength, 40)); fmt.setColumnWidthConstraints(widths); cursor.insertTable(1, 3, fmt); QTest::newRow("colwidths") << QTextDocumentFragment(&doc) << QString("<table border=\"1\" cellspacing=\"2\">" "\n<tr>\n<td></td>\n<td width=\"30%\"></td>\n<td width=\"40\"></td></tr>" "</table>"); } // ### rowspan/colspan tests, once texttable api for that is back again // { CREATE_DOC_AND_CURSOR(); QTextTable *table = cursor.insertTable(1, 1); QTextCursor cellCurs = table->cellAt(0, 0).firstCursorPosition(); QTextCharFormat fmt; fmt.setBackground(QColor("#ffffff")); cellCurs.mergeBlockCharFormat(fmt); QTest::newRow("cellproperties") << QTextDocumentFragment(&doc) << QString("<table border=\"1\" cellspacing=\"2\">" "\n<tr>\n<td bgcolor=\"#ffffff\"></td></tr>" "</table>"); } { CREATE_DOC_AND_CURSOR(); // ### fixme: use programmatic api as soon as we can create floats through it const char html[] = "<html><body>Blah<img src=\"image.png\" width=\"10\" height=\"20\" style=\"float: right;\" />Blubb</body></html>"; QTest::newRow("image") << QTextDocumentFragment::fromHtml(QString::fromLatin1(html)) << QString("<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Blah<img src=\"image.png\" width=\"10\" height=\"20\" style=\"float: right;\" />Blubb</p>"); } { CREATE_DOC_AND_CURSOR(); QTextImageFormat fmt; fmt.setName("foo"); fmt.setVerticalAlignment(QTextCharFormat::AlignMiddle); cursor.insertImage(fmt); QTest::newRow("image-malign") << QTextDocumentFragment(&doc) << QString("<p DEFAULTBLOCKSTYLE><img src=\"foo\" style=\"vertical-align: middle;\" /></p>"); } { CREATE_DOC_AND_CURSOR(); QTextImageFormat fmt; fmt.setName("foo"); fmt.setVerticalAlignment(QTextCharFormat::AlignTop); cursor.insertImage(fmt); QTest::newRow("image-malign") << QTextDocumentFragment(&doc) << QString("<p DEFAULTBLOCKSTYLE><img src=\"foo\" style=\"vertical-align: top;\" /></p>"); } { CREATE_DOC_AND_CURSOR(); QTextImageFormat fmt; fmt.setName("foo"); cursor.insertImage(fmt); cursor.insertImage(fmt); QTest::newRow("2images") << QTextDocumentFragment(&doc) << QString("<p DEFAULTBLOCKSTYLE><img src=\"foo\" /><img src=\"foo\" /></p>"); } { CREATE_DOC_AND_CURSOR(); QString txt = QLatin1String("Blah"); txt += QChar::LineSeparator; txt += QLatin1String("Bar"); cursor.insertText(txt); QTest::newRow("linebreaks") << QTextDocumentFragment(&doc) << QString("<p DEFAULTBLOCKSTYLE>Blah<br />Bar</p>"); } { CREATE_DOC_AND_CURSOR(); QTextBlockFormat fmt; fmt.setTopMargin(10); fmt.setBottomMargin(20); fmt.setLeftMargin(30); fmt.setRightMargin(40); cursor.insertBlock(fmt); cursor.insertText("Blah"); QTest::newRow("blockmargins") << QTextDocumentFragment(&doc) << QString("EMPTYBLOCK") + QString("<p style=\" margin-top:10px; margin-bottom:20px; margin-left:30px; margin-right:40px; -qt-block-indent:0; text-indent:0px;\">Blah</p>"); } { CREATE_DOC_AND_CURSOR(); QTextList *list = cursor.insertList(QTextListFormat::ListDisc); cursor.insertText("Blubb"); cursor.insertBlock(); cursor.insertText("Blah"); QCOMPARE(list->count(), 2); QTest::newRow("lists") << QTextDocumentFragment(&doc) << QString("EMPTYBLOCK") + QString("<ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\"><li DEFAULTBLOCKSTYLE>Blubb</li>\n<li DEFAULTBLOCKSTYLE>Blah</li></ul>"); } { CREATE_DOC_AND_CURSOR(); QTextList *list = cursor.insertList(QTextListFormat::ListDisc); cursor.insertText("Blubb"); cursor.insertBlock(); QTextCharFormat blockCharFmt; blockCharFmt.setForeground(QColor("#0000ff")); cursor.mergeBlockCharFormat(blockCharFmt); QTextCharFormat fmt; fmt.setForeground(QColor("#ff0000")); cursor.insertText("Blah", fmt); QCOMPARE(list->count(), 2); QTest::newRow("charfmt-for-list-item") << QTextDocumentFragment(&doc) << QString("EMPTYBLOCK") + QString("<ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\"><li DEFAULTBLOCKSTYLE>Blubb</li>\n<li style=\" color:#0000ff;\" DEFAULTBLOCKSTYLE><span style=\" color:#ff0000;\">Blah</span></li></ul>"); } { CREATE_DOC_AND_CURSOR(); QTextBlockFormat fmt; fmt.setIndent(3); fmt.setTextIndent(30); cursor.insertBlock(fmt); cursor.insertText("Test"); QTest::newRow("block-indent") << QTextDocumentFragment(&doc) << QString("EMPTYBLOCK") + QString("<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:3; text-indent:30px;\">Test</p>"); } { CREATE_DOC_AND_CURSOR(); QTextListFormat fmt; fmt.setStyle(QTextListFormat::ListDisc); fmt.setIndent(4); cursor.insertList(fmt); cursor.insertText("Blah"); QTest::newRow("list-indent") << QTextDocumentFragment(&doc) << QString("EMPTYBLOCK") + QString("<ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 4;\"><li DEFAULTBLOCKSTYLE>Blah</li></ul>"); } { CREATE_DOC_AND_CURSOR(); cursor.insertBlock(); QTest::newRow("emptyblock") << QTextDocumentFragment(&doc) // after insertBlock() we /do/ have two blocks in the document, so also expect // these in the html output << QString("EMPTYBLOCK") + QString("EMPTYBLOCK"); } { CREATE_DOC_AND_CURSOR(); // if you press enter twice in an empty textedit and then insert 'Test' // you actually get three visible paragraphs, two empty leading ones and // a third with the actual text. the corresponding html representation // therefore should also contain three paragraphs. cursor.insertBlock(); QTextCharFormat fmt; fmt.setForeground(QColor("#00ff00")); fmt.setProperty(QTextFormat::FontSizeIncrement, 1); cursor.mergeBlockCharFormat(fmt); fmt.setProperty(QTextFormat::FontSizeIncrement, 2); cursor.insertText("Test", fmt); QTest::newRow("blockcharfmt") << QTextDocumentFragment(&doc) << QString("EMPTYBLOCK<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-size:x-large; color:#00ff00;\">Test</span></p>"); } { CREATE_DOC_AND_CURSOR(); QTextCharFormat fmt; fmt.setForeground(QColor("#00ff00")); cursor.setBlockCharFormat(fmt); fmt.setForeground(QColor("#0000ff")); cursor.insertText("Test", fmt); QTest::newRow("blockcharfmt2") << QTextDocumentFragment(&doc) << QString("<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" color:#0000ff;\">Test</span></p>"); } { QTest::newRow("horizontal-ruler") << QTextDocumentFragment::fromHtml("<hr />") << QString("EMPTYBLOCK") + QString("<hr />"); } { QTest::newRow("horizontal-ruler-with-width") << QTextDocumentFragment::fromHtml("<hr width=\"50%\"/>") << QString("EMPTYBLOCK") + QString("<hr width=\"50%\"/>"); } { CREATE_DOC_AND_CURSOR(); QTextFrame *mainFrame = cursor.currentFrame(); QTextFrameFormat ffmt; ffmt.setBorder(1); ffmt.setPosition(QTextFrameFormat::FloatRight); ffmt.setMargin(2); ffmt.setWidth(100); ffmt.setHeight(50); ffmt.setBackground(QColor("#00ff00")); cursor.insertFrame(ffmt); cursor.insertText("Hello World"); cursor = mainFrame->lastCursorPosition(); QTest::newRow("frame") << QTextDocumentFragment(&doc) << QString("<table border=\"1\" style=\"-qt-table-type: frame; float: right; margin-top:2px; margin-bottom:2px; margin-left:2px; margin-right:2px;\" width=\"100\" height=\"50\" bgcolor=\"#00ff00\">\n<tr>\n<td style=\"border: none;\">\n<p DEFAULTBLOCKSTYLE>Hello World</p></td></tr></table>"); } { CREATE_DOC_AND_CURSOR(); QTextCharFormat fmt; fmt.setForeground(QColor("#00ff00")); // fmt.setBackground(QColor("#0000ff")); cursor.setBlockCharFormat(fmt); fmt.setForeground(QBrush()); // fmt.setBackground(QBrush()); cursor.insertText("Test", fmt); // QTest::newRow("nostylebrush") << QTextDocumentFragment(&doc) << QString("<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; color:#00ff00; -qt-blockcharfmt-background-color:#0000ff;\">Test</p>"); QTest::newRow("nostylebrush") << QTextDocumentFragment(&doc) << QString("<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Test</p>"); } { CREATE_DOC_AND_CURSOR(); QTextTable *table = cursor.insertTable(2, 2); table->mergeCells(0, 0, 1, 2); QTextTableFormat fmt = table->format(); QVector<QTextLength> widths; widths.append(QTextLength(QTextLength::FixedLength, 20)); widths.append(QTextLength(QTextLength::FixedLength, 40)); fmt.setColumnWidthConstraints(widths); table->setFormat(fmt); QTest::newRow("mergedtablecolwidths") << QTextDocumentFragment(&doc) << QString("<table border=\"1\" cellspacing=\"2\">" "\n<tr>\n<td colspan=\"2\"></td></tr>" "\n<tr>\n<td width=\"20\"></td>\n<td width=\"40\"></td></tr>" "</table>"); } { CREATE_DOC_AND_CURSOR(); QTextCharFormat fmt; cursor.insertText("Blah\nGreen yellow green"); cursor.setPosition(0); cursor.setPosition(23, QTextCursor::KeepAnchor); fmt.setBackground(Qt::green); cursor.mergeCharFormat(fmt); cursor.clearSelection(); cursor.setPosition(11); cursor.setPosition(17, QTextCursor::KeepAnchor); fmt.setBackground(Qt::yellow); cursor.mergeCharFormat(fmt); cursor.clearSelection(); QTest::newRow("multiparagraph-bgcolor") << QTextDocumentFragment(&doc) << QString("<p DEFAULTBLOCKSTYLE><span style=\" background-color:#00ff00;\">Blah</span></p>\n" "<p DEFAULTBLOCKSTYLE><span style=\" background-color:#00ff00;\">Green </span>" "<span style=\" background-color:#ffff00;\">yellow</span>" "<span style=\" background-color:#00ff00;\"> green</span></p>"); } { CREATE_DOC_AND_CURSOR(); QTextBlockFormat fmt; fmt.setBackground(QColor("#0000ff")); cursor.insertBlock(fmt); QTextCharFormat charfmt; charfmt.setBackground(QColor("#0000ff")); cursor.insertText("Blah", charfmt); QTest::newRow("nospan-bgcolor") << QTextDocumentFragment(&doc) << QString("EMPTYBLOCK") + QString("<p OPENDEFAULTBLOCKSTYLE background-color:#0000ff;\"><span style=\" background-color:#0000ff;\">Blah</span></p>"); } { CREATE_DOC_AND_CURSOR(); QTextTable *table = cursor.insertTable(2, 2); QTextCharFormat fmt = table->cellAt(0, 0).format(); fmt.setVerticalAlignment(QTextCharFormat::AlignMiddle); table->cellAt(0, 0).setFormat(fmt); fmt = table->cellAt(0, 1).format(); fmt.setVerticalAlignment(QTextCharFormat::AlignTop); table->cellAt(0, 1).setFormat(fmt); fmt = table->cellAt(1, 0).format(); fmt.setVerticalAlignment(QTextCharFormat::AlignBottom); table->cellAt(1, 0).setFormat(fmt); table->cellAt(0, 0).firstCursorPosition().insertText("Blah"); QTest::newRow("table-vertical-alignment") << QTextDocumentFragment(&doc) << QString("<table border=\"1\" cellspacing=\"2\">" "\n<tr>\n<td style=\" vertical-align:middle;\">\n" "<p DEFAULTBLOCKSTYLE>Blah</p></td>" "\n<td style=\" vertical-align:top;\"></td></tr>" "\n<tr>\n<td style=\" vertical-align:bottom;\"></td>" "\n<td></td></tr>" "</table>"); } { CREATE_DOC_AND_CURSOR(); QTextTable *table = cursor.insertTable(2, 2); QTextTableCellFormat fmt = table->cellAt(0, 0).format().toTableCellFormat(); fmt.setLeftPadding(1); table->cellAt(0, 0).setFormat(fmt); fmt = table->cellAt(0, 1).format().toTableCellFormat(); fmt.setRightPadding(1); table->cellAt(0, 1).setFormat(fmt); fmt = table->cellAt(1, 0).format().toTableCellFormat(); fmt.setTopPadding(1); table->cellAt(1, 0).setFormat(fmt); fmt = table->cellAt(1, 1).format().toTableCellFormat(); fmt.setBottomPadding(1); table->cellAt(1, 1).setFormat(fmt); table->cellAt(0, 0).firstCursorPosition().insertText("Blah"); QTest::newRow("table-cell-paddings") << QTextDocumentFragment(&doc) << QString("<table border=\"1\" cellspacing=\"2\">" "\n<tr>\n<td style=\" padding-left:1;\">\n" "<p DEFAULTBLOCKSTYLE>Blah</p></td>" "\n<td style=\" padding-right:1;\"></td></tr>" "\n<tr>\n<td style=\" padding-top:1;\"></td>" "\n<td style=\" padding-bottom:1;\"></td></tr>" "</table>"); } { CREATE_DOC_AND_CURSOR(); QTextTableFormat fmt; fmt.setBorderBrush(QColor("#0000ff")); fmt.setBorderStyle(QTextFrameFormat::BorderStyle_Solid); cursor.insertTable(2, 2, fmt); QTest::newRow("tableborder") << QTextDocumentFragment(&doc) << QString("<table border=\"1\" style=\" border-color:#0000ff; border-style:solid;\" cellspacing=\"2\">" "\n<tr>\n<td></td>\n<td></td></tr>" "\n<tr>\n<td></td>\n<td></td></tr>" "</table>"); } { CREATE_DOC_AND_CURSOR(); cursor.insertBlock(); cursor.insertText("Foo"); cursor.block().setUserState(42); QTest::newRow("userstate") << QTextDocumentFragment(&doc) << QString("EMPTYBLOCK") + QString("<p OPENDEFAULTBLOCKSTYLE -qt-user-state:42;\">Foo</p>"); } { CREATE_DOC_AND_CURSOR(); QTextBlockFormat blockFmt; blockFmt.setPageBreakPolicy(QTextFormat::PageBreak_AlwaysBefore); cursor.insertBlock(blockFmt); cursor.insertText("Foo"); blockFmt.setPageBreakPolicy(QTextFormat::PageBreak_AlwaysBefore | QTextFormat::PageBreak_AlwaysAfter); cursor.insertBlock(blockFmt); cursor.insertText("Bar"); QTextTableFormat tableFmt; tableFmt.setPageBreakPolicy(QTextFormat::PageBreak_AlwaysAfter); cursor.insertTable(1, 1, tableFmt); QTest::newRow("pagebreak") << QTextDocumentFragment(&doc) << QString("EMPTYBLOCK") + QString("<p OPENDEFAULTBLOCKSTYLE page-break-before:always;\">Foo</p>" "\n<p OPENDEFAULTBLOCKSTYLE page-break-before:always; page-break-after:always;\">Bar</p>" "\n<table border=\"1\" style=\" page-break-after:always;\" cellspacing=\"2\">\n<tr>\n<td></td></tr></table>"); } { CREATE_DOC_AND_CURSOR(); QTextListFormat listFmt; listFmt.setStyle(QTextListFormat::ListDisc); cursor.insertList(listFmt); cursor.insertText("Blah"); QTest::newRow("list-ul-margin") << QTextDocumentFragment(&doc) << QString("EMPTYBLOCK") + QString("<ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\"><li DEFAULTBLOCKSTYLE>Blah</li></ul>"); } } void tst_QTextDocument::toHtml() { QFETCH(QTextDocumentFragment, input); QFETCH(QString, expectedOutput); cursor.insertFragment(input); expectedOutput.prepend(htmlHead); expectedOutput.replace("OPENDEFAULTBLOCKSTYLE", "style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"); expectedOutput.replace("DEFAULTBLOCKSTYLE", "style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\""); expectedOutput.replace("EMPTYBLOCK", "<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"></p>\n"); if (expectedOutput.endsWith(QLatin1Char('\n'))) expectedOutput.chop(1); expectedOutput.append(htmlTail); QString output = doc->toHtml(); QCOMPARE(output, expectedOutput); QDomDocument document; QVERIFY2(document.setContent(output), "Output was not valid XML"); } void tst_QTextDocument::toHtml2() { QTextDocument doc; doc.setHtml("<p>text <img src=\"\"> text</p>"); // 4 spaces before the second 'text' QTextBlock block = doc.firstBlock(); QTextBlock::Iterator iter = block.begin(); QTextFragment f = iter.fragment(); QVERIFY(f.isValid()); QCOMPARE(f.position(), 0); QCOMPARE(f.length(), 5); //qDebug() << block.text().mid(f.position(), f.length()); iter++; f = iter.fragment(); QVERIFY(f.isValid()); QCOMPARE(f.position(), 5); QCOMPARE(f.length(), 1); //qDebug() << block.text().mid(f.position(), f.length()); iter++; f = iter.fragment(); //qDebug() << block.text().mid(f.position(), f.length()); QVERIFY(f.isValid()); QCOMPARE(f.position(), 6); QCOMPARE(f.length(), 5); // 1 space should be preserved. QCOMPARE(block.text().mid(f.position(), f.length()), QString(" text")); doc.setHtml("<table><tr><td> foo</td></tr></table> text"); // 4 spaces before the second 'text' block = doc.firstBlock().next(); //qDebug() << block.text(); QCOMPARE(block.text(), QString("foo")); block = block.next(); //qDebug() << block.text(); QCOMPARE(block.text(), QString("text")); } void tst_QTextDocument::setFragmentMarkersInHtmlExport() { { CREATE_DOC_AND_CURSOR(); cursor.insertText("Leadin"); const int startPos = cursor.position(); cursor.insertText("Test"); QTextCharFormat fmt; fmt.setForeground(QColor("#00ff00")); cursor.insertText("Blah", fmt); const int endPos = cursor.position(); cursor.insertText("Leadout", QTextCharFormat()); cursor.setPosition(startPos); cursor.setPosition(endPos, QTextCursor::KeepAnchor); QTextDocumentFragment fragment(cursor); QString expected = htmlHead; expected.replace(QRegExp("<body.*>"), QString("<body>")); expected += QString("<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><!--StartFragment-->Test<span style=\" color:#00ff00;\">Blah</span><!--EndFragment--></p>") + htmlTail; QCOMPARE(fragment.toHtml(), expected); } { CREATE_DOC_AND_CURSOR(); cursor.insertText("Leadin"); const int startPos = cursor.position(); cursor.insertText("Test"); const int endPos = cursor.position(); cursor.insertText("Leadout", QTextCharFormat()); cursor.setPosition(startPos); cursor.setPosition(endPos, QTextCursor::KeepAnchor); QTextDocumentFragment fragment(cursor); QString expected = htmlHead; expected.replace(QRegExp("<body.*>"), QString("<body>")); expected += QString("<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><!--StartFragment-->Test<!--EndFragment--></p>") + htmlTail; QCOMPARE(fragment.toHtml(), expected); } } void tst_QTextDocument::toHtmlBodyBgColor() { CREATE_DOC_AND_CURSOR(); cursor.insertText("Blah"); QTextFrameFormat fmt = doc.rootFrame()->frameFormat(); fmt.setBackground(QColor("#0000ff")); doc.rootFrame()->setFrameFormat(fmt); QString expectedHtml("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" " "\"http://www.w3.org/TR/REC-html40/strict.dtd\">\n" "<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n" "p, li { white-space: pre-wrap; }\n" "</style></head>" "<body style=\" font-family:'%1'; font-size:%2pt; font-weight:%3; font-style:%4;\"" " bgcolor=\"#0000ff\">\n" "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Blah</p>" "</body></html>"); expectedHtml = expectedHtml.arg(defaultFont.family()).arg(defaultFont.pointSizeF()).arg(defaultFont.weight() * 8).arg((defaultFont.italic() ? "italic" : "normal")); QCOMPARE(doc.toHtml(), expectedHtml); } void tst_QTextDocument::toHtmlRootFrameProperties() { CREATE_DOC_AND_CURSOR(); QTextFrameFormat fmt = doc.rootFrame()->frameFormat(); fmt.setTopMargin(10); fmt.setLeftMargin(10); fmt.setBorder(2); doc.rootFrame()->setFrameFormat(fmt); cursor.insertText("Blah"); QString expectedOutput("<table border=\"2\" style=\"-qt-table-type: root; margin-top:10px; " "margin-bottom:4px; margin-left:10px; margin-right:4px;\">\n" "<tr>\n<td style=\"border: none;\">\n" "<p DEFAULTBLOCKSTYLE>Blah</p></td></tr></table>"); expectedOutput.prepend(htmlHead); expectedOutput.replace("DEFAULTBLOCKSTYLE", "style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\""); expectedOutput.append(htmlTail); QCOMPARE(doc.toHtml(), expectedOutput); } void tst_QTextDocument::capitalizationHtmlInExport() { doc->setPlainText("Test"); QRegExp re(".*span style=\"(.*)\">Test.*"); QVERIFY(re.exactMatch(doc->toHtml()) == false); // no span QTextCursor cursor(doc); cursor.setPosition(4, QTextCursor::KeepAnchor); QTextCharFormat cf; cf.setFontCapitalization(QFont::SmallCaps); cursor.mergeCharFormat(cf); const QString smallcaps = doc->toHtml(); QVERIFY(re.exactMatch(doc->toHtml())); QCOMPARE(re.captureCount(), 1); QCOMPARE(re.cap(1).trimmed(), QString("font-variant:small-caps;")); cf.setFontCapitalization(QFont::AllUppercase); cursor.mergeCharFormat(cf); const QString uppercase = doc->toHtml(); QVERIFY(re.exactMatch(doc->toHtml())); QCOMPARE(re.captureCount(), 1); QCOMPARE(re.cap(1).trimmed(), QString("text-transform:uppercase;")); cf.setFontCapitalization(QFont::AllLowercase); cursor.mergeCharFormat(cf); const QString lowercase = doc->toHtml(); QVERIFY(re.exactMatch(doc->toHtml())); QCOMPARE(re.captureCount(), 1); QCOMPARE(re.cap(1).trimmed(), QString("text-transform:lowercase;")); doc->setHtml(smallcaps); cursor.setPosition(1); QCOMPARE(cursor.charFormat().fontCapitalization(), QFont::SmallCaps); doc->setHtml(uppercase); QCOMPARE(cursor.charFormat().fontCapitalization(), QFont::AllUppercase); doc->setHtml(lowercase); QCOMPARE(cursor.charFormat().fontCapitalization(), QFont::AllLowercase); } void tst_QTextDocument::wordspacingHtmlExport() { doc->setPlainText("Test"); QRegExp re(".*span style=\"(.*)\">Test.*"); QVERIFY(re.exactMatch(doc->toHtml()) == false); // no span QTextCursor cursor(doc); cursor.setPosition(4, QTextCursor::KeepAnchor); QTextCharFormat cf; cf.setFontWordSpacing(4); cursor.mergeCharFormat(cf); QVERIFY(re.exactMatch(doc->toHtml())); QCOMPARE(re.captureCount(), 1); QCOMPARE(re.cap(1).trimmed(), QString("word-spacing:4px;")); cf.setFontWordSpacing(-8.5); cursor.mergeCharFormat(cf); QVERIFY(re.exactMatch(doc->toHtml())); QCOMPARE(re.captureCount(), 1); QCOMPARE(re.cap(1).trimmed(), QString("word-spacing:-8.5px;")); } class CursorPosSignalSpy : public QObject { Q_OBJECT public: CursorPosSignalSpy(QTextDocument *doc) { calls = 0; connect(doc, SIGNAL(cursorPositionChanged(const QTextCursor &)), this, SLOT(cursorPositionChanged(const QTextCursor &))); } int calls; private slots: void cursorPositionChanged(const QTextCursor &) { ++calls; } }; void tst_QTextDocument::cursorPositionChanged() { CursorPosSignalSpy spy(doc); cursor.insertText("Test"); QCOMPARE(spy.calls, 1); spy.calls = 0; QTextCursor unrelatedCursor(doc); unrelatedCursor.insertText("Blah"); QCOMPARE(spy.calls, 2); spy.calls = 0; cursor.insertText("Blah"); QCOMPARE(spy.calls, 1); spy.calls = 0; cursor.movePosition(QTextCursor::PreviousCharacter); QCOMPARE(spy.calls, 0); } void tst_QTextDocument::cursorPositionChangedOnSetText() { CursorPosSignalSpy spy(doc); // doc has one QTextCursor stored in the // cursor member variable, thus the signal // gets emitted once. doc->setPlainText("Foo\nBar\nBaz\nBlub\nBlah"); QCOMPARE(spy.calls, 1); spy.calls = 0; doc->setHtml("<p>Foo<p>Bar<p>Baz<p>Blah"); QCOMPARE(spy.calls, 1); } void tst_QTextDocument::textFrameIterator() { cursor.insertTable(1, 1); int blockCount = 0; int frameCount = 0; for (QTextFrame::Iterator frameIt = doc->rootFrame()->begin(); !frameIt.atEnd(); ++frameIt) { if (frameIt.currentFrame()) ++frameCount; else if (frameIt.currentBlock().isValid()) ++blockCount; } QEXPECT_FAIL("", "This is currently worked around in the html export but needs fixing!", Continue); QCOMPARE(blockCount, 0); QCOMPARE(frameCount, 1); } void tst_QTextDocument::codecForHtml() { const QByteArray header("<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html;charset=utf-16\">"); QTextCodec *c = Qt::codecForHtml(header); QVERIFY(c); QCOMPARE(c->name(), QByteArray("UTF-16")); } class TestSyntaxHighlighter : public QObject { Q_OBJECT public: inline TestSyntaxHighlighter(QTextDocument *doc) : QObject(doc), ok(false) {} bool ok; private slots: inline void markBlockDirty(int from, int charsRemoved, int charsAdded) { Q_UNUSED(charsRemoved); Q_UNUSED(charsAdded); QTextDocument *doc = static_cast<QTextDocument *>(parent()); QTextBlock block = doc->findBlock(from); QTestDocumentLayout *lout = qobject_cast<QTestDocumentLayout *>(doc->documentLayout()); lout->called = false; doc->markContentsDirty(block.position(), block.length()); ok = (lout->called == false); } inline void modifyBlockAgain(int from, int charsRemoved, int charsAdded) { Q_UNUSED(charsRemoved); Q_UNUSED(charsAdded); QTextDocument *doc = static_cast<QTextDocument *>(parent()); QTextBlock block = doc->findBlock(from); QTextCursor cursor(block); QTestDocumentLayout *lout = qobject_cast<QTestDocumentLayout *>(doc->documentLayout()); lout->called = false; cursor.insertText("Foo"); ok = (lout->called == true); } }; void tst_QTextDocument::markContentsDirty() { QTestDocumentLayout *lout = new QTestDocumentLayout(doc); doc->setDocumentLayout(lout); TestSyntaxHighlighter *highlighter = new TestSyntaxHighlighter(doc); connect(doc, SIGNAL(contentsChange(int, int, int)), highlighter, SLOT(markBlockDirty(int, int, int))); highlighter->ok = false; cursor.insertText("Some dummy text blah blah"); QVERIFY(highlighter->ok); disconnect(doc, SIGNAL(contentsChange(int, int, int)), highlighter, SLOT(markBlockDirty(int, int, int))); connect(doc, SIGNAL(contentsChange(int, int, int)), highlighter, SLOT(modifyBlockAgain(int, int, int))); highlighter->ok = false; cursor.insertText("FooBar"); QVERIFY(highlighter->ok); lout->called = false; doc->markContentsDirty(1, 4); QVERIFY(lout->called); } void tst_QTextDocument::clonePreservesMetaInformation() { const QString title("Foobar"); const QString url("about:blank"); doc->setHtml("<html><head><title>" + title + "</title></head><body>Hrm</body></html>"); doc->setMetaInformation(QTextDocument::DocumentUrl, url); QCOMPARE(doc->metaInformation(QTextDocument::DocumentTitle), title); QCOMPARE(doc->metaInformation(QTextDocument::DocumentUrl), url); QTextDocument *clone = doc->clone(); QCOMPARE(clone->metaInformation(QTextDocument::DocumentTitle), title); QCOMPARE(clone->metaInformation(QTextDocument::DocumentUrl), url); delete clone; } void tst_QTextDocument::clonePreservesPageSize() { QSizeF sz(100., 100.); doc->setPageSize(sz); QTextDocument *clone = doc->clone(); QCOMPARE(clone->pageSize(), sz); delete clone; } void tst_QTextDocument::clonePreservesPageBreakPolicies() { QTextTableFormat tableFmt; tableFmt.setPageBreakPolicy(QTextFormat::PageBreak_AlwaysAfter); QTextBlockFormat blockFmt; blockFmt.setPageBreakPolicy(QTextFormat::PageBreak_AlwaysBefore); QTextCursor cursor(doc); cursor.setBlockFormat(blockFmt); cursor.insertText("foo"); cursor.insertTable(2, 2, tableFmt); QTextDocument *clone = doc->clone(); QCOMPARE(clone->begin().blockFormat().pageBreakPolicy(), QTextFormat::PageBreak_AlwaysBefore); QVERIFY(!clone->rootFrame()->childFrames().isEmpty()); QCOMPARE(clone->rootFrame()->childFrames().first()->frameFormat().pageBreakPolicy(), QTextFormat::PageBreak_AlwaysAfter); delete clone; } void tst_QTextDocument::clonePreservesDefaultFont() { QFont f = doc->defaultFont(); QVERIFY(f.pointSize() != 100); f.setPointSize(100); doc->setDefaultFont(f); QTextDocument *clone = doc->clone(); QCOMPARE(clone->defaultFont(), f); delete clone; } void tst_QTextDocument::clonePreservesResources() { QUrl testUrl(":/foobar"); QVariant testResource("hello world"); doc->addResource(QTextDocument::ImageResource, testUrl, testResource); QTextDocument *clone = doc->clone(); QVERIFY(clone->resource(QTextDocument::ImageResource, testUrl) == testResource); delete clone; } void tst_QTextDocument::clonePreservesUserStates() { QTextCursor cursor(doc); cursor.insertText("bla bla bla"); cursor.block().setUserState(1); cursor.insertBlock(); cursor.insertText("foo bar"); cursor.block().setUserState(2); cursor.insertBlock(); cursor.insertText("no user state"); QTextDocument *clone = doc->clone(); QTextBlock b1 = doc->begin(), b2 = clone->begin(); while (b1 != doc->end()) { b1 = b1.next(); b2 = b2.next(); QCOMPARE(b1.userState(), b2.userState()); } QVERIFY(b2 == clone->end()); delete clone; } void tst_QTextDocument::clonePreservesRootFrameFormat() { doc->setPlainText("Hello"); QTextFrameFormat fmt = doc->rootFrame()->frameFormat(); fmt.setMargin(200); doc->rootFrame()->setFrameFormat(fmt); QCOMPARE(doc->rootFrame()->frameFormat().margin(), qreal(200)); QTextDocument *copy = doc->clone(); QCOMPARE(copy->rootFrame()->frameFormat().margin(), qreal(200)); delete copy; } void tst_QTextDocument::clonePreservesIndentWidth() { doc->setIndentWidth(42); QTextDocument *clone = doc->clone(); QCOMPARE(clone->indentWidth(), qreal(42)); delete clone; } void tst_QTextDocument::blockCount() { QCOMPARE(doc->blockCount(), 1); cursor.insertBlock(); QCOMPARE(doc->blockCount(), 2); cursor.insertBlock(); QCOMPARE(doc->blockCount(), 3); cursor.insertText("blah blah"); QCOMPARE(doc->blockCount(), 3); doc->undo(); doc->undo(); QCOMPARE(doc->blockCount(), 2); doc->undo(); QCOMPARE(doc->blockCount(), 1); } void tst_QTextDocument::resolvedFontInEmptyFormat() { QFont font; font.setPointSize(42); doc->setDefaultFont(font); QTextCharFormat fmt = doc->begin().charFormat(); QVERIFY(fmt.properties().isEmpty()); QVERIFY(fmt.font() == font); } void tst_QTextDocument::defaultRootFrameMargin() { QCOMPARE(doc->rootFrame()->frameFormat().margin(), 4.0); } class TestDocument : public QTextDocument { public: inline TestDocument(const QUrl &testUrl, const QString &testString) : url(testUrl), string(testString), resourceLoaded(false) {} bool hasResourceCached(); protected: virtual QVariant loadResource(int type, const QUrl &name); private: QUrl url; QString string; bool resourceLoaded; }; bool TestDocument::hasResourceCached() { resourceLoaded = false; resource(QTextDocument::ImageResource, url); return !resourceLoaded; } QVariant TestDocument::loadResource(int type, const QUrl &name) { if (type == QTextDocument::ImageResource && name == url) { resourceLoaded = true; return string; } return QTextDocument::loadResource(type, name); } void tst_QTextDocument::clearResources() { // regular resource for QTextDocument QUrl testUrl(":/foobar"); QVariant testResource("hello world"); // implicitly cached resource, initially loaded through TestDocument::loadResource() QUrl cacheUrl(":/blub"); QString cacheResource("mah"); TestDocument doc(cacheUrl, cacheResource); doc.addResource(QTextDocument::ImageResource, testUrl, testResource); QVERIFY(doc.resource(QTextDocument::ImageResource, testUrl) == testResource); doc.setPlainText("Hah"); QVERIFY(doc.resource(QTextDocument::ImageResource, testUrl) == testResource); doc.setHtml("<b>Mooo</b><img src=\":/blub\"/>"); QVERIFY(doc.resource(QTextDocument::ImageResource, testUrl) == testResource); QVERIFY(doc.resource(QTextDocument::ImageResource, cacheUrl) == cacheResource); doc.clear(); QVERIFY(!doc.resource(QTextDocument::ImageResource, testUrl).isValid()); QVERIFY(!doc.hasResourceCached()); doc.clear(); doc.setHtml("<b>Mooo</b><img src=\":/blub\"/>"); QVERIFY(doc.resource(QTextDocument::ImageResource, cacheUrl) == cacheResource); doc.setPlainText("Foob"); QVERIFY(!doc.hasResourceCached()); } void tst_QTextDocument::setPlainText() { doc->setPlainText("Hello World"); QString s(""); doc->setPlainText(s); QCOMPARE(doc->toPlainText(), s); } void tst_QTextDocument::toPlainText() { doc->setHtml("Hello World"); QCOMPARE(doc->toPlainText(), QLatin1String("Hello World")); } void tst_QTextDocument::deleteTextObjectsOnClear() { QPointer<QTextTable> table = cursor.insertTable(2, 2); QVERIFY(!table.isNull()); doc->clear(); QVERIFY(table.isNull()); } void tst_QTextDocument::defaultStyleSheet() { const QString sheet("p { background-color: green; }"); QVERIFY(doc->defaultStyleSheet().isEmpty()); doc->setDefaultStyleSheet(sheet); QCOMPARE(doc->defaultStyleSheet(), sheet); cursor.insertHtml("<p>test"); QTextBlockFormat fmt = doc->begin().blockFormat(); QVERIFY(fmt.background().color() == QColor("green")); doc->clear(); cursor.insertHtml("<p>test"); fmt = doc->begin().blockFormat(); QVERIFY(fmt.background().color() == QColor("green")); QTextDocument *clone = doc->clone(); QCOMPARE(clone->defaultStyleSheet(), sheet); cursor = QTextCursor(clone); cursor.insertHtml("<p>test"); fmt = clone->begin().blockFormat(); QVERIFY(fmt.background().color() == QColor("green")); delete clone; cursor = QTextCursor(doc); cursor.insertHtml("<p>test"); fmt = doc->begin().blockFormat(); QVERIFY(fmt.background().color() == QColor("green")); doc->clear(); cursor.insertHtml("<style>p { background-color: red; }</style><p>test"); fmt = doc->begin().blockFormat(); QVERIFY(fmt.background().color() == QColor("red")); doc->clear(); doc->setDefaultStyleSheet("invalid style sheet...."); cursor.insertHtml("<p>test"); fmt = doc->begin().blockFormat(); QVERIFY(fmt.background().color() != QColor("green")); } void tst_QTextDocument::maximumBlockCount() { QCOMPARE(doc->maximumBlockCount(), 0); QVERIFY(doc->isUndoRedoEnabled()); cursor.insertBlock(); cursor.insertText("Blah"); cursor.insertBlock(); cursor.insertText("Foo"); QCOMPARE(doc->blockCount(), 3); QCOMPARE(doc->toPlainText(), QString("\nBlah\nFoo")); doc->setMaximumBlockCount(1); QVERIFY(!doc->isUndoRedoEnabled()); QCOMPARE(doc->blockCount(), 1); QCOMPARE(doc->toPlainText(), QString("Foo")); cursor.insertBlock(); cursor.insertText("Hello"); doc->setMaximumBlockCount(1); QCOMPARE(doc->blockCount(), 1); QCOMPARE(doc->toPlainText(), QString("Hello")); doc->setMaximumBlockCount(100); for (int i = 0; i < 1000; ++i) { cursor.insertBlock(); cursor.insertText("Blah)"); QVERIFY(doc->blockCount() <= 100); } cursor.movePosition(QTextCursor::End); QCOMPARE(cursor.blockNumber(), 99); QTextCharFormat fmt; fmt.setFontItalic(true); cursor.setBlockCharFormat(fmt); cursor.movePosition(QTextCursor::Start); QVERIFY(!cursor.blockCharFormat().fontItalic()); doc->setMaximumBlockCount(1); QVERIFY(cursor.blockCharFormat().fontItalic()); cursor.insertTable(2, 2); QCOMPARE(doc->blockCount(), 6); cursor.insertBlock(); QCOMPARE(doc->blockCount(), 1); } void tst_QTextDocument::adjustSize() { // avoid ugly tooltips like in task 125583 QString text("Test Text"); doc->setPlainText(text); doc->rootFrame()->setFrameFormat(QTextFrameFormat()); doc->adjustSize(); QCOMPARE(doc->size().width(), doc->idealWidth()); } void tst_QTextDocument::initialUserData() { doc->setPlainText("Hello"); QTextBlock block = doc->begin(); block.setUserData(new QTextBlockUserData); QVERIFY(block.userData()); doc->documentLayout(); QVERIFY(block.userData()); doc->setDocumentLayout(new QTestDocumentLayout(doc)); QVERIFY(!block.userData()); } void tst_QTextDocument::html_defaultFont() { QFont f; f.setItalic(true); f.setWeight(QFont::Bold); doc->setDefaultFont(f); doc->setPlainText("Test"); QString bodyPart = QString::fromLatin1("<body style=\" font-family:'%1'; font-size:%2pt; font-weight:%3; font-style:italic;\">") .arg(f.family()).arg(f.pointSizeF()).arg(f.weight() * 8); QString html = doc->toHtml(); if (!html.contains(bodyPart)) { qDebug() << "html:" << html; qDebug() << "expected body:" << bodyPart; QVERIFY(html.contains(bodyPart)); } if (html.contains("span")) qDebug() << "html:" << html; QVERIFY(!html.contains("<span style")); } void tst_QTextDocument::blockCountChanged() { QSignalSpy spy(doc, SIGNAL(blockCountChanged(int))); doc->setPlainText("Foo"); QCOMPARE(doc->blockCount(), 1); QCOMPARE(spy.count(), 0); spy.clear(); doc->setPlainText("Foo\nBar"); QCOMPARE(doc->blockCount(), 2); QCOMPARE(spy.count(), 1); QCOMPARE(spy.at(0).value(0).toInt(), 2); spy.clear(); cursor.movePosition(QTextCursor::End); cursor.insertText("Blahblah"); QCOMPARE(spy.count(), 0); cursor.insertBlock(); QCOMPARE(spy.count(), 1); QCOMPARE(spy.at(0).value(0).toInt(), 3); spy.clear(); doc->undo(); QCOMPARE(spy.count(), 1); QCOMPARE(spy.at(0).value(0).toInt(), 2); } void tst_QTextDocument::nonZeroDocumentLengthOnClear() { QTestDocumentLayout *lout = new QTestDocumentLayout(doc); doc->setDocumentLayout(lout); doc->clear(); QVERIFY(lout->called); QVERIFY(!lout->lastDocumentLengths.contains(0)); } void tst_QTextDocument::setTextPreservesUndoRedoEnabled() { QVERIFY(doc->isUndoRedoEnabled()); doc->setPlainText("Test"); QVERIFY(doc->isUndoRedoEnabled()); doc->setUndoRedoEnabled(false); QVERIFY(!doc->isUndoRedoEnabled()); doc->setPlainText("Test2"); QVERIFY(!doc->isUndoRedoEnabled()); doc->setHtml("<p>hello"); QVERIFY(!doc->isUndoRedoEnabled()); } void tst_QTextDocument::firstLast() { QCOMPARE(doc->blockCount(), 1); QVERIFY(doc->firstBlock() == doc->lastBlock()); doc->setPlainText("Hello\nTest\nWorld"); QCOMPARE(doc->blockCount(), 3); QVERIFY(doc->firstBlock() != doc->lastBlock()); QCOMPARE(doc->firstBlock().text(), QString("Hello")); QCOMPARE(doc->lastBlock().text(), QString("World")); // manual forward loop QTextBlock block = doc->firstBlock(); QVERIFY(block.isValid()); QCOMPARE(block.text(), QString("Hello")); block = block.next(); QVERIFY(block.isValid()); QCOMPARE(block.text(), QString("Test")); block = block.next(); QVERIFY(block.isValid()); QCOMPARE(block.text(), QString("World")); block = block.next(); QVERIFY(!block.isValid()); // manual backward loop block = doc->lastBlock(); QVERIFY(block.isValid()); QCOMPARE(block.text(), QString("World")); block = block.previous(); QVERIFY(block.isValid()); QCOMPARE(block.text(), QString("Test")); block = block.previous(); QVERIFY(block.isValid()); QCOMPARE(block.text(), QString("Hello")); block = block.previous(); QVERIFY(!block.isValid()); } const QString backgroundImage_html("<body><table><tr><td background=\"foo.png\">Blah</td></tr></table></body>"); void tst_QTextDocument::backgroundImage_checkExpectedHtml(const QTextDocument &doc) { QString expectedHtml("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" " "\"http://www.w3.org/TR/REC-html40/strict.dtd\">\n" "<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n" "p, li { white-space: pre-wrap; }\n" "</style></head>" "<body style=\" font-family:'%1'; font-size:%2pt; font-weight:%3; font-style:%4;\">\n" "<table border=\"0\" style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px;\" cellspacing=\"2\" cellpadding=\"0\">" "\n<tr>\n<td background=\"foo.png\">" "\n<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Blah</p>" "</td></tr></table></body></html>"); expectedHtml = expectedHtml.arg(defaultFont.family()).arg(defaultFont.pointSizeF()).arg(defaultFont.weight() * 8).arg((defaultFont.italic() ? "italic" : "normal")); QCOMPARE(doc.toHtml(), expectedHtml); } void tst_QTextDocument::backgroundImage_toHtml() { CREATE_DOC_AND_CURSOR(); doc.setHtml(backgroundImage_html); backgroundImage_checkExpectedHtml(doc); } void tst_QTextDocument::backgroundImage_toHtml2() { CREATE_DOC_AND_CURSOR(); cursor.insertHtml(backgroundImage_html); backgroundImage_checkExpectedHtml(doc); } void tst_QTextDocument::backgroundImage_clone() { CREATE_DOC_AND_CURSOR(); doc.setHtml(backgroundImage_html); QTextDocument *clone = doc.clone(); backgroundImage_checkExpectedHtml(*clone); delete clone; } void tst_QTextDocument::backgroundImage_copy() { CREATE_DOC_AND_CURSOR(); doc.setHtml(backgroundImage_html); QTextDocumentFragment fragment(&doc); { CREATE_DOC_AND_CURSOR(); cursor.insertFragment(fragment); backgroundImage_checkExpectedHtml(doc); } } void tst_QTextDocument::documentCleanup() { QTextDocument doc; QTextCursor cursor(&doc); cursor.insertText("d\nfoo\nbar\n"); doc.documentLayout(); // forces relayout // remove char 1 cursor.setPosition(0); QSizeF size = doc.documentLayout()->documentSize(); cursor.deleteChar(); // the size should be unchanged. QCOMPARE(doc.documentLayout()->documentSize(), size); } void tst_QTextDocument::characterAt() { QTextDocument doc; QTextCursor cursor(&doc); QString text("12345\n67890"); cursor.insertText(text); int length = doc.characterCount(); QCOMPARE(length, text.length() + 1); QCOMPARE(doc.characterAt(length-1), QChar(QChar::ParagraphSeparator)); QCOMPARE(doc.characterAt(-1), QChar()); QCOMPARE(doc.characterAt(length), QChar()); QCOMPARE(doc.characterAt(length + 1), QChar()); for (int i = 0; i < text.length(); ++i) { QChar c = text.at(i); if (c == QLatin1Char('\n')) c = QChar(QChar::ParagraphSeparator); QCOMPARE(doc.characterAt(i), c); } } void tst_QTextDocument::revisions() { QTextDocument doc; QTextCursor cursor(&doc); QString text("Hello World"); QCOMPARE(doc.firstBlock().revision(), 0); cursor.insertText(text); QCOMPARE(doc.firstBlock().revision(), 1); cursor.setPosition(6); cursor.insertBlock(); QCOMPARE(cursor.block().previous().revision(), 2); QCOMPARE(cursor.block().revision(), 2); cursor.insertText("candle"); QCOMPARE(cursor.block().revision(), 3); cursor.movePosition(QTextCursor::EndOfBlock); cursor.insertBlock(); // we are at the block end QCOMPARE(cursor.block().previous().revision(), 3); QCOMPARE(cursor.block().revision(), 4); cursor.insertText("lightbulb"); QCOMPARE(cursor.block().revision(), 5); cursor.movePosition(QTextCursor::StartOfBlock); cursor.insertBlock(); // we are the block start QCOMPARE(cursor.block().previous().revision(), 6); QCOMPARE(cursor.block().revision(), 5); } void tst_QTextDocument::revisionWithUndoCompressionAndUndo() { QTextDocument doc; QTextCursor cursor(&doc); cursor.insertText("This is the beginning of it all."); QCOMPARE(doc.firstBlock().revision(), 1); QCOMPARE(doc.revision(), 1); cursor.insertBlock(); QCOMPARE(doc.revision(), 2); cursor.insertText("this"); QCOMPARE(doc.revision(), 3); cursor.insertText("is"); QCOMPARE(doc.revision(), 4); cursor.insertText("compressed"); QCOMPARE(doc.revision(), 5); doc.undo(); QCOMPARE(doc.revision(), 6); QCOMPARE(doc.toPlainText(), QString("This is the beginning of it all.\n")) ; cursor.setPosition(0); QCOMPARE(doc.firstBlock().revision(), 1); cursor.insertText("Very beginnig"); QCOMPARE(doc.firstBlock().revision(), 7); doc.undo(); QCOMPARE(doc.revision(), 8); QCOMPARE(doc.firstBlock().revision(), 1); cursor.beginEditBlock(); cursor.insertText("Hello"); cursor.insertBlock(); cursor.insertText("world"); cursor.endEditBlock(); QCOMPARE(doc.revision(), 9); doc.undo(); QCOMPARE(doc.revision(), 10); } void tst_QTextDocument::testUndoCommandAdded() { QVERIFY(doc); QSignalSpy spy(doc, SIGNAL(undoCommandAdded())); QVERIFY(spy.isValid()); QVERIFY(spy.isEmpty()); cursor.insertText("a"); QCOMPARE(spy.count(), 1); cursor.insertText("b"); // should be merged QCOMPARE(spy.count(), 1); cursor.insertText("c"); // should be merged QCOMPARE(spy.count(), 1); QCOMPARE(doc->toPlainText(), QString("abc")); doc->undo(); QCOMPARE(doc->toPlainText(), QString("")); doc->clear(); spy.clear(); cursor.insertText("aaa"); QCOMPARE(spy.count(), 1); spy.clear(); cursor.insertText("aaaa\nbcd"); QCOMPARE(spy.count(), 1); spy.clear(); cursor.beginEditBlock(); cursor.insertText("aa"); cursor.insertText("bbb\n"); cursor.setCharFormat(QTextCharFormat()); cursor.insertText("\nccc"); QVERIFY(spy.isEmpty()); cursor.endEditBlock(); QCOMPARE(spy.count(), 1); spy.clear(); cursor.insertBlock(); QCOMPARE(spy.count(), 1); spy.clear(); cursor.setPosition(5); QVERIFY(spy.isEmpty()); cursor.setCharFormat(QTextCharFormat()); QVERIFY(spy.isEmpty()); cursor.setPosition(10, QTextCursor::KeepAnchor); QVERIFY(spy.isEmpty()); QTextCharFormat cf; cf.setFontItalic(true); cursor.mergeCharFormat(cf); QCOMPARE(spy.count(), 1); spy.clear(); doc->undo(); QCOMPARE(spy.count(), 0); doc->undo(); QCOMPARE(spy.count(), 0); spy.clear(); doc->redo(); QCOMPARE(spy.count(), 0); doc->redo(); QCOMPARE(spy.count(), 0); } void tst_QTextDocument::testUndoBlocks() { QVERIFY(doc); cursor.insertText("Hello World"); cursor.insertText("period"); doc->undo(); QCOMPARE(doc->toPlainText(), QString("")); cursor.insertText("Hello World"); cursor.insertText("One\nTwo\nThree"); QCOMPARE(doc->toPlainText(), QString("Hello WorldOne\nTwo\nThree")); doc->undo(); QCOMPARE(doc->toPlainText(), QString("Hello World")); cursor.insertText("One\nTwo\nThree"); cursor.insertText("Trailing text"); doc->undo(); QCOMPARE(doc->toPlainText(), QString("Hello WorldOne\nTwo\nThree")); doc->undo(); QCOMPARE(doc->toPlainText(), QString("Hello World")); doc->undo(); QCOMPARE(doc->toPlainText(), QString("")); cursor.insertText("quod"); cursor.beginEditBlock(); cursor.insertText(" erat"); cursor.endEditBlock(); cursor.insertText(" demonstrandum"); QCOMPARE(doc->toPlainText(), QString("quod erat demonstrandum")); doc->undo(); QCOMPARE(doc->toPlainText(), QString("quod erat")); doc->undo(); QCOMPARE(doc->toPlainText(), QString("quod")); doc->undo(); QCOMPARE(doc->toPlainText(), QString("")); } class Receiver : public QObject { Q_OBJECT public: QString first; public slots: void cursorPositionChanged() { if (first.isEmpty()) first = QLatin1String("cursorPositionChanged"); } void contentsChange() { if (first.isEmpty()) first = QLatin1String("contentsChanged"); } }; void tst_QTextDocument::receiveCursorPositionChangedAfterContentsChange() { QVERIFY(doc); doc->setDocumentLayout(new MyAbstractTextDocumentLayout(doc)); Receiver rec; connect(doc, SIGNAL(cursorPositionChanged(QTextCursor)), &rec, SLOT(cursorPositionChanged())); connect(doc, SIGNAL(contentsChange(int,int,int)), &rec, SLOT(contentsChange())); cursor.insertText("Hello World"); QCOMPARE(rec.first, QString("contentsChanged")); } void tst_QTextDocument::escape_data() { QTest::addColumn<QString>("original"); QTest::addColumn<QString>("expected"); QTest::newRow("1") << "Hello World\n" << "Hello World\n"; QTest::newRow("2") << "#include <QtCore>" << "#include <QtCore>"; QTest::newRow("3") << "<p class=\"cool\"><a href=\"http://example.com/?foo=bar&bar=foo\">plop --> </a></p>" << "<p class="cool"><a href="http://example.com/?foo=bar&amp;bar=foo">plop --&gt; </a></p>"; QTest::newRow("4") << QString::fromUtf8("<\320\222\321\201>") << QString::fromUtf8("<\320\222\321\201>"); } void tst_QTextDocument::escape() { QFETCH(QString, original); QFETCH(QString, expected); QCOMPARE(Qt::escape(original), expected); } QTEST_MAIN(tst_QTextDocument) #include "tst_qtextdocument.moc"