f776595cc1
From Qt 5.7 -> tools & applications are lisenced under GPL v3 with some exceptions, see http://blog.qt.io/blog/2016/01/13/new-agreement-with-the-kde-free-qt-foundation/ Updated license headers to use new GPL-EXCEPT header instead of LGPL21 one (in those files which will be under GPL 3 with exceptions) Change-Id: I42a473ddc97101492a60b9287d90979d9eb35ae1 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com> Reviewed-by: Lars Knoll <lars.knoll@theqtcompany.com>
4020 lines
136 KiB
C++
4020 lines
136 KiB
C++
/****************************************************************************
|
|
**
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
** Contact: https://www.qt.io/licensing/
|
|
**
|
|
** This file is part of the test suite of the Qt Toolkit.
|
|
**
|
|
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
|
|
** Commercial License Usage
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
** accordance with the commercial license agreement provided with the
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
|
**
|
|
** GNU General Public License Usage
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
** General Public License version 3 as published by the Free Software
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
** included in the packaging of this file. Please review the following
|
|
** information to ensure the GNU General Public License requirements will
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
|
**
|
|
** $QT_END_LICENSE$
|
|
**
|
|
****************************************************************************/
|
|
|
|
|
|
#include <QtTest/QtTest>
|
|
|
|
|
|
#include <qtextdocument.h>
|
|
#include <qtextdocumentfragment.h>
|
|
#include <qtexttable.h>
|
|
#include <qtextlist.h>
|
|
#include <qdebug.h>
|
|
#include <private/qtextdocument_p.h>
|
|
|
|
|
|
#include <qtextcursor.h>
|
|
|
|
QT_FORWARD_DECLARE_CLASS(QTextDocument)
|
|
|
|
class tst_QTextDocumentFragment : public QObject
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
tst_QTextDocumentFragment();
|
|
~tst_QTextDocumentFragment();
|
|
|
|
public slots:
|
|
void init();
|
|
void cleanup();
|
|
private slots:
|
|
void listCopying();
|
|
void listZeroCopying();
|
|
void listCopying2();
|
|
void tableCopying();
|
|
void tableCopyingWithColSpans();
|
|
void tableColSpanAndWidth();
|
|
void tableImport();
|
|
void tableImport2();
|
|
void tableImport3();
|
|
void tableImport4();
|
|
void tableImport5();
|
|
void textCopy();
|
|
void copyWholeDocument();
|
|
void title();
|
|
void html_listIndents1();
|
|
void html_listIndents2();
|
|
void html_listIndents3();
|
|
void html_listIndents4();
|
|
void html_listIndents5();
|
|
void html_listIndents6();
|
|
void html_listIndents7();
|
|
void blockCharFormat();
|
|
void blockCharFormatCopied();
|
|
void initialBlock();
|
|
void clone();
|
|
void dontRemoveInitialBlockIfItHoldsObjectIndexedCharFormat();
|
|
void dosLineFeed();
|
|
void unorderedListEnumeration();
|
|
void resetHasBlockAfterClosedBlockTags();
|
|
void ignoreStyleTags();
|
|
void hrefAnchor();
|
|
void namedAnchorFragments();
|
|
void namedAnchorFragments2();
|
|
void namedAnchorFragments3();
|
|
void dontInheritAlignmentInTables();
|
|
void cellBlockCount();
|
|
void cellBlockCount2();
|
|
void emptyTable();
|
|
void emptyTable2();
|
|
void emptyTable3();
|
|
void doubleRowClose();
|
|
void mayNotHaveChildren();
|
|
void inheritAlignment();
|
|
void dontEmitEmptyNodeWhenEmptyTagIsFollowedByCloseTag();
|
|
void toPlainText();
|
|
void copyTableRow();
|
|
void copyTableColumn();
|
|
void copySubTable();
|
|
void html_textDecoration();
|
|
void html_infiniteLoop();
|
|
void html_blockIndent();
|
|
void html_listIndent();
|
|
void html_whitespace();
|
|
void html_whitespace_data();
|
|
void html_qt3Whitespace();
|
|
void html_qt3WhitespaceWithFragments();
|
|
void html_qt3WhitespaceAfterTags();
|
|
void html_listStart1();
|
|
void html_listStart2();
|
|
void html_cssMargin();
|
|
void html_hexEntities();
|
|
void html_decEntities();
|
|
void html_thCentered();
|
|
void orderedListNumbering();
|
|
void html_blockAfterList();
|
|
void html_subAndSuperScript();
|
|
void html_cssColors();
|
|
void obeyFragmentMarkersInImport();
|
|
void whitespaceWithFragmentMarkers();
|
|
void html_emptyParapgraphs1();
|
|
void html_emptyParapgraphs2();
|
|
void html_emptyParagraphs3();
|
|
void html_emptyParagraphs4();
|
|
void html_font();
|
|
void html_fontSize();
|
|
void html_fontSizeAdjustment();
|
|
void html_cssFontSize();
|
|
void html_cssShorthandFont();
|
|
void html_bodyBgColor();
|
|
void html_qtBgColor();
|
|
void html_blockLevelDiv();
|
|
void html_spanNesting();
|
|
void html_nestedLists();
|
|
void noSpecialCharactersInPlainText();
|
|
void html_doNotInheritBackground();
|
|
void html_inheritBackgroundToInlineElements();
|
|
void html_doNotInheritBackgroundFromBlockElements();
|
|
void html_nobr();
|
|
void fromPlainText();
|
|
void fromPlainText2();
|
|
void html_closingImageTag();
|
|
void html_emptyDocument();
|
|
void html_closingTag();
|
|
void html_anchorAroundImage();
|
|
void html_floatBorder();
|
|
void html_frameImport();
|
|
void html_frameImport2();
|
|
void html_dontAddMarginsAcrossTableCells();
|
|
void html_dontMergeCenterBlocks();
|
|
void html_tableCellBgColor();
|
|
void html_tableCellBgColor2();
|
|
void html_cellSkip();
|
|
void nonZeroMarginOnImport();
|
|
void html_charFormatPropertiesUnset();
|
|
void html_headings();
|
|
void html_quotedFontFamily();
|
|
void html_spanBackgroundColor();
|
|
void defaultFont();
|
|
void html_brokenTitle_data();
|
|
void html_brokenTitle();
|
|
void html_blockVsInline();
|
|
void html_tbody();
|
|
void html_nestedTables();
|
|
void html_rowSpans();
|
|
void html_rowSpans2();
|
|
void html_implicitParagraphs();
|
|
void html_missingCloseTag();
|
|
void html_anchorColor();
|
|
void html_lastParagraphClosing();
|
|
void html_tableHeaderBodyFootParent();
|
|
void html_columnWidths();
|
|
void html_bodyBackground();
|
|
void html_tableCellBackground();
|
|
void css_bodyBackground();
|
|
void css_tableCellBackground();
|
|
void css_fontWeight();
|
|
void css_float();
|
|
void css_textIndent();
|
|
void css_inline();
|
|
void css_external();
|
|
void css_import();
|
|
void css_selectors_data();
|
|
void css_selectors();
|
|
void css_nodeNameCaseInsensitivity();
|
|
void css_textUnderlineStyle_data();
|
|
void css_textUnderlineStyle();
|
|
void css_textUnderlineStyleAndDecoration();
|
|
void css_listStyleType();
|
|
void css_linkPseudo();
|
|
void css_pageBreaks();
|
|
void css_cellPaddings();
|
|
void universalSelectors_data();
|
|
void universalSelectors();
|
|
void screenMedia();
|
|
void htmlResourceLoading();
|
|
void someCaseInsensitiveAttributeValues();
|
|
void backgroundImage();
|
|
void dontMergePreAndNonPre();
|
|
void leftMarginInsideHtml();
|
|
void html_margins();
|
|
void newlineInsidePreShouldBecomeNewParagraph();
|
|
void invalidColspan();
|
|
void html_brokenTableWithJustTr();
|
|
void html_brokenTableWithJustTd();
|
|
void html_preNewlineHandling_data();
|
|
void html_preNewlineHandling();
|
|
void html_br();
|
|
void html_dl();
|
|
void html_tableStrangeNewline();
|
|
void html_tableStrangeNewline2();
|
|
void html_tableStrangeNewline3();
|
|
void html_caption();
|
|
void html_windowsEntities();
|
|
void html_eatenText();
|
|
void html_hr();
|
|
void html_hrMargins();
|
|
void html_blockQuoteMargins();
|
|
void html_definitionListMargins();
|
|
void html_listMargins();
|
|
void html_titleAttribute();
|
|
void html_compressDivs();
|
|
void completeToPlainText();
|
|
void copyContents();
|
|
void html_textAfterHr();
|
|
void blockTagClosing();
|
|
void isEmpty();
|
|
void html_alignmentInheritance();
|
|
void html_ignoreEmptyDivs();
|
|
void html_dontInheritAlignmentForFloatingImages();
|
|
void html_verticalImageAlignment();
|
|
void html_verticalCellAlignment();
|
|
void html_borderColor();
|
|
void html_borderStyle();
|
|
void html_borderWidth();
|
|
void html_userState();
|
|
void html_rootFrameProperties();
|
|
void html_alignmentPropertySet();
|
|
void html_appendList();
|
|
void html_appendList2();
|
|
void html_qt3RichtextWhitespaceMode();
|
|
void html_brAfterHr();
|
|
void html_unclosedHead();
|
|
void html_entities();
|
|
void html_entities_data();
|
|
void html_ignore_script();
|
|
void html_directionWithHtml();
|
|
void html_directionWithRichText();
|
|
void html_metaInBody();
|
|
void html_importImageWithoutAspectRatio();
|
|
void html_fromFirefox();
|
|
void html_emptyInlineInsideBlock();
|
|
|
|
private:
|
|
inline void setHtml(const QString &html)
|
|
// don't take the shortcut in QTextDocument::setHtml
|
|
{ doc->clear(); QTextCursor(doc).insertFragment(QTextDocumentFragment::fromHtml(html)); }
|
|
|
|
inline void appendHtml(const QString &html)
|
|
{
|
|
QTextCursor cursor(doc);
|
|
cursor.movePosition(QTextCursor::End);
|
|
cursor.insertHtml(html);
|
|
}
|
|
|
|
QTextDocument *doc;
|
|
QTextCursor cursor;
|
|
};
|
|
|
|
tst_QTextDocumentFragment::tst_QTextDocumentFragment()
|
|
{
|
|
QImage img(16, 16, QImage::Format_ARGB32_Premultiplied);
|
|
img.save("foo.png");
|
|
}
|
|
|
|
tst_QTextDocumentFragment::~tst_QTextDocumentFragment()
|
|
{
|
|
QFile::remove(QLatin1String("foo.png"));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::init()
|
|
{
|
|
doc = new QTextDocument;
|
|
cursor = QTextCursor(doc);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::cleanup()
|
|
{
|
|
cursor = QTextCursor();
|
|
delete doc;
|
|
doc = 0;
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::listCopying()
|
|
{
|
|
cursor.insertList(QTextListFormat::ListDecimal);
|
|
|
|
QTextFormat originalBlockFormat = cursor.blockFormat();
|
|
QVERIFY(originalBlockFormat.objectIndex() != -1);
|
|
int originalListItemIdx = cursor.blockFormat().objectIndex();
|
|
|
|
cursor.insertText("Hello World");
|
|
|
|
QTextDocumentFragment fragment(doc);
|
|
|
|
cursor.insertFragment(fragment);
|
|
|
|
QVERIFY(cursor.currentList());
|
|
QVERIFY(cursor.blockFormat() != originalBlockFormat);
|
|
QVERIFY(cursor.blockFormat().objectIndex() != originalListItemIdx);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::listZeroCopying()
|
|
{
|
|
// same testcase as above but using the zero-copying
|
|
|
|
cursor.insertList(QTextListFormat::ListDecimal);
|
|
|
|
QTextFormat originalBlockFormat = cursor.blockFormat();
|
|
int originalListItemIdx = cursor.blockFormat().objectIndex();
|
|
|
|
cursor.insertText("Hello World");
|
|
|
|
QTextDocumentFragment fragment(doc);
|
|
cursor.insertFragment(fragment);
|
|
|
|
QVERIFY(cursor.currentList());
|
|
QVERIFY(cursor.blockFormat() != originalBlockFormat);
|
|
QVERIFY(cursor.blockFormat().objectIndex() != originalListItemIdx);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::listCopying2()
|
|
{
|
|
cursor.insertList(QTextListFormat::ListDecimal);
|
|
cursor.insertText("Hello World");
|
|
|
|
cursor.insertList(QTextListFormat::ListDisc);
|
|
cursor.insertText("Hello World");
|
|
|
|
QTextDocumentFragment fragment(doc);
|
|
|
|
cursor.insertFragment(fragment);
|
|
|
|
cursor.movePosition(QTextCursor::Start);
|
|
int listItemCount = 0;
|
|
do {
|
|
if (cursor.currentList())
|
|
listItemCount++;
|
|
} while (cursor.movePosition(QTextCursor::NextBlock));
|
|
|
|
QCOMPARE(listItemCount, 4);
|
|
|
|
// we call this here because it used to cause a failing assertion in the
|
|
// list manager.
|
|
doc->undo();
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::tableCopying()
|
|
{
|
|
// this tests both, the fragment to use the direction insertion instead of using the
|
|
// cursor, which might adjuts its position when inserting a table step by step, as well
|
|
// as the pasiveness of the tablemanager.
|
|
QTextDocumentFragment fragment;
|
|
{
|
|
QTextDocument doc;
|
|
QTextCursor cursor(&doc);
|
|
|
|
QTextTableFormat fmt;
|
|
QTextTable *table = cursor.insertTable(2, 2, fmt);
|
|
|
|
table->cellAt(0, 0).firstCursorPosition().insertText("First Cell");
|
|
table->cellAt(0, 1).firstCursorPosition().insertText("Second Cell");
|
|
table->cellAt(1, 0).firstCursorPosition().insertText("Third Cell");
|
|
table->cellAt(1, 1).firstCursorPosition().insertText("Fourth Cell");
|
|
|
|
fragment = QTextDocumentFragment(&doc);
|
|
}
|
|
{
|
|
QTextDocument doc;
|
|
QTextCursor cursor(&doc);
|
|
|
|
cursor.insertText("FooBar");
|
|
cursor.insertBlock();
|
|
cursor.movePosition(QTextCursor::Left);
|
|
|
|
cursor.insertFragment(fragment);
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
|
|
QTextTable *table = cursor.currentTable();
|
|
QVERIFY(table);
|
|
QCOMPARE(table->rows(), 2);
|
|
QCOMPARE(table->columns(), 2);
|
|
}
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::tableCopyingWithColSpans()
|
|
{
|
|
const char html[] = ""
|
|
"<table border>"
|
|
" <tr>"
|
|
" <td>First Cell"
|
|
" <td>Second Cell"
|
|
" </tr>"
|
|
" <tr>"
|
|
" <td colspan=\"2\">Third Cell"
|
|
" </tr>"
|
|
" <tr>"
|
|
" <td>Fourth Cell"
|
|
" <td>Fifth Cell"
|
|
" </tr>"
|
|
"</table>";
|
|
setHtml(html);
|
|
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QTextTable *table = cursor.currentTable();
|
|
QVERIFY(table);
|
|
QVERIFY(table->columns() == 2 && table->rows() == 3);
|
|
|
|
cursor = table->cellAt(2, 0).lastCursorPosition();
|
|
cursor.setPosition(table->cellAt(0, 0).firstPosition(), QTextCursor::KeepAnchor);
|
|
QVERIFY(cursor.hasComplexSelection());
|
|
|
|
int firstRow = 0, numRows = 0, firstCol = 0, numCols = 0;
|
|
cursor.selectedTableCells(&firstRow, &numRows, &firstCol, &numCols);
|
|
QCOMPARE(firstRow, 0);
|
|
QCOMPARE(numRows, 3);
|
|
QCOMPARE(firstCol, 0);
|
|
QCOMPARE(numCols, 1);
|
|
|
|
QTextDocumentFragment frag = cursor.selection();
|
|
cleanup();
|
|
init();
|
|
cursor.insertFragment(frag);
|
|
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
table = cursor.currentTable();
|
|
QVERIFY(table);
|
|
QVERIFY(table->columns() == 1 && table->rows() == 3);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::tableColSpanAndWidth()
|
|
{
|
|
const char html[] = ""
|
|
"<table border=\"0\">"
|
|
" <tr>"
|
|
" <td colspan=\"4\" width=\"400\">First Cell</td>"
|
|
" </tr>"
|
|
"</table>";
|
|
setHtml(html);
|
|
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QTextTable *table = cursor.currentTable();
|
|
QVERIFY(table);
|
|
QVERIFY(table->columns() == 4 && table->rows() == 1);
|
|
// make sure its approx 400 and not a multiple due to the colspan
|
|
QVERIFY(doc->size().width()> 398.);
|
|
QVERIFY(doc->size().width() < 420.);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::tableImport()
|
|
{
|
|
// used to cause a failing assertion, as HTMLImporter::closeTag was
|
|
// called twice with the last node.
|
|
QTextDocumentFragment fragment = QTextDocumentFragment::fromHtml(QString::fromLatin1("<table><tr><td>Hey</td><td>Blah"));
|
|
QVERIFY(!fragment.isEmpty());
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::tableImport2()
|
|
{
|
|
{
|
|
const char html[] = ""
|
|
"<table>"
|
|
"<tr><td>First Cell</td><td>Second Cell</td></tr>"
|
|
"<tr><td>Third Cell</td><td>Fourth Cell</td></tr>"
|
|
"</table>";
|
|
|
|
QTextDocument doc;
|
|
QTextCursor cursor(&doc);
|
|
cursor.insertFragment(QTextDocumentFragment::fromHtml(QByteArray::fromRawData(html, sizeof(html) / sizeof(html[0]))));
|
|
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QTextTable *table = cursor.currentTable();
|
|
QVERIFY(table);
|
|
QCOMPARE(table->columns(), 2);
|
|
QCOMPARE(table->rows(), 2);
|
|
}
|
|
{
|
|
const char html[] = ""
|
|
"<table>"
|
|
"<tr><td>First Cell</td><td>Second Cell</td></tr>"
|
|
"<tr><td>Third Cell</td><td>"
|
|
" <table>"
|
|
" <tr><td>First Nested Cell</td><td>Second Nested Cell</td></tr>"
|
|
" <tr><td>Third Nested Cell</td><td>Fourth Nested Cell</td></tr>"
|
|
" <tr><td>Fifth Nested Cell</td><td>Sixth Nested Cell</td></tr>"
|
|
" </table></td></tr>"
|
|
"</table>";
|
|
|
|
QTextDocument doc;
|
|
QTextCursor cursor(&doc);
|
|
cursor.insertFragment(QTextDocumentFragment::fromHtml(QByteArray::fromRawData(html, sizeof(html) / sizeof(html[0]))));
|
|
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QTextTable *table = cursor.currentTable();
|
|
QVERIFY(table);
|
|
QCOMPARE(table->columns(), 2);
|
|
QCOMPARE(table->rows(), 2);
|
|
|
|
/*
|
|
QTextCursor fourthCell = table->cellAt(1, 1).firstCursorPosition();
|
|
fourthCell.movePosition(QTextCursor::NextBlock);
|
|
table = fourthCell.currentTable();
|
|
QVERIFY(table);
|
|
QVERIFY(table != cursor.currentTable());
|
|
QCOMPARE(table->columns(), 2);
|
|
QCOMPARE(table->rows(), 3);
|
|
*/
|
|
}
|
|
{
|
|
const char buggyHtml[] = ""
|
|
"<table>"
|
|
"<tr><td>First Cell<td>Second Cell"
|
|
"<tr><td>Third Cell<td>Fourth Cell"
|
|
"</table>";
|
|
|
|
QTextDocument doc;
|
|
QTextCursor cursor(&doc);
|
|
cursor.insertFragment(QTextDocumentFragment::fromHtml(QByteArray::fromRawData(buggyHtml, sizeof(buggyHtml) / sizeof(buggyHtml[0]))));
|
|
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QTextTable *table = cursor.currentTable();
|
|
QVERIFY(table);
|
|
QCOMPARE(table->columns(), 2);
|
|
QCOMPARE(table->rows(), 2);
|
|
}
|
|
{
|
|
const char buggyHtml[] = ""
|
|
"<table>"
|
|
"<tr><th>First Cell<th>Second Cell"
|
|
"<tr><td>Third Cell<td>Fourth Cell"
|
|
"</table>";
|
|
|
|
QTextDocument doc;
|
|
QTextCursor cursor(&doc);
|
|
cursor.insertFragment(QTextDocumentFragment::fromHtml(QByteArray::fromRawData(buggyHtml, sizeof(buggyHtml) / sizeof(buggyHtml[0]))));
|
|
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QTextTable *table = cursor.currentTable();
|
|
QVERIFY(table);
|
|
QCOMPARE(table->columns(), 2);
|
|
QCOMPARE(table->rows(), 2);
|
|
}
|
|
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::tableImport3()
|
|
{
|
|
// ### would be better to have tree tests for QTextHtmlParser
|
|
// make sure the p is a child of the td. If not the following td
|
|
// ends up outside the table, causing an assertion
|
|
const char html[] = "<table><tr><td><p></p></td><td></td></tr></table>";
|
|
QTextDocumentFragment fragment = QTextDocumentFragment::fromHtml(QString::fromLatin1(html));
|
|
QVERIFY(!fragment.isEmpty());
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::tableImport4()
|
|
{
|
|
const char html[] = "<table>"
|
|
"<tr><td>blah</td></tr>"
|
|
"<tr><td>blah</td><td>blah</td></tr>"
|
|
"</table>";
|
|
cursor.insertFragment(QTextDocumentFragment::fromHtml(QString::fromLatin1(html)));
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QVERIFY(cursor.currentTable());
|
|
QCOMPARE(cursor.currentTable()->columns(), 2);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::tableImport5()
|
|
{
|
|
const char html[] = "<table>"
|
|
"<tr>"
|
|
" <td>Foo</td>"
|
|
" <td>Bar</td>"
|
|
" <td>Bleh</td>"
|
|
" <td>Blub</td>"
|
|
"</tr>"
|
|
"<tr>"
|
|
" <td>Ahh</td>"
|
|
" <td colspan=5>Gah</td>"
|
|
"</tr>"
|
|
"</table>";
|
|
|
|
cursor.insertFragment(QTextDocumentFragment::fromHtml(QString::fromLatin1(html)));
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QVERIFY(cursor.currentTable());
|
|
QCOMPARE(cursor.currentTable()->rows(), 2);
|
|
QCOMPARE(cursor.currentTable()->columns(), 6);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::textCopy()
|
|
{
|
|
/* this test used to cause failing assertions in QTextDocumentFragment */
|
|
/* copy&paste 'lo\bwor' */
|
|
cursor.insertText("Hello");
|
|
cursor.insertBlock();
|
|
cursor.insertText("World");
|
|
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::MoveAnchor, 3);
|
|
cursor.movePosition(QTextCursor::NextBlock, QTextCursor::KeepAnchor);
|
|
cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, 3);
|
|
|
|
QTextDocumentFragment fragment(cursor);
|
|
QVERIFY(!fragment.isEmpty());
|
|
cursor.insertFragment(fragment);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::copyWholeDocument()
|
|
{
|
|
// used to cause the famous currentBlock.position() == pos + 1 failing assertion
|
|
cursor.insertText("\nHey\nBlah\n");
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);
|
|
|
|
QTextFrameFormat fmt = doc->rootFrame()->frameFormat();
|
|
fmt.setBackground(Qt::blue);
|
|
doc->rootFrame()->setFrameFormat(fmt);
|
|
|
|
QTextDocumentFragment fragment(cursor);
|
|
QVERIFY(true); // good if we reach this point :)
|
|
|
|
cleanup();
|
|
init();
|
|
|
|
fmt.setBackground(Qt::red);
|
|
doc->rootFrame()->setFrameFormat(fmt);
|
|
|
|
cursor.insertFragment(fragment);
|
|
|
|
QVERIFY(doc->rootFrame()->frameFormat().background().color() == Qt::red);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::title()
|
|
{
|
|
doc->setHtml(QString::fromLatin1("<html><head><title>Test</title></head><body>Blah</body></html>"));
|
|
QCOMPARE(doc->metaInformation(QTextDocument::DocumentTitle), QString::fromLatin1("Test"));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_listIndents1()
|
|
{
|
|
const char html[] = "<ul><li>Hey</li><li>Hah</li></ul>";
|
|
setHtml(QString::fromLatin1(html));
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QTextList *list = cursor.currentList();
|
|
QVERIFY(list);
|
|
QCOMPARE(list->format().indent(), 1);
|
|
QCOMPARE(cursor.block().blockFormat().indent(), 0);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_listIndents2()
|
|
{
|
|
const char html[] = "<ul><li>Hey<p>Hah</ul>";
|
|
setHtml(QString::fromLatin1(html));
|
|
cursor.movePosition(QTextCursor::Start);
|
|
QTextList *list = cursor.currentList();
|
|
QVERIFY(list);
|
|
QCOMPARE(list->format().indent(), 1);
|
|
QCOMPARE(cursor.block().blockFormat().indent(), 0);
|
|
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QCOMPARE(cursor.block().blockFormat().indent(), 1);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_listIndents3()
|
|
{
|
|
const char html[] = "<ul><li><p>Hah</ul>";
|
|
setHtml(QString::fromLatin1(html));
|
|
cursor.movePosition(QTextCursor::Start);
|
|
QTextList *list = cursor.currentList();
|
|
QVERIFY(list);
|
|
QCOMPARE(list->format().indent(), 1);
|
|
QCOMPARE(cursor.block().blockFormat().indent(), 0);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_listIndents4()
|
|
{
|
|
const char html[] = "<ul><li>Foo</ul><p>This should not have the same indent as Foo";
|
|
setHtml(QString::fromLatin1(html));
|
|
cursor.movePosition(QTextCursor::Start);
|
|
QTextList *list = cursor.currentList();
|
|
QVERIFY(list);
|
|
QCOMPARE(list->format().indent(), 1);
|
|
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QVERIFY(!cursor.currentList());
|
|
QCOMPARE(cursor.blockFormat().indent(), 0);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_listIndents5()
|
|
{
|
|
const char html[] = "<ul><li>Foo<p><li>Bar</li></ul>";
|
|
setHtml(QString::fromLatin1(html));
|
|
cursor.movePosition(QTextCursor::Start);
|
|
QTextList *list = cursor.currentList();
|
|
QVERIFY(list);
|
|
QCOMPARE(list->format().indent(), 1);
|
|
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QCOMPARE(cursor.currentList(), list);
|
|
QCOMPARE(cursor.blockFormat().indent(), 0);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_listIndents6()
|
|
{
|
|
const char html[] = "<ul><li>Outer List<div class=\"testclass\"><ul><li>Nested Item 1</li></ul></div></li></ul>";
|
|
setHtml(QString::fromLatin1(html));
|
|
cursor.movePosition(QTextCursor::Start);
|
|
QTextList *list = cursor.currentList();
|
|
QVERIFY(list);
|
|
QCOMPARE(list->format().indent(), 1);
|
|
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QVERIFY(cursor.currentList() != list);
|
|
list = cursor.currentList();
|
|
QVERIFY(list);
|
|
QCOMPARE(list->format().indent(), 2);
|
|
|
|
QCOMPARE(cursor.blockFormat().indent(), 0);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_listIndents7()
|
|
{
|
|
const char html[] = "<ul><li style=\"-qt-block-indent:1;\">Hey</ul>";
|
|
setHtml(QString::fromLatin1(html));
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QTextList *list = cursor.currentList();
|
|
QVERIFY(list);
|
|
QCOMPARE(list->format().indent(), 1);
|
|
QCOMPARE(cursor.block().blockFormat().indent(), 1);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::blockCharFormat()
|
|
{
|
|
const char html[] = "<p style=\"font-style:italic\"><span style=\"font-style:normal\">Test</span></p>";
|
|
setHtml(QString::fromLatin1(html));
|
|
QVERIFY(doc->begin().charFormat().fontItalic());
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::blockCharFormatCopied()
|
|
{
|
|
QTextCharFormat fmt;
|
|
fmt.setForeground(Qt::green);
|
|
cursor.setBlockCharFormat(fmt);
|
|
cursor.insertText("Test", QTextCharFormat());
|
|
QTextDocumentFragment frag(doc);
|
|
cleanup();
|
|
init();
|
|
cursor.insertFragment(frag);
|
|
QCOMPARE(cursor.blockCharFormat(), fmt);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::initialBlock()
|
|
{
|
|
const char html[] = "<p>Test</p>";
|
|
setHtml(QString::fromLatin1(html));
|
|
QCOMPARE(doc->blockCount(), 1);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::clone()
|
|
{
|
|
QTextBlockFormat mod;
|
|
mod.setAlignment(Qt::AlignCenter);
|
|
cursor.mergeBlockFormat(mod);
|
|
cursor.insertText("Blah");
|
|
QCOMPARE(cursor.blockFormat().alignment(), Qt::AlignCenter);
|
|
QTextDocumentFragment frag(doc);
|
|
cleanup();
|
|
init();
|
|
cursor.insertFragment(frag);
|
|
cursor.movePosition(QTextCursor::Start);
|
|
QCOMPARE(cursor.blockFormat().alignment(), Qt::AlignCenter);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::dontRemoveInitialBlockIfItHoldsObjectIndexedCharFormat()
|
|
{
|
|
const char html[] = "<table><tr><td>cell one<td>cell two</tr><tr><td>cell three<td>cell four</tr></table>";
|
|
QCOMPARE(doc->begin().charFormat().objectIndex(), -1);
|
|
setHtml(QString::fromLatin1(html));
|
|
int cnt = 0;
|
|
|
|
int objectIndexOfLast = -1;
|
|
for (QTextBlock blk = doc->begin(); blk.isValid(); blk = blk.next()) {
|
|
++cnt;
|
|
objectIndexOfLast = blk.charFormat().objectIndex();
|
|
}
|
|
// beginning of frame for first cell
|
|
// + beginning of frame for second cell
|
|
// + beginning of frame for third cell
|
|
// + beginning of frame for fourth cell
|
|
// + end of frame
|
|
// + initial block
|
|
// ==> 6
|
|
QCOMPARE(cnt, 6);
|
|
QVERIFY(objectIndexOfLast != -1);
|
|
QVERIFY(doc->begin().next().charFormat().objectIndex() != -1);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::dosLineFeed()
|
|
{
|
|
const char html[] = "<pre>Test\r\n</pre>Bar";
|
|
setHtml(QString::fromLatin1(html));
|
|
QVERIFY(!doc->toPlainText().contains('\r'));
|
|
QCOMPARE(doc->toPlainText(), QString("Test\nBar"));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::unorderedListEnumeration()
|
|
{
|
|
const char html[] = "<ul><ul><ul><li>Blah</li></ul></ul>";
|
|
setHtml(QString::fromLatin1(html));
|
|
cursor.movePosition(QTextCursor::End);
|
|
QVERIFY(cursor.currentList());
|
|
QCOMPARE(cursor.currentList()->format().style(), QTextListFormat::ListDisc);
|
|
|
|
const char html2[] = "<ul><ul><ul type=circle><li>Blah</li></ul></ul>";
|
|
setHtml(QString::fromLatin1(html2));
|
|
cursor.movePosition(QTextCursor::End);
|
|
QVERIFY(cursor.currentList());
|
|
QCOMPARE(cursor.currentList()->format().style(), QTextListFormat::ListCircle);
|
|
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::resetHasBlockAfterClosedBlockTags()
|
|
{
|
|
// when closing tags we have to make sure hasBlock in import() gets reset
|
|
const char html[] = "<body><table><tr><td><td><p></table><p></body>";
|
|
setHtml(QString::fromLatin1(html));
|
|
QVERIFY(!doc->isEmpty());
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::ignoreStyleTags()
|
|
{
|
|
const char html[] = "<body><style>Blah</style>Hello</body>";
|
|
setHtml(QString::fromLatin1(html));
|
|
QCOMPARE(doc->toPlainText(), QString("Hello"));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::hrefAnchor()
|
|
{
|
|
{
|
|
const char html[] = "<a href=\"test\">blah</a>";
|
|
setHtml(QString::fromLatin1(html));
|
|
QVERIFY(doc->begin().begin().fragment().charFormat().isAnchor());
|
|
QCOMPARE(doc->begin().begin().fragment().charFormat().anchorHref(), QString::fromLatin1("test"));
|
|
QVERIFY(doc->begin().begin().fragment().charFormat().fontUnderline());
|
|
}
|
|
|
|
{
|
|
// only hyperlinks should have special formatting
|
|
const char html[] = "<a>blah</a>";
|
|
setHtml(QString::fromLatin1(html));
|
|
QVERIFY(doc->begin().begin().fragment().charFormat().isAnchor());
|
|
QVERIFY(!doc->begin().begin().fragment().charFormat().fontUnderline());
|
|
}
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::namedAnchorFragments()
|
|
{
|
|
// named anchors should be 'invisible', but the fragment right after it should
|
|
// hold the attribute
|
|
const char html[] = "a<a name=\"test\" />blah";
|
|
setHtml(QString::fromLatin1(html));
|
|
|
|
QTextBlock firstBlock = doc->begin();
|
|
QVERIFY(firstBlock.isValid());
|
|
|
|
QTextBlock::Iterator it = firstBlock.begin();
|
|
QVERIFY(!it.atEnd());
|
|
|
|
// the 'a'
|
|
QVERIFY(it.fragment().isValid());
|
|
QCOMPARE(it.fragment().text(), QString::fromLatin1("a"));
|
|
QVERIFY(!it.fragment().charFormat().isAnchor());
|
|
|
|
// the 'b' of 'blah' as separate fragment with the anchor attribute
|
|
++it;
|
|
QVERIFY(it.fragment().isValid());
|
|
QCOMPARE(it.fragment().text(), QString::fromLatin1("b"));
|
|
QVERIFY(it.fragment().charFormat().isAnchor());
|
|
|
|
// the 'lah' of 'blah' as remainder
|
|
++it;
|
|
QVERIFY(it.fragment().isValid());
|
|
QVERIFY(it.fragment().text().startsWith("lah"));
|
|
QVERIFY(!it.fragment().charFormat().isAnchor());
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::namedAnchorFragments2()
|
|
{
|
|
const char html[] = "<p> <a name=\"foo\"> Hello";
|
|
setHtml(QString::fromLatin1(html));
|
|
|
|
QCOMPARE(doc->toPlainText(), QString("Hello"));
|
|
|
|
QTextBlock::Iterator it = doc->begin().begin();
|
|
QVERIFY(!it.atEnd());
|
|
|
|
QCOMPARE(it.fragment().text(), QString::fromLatin1("H"));
|
|
QVERIFY(it.fragment().charFormat().isAnchor());
|
|
|
|
++it;
|
|
|
|
QCOMPARE(it.fragment().text(), QString::fromLatin1("ello"));
|
|
QVERIFY(!it.fragment().charFormat().isAnchor());
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::namedAnchorFragments3()
|
|
{
|
|
setHtml("<a name=\"target\" /><a name=\"target2\"/><span>Text</span>");
|
|
|
|
QCOMPARE(doc->toPlainText(), QString("Text"));
|
|
|
|
QTextBlock::Iterator it = doc->begin().begin();
|
|
QVERIFY(!it.atEnd());
|
|
|
|
QCOMPARE(it.fragment().text(), QString::fromLatin1("T"));
|
|
QVERIFY(it.fragment().charFormat().isAnchor());
|
|
QCOMPARE(it.fragment().charFormat().anchorName(), QString("target"));
|
|
QStringList targets; targets << "target" << "target2";
|
|
QCOMPARE(it.fragment().charFormat().anchorNames(), targets);
|
|
|
|
++it;
|
|
|
|
QCOMPARE(it.fragment().text(), QString::fromLatin1("ext"));
|
|
QVERIFY(!it.fragment().charFormat().isAnchor());
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::dontInheritAlignmentInTables()
|
|
{
|
|
const char html[] = "<table align=center><tr><td>Hey</td></tr></table>";
|
|
setHtml(QString::fromLatin1(html));
|
|
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QVERIFY(cursor.currentTable());
|
|
QVERIFY(cursor.currentTable()->cellAt(0, 0).isValid());
|
|
QVERIFY(cursor.currentTable()->cellAt(0, 0).firstCursorPosition().block().next().blockFormat().alignment() != Qt::AlignHCenter);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::cellBlockCount()
|
|
{
|
|
const char html[] = "<table><tr><td>Hey</td></tr></table>";
|
|
setHtml(QString::fromLatin1(html));
|
|
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QVERIFY(cursor.currentTable());
|
|
|
|
QTextTableCell cell = cursor.currentTable()->cellAt(0, 0);
|
|
QVERIFY(cell.isValid());
|
|
|
|
int blockCount = 0;
|
|
for (QTextFrame::iterator it = cell.begin(); !it.atEnd(); ++it) {
|
|
QVERIFY(!it.currentFrame());
|
|
QVERIFY(it.currentBlock().isValid());
|
|
++blockCount;
|
|
}
|
|
QCOMPARE(blockCount, 1);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::cellBlockCount2()
|
|
{
|
|
const char html[] = "<table><tr><td><p>Hey</p></td></tr></table>";
|
|
setHtml(QString::fromLatin1(html));
|
|
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QVERIFY(cursor.currentTable());
|
|
|
|
QTextTableCell cell = cursor.currentTable()->cellAt(0, 0);
|
|
QVERIFY(cell.isValid());
|
|
|
|
int blockCount = 0;
|
|
for (QTextFrame::iterator it = cell.begin(); !it.atEnd(); ++it) {
|
|
QVERIFY(!it.currentFrame());
|
|
QVERIFY(it.currentBlock().isValid());
|
|
++blockCount;
|
|
}
|
|
QCOMPARE(blockCount, 1);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::emptyTable()
|
|
{
|
|
const char html[] = "<table></table>";
|
|
setHtml(QString::fromLatin1(html));
|
|
QVERIFY(true); // don't crash with a failing assertion
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::emptyTable2()
|
|
{
|
|
const char html[] = "<table></td></tr></table><p>blah</p>";
|
|
setHtml(QString::fromLatin1(html));
|
|
QVERIFY(true); // don't crash with a failing assertion
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::emptyTable3()
|
|
{
|
|
const char html[] = "<table><tr><td><table></table></td><td>Foobar</td></tr></table>";
|
|
setHtml(QString::fromLatin1(html));
|
|
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QTextTable *table = cursor.currentTable();
|
|
QVERIFY(table);
|
|
QCOMPARE(table->rows(), 1);
|
|
QCOMPARE(table->columns(), 2);
|
|
QTextTableCell cell = table->cellAt(0, 0);
|
|
QVERIFY(cell.isValid());
|
|
QCOMPARE(cell.firstPosition(), cell.lastPosition());
|
|
cell = table->cellAt(0, 1);
|
|
QTextCursor cursor = cell.firstCursorPosition();
|
|
cursor.setPosition(cell.lastPosition(), QTextCursor::KeepAnchor);
|
|
QCOMPARE(cursor.selectedText(), QString("Foobar"));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::doubleRowClose()
|
|
{
|
|
const char html[] = "<table><tr><td>Blah</td></tr></tr><tr><td>Hm</td></tr></table>";
|
|
setHtml(QString::fromLatin1(html));
|
|
QVERIFY(true); // don't crash with a failing assertion
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::mayNotHaveChildren()
|
|
{
|
|
// make sure the Hey does not end up as tag text for the img tag
|
|
const char html[] = "<img />Hey";
|
|
setHtml(QString::fromLatin1(html));
|
|
QCOMPARE(doc->toPlainText().mid(1), QString::fromLatin1("Hey"));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::inheritAlignment()
|
|
{
|
|
// make sure attributes from the body tag get inherited
|
|
const char html[] = "<body align=right><p>Hey";
|
|
setHtml(QString::fromLatin1(html));
|
|
// html alignment is absolute
|
|
QCOMPARE(doc->begin().blockFormat().alignment(), Qt::Alignment(Qt::AlignRight|Qt::AlignAbsolute));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::dontEmitEmptyNodeWhenEmptyTagIsFollowedByCloseTag()
|
|
{
|
|
// make sure the Hey does not end up as tag text for the img tag
|
|
const char html[] = "<body align=right><p align=left>Blah<img></img><p>Hey";
|
|
setHtml(QString::fromLatin1(html));
|
|
QCOMPARE(doc->begin().blockFormat().alignment(), Qt::Alignment(Qt::AlignLeft|Qt::AlignAbsolute));
|
|
QCOMPARE(doc->begin().next().blockFormat().alignment(), Qt::Alignment(Qt::AlignRight|Qt::AlignAbsolute));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::toPlainText()
|
|
{
|
|
QString input = "Hello\nWorld";
|
|
input += QChar::ParagraphSeparator;
|
|
input += "Blah";
|
|
doc->setPlainText(input);
|
|
QCOMPARE(doc->blockCount(), 3);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::copyTableRow()
|
|
{
|
|
QTextDocumentFragment frag;
|
|
{
|
|
QTextTable *table = cursor.insertTable(2, 2);
|
|
table->cellAt(0, 0).firstCursorPosition().insertText("Blah");
|
|
table->cellAt(0, 1).firstCursorPosition().insertText("Foo");
|
|
table->cellAt(1, 0).firstCursorPosition().insertText("Bar");
|
|
table->cellAt(1, 1).firstCursorPosition().insertText("Hah");
|
|
|
|
// select second row
|
|
cursor = table->cellAt(1, 1).firstCursorPosition();
|
|
cursor.movePosition(QTextCursor::PreviousBlock, QTextCursor::KeepAnchor);
|
|
|
|
QCOMPARE(table->cellAt(cursor.position()).row(), 1);
|
|
QCOMPARE(table->cellAt(cursor.position()).column(), 0);
|
|
QCOMPARE(table->cellAt(cursor.anchor()).row(), 1);
|
|
QCOMPARE(table->cellAt(cursor.anchor()).column(), 1);
|
|
|
|
frag = QTextDocumentFragment(cursor);
|
|
}
|
|
{
|
|
QTextDocument doc2;
|
|
cursor = QTextCursor(&doc2);
|
|
cursor.insertFragment(frag);
|
|
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QTextTable *table = cursor.currentTable();
|
|
|
|
QVERIFY(table);
|
|
QCOMPARE(table->columns(), 2);
|
|
QCOMPARE(table->rows(), 1);
|
|
|
|
QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("Bar"));
|
|
QCOMPARE(table->cellAt(0, 1).firstCursorPosition().block().text(), QString("Hah"));
|
|
}
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::copyTableColumn()
|
|
{
|
|
QTextDocumentFragment frag;
|
|
{
|
|
QTextTable *table = cursor.insertTable(2, 2);
|
|
table->cellAt(0, 0).firstCursorPosition().insertText("Blah");
|
|
table->cellAt(0, 1).firstCursorPosition().insertText("Foo");
|
|
table->cellAt(1, 0).firstCursorPosition().insertText("Bar");
|
|
table->cellAt(1, 1).firstCursorPosition().insertText("Hah");
|
|
|
|
// select second column
|
|
cursor = table->cellAt(0, 1).firstCursorPosition();
|
|
cursor.movePosition(QTextCursor::Down, QTextCursor::KeepAnchor);
|
|
|
|
QCOMPARE(table->cellAt(cursor.anchor()).row(), 0);
|
|
QCOMPARE(table->cellAt(cursor.anchor()).column(), 1);
|
|
QCOMPARE(table->cellAt(cursor.position()).row(), 1);
|
|
QCOMPARE(table->cellAt(cursor.position()).column(), 1);
|
|
|
|
frag = QTextDocumentFragment(cursor);
|
|
}
|
|
{
|
|
QTextDocument doc2;
|
|
cursor = QTextCursor(&doc2);
|
|
cursor.insertFragment(frag);
|
|
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QTextTable *table = cursor.currentTable();
|
|
|
|
QVERIFY(table);
|
|
QCOMPARE(table->columns(), 1);
|
|
QCOMPARE(table->rows(), 2);
|
|
|
|
QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("Foo"));
|
|
QCOMPARE(table->cellAt(1, 0).firstCursorPosition().block().text(), QString("Hah"));
|
|
}
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::copySubTable()
|
|
{
|
|
QTextDocumentFragment frag;
|
|
{
|
|
QTextTableFormat fmt;
|
|
QVector<QTextLength> constraints;
|
|
constraints << QTextLength(QTextLength::PercentageLength, 16);
|
|
constraints << QTextLength(QTextLength::PercentageLength, 28);
|
|
constraints << QTextLength(QTextLength::PercentageLength, 28);
|
|
constraints << QTextLength(QTextLength::PercentageLength, 28);
|
|
fmt.setColumnWidthConstraints(constraints);
|
|
|
|
QTextTable *table = cursor.insertTable(4, 4, fmt);
|
|
for (int row = 0; row < 4; ++row) {
|
|
const QString rowS = QString::number(row) + QLatin1Char('/');
|
|
for (int col = 0; col < 4; ++col)
|
|
table->cellAt(row, col).firstCursorPosition().insertText(rowS + QString::number(col));
|
|
}
|
|
|
|
QCOMPARE(table->format().columnWidthConstraints().count(), table->columns());
|
|
|
|
// select 2x2 subtable
|
|
cursor = table->cellAt(1, 1).firstCursorPosition();
|
|
cursor.movePosition(QTextCursor::Down, QTextCursor::KeepAnchor);
|
|
cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor);
|
|
|
|
QCOMPARE(table->cellAt(cursor.anchor()).row(), 1);
|
|
QCOMPARE(table->cellAt(cursor.anchor()).column(), 1);
|
|
QCOMPARE(table->cellAt(cursor.position()).row(), 2);
|
|
QCOMPARE(table->cellAt(cursor.position()).column(), 2);
|
|
|
|
frag = QTextDocumentFragment(cursor);
|
|
}
|
|
{
|
|
QTextDocument doc2;
|
|
cursor = QTextCursor(&doc2);
|
|
cursor.insertFragment(frag);
|
|
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QTextTable *table = cursor.currentTable();
|
|
|
|
QVERIFY(table);
|
|
QVERIFY(table->format().columnWidthConstraints().isEmpty());
|
|
QCOMPARE(table->columns(), 2);
|
|
QCOMPARE(table->rows(), 2);
|
|
|
|
QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("1/1"));
|
|
QCOMPARE(table->cellAt(0, 1).firstCursorPosition().block().text(), QString("1/2"));
|
|
QCOMPARE(table->cellAt(1, 0).firstCursorPosition().block().text(), QString("2/1"));
|
|
QCOMPARE(table->cellAt(1, 1).firstCursorPosition().block().text(), QString("2/2"));
|
|
}
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_textDecoration()
|
|
{
|
|
const char html[] = "<span style='text-decoration: overline line-through underline'>Blah</span>";
|
|
cursor.insertFragment(QTextDocumentFragment::fromHtml(QByteArray::fromRawData(html, sizeof(html) / sizeof(html[0]))));
|
|
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextCharacter);
|
|
QVERIFY(cursor.charFormat().fontUnderline());
|
|
QVERIFY(cursor.charFormat().fontOverline());
|
|
QVERIFY(cursor.charFormat().fontStrikeOut());
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_infiniteLoop()
|
|
{
|
|
{
|
|
// used to cause an infinite loop due to the lack of a space after the
|
|
// tag name
|
|
const char html[] = "<ahref=\"argl\">Link</a>";
|
|
cursor.insertFragment(QTextDocumentFragment::fromHtml(html));
|
|
QVERIFY(true);
|
|
}
|
|
|
|
{
|
|
const char html[] = "<a href=\"\"a<";
|
|
cursor.insertFragment(QTextDocumentFragment::fromHtml(html));
|
|
QVERIFY(true);
|
|
}
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_blockIndent()
|
|
{
|
|
const char html[] = "<p style=\"-qt-block-indent:3;\">Test</p>";
|
|
cursor.insertFragment(QTextDocumentFragment::fromHtml(html));
|
|
QCOMPARE(cursor.blockFormat().indent(), 3);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_listIndent()
|
|
{
|
|
const char html[] = "<ul style=\"-qt-list-indent:4;\"><li>Blah</ul>";
|
|
cursor.insertFragment(QTextDocumentFragment::fromHtml(html));
|
|
QVERIFY(cursor.currentList());
|
|
QCOMPARE(cursor.currentList()->format().indent(), 4);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_whitespace_data()
|
|
{
|
|
QTest::addColumn<QString>("html");
|
|
QTest::addColumn<QString>("expectedPlainText");
|
|
|
|
QTest::newRow("1") << QString("<span>This is some test</span><span> with spaces between words</span>")
|
|
<< QString("This is some test with spaces between words");
|
|
|
|
QTest::newRow("2") << QString("<span> </span><span>nowhitespacehereplease</span>")
|
|
<< QString::fromLatin1("nowhitespacehereplease");
|
|
|
|
QTest::newRow("3") << QString("<span style=\"white-space: pre;\"> white space here </span>")
|
|
<< QString::fromLatin1(" white space here ");
|
|
|
|
QTest::newRow("4") << QString("<span style=\"white-space: pre-wrap;\"> white space here </span>")
|
|
<< QString::fromLatin1(" white space here ");
|
|
|
|
QTest::newRow("5") << QString("<a href=\"One.html\">One</a> <a href=\"Two.html\">Two</a> <b>Three</b>\n"
|
|
"<b>Four</b>")
|
|
<< QString::fromLatin1("One Two Three Four");
|
|
|
|
QTest::newRow("6") << QString("<p>Testing: <b><i><u>BoldItalic</u></i></b> <i>Italic</i></p>")
|
|
<< QString("Testing: BoldItalic Italic");
|
|
|
|
QTest::newRow("7") << QString("<table><tr><td>Blah</td></tr></table> <table border><tr><td>Foo</td></tr></table>")
|
|
<< QString("\nBlah\n\nFoo\n");
|
|
|
|
QTest::newRow("8") << QString("<table><tr><td><i>Blah</i></td></tr></table> <i>Blub</i>")
|
|
<< QString("\nBlah\nBlub");
|
|
|
|
QTest::newRow("task116492") << QString("<p>a<font=\"Times\"> b </font>c</p>")
|
|
<< QString("a b c");
|
|
|
|
QTest::newRow("task121653") << QString("abc<b> def</b>")
|
|
<< QString("abc def");
|
|
|
|
QTest::newRow("task122650") << QString("<p>Foo</p> Bar")
|
|
<< QString("Foo\nBar");
|
|
|
|
QTest::newRow("task122650-2") << QString("<p>Foo</p> <p> Bar")
|
|
<< QString("Foo \nBar");
|
|
|
|
QTest::newRow("task122650-3") << QString("<html>Before<pre>\nTest</pre>")
|
|
<< QString("Before\nTest");
|
|
|
|
QTest::newRow("br-with-whitespace") << QString("Foo<br>\nBlah")
|
|
<< QString("Foo\nBlah");
|
|
|
|
QTest::newRow("collapse-p-with-newline") << QString("Foo<p>\n<p>\n<p>\n<p>\n<p>\n<p>\nBar")
|
|
<< QString("Foo\nBar");
|
|
|
|
QTest::newRow("table") << QString("<table><tr><td>Blah</td></tr></table>\nTest")
|
|
<< QString("\nBlah\nTest");
|
|
|
|
QTest::newRow("table2") << QString("<table><tr><td><pre>\nTest\n</pre></td>\n </tr></table>")
|
|
<< QString("\nTest\n");
|
|
|
|
QTest::newRow("table3") << QString("<table><tr><td><pre>\nTest\n</pre> \n \n </td></tr></table>")
|
|
<< QString("\nTest \n");
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_whitespace()
|
|
{
|
|
QFETCH(QString, html);
|
|
QFETCH(QString, expectedPlainText);
|
|
|
|
setHtml(html);
|
|
|
|
QCOMPARE(doc->toPlainText(), expectedPlainText);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_qt3Whitespace()
|
|
{
|
|
QString text = "This text has some whitespace"
|
|
"\n and \nnewlines that \n should be ignored\n\n";
|
|
const QString html = QString("<html><head><meta name=\"qrichtext\" content=\"1\" /></head><body>")
|
|
+ text
|
|
+ QString("</body></html>");
|
|
|
|
cursor.insertFragment(QTextDocumentFragment::fromHtml(html));
|
|
|
|
text.remove(QChar::fromLatin1('\n'));
|
|
|
|
QCOMPARE(doc->toPlainText(), text);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_qt3WhitespaceWithFragments()
|
|
{
|
|
QString text = "This text has some whitespace"
|
|
"\n and \nnewlines that \n should be ignored\n\n";
|
|
const QString html = QString("<html><head><meta name=\"qrichtext\" content=\"1\" /></head><body>"
|
|
"blah blah<!--StartFragment--><span>")
|
|
+ text
|
|
+ QString("</span><!--EndFragment--></body></html>");
|
|
|
|
cursor.insertFragment(QTextDocumentFragment::fromHtml(html));
|
|
|
|
text.remove(QChar::fromLatin1('\n'));
|
|
|
|
QCOMPARE(doc->toPlainText(), text);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_qt3WhitespaceAfterTags()
|
|
{
|
|
QString text = " This text has some whitespace ";
|
|
const QString html = QString("<html><head><meta name=\"qrichtext\" content=\"1\" /></head><body><span>")
|
|
+ text
|
|
+ QString("</span></body></html>");
|
|
|
|
cursor.insertFragment(QTextDocumentFragment::fromHtml(html));
|
|
|
|
QCOMPARE(doc->toPlainText(), text);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_listStart1()
|
|
{
|
|
// don't create a block for the <ul> element, even if there's some whitespace between
|
|
// it and the <li>
|
|
const QString html = QStringLiteral("<ul> <li>list item</li><ul>");
|
|
cursor.insertFragment(QTextDocumentFragment::fromHtml(html));
|
|
|
|
QCOMPARE(doc->blockCount(), 1);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_listStart2()
|
|
{
|
|
// unlike with html_listStart1 we want a block showing the 'buggy' text here
|
|
const QString html = QStringLiteral("<ul>buggy, but text should appear<li>list item</li><ul>");
|
|
cursor.insertFragment(QTextDocumentFragment::fromHtml(html));
|
|
|
|
QCOMPARE(doc->blockCount(), 2);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_cssMargin()
|
|
{
|
|
const char html[] = "<p style=\"margin-top: 1px; margin-bottom: 2px; margin-left: 3px; margin-right: 4px\">Test</p>";
|
|
cursor.insertFragment(QTextDocumentFragment::fromHtml(html));
|
|
const QTextBlockFormat fmt = cursor.blockFormat();
|
|
QCOMPARE(fmt.topMargin(), qreal(1));
|
|
QCOMPARE(fmt.bottomMargin(), qreal(2));
|
|
QCOMPARE(fmt.leftMargin(), qreal(3));
|
|
QCOMPARE(fmt.rightMargin(), qreal(4));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_hexEntities()
|
|
{
|
|
const char html[] = "@";
|
|
cursor.insertFragment(QTextDocumentFragment::fromHtml(html));
|
|
QCOMPARE(doc->begin().begin().fragment().text(), QString("@"));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_decEntities()
|
|
{
|
|
const char html[] = "@";
|
|
cursor.insertFragment(QTextDocumentFragment::fromHtml(html));
|
|
QCOMPARE(doc->begin().begin().fragment().text(), QString("@"));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_thCentered()
|
|
{
|
|
const char html[] = "<table><tr><th>This should be centered</th></tr></table>";
|
|
cursor.insertFragment(QTextDocumentFragment::fromHtml(html));
|
|
|
|
cursor.movePosition(QTextCursor::PreviousBlock);
|
|
QTextTable *table = cursor.currentTable();
|
|
QVERIFY(table);
|
|
|
|
QVERIFY(table->cellAt(0, 0).begin().currentBlock().blockFormat().alignment() == Qt::AlignCenter);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::orderedListNumbering()
|
|
{
|
|
// Supporter issue 45941 - make sure _two_ separate lists
|
|
// are imported, which have their own numbering
|
|
const char html[] = "<html><body>"
|
|
"<ol><li>elem 1</li></ol>"
|
|
"<ol><li>elem 1</li></ol>"
|
|
"</body></html>";
|
|
|
|
cursor.insertFragment(QTextDocumentFragment::fromHtml(html));
|
|
|
|
int numberOfLists = 0;
|
|
|
|
cursor.movePosition(QTextCursor::Start);
|
|
QTextList *lastList = 0;
|
|
do {
|
|
QTextList *list = cursor.currentList();
|
|
if (list && list != lastList) {
|
|
lastList = list;
|
|
++numberOfLists;
|
|
}
|
|
} while (cursor.movePosition(QTextCursor::NextBlock));
|
|
|
|
QCOMPARE(numberOfLists, 2);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_blockAfterList()
|
|
{
|
|
const char html[] = "<ul><li>Foo</ul>This should be a separate paragraph and not be indented at the same level as Foo";
|
|
cursor.insertFragment(QTextDocumentFragment::fromHtml(html));
|
|
|
|
cursor.movePosition(QTextCursor::Start);
|
|
|
|
QVERIFY(cursor.currentList());
|
|
QCOMPARE(cursor.currentList()->format().indent(), 1);
|
|
|
|
QVERIFY(cursor.movePosition(QTextCursor::NextBlock));
|
|
QVERIFY(!cursor.currentList());
|
|
QCOMPARE(cursor.blockFormat().indent(), 0);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_subAndSuperScript()
|
|
{
|
|
const char subHtml[] = "<sub>Subby</sub>";
|
|
const char superHtml[] = "<sup>Super</sup>";
|
|
const char subHtmlCss[] = "<span style=\"vertical-align: sub\">Subby</span>";
|
|
const char superHtmlCss[] = "<span style=\"vertical-align: super\">Super</span>";
|
|
const char alignmentInherited[] = "<sub><font face=\"Verdana\">Subby</font></sub>";
|
|
|
|
setHtml(subHtml);
|
|
QCOMPARE(cursor.charFormat().verticalAlignment(), QTextCharFormat::AlignSubScript);
|
|
|
|
setHtml(subHtmlCss);
|
|
QCOMPARE(cursor.charFormat().verticalAlignment(), QTextCharFormat::AlignSubScript);
|
|
|
|
setHtml(superHtml);
|
|
QCOMPARE(cursor.charFormat().verticalAlignment(), QTextCharFormat::AlignSuperScript);
|
|
|
|
setHtml(superHtmlCss);
|
|
QCOMPARE(cursor.charFormat().verticalAlignment(), QTextCharFormat::AlignSuperScript);
|
|
|
|
setHtml(alignmentInherited);
|
|
QCOMPARE(cursor.charFormat().verticalAlignment(), QTextCharFormat::AlignSubScript);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_cssColors()
|
|
{
|
|
const char color[] = "<span style=\"color:red\"><span style=\"color:blue\">Blue</span></span>";
|
|
setHtml(color);
|
|
QVERIFY(cursor.charFormat().foreground().color() == Qt::blue);
|
|
|
|
const char rgbColor[] = "<span style=\"color:red\"><span style=\"color:rgb(0, 0, 255)\">Blue</span></span>";
|
|
setHtml(rgbColor);
|
|
QVERIFY(cursor.charFormat().foreground().color() == Qt::blue);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::obeyFragmentMarkersInImport()
|
|
{
|
|
const char html[] = "This leading text should not appear<!--StartFragment--><span>Text</span><!--EndFragment-->This text at the end should not appear";
|
|
setHtml(html);
|
|
|
|
QCOMPARE(doc->toPlainText(), QString("Text"));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::whitespaceWithFragmentMarkers()
|
|
{
|
|
QString text(" text with leading and trailing whitespace ");
|
|
const char html[] = "This leading text should not appear<!--StartFragment-->%1<!--EndFragment-->This text at the end should not appear";
|
|
setHtml(QString::fromLatin1(html).arg(text));
|
|
|
|
QString expected("text with leading and trailing whitespace ");
|
|
QCOMPARE(doc->toPlainText(), expected);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_emptyParapgraphs1()
|
|
{
|
|
const char html[] = "<p style=\"-qt-paragraph-type:empty;\"> </p><p>Two paragraphs</p>";
|
|
setHtml(html);
|
|
|
|
QCOMPARE(doc->blockCount(), 2);
|
|
QVERIFY(doc->begin().text().isEmpty());
|
|
QCOMPARE(doc->begin().next().text(), QString("Two paragraphs"));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_emptyParapgraphs2()
|
|
{
|
|
const char html[] = "<p style=\"margin-left:80px\"></p><p>One paragraph</p>";
|
|
setHtml(html);
|
|
|
|
QCOMPARE(doc->blockCount(), 1);
|
|
QCOMPARE(cursor.blockFormat().leftMargin(), qreal(0));
|
|
|
|
const char html2[] = "<p style=\"margin-left:80px\"></p>One paragraph";
|
|
setHtml(html2);
|
|
QCOMPARE(doc->blockCount(), 1);
|
|
QCOMPARE(cursor.blockFormat().leftMargin(), qreal(0));
|
|
|
|
const char html3[] = "<p style=\"margin-left:80px\">Foo</p><p></p>Two paragraphs";
|
|
setHtml(html3);
|
|
QCOMPARE(doc->blockCount(), 2);
|
|
cursor = QTextCursor(doc);
|
|
QCOMPARE(cursor.blockFormat().leftMargin(), qreal(80));
|
|
QCOMPARE(cursor.block().next().blockFormat().leftMargin(), qreal(0));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_emptyParagraphs3()
|
|
{
|
|
const char html[] = "<ul><p>Foo</p><p></p></ul><h4>Bar</h4>";
|
|
|
|
setHtml(html);
|
|
|
|
QCOMPARE(doc->blockCount(), 2);
|
|
|
|
cursor = QTextCursor(doc);
|
|
QCOMPARE(cursor.block().next().blockFormat().indent(), 0);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_emptyParagraphs4()
|
|
{
|
|
const char html[] = "<p>foo</p><p style=\"page-break-before: always\"></p><p>bar</p>";
|
|
setHtml(html);
|
|
|
|
QTextBlock block = doc->begin();
|
|
QVERIFY(block.isValid());
|
|
QCOMPARE(block.text(), QString("foo"));
|
|
block = block.next();
|
|
QVERIFY(block.isValid());
|
|
QTextBlockFormat bf = block.blockFormat();
|
|
QVERIFY(bf.hasProperty(QTextFormat::PageBreakPolicy));
|
|
QCOMPARE(bf.pageBreakPolicy(), QTextFormat::PageBreak_AlwaysBefore);
|
|
QCOMPARE(block.text(), QString("bar"));
|
|
|
|
const char html2[] = "<p>foo</p><p style=\"page-break-after: always\"></p><p>bar</p>";
|
|
setHtml(html2);
|
|
|
|
block = doc->begin();
|
|
QVERIFY(block.isValid());
|
|
QCOMPARE(block.text(), QString("foo"));
|
|
block = block.next();
|
|
QVERIFY(block.isValid());
|
|
bf = block.blockFormat();
|
|
QVERIFY(bf.hasProperty(QTextFormat::PageBreakPolicy));
|
|
QCOMPARE(bf.pageBreakPolicy(), QTextFormat::PageBreak_AlwaysBefore); // after the empty line means it should appear for 'bar'
|
|
QCOMPARE(block.text(), QString("bar"));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_font()
|
|
{
|
|
const char html[] = "<font color=\"blue\"><p>Hah</p></font>";
|
|
setHtml(html);
|
|
|
|
QVERIFY(cursor.charFormat().foreground().color() == Qt::blue);
|
|
QVERIFY(cursor.blockCharFormat().foreground().color() == Qt::blue);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_fontSize()
|
|
{
|
|
const char html[] = "<font size=\"2\">Hah</font>";
|
|
setHtml(html);
|
|
|
|
QCOMPARE(cursor.charFormat().property(QTextFormat::FontSizeAdjustment).toInt(), -1);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_fontSizeAdjustment()
|
|
{
|
|
const char html[] = "<font size=\"7\"><b>Hah</b></font>";
|
|
setHtml(html);
|
|
|
|
QCOMPARE(cursor.charFormat().property(QTextFormat::FontSizeAdjustment).toInt(), 4);
|
|
QCOMPARE(cursor.charFormat().fontWeight(), int(QFont::Bold));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_cssFontSize()
|
|
{
|
|
const char html[] = "<span style=\"font-size: 50pt\">Foo</span>";
|
|
setHtml(html);
|
|
|
|
QCOMPARE(cursor.charFormat().property(QTextFormat::FontPointSize).toInt(), 50);
|
|
|
|
const char html2[] = "<span style=\"font-size: 50px\">Foo</span>";
|
|
setHtml(html2);
|
|
|
|
QCOMPARE(cursor.charFormat().property(QTextFormat::FontPixelSize).toInt(), 50);
|
|
|
|
const char html3[] = "<span style=\"font-size: large\">Foo</span>";
|
|
setHtml(html3);
|
|
|
|
QCOMPARE(cursor.charFormat().property(QTextFormat::FontSizeAdjustment).toInt(), 1);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_cssShorthandFont()
|
|
{
|
|
{
|
|
const char html[] = "<span style=\"font: 50px sans-serif\">Foo</span>";
|
|
setHtml(html);
|
|
QCOMPARE(cursor.charFormat().property(QTextFormat::FontPixelSize).toInt(), 50);
|
|
QCOMPARE(cursor.charFormat().property(QTextFormat::FontFamily).toString(), QString("sans-serif"));
|
|
}
|
|
{
|
|
const char html[] = "<span style=\"font: 50pt sans-serif\">Foo</span>";
|
|
setHtml(html);
|
|
QCOMPARE(cursor.charFormat().property(QTextFormat::FontPointSize).toInt(), 50);
|
|
QCOMPARE(cursor.charFormat().property(QTextFormat::FontFamily).toString(), QString("sans-serif"));
|
|
}
|
|
{
|
|
const char html[] = "<span style='font:7.0pt \"Times New Roman\"'>Foo</span>";
|
|
setHtml(html);
|
|
QCOMPARE(cursor.charFormat().property(QTextFormat::FontPointSize).toInt(), 7);
|
|
QCOMPARE(cursor.charFormat().property(QTextFormat::FontFamily).toString(), QString("Times New Roman"));
|
|
}
|
|
{
|
|
const char html[] = "<span style='font:bold 7.0pt'>Foo</span>";
|
|
setHtml(html);
|
|
QCOMPARE(cursor.charFormat().property(QTextFormat::FontWeight).toInt(), int(QFont::Bold));
|
|
QCOMPARE(cursor.charFormat().property(QTextFormat::FontPointSize).toInt(), 7);
|
|
}
|
|
{
|
|
const char html[] = "<span style='font:bold italic 7.0pt'>Foo</span>";
|
|
setHtml(html);
|
|
QCOMPARE(cursor.charFormat().property(QTextFormat::FontWeight).toInt(), int(QFont::Bold));
|
|
QCOMPARE(cursor.charFormat().property(QTextFormat::FontItalic).toBool(), true);
|
|
}
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_bodyBgColor()
|
|
{
|
|
const char html[] = "<body bgcolor=\"blue\">Foo</body>";
|
|
doc->setHtml(html);
|
|
|
|
QVERIFY(doc->rootFrame()->frameFormat().background().color() == Qt::blue);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_qtBgColor()
|
|
{
|
|
const char html[] = "<qt bgcolor=\"blue\">Foo</qt>";
|
|
doc->setHtml(html);
|
|
|
|
QVERIFY(doc->rootFrame()->frameFormat().background().color() == Qt::blue);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_bodyBackground()
|
|
{
|
|
const char html[] = "<body background=\"foo.png\">Foo</body>";
|
|
doc->setHtml(html);
|
|
|
|
QCOMPARE(doc->rootFrame()->frameFormat().background().style(), Qt::TexturePattern);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_tableCellBackground()
|
|
{
|
|
const char html[] = "<body><table><tr><td background=\"foo.png\">Foo</td></tr></table></body>";
|
|
doc->setHtml(html);
|
|
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QTextTable *table = cursor.currentTable();
|
|
QVERIFY(table);
|
|
|
|
QTextTableCell cell = table->cellAt(0, 0);
|
|
QCOMPARE(cell.format().background().style(), Qt::TexturePattern);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::css_bodyBackground()
|
|
{
|
|
const char html[] = "<body style=\"background-image:url('foo.png')\">Foo</body>";
|
|
doc->setHtml(html);
|
|
|
|
QCOMPARE(doc->rootFrame()->frameFormat().background().style(), Qt::TexturePattern);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::css_tableCellBackground()
|
|
{
|
|
const char html[] = "<body><table><tr><td style=\"background-image:url('foo.png')\">Foo</td></tr></table></body>";
|
|
doc->setHtml(html);
|
|
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QTextTable *table = cursor.currentTable();
|
|
QVERIFY(table);
|
|
|
|
QTextTableCell cell = table->cellAt(0, 0);
|
|
QCOMPARE(cell.format().background().style(), Qt::TexturePattern);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::css_cellPaddings()
|
|
{
|
|
const char html[] = "<body><table><tr><td style=\"padding-left:1\">Foo</td>"
|
|
"<td style=\"padding-right:1\"></td><td style=\"padding-top:10\"></td>"
|
|
"<td style=\"padding-bottom:5\"></td><td style=\"padding:15\"></td></tr></table></body>";
|
|
doc->setHtml(html);
|
|
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QTextTable *table = cursor.currentTable();
|
|
QVERIFY(table);
|
|
|
|
QTextTableCell cell = table->cellAt(0, 0);
|
|
QCOMPARE(cell.format().toTableCellFormat().leftPadding(), qreal(1));
|
|
cell = table->cellAt(0, 1);
|
|
QCOMPARE(cell.format().toTableCellFormat().rightPadding(), qreal(1));
|
|
cell = table->cellAt(0, 2);
|
|
QCOMPARE(cell.format().toTableCellFormat().topPadding(), qreal(10));
|
|
cell = table->cellAt(0, 3);
|
|
QCOMPARE(cell.format().toTableCellFormat().bottomPadding(), qreal(5));
|
|
cell = table->cellAt(0, 4);
|
|
QCOMPARE(cell.format().toTableCellFormat().leftPadding(), qreal(15));
|
|
QCOMPARE(cell.format().toTableCellFormat().rightPadding(), qreal(15));
|
|
QCOMPARE(cell.format().toTableCellFormat().topPadding(), qreal(15));
|
|
QCOMPARE(cell.format().toTableCellFormat().bottomPadding(), qreal(15));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_blockLevelDiv()
|
|
{
|
|
const char html[] = "<div align=right><b>Hello World";
|
|
setHtml(html);
|
|
|
|
QCOMPARE(doc->begin().blockFormat().alignment(), Qt::AlignRight|Qt::AlignAbsolute);
|
|
QCOMPARE(doc->begin().next(), doc->end());
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_spanNesting()
|
|
{
|
|
const char html[] = "<span style=\"color:black\">a<span style=\"color:red\">b<span style=\"color:black\">c</span></span>d</span>";
|
|
setHtml(html);
|
|
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextCharacter);
|
|
QVERIFY(cursor.charFormat().foreground() == Qt::black);
|
|
cursor.movePosition(QTextCursor::NextCharacter);
|
|
QVERIFY(cursor.charFormat().foreground() == Qt::red);
|
|
cursor.movePosition(QTextCursor::NextCharacter);
|
|
QVERIFY(cursor.charFormat().foreground() == Qt::black);
|
|
cursor.movePosition(QTextCursor::NextCharacter);
|
|
QVERIFY(cursor.charFormat().foreground() == Qt::black);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_nestedLists()
|
|
{
|
|
const char html[] = "<p><ul><li>Foo<ul><li>In nested list</li></ul></li><li>Last item</li></ul></p>";
|
|
setHtml(html);
|
|
|
|
cursor.movePosition(QTextCursor::Start);
|
|
QTextList *firstList = cursor.currentList();
|
|
QVERIFY(firstList);
|
|
QCOMPARE(firstList->format().indent(), 1);
|
|
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QTextList *secondList = cursor.currentList();
|
|
QVERIFY(secondList);
|
|
QVERIFY(secondList != firstList);
|
|
QCOMPARE(cursor.currentList()->format().indent(), 2);
|
|
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QTextList *thirdList = cursor.currentList();
|
|
QVERIFY(thirdList);
|
|
QCOMPARE(thirdList, firstList);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::noSpecialCharactersInPlainText()
|
|
{
|
|
cursor.insertTable(2, 2);
|
|
cursor.insertBlock();
|
|
cursor.insertText(QString(QChar::LineSeparator));
|
|
cursor.insertText(QString(QChar::Nbsp));
|
|
|
|
QString plain = doc->toPlainText();
|
|
QVERIFY(!plain.contains(QChar::ParagraphSeparator));
|
|
QVERIFY(!plain.contains(QChar::Nbsp));
|
|
QVERIFY(!plain.contains(QTextBeginningOfFrame));
|
|
QVERIFY(!plain.contains(QTextEndOfFrame));
|
|
QVERIFY(!plain.contains(QChar::LineSeparator));
|
|
|
|
plain = QTextDocumentFragment(doc).toPlainText();
|
|
QVERIFY(!plain.contains(QChar::ParagraphSeparator));
|
|
QVERIFY(!plain.contains(QChar::Nbsp));
|
|
QVERIFY(!plain.contains(QTextBeginningOfFrame));
|
|
QVERIFY(!plain.contains(QTextEndOfFrame));
|
|
QVERIFY(!plain.contains(QChar::LineSeparator));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_doNotInheritBackground()
|
|
{
|
|
const char html[] = "<html><body bgcolor=\"blue\"><p>Blah</p></body></html>";
|
|
doc->setHtml(html);
|
|
|
|
for (QTextBlock block = doc->begin();
|
|
block.isValid(); block = block.next()) {
|
|
QVERIFY(!block.blockFormat().hasProperty(QTextFormat::BackgroundBrush));
|
|
}
|
|
|
|
QVERIFY(doc->rootFrame()->frameFormat().hasProperty(QTextFormat::BackgroundBrush));
|
|
QVERIFY(doc->rootFrame()->frameFormat().background().color() == Qt::blue);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_inheritBackgroundToInlineElements()
|
|
{
|
|
const char html[] = "<span style=\"background: blue\">Foo<span>Bar</span></span>";
|
|
doc->setHtml(html);
|
|
|
|
int fragmentCount = 0;
|
|
|
|
QTextBlock block = doc->begin();
|
|
for (QTextBlock::Iterator it = block.begin();
|
|
!it.atEnd(); ++it, ++fragmentCount) {
|
|
|
|
const QTextFragment fragment = it.fragment();
|
|
if (fragmentCount == 0) {
|
|
QCOMPARE(fragment.text(), QString("FooBar"));
|
|
QVERIFY(fragment.charFormat().background().color() == Qt::blue);
|
|
}
|
|
}
|
|
|
|
QCOMPARE(fragmentCount, 1);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_doNotInheritBackgroundFromBlockElements()
|
|
{
|
|
const char html[] = "<p style=\"background: blue\"><span>Foo</span></span>";
|
|
doc->setHtml(html);
|
|
|
|
int fragmentCount = 0;
|
|
|
|
QTextBlock block = doc->begin();
|
|
for (QTextBlock::Iterator it = block.begin();
|
|
!it.atEnd(); ++it, ++fragmentCount) {
|
|
|
|
const QTextFragment fragment = it.fragment();
|
|
if (fragmentCount == 0) {
|
|
QCOMPARE(fragment.text(), QString("Foo"));
|
|
QVERIFY(!fragment.charFormat().hasProperty(QTextFormat::BackgroundBrush));
|
|
}
|
|
}
|
|
|
|
QCOMPARE(fragmentCount, 1);
|
|
}
|
|
void tst_QTextDocumentFragment::html_nobr()
|
|
{
|
|
const QString input = "Blah Foo Bar";
|
|
const QString html = QString::fromLatin1("<html><body><p><nobr>") + input + QString::fromLatin1("</nobr></p></body></html>");
|
|
setHtml(html);
|
|
|
|
QString text = doc->begin().begin().fragment().text();
|
|
QString expectedText = input;
|
|
expectedText.replace(QRegExp("\\s+"), QString(QChar::Nbsp));
|
|
QCOMPARE(text, expectedText);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::fromPlainText()
|
|
{
|
|
QString plainText;
|
|
plainText = "Hello\nWorld\r\nBlub";
|
|
plainText += QChar::ParagraphSeparator;
|
|
// TextEdit on OS 10 gives us OS 9 style linefeeds
|
|
// when copy & pasteing multi-line plaintext.
|
|
plainText += "OS9IsOldSchool\r";
|
|
plainText += "Last Parag";
|
|
|
|
doc->setPlainText(plainText);
|
|
|
|
int blockCount = 0;
|
|
for (QTextBlock block = doc->begin(); block.isValid(); block = block.next()) {
|
|
QVERIFY(!block.text().contains(QLatin1Char('\n')));
|
|
QVERIFY(!block.text().contains(QLatin1Char('\r')));
|
|
QVERIFY(!block.text().contains(QChar::ParagraphSeparator));
|
|
|
|
if (blockCount == 0)
|
|
QCOMPARE(block.text(), QString("Hello"));
|
|
else if (blockCount == 1)
|
|
QCOMPARE(block.text(), QString("World"));
|
|
else if (blockCount == 2)
|
|
QCOMPARE(block.text(), QString("Blub"));
|
|
else if (blockCount == 3)
|
|
QCOMPARE(block.text(), QString("OS9IsOldSchool"));
|
|
else if (blockCount == 4)
|
|
QCOMPARE(block.text(), QString("Last Parag"));
|
|
|
|
|
|
++blockCount;
|
|
}
|
|
|
|
QCOMPARE(blockCount, 5);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::fromPlainText2()
|
|
{
|
|
doc->setPlainText("Hello World");
|
|
QCOMPARE(QTextDocumentFragment(doc).toPlainText(), doc->toPlainText());
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_closingImageTag()
|
|
{
|
|
const char html[] = "<span style=\"font-size: 10pt\"><span style=\"font-size: 40pt\">Blah<img src=\"blah\"></img>Foo</span></span>";
|
|
setHtml(html);
|
|
|
|
int fragmentCount = 0;
|
|
|
|
QTextBlock block = doc->begin();
|
|
for (QTextBlock::Iterator it = block.begin();
|
|
!it.atEnd(); ++it, ++fragmentCount) {
|
|
|
|
const QTextFragment fragment = it.fragment();
|
|
if (fragmentCount == 0) {
|
|
QCOMPARE(fragment.text(), QString("Blah"));
|
|
QCOMPARE(fragment.charFormat().fontPointSize(), qreal(40));
|
|
} else if (fragmentCount == 1) {
|
|
QCOMPARE(fragment.text(), QString(QChar::ObjectReplacementCharacter));
|
|
} else if (fragmentCount == 2) {
|
|
QCOMPARE(fragment.text(), QString("Foo"));
|
|
QCOMPARE(fragment.charFormat().fontPointSize(), qreal(40));
|
|
}
|
|
}
|
|
|
|
QCOMPARE(fragmentCount, 3);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_emptyDocument()
|
|
{
|
|
const char html[] = "<html><body><p style=\"-qt-paragraph-type:empty;\"></p></body></html>";
|
|
setHtml(html);
|
|
QCOMPARE(doc->blockCount(), 1);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_closingTag()
|
|
{
|
|
const char html[] = "<i />text";
|
|
setHtml(html);
|
|
|
|
QVERIFY(!cursor.charFormat().fontItalic());
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_anchorAroundImage()
|
|
{
|
|
const char html[] = "<a href=\"http://www.troll.no\"><img src=test.png></a>";
|
|
setHtml(html);
|
|
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextCharacter);
|
|
QTextImageFormat fmt = cursor.charFormat().toImageFormat();
|
|
QCOMPARE(fmt.name(), QString("test.png"));
|
|
QVERIFY(fmt.isAnchor());
|
|
QCOMPARE(fmt.anchorHref(), QString("http://www.troll.no"));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_floatBorder()
|
|
{
|
|
const char html[] = "<table border=1.2><tr><td>Foo";
|
|
cursor.insertFragment(QTextDocumentFragment::fromHtml(QString::fromLatin1(html)));
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QVERIFY(cursor.currentTable());
|
|
QCOMPARE(cursor.currentTable()->format().border(), qreal(1.2));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_frameImport()
|
|
{
|
|
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");
|
|
|
|
QTextDocumentFragment frag(doc);
|
|
cleanup();
|
|
init();
|
|
frag = QTextDocumentFragment::fromHtml(frag.toHtml());
|
|
cursor.insertFragment(frag);
|
|
|
|
QList<QTextFrame *> childFrames = doc->rootFrame()->childFrames();
|
|
QCOMPARE(childFrames.count(), 1);
|
|
QTextFrame *frame = childFrames.first();
|
|
QCOMPARE(frame->frameFormat().margin(), ffmt.margin());
|
|
QCOMPARE(frame->frameFormat().border(), ffmt.border());
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_frameImport2()
|
|
{
|
|
QTextFrameFormat ffmt;
|
|
ffmt.setBorder(1);
|
|
ffmt.setPosition(QTextFrameFormat::FloatRight);
|
|
ffmt.setLeftMargin(200);
|
|
ffmt.setTopMargin(100);
|
|
ffmt.setBottomMargin(50);
|
|
ffmt.setRightMargin(250);
|
|
ffmt.setWidth(100);
|
|
ffmt.setHeight(50);
|
|
ffmt.setBackground(QColor("#00ff00"));
|
|
cursor.insertFrame(ffmt);
|
|
cursor.insertText("Hello World");
|
|
|
|
QTextDocumentFragment frag(doc);
|
|
cleanup();
|
|
init();
|
|
frag = QTextDocumentFragment::fromHtml(frag.toHtml());
|
|
cursor.insertFragment(frag);
|
|
|
|
QList<QTextFrame *> childFrames = doc->rootFrame()->childFrames();
|
|
QCOMPARE(childFrames.count(), 1);
|
|
QTextFrame *frame = childFrames.first();
|
|
QCOMPARE(frame->frameFormat().topMargin(), ffmt.topMargin());
|
|
QCOMPARE(frame->frameFormat().bottomMargin(), ffmt.bottomMargin());
|
|
QCOMPARE(frame->frameFormat().leftMargin(), ffmt.leftMargin());
|
|
QCOMPARE(frame->frameFormat().rightMargin(), ffmt.rightMargin());
|
|
QCOMPARE(frame->frameFormat().border(), ffmt.border());
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_dontAddMarginsAcrossTableCells()
|
|
{
|
|
const char html[] = "<table style=\"margin-left: 100px;\"><tr><td><p style=\"margin-left:50px;\">Foo</p></td></tr></table>";
|
|
cursor.insertFragment(QTextDocumentFragment::fromHtml(QString::fromLatin1(html)));
|
|
|
|
QList<QTextFrame *> childFrames = doc->rootFrame()->childFrames();
|
|
QCOMPARE(childFrames.count(), 1);
|
|
QTextFrame *frame = childFrames.first();
|
|
cursor = frame->firstCursorPosition();
|
|
QCOMPARE(cursor.blockFormat().leftMargin(), qreal(50.0));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_dontMergeCenterBlocks()
|
|
{
|
|
const char html[] = "<center>This should be centered</center>And this should not be centered anymore";
|
|
cursor.insertFragment(QTextDocumentFragment::fromHtml(QString::fromLatin1(html)));
|
|
|
|
QCOMPARE(doc->blockCount(), 2);
|
|
QTextBlock blk = doc->begin();
|
|
QCOMPARE(blk.blockFormat().alignment(), Qt::AlignCenter);
|
|
blk = blk.next();
|
|
QVERIFY(blk.blockFormat().alignment() != Qt::AlignCenter);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_tableCellBgColor()
|
|
{
|
|
const char html[] = "<table><tr><td bgcolor=\"blue\">Test<p>Second Parag</p></td></tr></table>";
|
|
cursor.insertFragment(QTextDocumentFragment::fromHtml(QString::fromLatin1(html)));
|
|
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QTextTable *table = cursor.currentTable();
|
|
QVERIFY(table);
|
|
|
|
QTextTableCell cell = table->cellAt(0, 0);
|
|
QVERIFY(cell.format().background().color() == Qt::blue);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_tableCellBgColor2()
|
|
{
|
|
const char html[] = "<table><tr><td bgcolor=\"blue\"><table><tr><td>Blah</td></tr></table></td></tr></table>";
|
|
cursor.insertFragment(QTextDocumentFragment::fromHtml(QString::fromLatin1(html)));
|
|
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QTextTable *table = cursor.currentTable();
|
|
QVERIFY(table);
|
|
|
|
QTextTableCell cell = table->cellAt(0, 0);
|
|
QVERIFY(cell.format().background().color() == Qt::blue);
|
|
|
|
QTextFrame::Iterator it = cell.begin();
|
|
QVERIFY(!it.atEnd());
|
|
QVERIFY(!it.currentFrame());
|
|
QVERIFY(it.currentBlock().isValid());
|
|
|
|
++it;
|
|
QVERIFY(!it.atEnd());
|
|
QVERIFY(it.currentFrame() != 0);
|
|
QVERIFY(!it.currentBlock().isValid());
|
|
|
|
++it;
|
|
QVERIFY(!it.atEnd());
|
|
QVERIFY(!it.currentFrame());
|
|
QVERIFY(it.currentBlock().isValid());
|
|
QCOMPARE(it.currentBlock().blockFormat().background(), QBrush(Qt::NoBrush));
|
|
|
|
++it;
|
|
QVERIFY(it.atEnd());
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_cellSkip()
|
|
{
|
|
const char html[] = ""
|
|
"<table border>"
|
|
" <tr>"
|
|
" <td>First Cell</td>"
|
|
" </tr>"
|
|
" <tr>"
|
|
" <td>Second Cell</td>"
|
|
" <td>Third Cell</td>"
|
|
" </tr>"
|
|
"</table>";
|
|
|
|
setHtml(html);
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QTextTable *table = cursor.currentTable();
|
|
QVERIFY(table);
|
|
QVERIFY(table->columns() == 2 && table->rows() == 2);
|
|
|
|
QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("First Cell"));
|
|
QVERIFY(table->cellAt(0, 1).firstCursorPosition().block().text().isEmpty());
|
|
QCOMPARE(table->cellAt(1, 0).firstCursorPosition().block().text(), QString("Second Cell"));
|
|
QCOMPARE(table->cellAt(1, 1).firstCursorPosition().block().text(), QString("Third Cell"));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::nonZeroMarginOnImport()
|
|
{
|
|
// specify bgcolor so that the html import creates a root frame format
|
|
setHtml("<html><body bgcolor=\"#00ff00\"><b>Hello World</b></body></html>");
|
|
QVERIFY(doc->rootFrame()->frameFormat().margin() > 0.0);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_charFormatPropertiesUnset()
|
|
{
|
|
setHtml("Hello World");
|
|
QVERIFY(doc->begin().begin().fragment().charFormat().properties().isEmpty());
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_headings()
|
|
{
|
|
setHtml("<h1>foo</h1>bar");
|
|
QCOMPARE(doc->blockCount(), 2);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_quotedFontFamily()
|
|
{
|
|
setHtml("<div style=\"font-family: 'Foo Bar';\">Test</div>");
|
|
QCOMPARE(doc->begin().begin().fragment().charFormat().fontFamily(), QString("Foo Bar"));
|
|
|
|
setHtml("<div style='font-family: \"Foo Bar\";'>Test</div>");
|
|
QCOMPARE(doc->begin().begin().fragment().charFormat().fontFamily(), QString("Foo Bar"));
|
|
|
|
setHtml("<div style='font-family: \"Foo Bar\";'>Test</div>");
|
|
QCOMPARE(doc->begin().begin().fragment().charFormat().fontFamily(), QString("Foo Bar"));
|
|
|
|
setHtml("<div style='font-family: Foo\n Bar;'>Test</div>");
|
|
QCOMPARE(doc->begin().begin().fragment().charFormat().fontFamily(), QString("Foo Bar"));
|
|
|
|
setHtml("<div style='font-family: Foo\n Bar, serif, \"bar foo\";'>Test</div>");
|
|
QCOMPARE(doc->begin().begin().fragment().charFormat().fontFamily(), QString("Foo Bar,serif,bar foo"));
|
|
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::defaultFont()
|
|
{
|
|
QFont f;
|
|
f.setFamily("Courier New");
|
|
f.setBold(true);
|
|
f.setItalic(true);
|
|
f.setStrikeOut(true); // set here but deliberately ignored for the html export
|
|
f.setPointSize(100);
|
|
doc->setDefaultFont(f);
|
|
doc->setPlainText("Hello World");
|
|
const QString html = doc->toHtml();
|
|
QLatin1String str("<body style=\" font-family:'Courier New'; font-size:100pt; font-weight:600; font-style:italic;\">");
|
|
QVERIFY(html.contains(str));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_spanBackgroundColor()
|
|
{
|
|
setHtml("<span style=\"background-color: blue\">Foo</span>");
|
|
QVERIFY(doc->begin().begin().fragment().charFormat().background().color() == QColor(Qt::blue));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_brokenTitle_data()
|
|
{
|
|
QTest::addColumn<QString>("html");
|
|
QTest::addColumn<QString>("expectedBody");
|
|
QTest::addColumn<QString>("expectedTitle");
|
|
|
|
QTest::newRow("brokentitle") << QString("<html><head><title>Foo<b>bar</b></title></head><body>Blah</body></html>")
|
|
<< QString("Blah") << QString("Foo");
|
|
QTest::newRow("brokentitle2") << QString("<html><head><title>Foo<font color=red>i</font>t<font color=red>i</font>Blub</title></head><body>Blah</body></html>")
|
|
<< QString("Blah") << QString("Foo");
|
|
QTest::newRow("entities") << QString("<html><head><title>Foo<bar</title></head><body>Blah</body></html>")
|
|
<< QString("Blah") << QString("Foo<bar");
|
|
QTest::newRow("unclosedtitle") << QString("<html><head><title>Foo</head><body>Blah</body></html>")
|
|
<< QString("Blah") << QString("Foo");
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_brokenTitle()
|
|
{
|
|
QFETCH(QString, html);
|
|
QFETCH(QString, expectedBody);
|
|
QFETCH(QString, expectedTitle);
|
|
doc->setHtml(html);
|
|
QCOMPARE(doc->toPlainText(), expectedBody);
|
|
QCOMPARE(doc->metaInformation(QTextDocument::DocumentTitle), expectedTitle);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_blockVsInline()
|
|
{
|
|
{
|
|
setHtml("<html><body><div><b>Foo<div>Bar");
|
|
QCOMPARE(cursor.charFormat().fontWeight(), int(QFont::Bold));
|
|
QCOMPARE(cursor.blockCharFormat().fontWeight(), int(QFont::Bold));
|
|
}
|
|
{
|
|
setHtml("<html><body><p><b>Foo<p>Bar");
|
|
QVERIFY(cursor.charFormat().fontWeight() != QFont::Bold);
|
|
QVERIFY(cursor.blockCharFormat().fontWeight() != QFont::Bold);
|
|
}
|
|
{
|
|
setHtml("<html><body><b><center>Foo</center></b>");
|
|
QCOMPARE(cursor.charFormat().fontWeight(), int(QFont::Bold));
|
|
QCOMPARE(cursor.blockCharFormat().fontWeight(), int(QFont::Bold));
|
|
}
|
|
{
|
|
setHtml("<html><body><b><p>Foo");
|
|
QCOMPARE(cursor.charFormat().fontWeight(), int(QFont::Bold));
|
|
QCOMPARE(cursor.blockCharFormat().fontWeight(), int(QFont::Bold));
|
|
}
|
|
{
|
|
setHtml("<html><body><b><p>Foo<p>Bar");
|
|
QCOMPARE(cursor.charFormat().fontWeight(), int(QFont::Bold));
|
|
QCOMPARE(cursor.blockCharFormat().fontWeight(), int(QFont::Bold));
|
|
}
|
|
{
|
|
setHtml("<div><b>Foo<div>Bar");
|
|
QCOMPARE(cursor.charFormat().fontWeight(), int(QFont::Bold));
|
|
QCOMPARE(cursor.blockCharFormat().fontWeight(), int(QFont::Bold));
|
|
}
|
|
{
|
|
setHtml("<p><b>Foo<p>Bar");
|
|
QVERIFY(cursor.charFormat().fontWeight() != QFont::Bold);
|
|
QVERIFY(cursor.blockCharFormat().fontWeight() != QFont::Bold);
|
|
}
|
|
{
|
|
setHtml("<b><center>Foo</center></b>");
|
|
QCOMPARE(cursor.charFormat().fontWeight(), int(QFont::Bold));
|
|
QCOMPARE(cursor.blockCharFormat().fontWeight(), int(QFont::Bold));
|
|
}
|
|
{
|
|
setHtml("<b><p>Foo");
|
|
QCOMPARE(cursor.charFormat().fontWeight(), int(QFont::Bold));
|
|
QCOMPARE(cursor.blockCharFormat().fontWeight(), int(QFont::Bold));
|
|
}
|
|
{
|
|
setHtml("<b><p>Foo<p>Bar");
|
|
QCOMPARE(cursor.charFormat().fontWeight(), int(QFont::Bold));
|
|
QCOMPARE(cursor.blockCharFormat().fontWeight(), int(QFont::Bold));
|
|
}
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_tbody()
|
|
{
|
|
setHtml("<table><thead><tr><td>First Cell</td></tr></thead><tbody><tr><td>Second Cell</td></tr></tbody></table>");
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QTextTable *table = cursor.currentTable();
|
|
QVERIFY(table);
|
|
QCOMPARE(table->columns(), 1);
|
|
QCOMPARE(table->rows(), 2);
|
|
QCOMPARE(table->format().headerRowCount(), 1);
|
|
QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("First Cell"));
|
|
QCOMPARE(table->cellAt(1, 0).firstCursorPosition().block().text(), QString("Second Cell"));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_nestedTables()
|
|
{
|
|
setHtml("<table>"
|
|
" <tr><td>"
|
|
""
|
|
" <table>"
|
|
" <tr><td>Hello</td></tr>"
|
|
" </table>"
|
|
""
|
|
" <table>"
|
|
" <tr><td>World</td></tr>"
|
|
" </table>"
|
|
""
|
|
" </td></tr>"
|
|
"</table>"
|
|
);
|
|
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QTextTable *table = cursor.currentTable();
|
|
QVERIFY(table);
|
|
QCOMPARE(table->rows(), 1);
|
|
QCOMPARE(table->columns(), 1);
|
|
|
|
cursor = table->cellAt(0, 0).firstCursorPosition();
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
|
|
QTextTable *firstNestedTable = cursor.currentTable();
|
|
QVERIFY(firstNestedTable);
|
|
QCOMPARE(firstNestedTable->parentFrame(), table);
|
|
QCOMPARE(firstNestedTable->rows(), 1);
|
|
QCOMPARE(firstNestedTable->columns(), 1);
|
|
QCOMPARE(firstNestedTable->cellAt(0, 0).firstCursorPosition().block().text(), QString("Hello"));
|
|
|
|
while (cursor.currentTable() == firstNestedTable
|
|
&& cursor.movePosition(QTextCursor::NextBlock))
|
|
;
|
|
|
|
QVERIFY(!cursor.isNull());
|
|
QCOMPARE(cursor.currentTable(), table);
|
|
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
|
|
QTextTable *secondNestedTable = cursor.currentTable();
|
|
QVERIFY(secondNestedTable);
|
|
QCOMPARE(secondNestedTable->parentFrame(), table);
|
|
QCOMPARE(secondNestedTable->rows(), 1);
|
|
QCOMPARE(secondNestedTable->columns(), 1);
|
|
QCOMPARE(secondNestedTable->cellAt(0, 0).firstCursorPosition().block().text(), QString("World"));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_rowSpans()
|
|
{
|
|
setHtml(""
|
|
"<table border=\"1\" width=\"100%\">"
|
|
" <tr>"
|
|
" <td rowspan=\"2\">blah</td>"
|
|
" <td rowspan=\"2\">foo</td>"
|
|
" </tr>"
|
|
" <tr></tr>"
|
|
" <tr>"
|
|
" <td rowspan=\"2\">blubb</td>"
|
|
" <td rowspan=\"2\">baz</td>"
|
|
" </tr>"
|
|
" <tr></tr>"
|
|
"</table>");
|
|
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QTextTable *table = cursor.currentTable();
|
|
QVERIFY(table);
|
|
QCOMPARE(table->rows(), 4);
|
|
QCOMPARE(table->columns(), 2);
|
|
|
|
QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("blah"));
|
|
QCOMPARE(table->cellAt(0, 1).firstCursorPosition().block().text(), QString("foo"));
|
|
|
|
QCOMPARE(table->cellAt(1, 0).firstCursorPosition().block().text(), QString("blah"));
|
|
QCOMPARE(table->cellAt(1, 1).firstCursorPosition().block().text(), QString("foo"));
|
|
|
|
QCOMPARE(table->cellAt(2, 0).firstCursorPosition().block().text(), QString("blubb"));
|
|
QCOMPARE(table->cellAt(2, 1).firstCursorPosition().block().text(), QString("baz"));
|
|
|
|
QCOMPARE(table->cellAt(3, 0).firstCursorPosition().block().text(), QString("blubb"));
|
|
QCOMPARE(table->cellAt(3, 1).firstCursorPosition().block().text(), QString("baz"));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_rowSpans2()
|
|
{
|
|
setHtml(""
|
|
"<html><body>"
|
|
"<table border=\"1\">"
|
|
"<tr>"
|
|
"<td>Row 1 col 1</td>"
|
|
"</tr>"
|
|
"<tr>"
|
|
"<td rowspan=\"3\">Row 2 col 1, rowspan 3</td>"
|
|
"<td>Row 2 col 2</td>"
|
|
"</tr>"
|
|
"<tr>"
|
|
"<td rowspan=\"2\">Row 3 col 2, rowspan 2</td>"
|
|
"</tr>"
|
|
"<tr>"
|
|
"</tr>"
|
|
"</table>"
|
|
"</body></html>");
|
|
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QTextTable *table = cursor.currentTable();
|
|
QVERIFY(table);
|
|
QCOMPARE(table->rows(), 4);
|
|
QCOMPARE(table->columns(), 2);
|
|
QCOMPARE(table->cellAt(0, 1).rowSpan(), 1);
|
|
QCOMPARE(table->cellAt(1, 0).rowSpan(), 3);
|
|
QCOMPARE(table->cellAt(2, 1).rowSpan(), 2);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_implicitParagraphs()
|
|
{
|
|
setHtml("<p>foo</p>bar");
|
|
QCOMPARE(doc->blockCount(), 2);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_missingCloseTag()
|
|
{
|
|
setHtml("<font color=\"red\"><span style=\"color:blue\">blue</span></span> red</font>");
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextCharacter);
|
|
QVERIFY(cursor.charFormat().foreground().color() == Qt::blue);
|
|
cursor.movePosition(QTextCursor::NextWord);
|
|
cursor.movePosition(QTextCursor::NextCharacter);
|
|
QVERIFY(cursor.charFormat().foreground().color() == Qt::red);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_anchorColor()
|
|
{
|
|
setHtml("<span style=\"color: red;\">Red</span>");
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextCharacter);
|
|
QVERIFY(cursor.charFormat().foreground().color() == Qt::red);
|
|
|
|
setHtml("<span style=\"color: red;\"><a href=\"http://www.kde.org/\">Blue</a></span>");
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextCharacter);
|
|
QCOMPARE(cursor.charFormat().foreground().color(), QGuiApplication::palette().link().color());
|
|
|
|
setHtml("<span style=\"color: red;\"><a href=\"http://www.kde.org/\" style=\"color: yellow;\">Green</a></span>");
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextCharacter);
|
|
QVERIFY(cursor.charFormat().foreground().color() == Qt::yellow);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_lastParagraphClosing()
|
|
{
|
|
setHtml("<p>Foo<b>Bar</b>Baz");
|
|
QCOMPARE(doc->blockCount(), 1);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_tableHeaderBodyFootParent()
|
|
{
|
|
// don't get confused by strange tags, keep tbody/thead/tfoot children of
|
|
// the table tag
|
|
setHtml("<table><col><col><col><tbody><tr><td>Hey</td></tr></tbody></table>");
|
|
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QTextTable *table = cursor.currentTable();
|
|
QVERIFY(table);
|
|
QCOMPARE(table->columns(), 1);
|
|
QCOMPARE(table->rows(), 1);
|
|
QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("Hey"));
|
|
|
|
setHtml("<table><col><col><col><thead><tr><td>Hey</td></tr></thead></table>");
|
|
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
table = cursor.currentTable();
|
|
QVERIFY(table);
|
|
QCOMPARE(table->columns(), 1);
|
|
QCOMPARE(table->rows(), 1);
|
|
QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("Hey"));
|
|
|
|
setHtml("<table><col><col><col><tfoot><tr><td>Hey</td></tr></tfoot></table>");
|
|
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
table = cursor.currentTable();
|
|
QVERIFY(table);
|
|
QCOMPARE(table->columns(), 1);
|
|
QCOMPARE(table->rows(), 1);
|
|
QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("Hey"));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_columnWidths()
|
|
{
|
|
setHtml("<table>"
|
|
" <tr>"
|
|
" <td colspan=\"2\">Foo</td>"
|
|
" </tr>"
|
|
" <tr>"
|
|
" <td>Bar</td>"
|
|
" <td width=\"1%\">Baz</td>"
|
|
" </tr>"
|
|
"</table>");
|
|
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QTextTable *table = cursor.currentTable();
|
|
QVERIFY(table);
|
|
QCOMPARE(table->columns(), 2);
|
|
QCOMPARE(table->rows(), 2);
|
|
QTextTableFormat fmt = table->format();
|
|
|
|
const QVector<QTextLength> columnWidths = fmt.columnWidthConstraints();
|
|
QCOMPARE(columnWidths.count(), 2);
|
|
QCOMPARE(columnWidths.at(0).type(), QTextLength::VariableLength);
|
|
QCOMPARE(columnWidths.at(1).type(), QTextLength::PercentageLength);
|
|
QCOMPARE(columnWidths.at(1).rawValue(), qreal(1));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::css_fontWeight()
|
|
{
|
|
setHtml("<p style=\"font-weight:bold\">blah</p>");
|
|
QCOMPARE(doc->begin().charFormat().fontWeight(), int(QFont::Bold));
|
|
setHtml("<p style=\"font-weight:600\">blah</p>");
|
|
QCOMPARE(doc->begin().charFormat().fontWeight(), int(QFont::Bold));
|
|
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::css_float()
|
|
{
|
|
setHtml("<img src=\"foo\" style=\"float: right\">");
|
|
QTextCharFormat fmt = doc->begin().begin().fragment().charFormat();
|
|
QVERIFY(fmt.isImageFormat());
|
|
QTextObject *o = doc->objectForFormat(fmt);
|
|
QVERIFY(o);
|
|
QTextFormat f = o->format();
|
|
QVERIFY(f.isFrameFormat());
|
|
QCOMPARE(f.toFrameFormat().position(), QTextFrameFormat::FloatRight);
|
|
|
|
setHtml("<img src=\"foo\" align=right>");
|
|
fmt = doc->begin().begin().fragment().charFormat();
|
|
QVERIFY(fmt.isImageFormat());
|
|
o = doc->objectForFormat(fmt);
|
|
QVERIFY(o);
|
|
f = o->format();
|
|
QVERIFY(f.isFrameFormat());
|
|
QCOMPARE(f.toFrameFormat().position(), QTextFrameFormat::FloatRight);
|
|
|
|
setHtml("<img src=\"foo\" align=left>");
|
|
fmt = doc->begin().begin().fragment().charFormat();
|
|
QVERIFY(fmt.isImageFormat());
|
|
o = doc->objectForFormat(fmt);
|
|
QVERIFY(o);
|
|
f = o->format();
|
|
QVERIFY(f.isFrameFormat());
|
|
QCOMPARE(f.toFrameFormat().position(), QTextFrameFormat::FloatLeft);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::css_textIndent()
|
|
{
|
|
setHtml("<p style=\"text-indent: 42px\">foo</p>");
|
|
QTextBlockFormat fmt = doc->begin().blockFormat();
|
|
QCOMPARE(fmt.textIndent(), qreal(42));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::css_inline()
|
|
{
|
|
setHtml(""
|
|
"<style>"
|
|
" p { background-color: green;}"
|
|
"</style>"
|
|
"<p>test</p>"
|
|
);
|
|
QTextBlockFormat fmt = doc->begin().blockFormat();
|
|
QCOMPARE(fmt.background().color(), QColor("green"));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::css_external()
|
|
{
|
|
doc->addResource(QTextDocument::StyleSheetResource, QUrl("test.css"), QString("p { background-color: green; }"));
|
|
doc->setHtml(""
|
|
"<link href=\"test.css\" type=\"text/css\" />"
|
|
"<p>test</p>"
|
|
);
|
|
QTextBlockFormat fmt = doc->begin().blockFormat();
|
|
QCOMPARE(fmt.background().color(), QColor("green"));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::css_import()
|
|
{
|
|
const QColor green("green");
|
|
doc->addResource(QTextDocument::StyleSheetResource, QUrl("test.css"), QString("@import \"other.css\";"));
|
|
doc->addResource(QTextDocument::StyleSheetResource, QUrl("other.css"), QString("@import url(\"other2.css\");"));
|
|
doc->addResource(QTextDocument::StyleSheetResource, QUrl("other2.css"), QString("p { background-color: green; }"));
|
|
doc->setHtml(""
|
|
"<link href=\"test.css\" type=\"text/css\" />"
|
|
"<p>test</p>"
|
|
);
|
|
QTextBlockFormat fmt = doc->begin().blockFormat();
|
|
QCOMPARE(fmt.background().color(), green);
|
|
|
|
doc->setHtml(""
|
|
"<style>@import \"test.css\" screen;</style>"
|
|
"<p>test</p>"
|
|
);
|
|
fmt = doc->begin().blockFormat();
|
|
QCOMPARE(fmt.background().color(), green);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::css_selectors_data()
|
|
{
|
|
QTest::addColumn<bool>("match");
|
|
QTest::addColumn<QString>("selector");
|
|
QTest::addColumn<QString>("attributes");
|
|
|
|
QTest::newRow("plain") << true << QString() << QString();
|
|
|
|
QTest::newRow("class") << true << QString(".foo") << QString("class=foo");
|
|
QTest::newRow("notclass") << false << QString(".foo") << QString("class=bar");
|
|
|
|
QTest::newRow("attrset") << true << QString("[justset]") << QString("justset");
|
|
QTest::newRow("notattrset") << false << QString("[justset]") << QString("otherattribute");
|
|
|
|
QTest::newRow("attrmatch") << true << QString("[foo=bar]") << QString("foo=bar");
|
|
QTest::newRow("noattrmatch") << false << QString("[foo=bar]") << QString("foo=xyz");
|
|
|
|
QTest::newRow("contains") << true << QString("[foo~=bar]") << QString("foo=\"baz bleh bar\"");
|
|
QTest::newRow("notcontains") << false << QString("[foo~=bar]") << QString("foo=\"test\"");
|
|
|
|
QTest::newRow("beingswith") << true << QString("[foo|=bar]") << QString("foo=\"bar-bleh\"");
|
|
QTest::newRow("notbeingswith") << false << QString("[foo|=bar]") << QString("foo=\"bleh-bar\"");
|
|
|
|
QTest::newRow("attr2") << true << QString("[bar=foo]") << QString("bleh=bar bar=foo");
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::css_selectors()
|
|
{
|
|
QFETCH(bool, match);
|
|
QFETCH(QString, selector);
|
|
QFETCH(QString, attributes);
|
|
|
|
QString html = QString(""
|
|
"<style>"
|
|
" p { background-color: green }"
|
|
" p%1 { background-color: red }"
|
|
"</style>"
|
|
"<p %2>test</p>"
|
|
).arg(selector).arg(attributes);
|
|
setHtml(html);
|
|
|
|
QTextBlockFormat fmt = doc->begin().blockFormat();
|
|
if (match)
|
|
QCOMPARE(fmt.background().color(), QColor("red"));
|
|
else
|
|
QCOMPARE(fmt.background().color(), QColor("green"));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::css_nodeNameCaseInsensitivity()
|
|
{
|
|
setHtml("<style>"
|
|
"P { background-color: green }"
|
|
"</style>"
|
|
"<p>test</p>");
|
|
QTextBlockFormat fmt = doc->begin().blockFormat();
|
|
QCOMPARE(fmt.background().color(), QColor("green"));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::css_textUnderlineStyle_data()
|
|
{
|
|
QTest::addColumn<QString>("styleName");
|
|
QTest::addColumn<int>("expectedStyle");
|
|
|
|
QTest::newRow("none") << QString("none") << int(QTextCharFormat::NoUnderline);
|
|
QTest::newRow("solid") << QString("solid") << int(QTextCharFormat::SingleUnderline);
|
|
QTest::newRow("dash") << QString("dashed") << int(QTextCharFormat::DashUnderline);
|
|
QTest::newRow("dot") << QString("dotted") << int(QTextCharFormat::DotLine);
|
|
QTest::newRow("dashdot") << QString("dot-dash") << int(QTextCharFormat::DashDotLine);
|
|
QTest::newRow("dashdotdot") << QString("dot-dot-dash") << int(QTextCharFormat::DashDotDotLine);
|
|
QTest::newRow("wave") << QString("wave") << int(QTextCharFormat::WaveUnderline);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::css_textUnderlineStyle()
|
|
{
|
|
QFETCH(QString, styleName);
|
|
QFETCH(int, expectedStyle);
|
|
|
|
QString html = QString::fromLatin1("<span style=\"text-underline-style: %1\">Blah</span>").arg(styleName);
|
|
doc->setHtml(html);
|
|
|
|
QTextFragment fragment = doc->begin().begin().fragment();
|
|
QVERIFY(fragment.isValid());
|
|
QCOMPARE(int(fragment.charFormat().underlineStyle()), expectedStyle);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::css_textUnderlineStyleAndDecoration()
|
|
{
|
|
doc->setHtml("<span style=\"text-decoration: overline; text-underline-style: solid\">Test</span>");
|
|
|
|
QTextFragment fragment = doc->begin().begin().fragment();
|
|
QVERIFY(fragment.isValid());
|
|
QCOMPARE(fragment.charFormat().underlineStyle(), QTextCharFormat::SingleUnderline);
|
|
QVERIFY(fragment.charFormat().fontOverline());
|
|
|
|
doc->setHtml("<span style=\"text-underline-style: solid; text-decoration: overline\">Test</span>");
|
|
|
|
fragment = doc->begin().begin().fragment();
|
|
QVERIFY(fragment.isValid());
|
|
QCOMPARE(fragment.charFormat().underlineStyle(), QTextCharFormat::SingleUnderline);
|
|
QVERIFY(fragment.charFormat().fontOverline());
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::css_listStyleType()
|
|
{
|
|
doc->setHtml("<ol style=\"list-style-type: disc\"><li>Blah</li></ol>");
|
|
cursor.movePosition(QTextCursor::End);
|
|
QVERIFY(cursor.currentList());
|
|
QCOMPARE(cursor.currentList()->format().style(), QTextListFormat::ListDisc);
|
|
|
|
doc->setHtml("<ul style=\"list-style-type: square\"><li>Blah</li></ul>");
|
|
cursor.movePosition(QTextCursor::End);
|
|
QVERIFY(cursor.currentList());
|
|
QCOMPARE(cursor.currentList()->format().style(), QTextListFormat::ListSquare);
|
|
|
|
doc->setHtml("<ul style=\"list-style-type: circle\"><li>Blah</li></ul>");
|
|
cursor.movePosition(QTextCursor::End);
|
|
QVERIFY(cursor.currentList());
|
|
QCOMPARE(cursor.currentList()->format().style(), QTextListFormat::ListCircle);
|
|
|
|
doc->setHtml("<ul style=\"list-style-type: decimal\"><li>Blah</li></ul>");
|
|
cursor.movePosition(QTextCursor::End);
|
|
QVERIFY(cursor.currentList());
|
|
QCOMPARE(cursor.currentList()->format().style(), QTextListFormat::ListDecimal);
|
|
|
|
doc->setHtml("<ul style=\"list-style-type: lower-alpha\"><li>Blah</li></ul>");
|
|
cursor.movePosition(QTextCursor::End);
|
|
QVERIFY(cursor.currentList());
|
|
QCOMPARE(cursor.currentList()->format().style(), QTextListFormat::ListLowerAlpha);
|
|
|
|
doc->setHtml("<ul style=\"list-style-type: upper-alpha\"><li>Blah</li></ul>");
|
|
cursor.movePosition(QTextCursor::End);
|
|
QVERIFY(cursor.currentList());
|
|
QCOMPARE(cursor.currentList()->format().style(), QTextListFormat::ListUpperAlpha);
|
|
|
|
doc->setHtml("<ul style=\"list-style-type: upper-roman\"><li>Blah</li></ul>");
|
|
cursor.movePosition(QTextCursor::End);
|
|
QVERIFY(cursor.currentList());
|
|
QCOMPARE(cursor.currentList()->format().style(), QTextListFormat::ListUpperRoman);
|
|
|
|
doc->setHtml("<ul style=\"list-style-type: lower-roman\"><li>Blah</li></ul>");
|
|
cursor.movePosition(QTextCursor::End);
|
|
QVERIFY(cursor.currentList());
|
|
QCOMPARE(cursor.currentList()->format().style(), QTextListFormat::ListLowerRoman);
|
|
|
|
// ignore the unsupported list-style-position inside the list-style shorthand property
|
|
doc->setHtml("<ul style=\"list-style: outside decimal\"><li>Blah</li></ul>");
|
|
cursor.movePosition(QTextCursor::End);
|
|
QVERIFY(cursor.currentList());
|
|
QCOMPARE(cursor.currentList()->format().style(), QTextListFormat::ListDecimal);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::css_linkPseudo()
|
|
{
|
|
doc->setHtml("<a href=\"foobar\">Blah</a>");
|
|
QVERIFY(doc->begin().begin().fragment().charFormat().fontUnderline());
|
|
|
|
doc->setHtml("<style>a { text-decoration: none; }</style><a href=\"foobar\">Blah</a>");
|
|
QVERIFY(!doc->begin().begin().fragment().charFormat().fontUnderline());
|
|
|
|
doc->setHtml("<style>a:link { text-decoration: none; }</style><a href=\"foobar\">Blah</a>");
|
|
QVERIFY(!doc->begin().begin().fragment().charFormat().fontUnderline());
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::css_pageBreaks()
|
|
{
|
|
doc->setHtml("<p>Foo</p>");
|
|
QCOMPARE(doc->begin().blockFormat().pageBreakPolicy(), QTextFormat::PageBreak_Auto);
|
|
|
|
doc->setHtml("<p style=\" page-break-before:always;\">Foo</p>");
|
|
QCOMPARE(doc->begin().blockFormat().pageBreakPolicy(), QTextFormat::PageBreak_AlwaysBefore);
|
|
|
|
doc->setHtml("<p style=\" page-break-after:always;\">Foo</p>");
|
|
QCOMPARE(doc->begin().blockFormat().pageBreakPolicy(), QTextFormat::PageBreak_AlwaysAfter);
|
|
|
|
doc->setHtml("<p style=\" page-break-before:always; page-break-after:always;\">Foo</p>");
|
|
QVERIFY(doc->begin().blockFormat().pageBreakPolicy() == (QTextFormat::PageBreak_AlwaysAfter | QTextFormat::PageBreak_AlwaysBefore));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::universalSelectors_data()
|
|
{
|
|
QTest::addColumn<bool>("match");
|
|
QTest::addColumn<QString>("selector");
|
|
QTest::addColumn<QString>("attributes");
|
|
|
|
QTest::newRow("1") << true << QString("*") << QString();
|
|
QTest::newRow("2") << false << QString() << QString(); // invalid totally empty selector
|
|
|
|
QTest::newRow("3") << false << QString("*[foo=bar]") << QString("foo=bleh");
|
|
QTest::newRow("4") << true << QString("*[foo=bar]") << QString("foo=bar");
|
|
|
|
QTest::newRow("5") << false << QString("[foo=bar]") << QString("foo=bleh");
|
|
QTest::newRow("6") << true << QString("[foo=bar]") << QString("foo=bar");
|
|
|
|
QTest::newRow("7") << true << QString(".charfmt1") << QString("class=charfmt1");
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::universalSelectors()
|
|
{
|
|
QFETCH(bool, match);
|
|
QFETCH(QString, selector);
|
|
QFETCH(QString, attributes);
|
|
|
|
QString html = QString(""
|
|
"<style>"
|
|
"%1 { background-color: green }"
|
|
"</style>"
|
|
"<p %2>test</p>"
|
|
).arg(selector).arg(attributes);
|
|
|
|
setHtml(html);
|
|
|
|
QTextBlockFormat fmt = doc->begin().blockFormat();
|
|
if (match)
|
|
QCOMPARE(fmt.background().color(), QColor("green"));
|
|
else
|
|
QVERIFY(!fmt.hasProperty(QTextFormat::BackgroundBrush));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::screenMedia()
|
|
{
|
|
const QColor green("green");
|
|
setHtml("<style>"
|
|
"@media screen {"
|
|
"p { background-color: green }"
|
|
"}"
|
|
"</style>"
|
|
"<p>test</p>"
|
|
"");
|
|
QTextBlockFormat fmt = doc->begin().blockFormat();
|
|
QCOMPARE(fmt.background().color(), green);
|
|
|
|
setHtml("<style>"
|
|
"@media foobar {"
|
|
"p { background-color: green }"
|
|
"}"
|
|
"</style>"
|
|
"<p>test</p>"
|
|
"");
|
|
fmt = doc->begin().blockFormat();
|
|
QVERIFY(fmt.background().color() != green);
|
|
|
|
setHtml("<style>"
|
|
"@media sCrEeN {"
|
|
"p { background-color: green }"
|
|
"}"
|
|
"</style>"
|
|
"<p>test</p>"
|
|
"");
|
|
fmt = doc->begin().blockFormat();
|
|
QCOMPARE(fmt.background().color(), green);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::htmlResourceLoading()
|
|
{
|
|
const QString html("<link href=\"test.css\" type=\"text/css\" />"
|
|
"<p>test</p>");
|
|
|
|
QTextDocument tmp;
|
|
tmp.addResource(QTextDocument::StyleSheetResource, QUrl("test.css"), QString("p { background-color: green; }"));
|
|
QTextDocumentFragment frag = QTextDocumentFragment::fromHtml(html, &tmp);
|
|
doc->clear();
|
|
QTextCursor(doc).insertFragment(frag);
|
|
QTextBlockFormat fmt = doc->begin().blockFormat();
|
|
QCOMPARE(fmt.background().color(), QColor("green"));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::someCaseInsensitiveAttributeValues()
|
|
{
|
|
const char html1[] = "<ul type=sQUarE><li>Blah</li></ul>";
|
|
setHtml(QString::fromLatin1(html1));
|
|
cursor.movePosition(QTextCursor::End);
|
|
QVERIFY(cursor.currentList());
|
|
QCOMPARE(cursor.currentList()->format().style(), QTextListFormat::ListSquare);
|
|
|
|
const char html2[] = "<div align=ceNTeR><b>Hello World";
|
|
setHtml(html2);
|
|
|
|
QCOMPARE(doc->begin().blockFormat().alignment(), Qt::AlignHCenter);
|
|
|
|
const char html3[] = "<p dir=rTL><b>Hello World";
|
|
setHtml(html3);
|
|
|
|
QCOMPARE(doc->begin().blockFormat().layoutDirection(), Qt::RightToLeft);
|
|
}
|
|
|
|
class TestDocument : public QTextDocument
|
|
{
|
|
public:
|
|
inline TestDocument() {}
|
|
|
|
QPixmap testPixmap;
|
|
|
|
virtual QVariant loadResource(int type, const QUrl &name) {
|
|
if (name.toString() == QLatin1String("testPixmap")) {
|
|
return testPixmap;
|
|
}
|
|
return QTextDocument::loadResource(type, name);
|
|
}
|
|
};
|
|
|
|
void tst_QTextDocumentFragment::backgroundImage()
|
|
{
|
|
TestDocument doc;
|
|
doc.testPixmap = QPixmap(100, 100);
|
|
doc.testPixmap.fill(Qt::blue);
|
|
doc.setHtml("<p style=\"background-image: url(testPixmap)\">Hello</p>");
|
|
QBrush bg = doc.begin().blockFormat().background();
|
|
QCOMPARE(bg.style(), Qt::TexturePattern);
|
|
QCOMPARE(bg.texture().cacheKey(), doc.testPixmap.cacheKey());
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::dontMergePreAndNonPre()
|
|
{
|
|
doc->setHtml("<pre>Pre text</pre>Text that should be wrapped");
|
|
QCOMPARE(doc->blockCount(), 2);
|
|
QCOMPARE(doc->begin().text(), QString("Pre text"));
|
|
QCOMPARE(doc->begin().next().text(), QString("Text that should be wrapped"));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::leftMarginInsideHtml()
|
|
{
|
|
doc->setHtml("<html><dl><dd>Blah");
|
|
QCOMPARE(doc->blockCount(), 1);
|
|
QVERIFY(doc->begin().blockFormat().leftMargin() > 0);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_margins()
|
|
{
|
|
doc->setHtml("<p style=\"margin-left: 42px\">Test");
|
|
QCOMPARE(doc->blockCount(), 1);
|
|
QCOMPARE(doc->begin().blockFormat().topMargin(), 12.);
|
|
QCOMPARE(doc->begin().blockFormat().bottomMargin(), 12.);
|
|
QCOMPARE(doc->begin().blockFormat().leftMargin(), 42.);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::newlineInsidePreShouldBecomeNewParagraph()
|
|
{
|
|
// rationale: we used to map newlines inside <pre> to QChar::LineSeparator, but
|
|
// if you display a lot of text inside pre it all ended up inside one single paragraph,
|
|
// which doesn't scale very well with our text engine. Paragraphs spanning thousands of
|
|
// lines are not a common use-case otherwise.
|
|
|
|
doc->setHtml("<pre>Foo\nBar</pre>");
|
|
QCOMPARE(doc->blockCount(), 2);
|
|
QTextBlock block = doc->begin();
|
|
QCOMPARE(block.blockFormat().topMargin(), qreal(12));
|
|
QVERIFY(qIsNull(block.blockFormat().bottomMargin()));
|
|
|
|
block = block.next();
|
|
|
|
QVERIFY(qIsNull(block.blockFormat().topMargin()));
|
|
QCOMPARE(block.blockFormat().bottomMargin(), qreal(12));
|
|
|
|
doc->setHtml("<pre style=\"margin-top: 32px; margin-bottom: 45px; margin-left: 50px\">Foo\nBar</pre>");
|
|
QCOMPARE(doc->blockCount(), 2);
|
|
block = doc->begin();
|
|
QCOMPARE(block.blockFormat().topMargin(), qreal(32));
|
|
QVERIFY(qIsNull(block.blockFormat().bottomMargin()));
|
|
QCOMPARE(block.blockFormat().leftMargin(), qreal(50));
|
|
|
|
block = block.next();
|
|
|
|
QVERIFY(qIsNull(block.blockFormat().topMargin()));
|
|
QCOMPARE(block.blockFormat().bottomMargin(), qreal(45));
|
|
QCOMPARE(block.blockFormat().leftMargin(), qreal(50));
|
|
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::invalidColspan()
|
|
{
|
|
doc->setHtml("<table><tr rowspan=-1><td colspan=-1>Blah</td></tr></table>");
|
|
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QTextTable *table = cursor.currentTable();
|
|
QVERIFY(table);
|
|
QCOMPARE(table->columns(), 1);
|
|
QCOMPARE(table->rows(), 1);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_brokenTableWithJustTr()
|
|
{
|
|
doc->setHtml("<tr><td>First Cell</td><tr><td>Second Cell");
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QTextTable *table = cursor.currentTable();
|
|
QVERIFY(table);
|
|
QCOMPARE(table->rows(), 2);
|
|
QCOMPARE(table->columns(), 1);
|
|
QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("First Cell"));
|
|
QCOMPARE(table->cellAt(1, 0).firstCursorPosition().block().text(), QString("Second Cell"));
|
|
|
|
doc->setHtml(""
|
|
"<col width=286 style='mso-width-source:userset;mso-width-alt:10459;width:215pt'>"
|
|
"<col width=64 span=3 style='width:48pt'>"
|
|
"<tr height=17 style='height:12.75pt'>"
|
|
"<td height=17 width=286 style='height:12.75pt;width:215pt'>1a</td>"
|
|
"<td width=64 style='width:48pt'>1b</td>"
|
|
"<td width=64 style='width:48pt'>1c</td>"
|
|
"<td width=64 style='width:48pt'>1d</td>"
|
|
"</tr>"
|
|
"<tr height=17 style='height:12.75pt'>"
|
|
"<td height=17 style='height:12.75pt'>|2a</td>"
|
|
"<td>2b</td>"
|
|
"<td>2c</td>"
|
|
"<td>2d</td>"
|
|
"</tr>");
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
table = cursor.currentTable();
|
|
QVERIFY(table);
|
|
QCOMPARE(table->rows(), 2);
|
|
QCOMPARE(table->columns(), 4);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_brokenTableWithJustTd()
|
|
{
|
|
doc->setHtml("<td>First Cell</td><td>Second Cell");
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QTextTable *table = cursor.currentTable();
|
|
QVERIFY(table);
|
|
QCOMPARE(table->rows(), 1);
|
|
QCOMPARE(table->columns(), 2);
|
|
QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("First Cell"));
|
|
QCOMPARE(table->cellAt(0, 1).firstCursorPosition().block().text(), QString("Second Cell"));
|
|
|
|
doc->setHtml("<td height=17 width=286 style='height:12.75pt;width:215pt'>1a</td>"
|
|
"<td width=64 style='width:48pt'>1b</td>"
|
|
"<td width=64 style='width:48pt'>1c</td>"
|
|
"<td width=64 style='width:48pt'>1d</td>");
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
table = cursor.currentTable();
|
|
QVERIFY(table);
|
|
QCOMPARE(table->rows(), 1);
|
|
QCOMPARE(table->columns(), 4);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_preNewlineHandling_data()
|
|
{
|
|
QTest::addColumn<QString>("html");
|
|
QTest::addColumn<QString>("expectedPlainText");
|
|
|
|
QTest::newRow("pre1") << QString("Foo<pre>Bar")
|
|
<< QString("Foo\nBar");
|
|
QTest::newRow("pre2") << QString("Foo<pre>\nBar")
|
|
<< QString("Foo\nBar");
|
|
QTest::newRow("pre3") << QString("Foo<pre>\n\nBar")
|
|
<< QString("Foo\n\nBar");
|
|
QTest::newRow("pre4") << QString("<html>Foo<pre>\nBar")
|
|
<< QString("Foo\nBar");
|
|
QTest::newRow("pre5") << QString("<pre>Foo\n</pre>\nBar")
|
|
<< QString("Foo\nBar");
|
|
QTest::newRow("pre6") << QString("<pre>Foo<b>Bar</b>Blah\n</pre>\nMooh")
|
|
<< QString("FooBarBlah\nMooh");
|
|
QTest::newRow("pre7") << QString("<pre>\nPara1\n</pre>\n<pre>\nPara2\n</pre>")
|
|
<< QString("Para1\nPara2");
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_preNewlineHandling()
|
|
{
|
|
QFETCH(QString, html);
|
|
|
|
doc->setHtml(html);
|
|
QTEST(doc->toPlainText(), "expectedPlainText");
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_br()
|
|
{
|
|
doc->setHtml("Foo<br><br><br>Blah");
|
|
QCOMPARE(doc->toPlainText(), QString("Foo\n\n\nBlah"));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_dl()
|
|
{
|
|
doc->setHtml("<dl><dt>term<dd>data</dl>Text afterwards");
|
|
QCOMPARE(doc->toPlainText(), QString("term\ndata\nText afterwards"));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_tableStrangeNewline()
|
|
{
|
|
doc->setHtml("<table><tr><td>Foo</td></tr>\n</table>");
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QTextTable *table = cursor.currentTable();
|
|
QVERIFY(table);
|
|
QCOMPARE(table->rows(), 1);
|
|
QCOMPARE(table->columns(), 1);
|
|
const QTextTableCell cell = table->cellAt(0, 0);
|
|
QCOMPARE(cell.firstCursorPosition().block().text(), QString("Foo"));
|
|
QCOMPARE(cell.firstCursorPosition().block(), cell.lastCursorPosition().block());
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_tableStrangeNewline2()
|
|
{
|
|
doc->setHtml("<table><tr><td>Foo</td></tr><tr>\n<td/></tr></table>");
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QTextTable *table = cursor.currentTable();
|
|
QVERIFY(table);
|
|
QCOMPARE(table->rows(), 2);
|
|
QCOMPARE(table->columns(), 1);
|
|
const QTextTableCell cell = table->cellAt(0, 0);
|
|
QCOMPARE(cell.firstCursorPosition().block().text(), QString("Foo"));
|
|
QCOMPARE(cell.firstCursorPosition().block(), cell.lastCursorPosition().block());
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_tableStrangeNewline3()
|
|
{
|
|
doc->setHtml("<table border>"
|
|
"<tr>"
|
|
"<td>"
|
|
"<ul>"
|
|
"<li>Meh</li>"
|
|
"</ul>"
|
|
"</td>"
|
|
"<td>\n"
|
|
"<ul>"
|
|
"<li>Foo</li>"
|
|
"</ul>"
|
|
"</td>"
|
|
"</tr>"
|
|
"</table>");
|
|
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QTextTable *table = cursor.currentTable();
|
|
QVERIFY(table);
|
|
QCOMPARE(table->rows(), 1);
|
|
QCOMPARE(table->columns(), 2);
|
|
|
|
QTextTableCell cell = table->cellAt(0, 0);
|
|
QCOMPARE(cell.firstCursorPosition().block().text(), QString("Meh"));
|
|
QCOMPARE(cell.firstCursorPosition().block(), cell.lastCursorPosition().block());
|
|
|
|
cell = table->cellAt(0, 1);
|
|
QCOMPARE(cell.firstCursorPosition().block().text(), QString("Foo"));
|
|
QCOMPARE(cell.firstCursorPosition().block(), cell.lastCursorPosition().block());
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_caption()
|
|
{
|
|
doc->setHtml("<table border align=center>"
|
|
"<caption>This <b> is a</b> Caption!</caption>"
|
|
"<tr><td>Blah</td></tr>"
|
|
"</table>");
|
|
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
|
|
QCOMPARE(cursor.block().text(), QString("This is a Caption!"));
|
|
QCOMPARE(cursor.blockFormat().alignment(), Qt::AlignHCenter);
|
|
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QTextTable *table = cursor.currentTable();
|
|
QVERIFY(table);
|
|
QCOMPARE(table->rows(), 1);
|
|
QCOMPARE(table->columns(), 1);
|
|
|
|
QTextTableCell cell = table->cellAt(0, 0);
|
|
QCOMPARE(cell.firstCursorPosition().block().text(), QString("Blah"));
|
|
}
|
|
|
|
static const uint windowsLatin1ExtendedCharacters[0xA0 - 0x80] = {
|
|
0x20ac, // 0x80
|
|
0x0081, // 0x81 direct mapping
|
|
0x201a, // 0x82
|
|
0x0192, // 0x83
|
|
0x201e, // 0x84
|
|
0x2026, // 0x85
|
|
0x2020, // 0x86
|
|
0x2021, // 0x87
|
|
0x02C6, // 0x88
|
|
0x2030, // 0x89
|
|
0x0160, // 0x8A
|
|
0x2039, // 0x8B
|
|
0x0152, // 0x8C
|
|
0x008D, // 0x8D direct mapping
|
|
0x017D, // 0x8E
|
|
0x008F, // 0x8F directmapping
|
|
0x0090, // 0x90 directmapping
|
|
0x2018, // 0x91
|
|
0x2019, // 0x92
|
|
0x201C, // 0x93
|
|
0X201D, // 0x94
|
|
0x2022, // 0x95
|
|
0x2013, // 0x96
|
|
0x2014, // 0x97
|
|
0x02DC, // 0x98
|
|
0x2122, // 0x99
|
|
0x0161, // 0x9A
|
|
0x203A, // 0x9B
|
|
0x0153, // 0x9C
|
|
0x009D, // 0x9D direct mapping
|
|
0x017E, // 0x9E
|
|
0x0178 // 0x9F
|
|
};
|
|
|
|
void tst_QTextDocumentFragment::html_windowsEntities()
|
|
{
|
|
for (uint i = 0; i < sizeof(windowsLatin1ExtendedCharacters)/sizeof(windowsLatin1ExtendedCharacters[0]); ++i) {
|
|
QString html = QString::number(i + 0x80);
|
|
html.prepend("<p>&#");
|
|
html.append(";");
|
|
doc->setHtml(html);
|
|
QCOMPARE(doc->toPlainText(), QString(QChar(windowsLatin1ExtendedCharacters[i])));
|
|
}
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_eatenText()
|
|
{
|
|
doc->setHtml("<h1>Test1</h1>\nTest2<h1>Test3</h1>");
|
|
cursor.movePosition(QTextCursor::Start);
|
|
QCOMPARE(cursor.block().text(), QString("Test1"));
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QCOMPARE(cursor.block().text(), QString("Test2"));
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QCOMPARE(cursor.block().text(), QString("Test3"));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_hr()
|
|
{
|
|
doc->setHtml("<hr />");
|
|
QCOMPARE(doc->blockCount(), 1);
|
|
QVERIFY(doc->begin().blockFormat().hasProperty(QTextFormat::BlockTrailingHorizontalRulerWidth));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_hrMargins()
|
|
{
|
|
doc->setHtml("<p>Test<hr/>Blah");
|
|
QCOMPARE(doc->blockCount(), 3);
|
|
|
|
cursor.movePosition(QTextCursor::Start);
|
|
QTextBlock block = cursor.block();
|
|
QCOMPARE(block.text(), QString("Test"));
|
|
QVERIFY(block.blockFormat().bottomMargin() <= qreal(12.));
|
|
QTextBlock first = block;
|
|
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
block = cursor.block();
|
|
QVERIFY(qMax(first.blockFormat().bottomMargin(), block.blockFormat().topMargin()) > 0);
|
|
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
block = cursor.block();
|
|
|
|
QCOMPARE(block.text(), QString("Blah"));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_blockQuoteMargins()
|
|
{
|
|
doc->setHtml("<blockquote>Bar</blockquote>");
|
|
QCOMPARE(doc->blockCount(), 1);
|
|
cursor.movePosition(QTextCursor::Start);
|
|
QTextBlock block = cursor.block();
|
|
QCOMPARE(block.text(), QString("Bar"));
|
|
QCOMPARE(block.blockFormat().leftMargin(), qreal(40.));
|
|
QCOMPARE(block.blockFormat().rightMargin(), qreal(40.));
|
|
QCOMPARE(block.blockFormat().topMargin(), qreal(12.));
|
|
QCOMPARE(block.blockFormat().bottomMargin(), qreal(12.));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_definitionListMargins()
|
|
{
|
|
doc->setHtml("Foo<dl><dt>tag<dd>data</dl>Bar");
|
|
QCOMPARE(doc->blockCount(), 4);
|
|
|
|
cursor.movePosition(QTextCursor::Start);
|
|
QTextBlock block = cursor.block();
|
|
QCOMPARE(block.text(), QString("Foo"));
|
|
|
|
block = block.next();
|
|
QCOMPARE(block.text(), QString("tag"));
|
|
QCOMPARE(block.blockFormat().topMargin(), qreal(8.));
|
|
|
|
block = block.next();
|
|
QCOMPARE(block.text(), QString("data"));
|
|
QCOMPARE(block.blockFormat().bottomMargin(), qreal(8.));
|
|
|
|
block = block.next();
|
|
QCOMPARE(block.text(), QString("Bar"));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_listMargins()
|
|
{
|
|
doc->setHtml("Foo<ol><li>First<li>Second</ol>Bar");
|
|
QCOMPARE(doc->blockCount(), 4);
|
|
|
|
cursor.movePosition(QTextCursor::Start);
|
|
QTextBlock block = cursor.block();
|
|
QCOMPARE(block.text(), QString("Foo"));
|
|
|
|
block = block.next();
|
|
QCOMPARE(block.text(), QString("First"));
|
|
QCOMPARE(block.blockFormat().topMargin(), qreal(12.));
|
|
|
|
block = block.next();
|
|
QCOMPARE(block.text(), QString("Second"));
|
|
QCOMPARE(block.blockFormat().bottomMargin(), qreal(12.));
|
|
|
|
block = block.next();
|
|
QCOMPARE(block.text(), QString("Bar"));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_titleAttribute()
|
|
{
|
|
doc->setHtml("<span title=\"this is my title\">Test</span>");
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextCharacter);
|
|
QCOMPARE(cursor.charFormat().toolTip(), QString("this is my title"));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_compressDivs()
|
|
{
|
|
doc->setHtml("<p/><div/><div/><div/><div/>Test");
|
|
QCOMPARE(doc->blockCount(), 1);
|
|
QCOMPARE(doc->begin().text(), QString("Test"));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::completeToPlainText()
|
|
{
|
|
doc->setPlainText("Hello\nWorld");
|
|
QCOMPARE(doc->toPlainText(), QString("Hello\nWorld"));
|
|
QTextDocumentFragment fragment(doc);
|
|
QCOMPARE(fragment.toPlainText(), QString("Hello\nWorld"));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::copyContents()
|
|
{
|
|
doc->setPlainText("Hello");
|
|
QFont f;
|
|
doc->setDefaultFont(f);
|
|
QTextFragment fragment = doc->begin().begin().fragment();
|
|
QCOMPARE(fragment.text(), QString("Hello"));
|
|
QCOMPARE(fragment.charFormat().font().pointSize(), f.pointSize());
|
|
|
|
QTextDocumentFragment frag(doc);
|
|
doc->clear();
|
|
f.setPointSize(48);
|
|
doc->setDefaultFont(f);
|
|
QTextCursor(doc).insertFragment(QTextDocumentFragment::fromHtml(frag.toHtml()));
|
|
fragment = doc->begin().begin().fragment();
|
|
QCOMPARE(fragment.text(), QString("Hello"));
|
|
QCOMPARE(fragment.charFormat().font().pointSize(), f.pointSize());
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_textAfterHr()
|
|
{
|
|
doc->setHtml("<hr><nobr><b>After the centered text</b></nobr>");
|
|
QCOMPARE(doc->blockCount(), 2);
|
|
QTextBlock block = doc->begin();
|
|
QVERIFY(block.text().isEmpty());
|
|
QVERIFY(block.blockFormat().hasProperty(QTextFormat::BlockTrailingHorizontalRulerWidth));
|
|
block = block.next();
|
|
|
|
QString txt("After the centered text");
|
|
txt.replace(QLatin1Char(' '), QChar::Nbsp);
|
|
QCOMPARE(block.text(), txt);
|
|
QVERIFY(!block.blockFormat().hasProperty(QTextFormat::BlockTrailingHorizontalRulerWidth));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::blockTagClosing()
|
|
{
|
|
doc->setHtml("<p>foo<p>bar<span>baz</span>");
|
|
QCOMPARE(doc->blockCount(), 2);
|
|
QTextBlock block = doc->begin();
|
|
QCOMPARE(block.text(), QString("foo"));
|
|
block = block.next();
|
|
QCOMPARE(block.text(), QString("barbaz"));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::isEmpty()
|
|
{
|
|
QTextDocumentFragment frag;
|
|
QVERIFY(frag.isEmpty());
|
|
frag = QTextDocumentFragment::fromHtml("test");
|
|
QVERIFY(!frag.isEmpty());
|
|
frag = QTextDocumentFragment::fromHtml("<hr />");
|
|
QVERIFY(!frag.isEmpty());
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_alignmentInheritance()
|
|
{
|
|
doc->setHtml("<center>Centered text<hr></center><b>After the centered text</b>");
|
|
QCOMPARE(doc->blockCount(), 3);
|
|
QTextBlock block = doc->begin();
|
|
QVERIFY(block.blockFormat().alignment() & Qt::AlignHCenter);
|
|
block = block.next();
|
|
QVERIFY(block.blockFormat().alignment() & Qt::AlignHCenter);
|
|
block = block.next();
|
|
QVERIFY(!(block.blockFormat().alignment() & Qt::AlignHCenter));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_ignoreEmptyDivs()
|
|
{
|
|
doc->setHtml("<p><div/><b>Foo</b>");
|
|
QCOMPARE(doc->blockCount(), 1);
|
|
QCOMPARE(doc->begin().text(), QString("Foo"));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_dontInheritAlignmentForFloatingImages()
|
|
{
|
|
doc->setHtml("<p align=right><img align=unknownignored src=\"foo\" /></p>");
|
|
QTextCharFormat fmt = doc->begin().begin().fragment().charFormat();
|
|
QVERIFY(fmt.isImageFormat());
|
|
QTextObject *o = doc->objectForFormat(fmt);
|
|
QVERIFY(o);
|
|
QTextFormat f = o->format();
|
|
QVERIFY(f.isFrameFormat());
|
|
QCOMPARE(f.toFrameFormat().position(), QTextFrameFormat::InFlow);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_verticalImageAlignment()
|
|
{
|
|
doc->setHtml("<img src=\"foo\"/>");
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextCharacter);
|
|
QVERIFY(cursor.charFormat().isImageFormat());
|
|
QTextImageFormat fmt = cursor.charFormat().toImageFormat();
|
|
QCOMPARE(fmt.verticalAlignment(), QTextCharFormat::AlignNormal);
|
|
|
|
doc->setHtml("<img src=\"foo\" align=middle />");
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextCharacter);
|
|
QVERIFY(cursor.charFormat().isImageFormat());
|
|
fmt = cursor.charFormat().toImageFormat();
|
|
QCOMPARE(fmt.verticalAlignment(), QTextCharFormat::AlignMiddle);
|
|
|
|
doc->setHtml("<img src=\"foo\" style=\"vertical-align: middle\" />");
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextCharacter);
|
|
QVERIFY(cursor.charFormat().isImageFormat());
|
|
fmt = cursor.charFormat().toImageFormat();
|
|
QCOMPARE(fmt.verticalAlignment(), QTextCharFormat::AlignMiddle);
|
|
|
|
doc->setHtml("<img src=\"foo\" align=top />");
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextCharacter);
|
|
QVERIFY(cursor.charFormat().isImageFormat());
|
|
fmt = cursor.charFormat().toImageFormat();
|
|
QCOMPARE(fmt.verticalAlignment(), QTextCharFormat::AlignTop);
|
|
|
|
doc->setHtml("<img src=\"foo\" style=\"vertical-align: top\" />");
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextCharacter);
|
|
QVERIFY(cursor.charFormat().isImageFormat());
|
|
fmt = cursor.charFormat().toImageFormat();
|
|
QCOMPARE(fmt.verticalAlignment(), QTextCharFormat::AlignTop);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_verticalCellAlignment()
|
|
{
|
|
const char *alt[] =
|
|
{
|
|
// vertical-align property
|
|
"<table>"
|
|
"<tr>"
|
|
"<td style=\"vertical-align: middle\"></td>"
|
|
"<td style=\"vertical-align: top\"></td>"
|
|
"<td style=\"vertical-align: bottom\"></td>"
|
|
"</tr>"
|
|
"</table>",
|
|
// valign property
|
|
"<table>"
|
|
"<tr>"
|
|
"<td valign=\"middle\"></td>"
|
|
"<td valign=\"top\"></td>"
|
|
"<td valign=\"bottom\"></td>"
|
|
"</tr>"
|
|
"</table>",
|
|
// test td override of tr property
|
|
"<table>"
|
|
"<tr valign=\"bottom\">"
|
|
"<td valign=\"middle\"></td>"
|
|
"<td valign=\"top\"></td>"
|
|
"<td></td>"
|
|
"</tr>"
|
|
"</table>"
|
|
};
|
|
|
|
const int numTestCases = sizeof(alt) / sizeof(*alt);
|
|
for (int i = 0; i < numTestCases; ++i) {
|
|
doc->setHtml(alt[i]);
|
|
|
|
QTextTable *table = qobject_cast<QTextTable *>(doc->rootFrame()->childFrames().at(0));
|
|
QVERIFY(table);
|
|
|
|
QCOMPARE(table->cellAt(0, 0).format().verticalAlignment(), QTextCharFormat::AlignMiddle);
|
|
QCOMPARE(table->cellAt(0, 1).format().verticalAlignment(), QTextCharFormat::AlignTop);
|
|
QCOMPARE(table->cellAt(0, 2).format().verticalAlignment(), QTextCharFormat::AlignBottom);
|
|
}
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_borderColor()
|
|
{
|
|
const char html[] = "<table border=1 style=\"border-color:#0000ff;\"><tr><td>Foo</td></tr></table>";
|
|
cursor.insertFragment(QTextDocumentFragment::fromHtml(QString::fromLatin1(html)));
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QVERIFY(cursor.currentTable());
|
|
QCOMPARE(cursor.currentTable()->format().borderStyle(), QTextFrameFormat::BorderStyle_Outset);
|
|
QCOMPARE(cursor.currentTable()->format().borderBrush(), QBrush(QColor("#0000ff")));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_borderStyle()
|
|
{
|
|
const char html[] = "<table border=1 style=\"border-style:solid;\"><tr><td>Foo</td></tr></table>";
|
|
cursor.insertFragment(QTextDocumentFragment::fromHtml(QString::fromLatin1(html)));
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QVERIFY(cursor.currentTable());
|
|
QCOMPARE(cursor.currentTable()->format().borderStyle(), QTextFrameFormat::BorderStyle_Solid);
|
|
QCOMPARE(cursor.currentTable()->format().borderBrush(), QBrush(Qt::darkGray));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_borderWidth()
|
|
{
|
|
const char *html[2] = { "<table style=\"border-width:2;\"><tr><td>Foo</td></tr></table>",
|
|
"<table style=\"border-width:2px;\"><tr><td>Foo</td></tr></table>" };
|
|
|
|
for (int i = 0; i < 2; ++i) {
|
|
cursor.insertFragment(QTextDocumentFragment::fromHtml(QString::fromLatin1(html[i])));
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextBlock);
|
|
QVERIFY(cursor.currentTable());
|
|
QCOMPARE(cursor.currentTable()->format().border(), qreal(2));
|
|
}
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_userState()
|
|
{
|
|
const char html[] = "<p style=\"-qt-user-state:42;\">A</p><p style=\"-qt-user-state:0;\">B</p><p>C</p>";
|
|
cursor.insertFragment(QTextDocumentFragment::fromHtml(QString::fromLatin1(html)));
|
|
QTextBlock block = doc->begin();
|
|
QCOMPARE(block.userState(), 42);
|
|
QCOMPARE(block.next().userState(), 0);
|
|
QCOMPARE(block.next().next().userState(), -1);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_rootFrameProperties()
|
|
{
|
|
const char html[] = "<table border=1 style=\"-qt-table-type:root; margin-top:10px;\"><tr><td>Foo</tr></td>";
|
|
doc->setHtml(html);
|
|
|
|
QCOMPARE(doc->rootFrame()->childFrames().size(), 0);
|
|
|
|
QTextFrameFormat fmt = doc->rootFrame()->frameFormat();
|
|
QCOMPARE(fmt.topMargin(), qreal(10));
|
|
QCOMPARE(fmt.bottomMargin(), qreal(0));
|
|
QCOMPARE(fmt.leftMargin(), qreal(0));
|
|
QCOMPARE(fmt.rightMargin(), qreal(0));
|
|
QCOMPARE(fmt.border(), qreal(1));
|
|
|
|
QString normalFrameHtml = QLatin1String(html);
|
|
normalFrameHtml.replace(QLatin1String("root"), QLatin1String("frame"));
|
|
|
|
doc->setHtml(normalFrameHtml);
|
|
QCOMPARE(doc->rootFrame()->childFrames().size(), 1);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_appendList()
|
|
{
|
|
appendHtml("<p>foo</p>");
|
|
appendHtml("<ul><li>Line 1</li><li>Line 2</li></ul>");
|
|
|
|
QCOMPARE(doc->blockCount(), 3);
|
|
QVERIFY(doc->begin().next().textList() != 0);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_appendList2()
|
|
{
|
|
appendHtml("1");
|
|
appendHtml("<ul><li><img src=\"/foo/bar\" /></li></ul>");
|
|
|
|
QCOMPARE(doc->blockCount(), 2);
|
|
QVERIFY(doc->begin().next().textList() != 0);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_alignmentPropertySet()
|
|
{
|
|
const char html[] = "<p>Test</p>";
|
|
setHtml(QString::fromLatin1(html));
|
|
QVERIFY(!doc->begin().blockFormat().hasProperty(QTextFormat::BlockAlignment));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_qt3RichtextWhitespaceMode()
|
|
{
|
|
setHtml(QString::fromLatin1("<html><head><meta name=\"qrichtext\" content=\"1\" /></head><p> line with whitespace</p><p> another line with whitespace</p></body></html>"));
|
|
QCOMPARE(doc->blockCount(), 2);
|
|
|
|
QTextBlock block = doc->begin();
|
|
QVERIFY(block.text().startsWith(" "));
|
|
|
|
block = block.next();
|
|
QVERIFY(block.text().startsWith(" "));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_brAfterHr()
|
|
{
|
|
setHtml(QString::fromLatin1("Text A<br><hr><br>Text B<hr>"));
|
|
|
|
QCOMPARE(doc->blockCount(), 4);
|
|
|
|
QTextBlock block = doc->begin();
|
|
QCOMPARE(block.text(), QString("Text A") + QChar(QChar::LineSeparator));
|
|
|
|
block = block.next();
|
|
QVERIFY(block.text().isEmpty());
|
|
|
|
block = block.next();
|
|
QCOMPARE(block.text(), QChar(QChar::LineSeparator) + QString("Text B"));
|
|
|
|
block = block.next();
|
|
QVERIFY(block.text().isEmpty());
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_unclosedHead()
|
|
{
|
|
doc->setHtml(QString::fromLatin1("<html><head><title>Test</title><body>Blah</body></html>"));
|
|
QCOMPARE(doc->metaInformation(QTextDocument::DocumentTitle), QString::fromLatin1("Test"));
|
|
QCOMPARE(doc->toPlainText(), QString::fromLatin1("Blah"));
|
|
}
|
|
|
|
// duplicated from qtexthtmlparser.cpp
|
|
#define MAX_ENTITY 258
|
|
static const struct { const char *name; quint16 code; } entities[MAX_ENTITY]= {
|
|
{ "AElig", 0x00c6 },
|
|
{ "Aacute", 0x00c1 },
|
|
{ "Acirc", 0x00c2 },
|
|
{ "Agrave", 0x00c0 },
|
|
{ "Alpha", 0x0391 },
|
|
{ "AMP", 38 },
|
|
{ "Aring", 0x00c5 },
|
|
{ "Atilde", 0x00c3 },
|
|
{ "Auml", 0x00c4 },
|
|
{ "Beta", 0x0392 },
|
|
{ "Ccedil", 0x00c7 },
|
|
{ "Chi", 0x03a7 },
|
|
{ "Dagger", 0x2021 },
|
|
{ "Delta", 0x0394 },
|
|
{ "ETH", 0x00d0 },
|
|
{ "Eacute", 0x00c9 },
|
|
{ "Ecirc", 0x00ca },
|
|
{ "Egrave", 0x00c8 },
|
|
{ "Epsilon", 0x0395 },
|
|
{ "Eta", 0x0397 },
|
|
{ "Euml", 0x00cb },
|
|
{ "Gamma", 0x0393 },
|
|
{ "GT", 62 },
|
|
{ "Iacute", 0x00cd },
|
|
{ "Icirc", 0x00ce },
|
|
{ "Igrave", 0x00cc },
|
|
{ "Iota", 0x0399 },
|
|
{ "Iuml", 0x00cf },
|
|
{ "Kappa", 0x039a },
|
|
{ "Lambda", 0x039b },
|
|
{ "LT", 60 },
|
|
{ "Mu", 0x039c },
|
|
{ "Ntilde", 0x00d1 },
|
|
{ "Nu", 0x039d },
|
|
{ "OElig", 0x0152 },
|
|
{ "Oacute", 0x00d3 },
|
|
{ "Ocirc", 0x00d4 },
|
|
{ "Ograve", 0x00d2 },
|
|
{ "Omega", 0x03a9 },
|
|
{ "Omicron", 0x039f },
|
|
{ "Oslash", 0x00d8 },
|
|
{ "Otilde", 0x00d5 },
|
|
{ "Ouml", 0x00d6 },
|
|
{ "Phi", 0x03a6 },
|
|
{ "Pi", 0x03a0 },
|
|
{ "Prime", 0x2033 },
|
|
{ "Psi", 0x03a8 },
|
|
{ "QUOT", 34 },
|
|
{ "Rho", 0x03a1 },
|
|
{ "Scaron", 0x0160 },
|
|
{ "Sigma", 0x03a3 },
|
|
{ "THORN", 0x00de },
|
|
{ "Tau", 0x03a4 },
|
|
{ "Theta", 0x0398 },
|
|
{ "Uacute", 0x00da },
|
|
{ "Ucirc", 0x00db },
|
|
{ "Ugrave", 0x00d9 },
|
|
{ "Upsilon", 0x03a5 },
|
|
{ "Uuml", 0x00dc },
|
|
{ "Xi", 0x039e },
|
|
{ "Yacute", 0x00dd },
|
|
{ "Yuml", 0x0178 },
|
|
{ "Zeta", 0x0396 },
|
|
{ "aacute", 0x00e1 },
|
|
{ "acirc", 0x00e2 },
|
|
{ "acute", 0x00b4 },
|
|
{ "aelig", 0x00e6 },
|
|
{ "agrave", 0x00e0 },
|
|
{ "alefsym", 0x2135 },
|
|
{ "alpha", 0x03b1 },
|
|
{ "amp", 38 },
|
|
{ "and", 0x22a5 },
|
|
{ "ang", 0x2220 },
|
|
{ "apos", 0x0027 },
|
|
{ "aring", 0x00e5 },
|
|
{ "asymp", 0x2248 },
|
|
{ "atilde", 0x00e3 },
|
|
{ "auml", 0x00e4 },
|
|
{ "bdquo", 0x201e },
|
|
{ "beta", 0x03b2 },
|
|
{ "brvbar", 0x00a6 },
|
|
{ "bull", 0x2022 },
|
|
{ "cap", 0x2229 },
|
|
{ "ccedil", 0x00e7 },
|
|
{ "cedil", 0x00b8 },
|
|
{ "cent", 0x00a2 },
|
|
{ "chi", 0x03c7 },
|
|
{ "circ", 0x02c6 },
|
|
{ "clubs", 0x2663 },
|
|
{ "cong", 0x2245 },
|
|
{ "copy", 0x00a9 },
|
|
{ "crarr", 0x21b5 },
|
|
{ "cup", 0x222a },
|
|
{ "curren", 0x00a4 },
|
|
{ "dArr", 0x21d3 },
|
|
{ "dagger", 0x2020 },
|
|
{ "darr", 0x2193 },
|
|
{ "deg", 0x00b0 },
|
|
{ "delta", 0x03b4 },
|
|
{ "diams", 0x2666 },
|
|
{ "divide", 0x00f7 },
|
|
{ "eacute", 0x00e9 },
|
|
{ "ecirc", 0x00ea },
|
|
{ "egrave", 0x00e8 },
|
|
{ "empty", 0x2205 },
|
|
{ "emsp", 0x2003 },
|
|
{ "ensp", 0x2002 },
|
|
{ "epsilon", 0x03b5 },
|
|
{ "equiv", 0x2261 },
|
|
{ "eta", 0x03b7 },
|
|
{ "eth", 0x00f0 },
|
|
{ "euml", 0x00eb },
|
|
{ "euro", 0x20ac },
|
|
{ "exist", 0x2203 },
|
|
{ "fnof", 0x0192 },
|
|
{ "forall", 0x2200 },
|
|
{ "frac12", 0x00bd },
|
|
{ "frac14", 0x00bc },
|
|
{ "frac34", 0x00be },
|
|
{ "frasl", 0x2044 },
|
|
{ "gamma", 0x03b3 },
|
|
{ "ge", 0x2265 },
|
|
{ "gt", 62 },
|
|
{ "hArr", 0x21d4 },
|
|
{ "harr", 0x2194 },
|
|
{ "hearts", 0x2665 },
|
|
{ "hellip", 0x2026 },
|
|
{ "iacute", 0x00ed },
|
|
{ "icirc", 0x00ee },
|
|
{ "iexcl", 0x00a1 },
|
|
{ "igrave", 0x00ec },
|
|
{ "image", 0x2111 },
|
|
{ "infin", 0x221e },
|
|
{ "int", 0x222b },
|
|
{ "iota", 0x03b9 },
|
|
{ "iquest", 0x00bf },
|
|
{ "isin", 0x2208 },
|
|
{ "iuml", 0x00ef },
|
|
{ "kappa", 0x03ba },
|
|
{ "lArr", 0x21d0 },
|
|
{ "lambda", 0x03bb },
|
|
{ "lang", 0x2329 },
|
|
{ "laquo", 0x00ab },
|
|
{ "larr", 0x2190 },
|
|
{ "lceil", 0x2308 },
|
|
{ "ldquo", 0x201c },
|
|
{ "le", 0x2264 },
|
|
{ "lfloor", 0x230a },
|
|
{ "lowast", 0x2217 },
|
|
{ "loz", 0x25ca },
|
|
{ "lrm", 0x200e },
|
|
{ "lsaquo", 0x2039 },
|
|
{ "lsquo", 0x2018 },
|
|
{ "lt", 60 },
|
|
{ "macr", 0x00af },
|
|
{ "mdash", 0x2014 },
|
|
{ "micro", 0x00b5 },
|
|
{ "middot", 0x00b7 },
|
|
{ "minus", 0x2212 },
|
|
{ "mu", 0x03bc },
|
|
{ "nabla", 0x2207 },
|
|
{ "nbsp", 0x00a0 },
|
|
{ "ndash", 0x2013 },
|
|
{ "ne", 0x2260 },
|
|
{ "ni", 0x220b },
|
|
{ "not", 0x00ac },
|
|
{ "notin", 0x2209 },
|
|
{ "nsub", 0x2284 },
|
|
{ "ntilde", 0x00f1 },
|
|
{ "nu", 0x03bd },
|
|
{ "oacute", 0x00f3 },
|
|
{ "ocirc", 0x00f4 },
|
|
{ "oelig", 0x0153 },
|
|
{ "ograve", 0x00f2 },
|
|
{ "oline", 0x203e },
|
|
{ "omega", 0x03c9 },
|
|
{ "omicron", 0x03bf },
|
|
{ "oplus", 0x2295 },
|
|
{ "or", 0x22a6 },
|
|
{ "ordf", 0x00aa },
|
|
{ "ordm", 0x00ba },
|
|
{ "oslash", 0x00f8 },
|
|
{ "otilde", 0x00f5 },
|
|
{ "otimes", 0x2297 },
|
|
{ "ouml", 0x00f6 },
|
|
{ "para", 0x00b6 },
|
|
{ "part", 0x2202 },
|
|
{ "percnt", 0x0025 },
|
|
{ "permil", 0x2030 },
|
|
{ "perp", 0x22a5 },
|
|
{ "phi", 0x03c6 },
|
|
{ "pi", 0x03c0 },
|
|
{ "piv", 0x03d6 },
|
|
{ "plusmn", 0x00b1 },
|
|
{ "pound", 0x00a3 },
|
|
{ "prime", 0x2032 },
|
|
{ "prod", 0x220f },
|
|
{ "prop", 0x221d },
|
|
{ "psi", 0x03c8 },
|
|
{ "quot", 34 },
|
|
{ "rArr", 0x21d2 },
|
|
{ "radic", 0x221a },
|
|
{ "rang", 0x232a },
|
|
{ "raquo", 0x00bb },
|
|
{ "rarr", 0x2192 },
|
|
{ "rceil", 0x2309 },
|
|
{ "rdquo", 0x201d },
|
|
{ "real", 0x211c },
|
|
{ "reg", 0x00ae },
|
|
{ "rfloor", 0x230b },
|
|
{ "rho", 0x03c1 },
|
|
{ "rlm", 0x200f },
|
|
{ "rsaquo", 0x203a },
|
|
{ "rsquo", 0x2019 },
|
|
{ "sbquo", 0x201a },
|
|
{ "scaron", 0x0161 },
|
|
{ "sdot", 0x22c5 },
|
|
{ "sect", 0x00a7 },
|
|
{ "shy", 0x00ad },
|
|
{ "sigma", 0x03c3 },
|
|
{ "sigmaf", 0x03c2 },
|
|
{ "sim", 0x223c },
|
|
{ "spades", 0x2660 },
|
|
{ "sub", 0x2282 },
|
|
{ "sube", 0x2286 },
|
|
{ "sum", 0x2211 },
|
|
{ "sup1", 0x00b9 },
|
|
{ "sup2", 0x00b2 },
|
|
{ "sup3", 0x00b3 },
|
|
{ "sup", 0x2283 },
|
|
{ "supe", 0x2287 },
|
|
{ "szlig", 0x00df },
|
|
{ "tau", 0x03c4 },
|
|
{ "there4", 0x2234 },
|
|
{ "theta", 0x03b8 },
|
|
{ "thetasym", 0x03d1 },
|
|
{ "thinsp", 0x2009 },
|
|
{ "thorn", 0x00fe },
|
|
{ "tilde", 0x02dc },
|
|
{ "times", 0x00d7 },
|
|
{ "trade", 0x2122 },
|
|
{ "uArr", 0x21d1 },
|
|
{ "uacute", 0x00fa },
|
|
{ "uarr", 0x2191 },
|
|
{ "ucirc", 0x00fb },
|
|
{ "ugrave", 0x00f9 },
|
|
{ "uml", 0x00a8 },
|
|
{ "upsih", 0x03d2 },
|
|
{ "upsilon", 0x03c5 },
|
|
{ "uuml", 0x00fc },
|
|
{ "weierp", 0x2118 },
|
|
{ "xi", 0x03be },
|
|
{ "yacute", 0x00fd },
|
|
{ "yen", 0x00a5 },
|
|
{ "yuml", 0x00ff },
|
|
{ "zeta", 0x03b6 },
|
|
{ "zwj", 0x200d },
|
|
{ "zwnj", 0x200c }
|
|
};
|
|
|
|
void tst_QTextDocumentFragment::html_entities_data()
|
|
{
|
|
QTest::addColumn<QString>("html");
|
|
QTest::addColumn<quint16>("code");
|
|
|
|
for (int i = 0; i < MAX_ENTITY; ++i) {
|
|
QTest::newRow(entities[i].name) << QString("<pre>&") + QString::fromLatin1(entities[i].name) + QString(";</pre>")
|
|
<< entities[i].code;
|
|
}
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_entities()
|
|
{
|
|
QFETCH(QString, html);
|
|
QFETCH(quint16, code);
|
|
|
|
setHtml(html);
|
|
QCOMPARE(doc->blockCount(), 1);
|
|
QString txt = doc->begin().text();
|
|
QCOMPARE(txt.length(), 1);
|
|
QCOMPARE(txt.at(0).unicode(), code);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_ignore_script()
|
|
{
|
|
doc->setHtml(QString::fromLatin1("<html><script>Test</script><body>Blah</body></html>"));
|
|
QCOMPARE(doc->toPlainText(), QString("Blah"));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_directionWithHtml()
|
|
{
|
|
doc->setHtml(QString::fromLatin1("<html><body><p>Test<p dir=rtl>RTL<p dir=ltr>LTR"));
|
|
QCOMPARE(doc->blockCount(), 3);
|
|
|
|
QTextBlock block = doc->firstBlock();
|
|
QVERIFY(block.blockFormat().hasProperty(QTextFormat::LayoutDirection));
|
|
QVERIFY(block.blockFormat().layoutDirection() == Qt::LeftToRight); // HTML default
|
|
|
|
block = block.next();
|
|
QVERIFY(block.blockFormat().hasProperty(QTextFormat::LayoutDirection));
|
|
QCOMPARE(block.blockFormat().layoutDirection(), Qt::RightToLeft);
|
|
|
|
block = block.next();
|
|
QVERIFY(block.blockFormat().hasProperty(QTextFormat::LayoutDirection));
|
|
QCOMPARE(block.blockFormat().layoutDirection(), Qt::LeftToRight);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_directionWithRichText()
|
|
{
|
|
doc->setHtml(QString::fromLatin1("<p>Test<p dir=rtl>RTL<p dir=ltr>LTR"));
|
|
QCOMPARE(doc->blockCount(), 3);
|
|
|
|
QTextBlock block = doc->firstBlock();
|
|
QVERIFY(!block.blockFormat().hasProperty(QTextFormat::LayoutDirection));
|
|
|
|
block = block.next();
|
|
QVERIFY(block.blockFormat().hasProperty(QTextFormat::LayoutDirection));
|
|
QCOMPARE(block.blockFormat().layoutDirection(), Qt::RightToLeft);
|
|
|
|
block = block.next();
|
|
QVERIFY(block.blockFormat().hasProperty(QTextFormat::LayoutDirection));
|
|
QCOMPARE(block.blockFormat().layoutDirection(), Qt::LeftToRight);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_metaInBody()
|
|
{
|
|
setHtml("<body>Hello<meta>World</body>");
|
|
QCOMPARE(doc->toPlainText(), QString("HelloWorld"));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_importImageWithoutAspectRatio()
|
|
{
|
|
doc->setHtml("<img src=\"foo\" width=\"100%\" height=\"43\">");
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextCharacter);
|
|
QVERIFY(cursor.charFormat().isImageFormat());
|
|
QTextImageFormat fmt = cursor.charFormat().toImageFormat();
|
|
// qDebug() << fmt.width() << fmt.height();
|
|
QVERIFY (fmt.hasProperty(QTextFormat::ImageWidth));
|
|
QCOMPARE (fmt.height(), 43.);
|
|
|
|
doc->setHtml("<img src=\"foo\" height=\"43\">");
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextCharacter);
|
|
QVERIFY(cursor.charFormat().isImageFormat());
|
|
fmt = cursor.charFormat().toImageFormat();
|
|
QVERIFY (! fmt.hasProperty(QTextFormat::ImageWidth));
|
|
QCOMPARE (fmt.height(), 43.);
|
|
|
|
doc->setHtml("<img src=\"foo\" width=\"200\">");
|
|
cursor.movePosition(QTextCursor::Start);
|
|
cursor.movePosition(QTextCursor::NextCharacter);
|
|
QVERIFY(cursor.charFormat().isImageFormat());
|
|
fmt = cursor.charFormat().toImageFormat();
|
|
QVERIFY (! fmt.hasProperty(QTextFormat::ImageHeight));
|
|
QCOMPARE (fmt.width(), 200.);
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_fromFirefox()
|
|
{
|
|
// if you have a html loaded in firefox like <html>Test\nText</html> then selecting all and copying will
|
|
// result in the following text on the clipboard (for text/html)
|
|
doc->setHtml(QString::fromLatin1("<!--StartFragment-->Test\nText\n\n<!--EndFragment-->"));
|
|
QCOMPARE(doc->toPlainText(), QString::fromLatin1("Test Text "));
|
|
}
|
|
|
|
void tst_QTextDocumentFragment::html_emptyInlineInsideBlock()
|
|
{
|
|
doc->setHtml(QString::fromLatin1("<!--StartFragment--><blockquote><span/>Foobar</blockquote><!--EndFragment-->"));
|
|
QVERIFY(doc->firstBlock().blockFormat().leftMargin() > 0);
|
|
}
|
|
|
|
QTEST_MAIN(tst_QTextDocumentFragment)
|
|
#include "tst_qtextdocumentfragment.moc"
|