qtdeclarative/tests/auto/quick/qquicktext/tst_qquicktext.cpp

3607 lines
139 KiB
C++
Raw Normal View History

/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <qtest.h>
#include <QtTest/QSignalSpy>
#include <QTextDocument>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcomponent.h>
Say hello to QtQuick module This change moves the QtQuick 2 types and C++ API (including SceneGraph) to a new module (AKA library), QtQuick. 99% of this change is moving files from src/declarative to src/quick, and from tests/auto/declarative to tests/auto/qtquick2. The loading of QtQuick 2 ("import QtQuick 2.0") is now delegated to a plugin, src/imports/qtquick2, just like it's done for QtQuick 1. All tools, examples, and tests that use QtQuick C++ API have gotten "QT += quick" or "QT += quick-private" added to their .pro file. A few additional internal QtDeclarative classes had to be exported (via Q_DECLARATIVE_PRIVATE_EXPORT) since they're needed by the QtQuick 2 implementation. The old header locations (e.g. QtDeclarative/qquickitem.h) will still be supported for some time, but will produce compile-time warnings. (To avoid the QtQuick implementation using the compatibility headers (since QtDeclarative's includepath comes first), a few include statements were modified, e.g. from "#include <qsgnode.h>" to "#include <QtQuick/qsgnode.h>".) There's a change in qtbase that automatically adds QtQuick to the module list if QtDeclarative is used. Together with the compatibility headers, this should help reduce the migration pain for existing projects. In theory, simply getting an existing QtDeclarative-based project to compile and link shouldn't require any changes for now -- but porting to the new scheme is of course recommended, and will eventually become mandatory. Task-number: QTBUG-22889 Reviewed-by: Lars Knoll <lars.knoll@nokia.com> Change-Id: Ia52be9373172ba2f37e7623231ecb060316c96a7 Reviewed-by: Kent Hansen <kent.hansen@nokia.com> Reviewed-by: Sergio Ahumada <sergio.ahumada@nokia.com>
2011-11-23 14:14:07 +00:00
#include <QtQuick/private/qquicktext_p.h>
#include <private/qquicktext_p_p.h>
#include <private/qquickvaluetypes_p.h>
#include <QFontMetrics>
#include <qmath.h>
Say hello to QtQuick module This change moves the QtQuick 2 types and C++ API (including SceneGraph) to a new module (AKA library), QtQuick. 99% of this change is moving files from src/declarative to src/quick, and from tests/auto/declarative to tests/auto/qtquick2. The loading of QtQuick 2 ("import QtQuick 2.0") is now delegated to a plugin, src/imports/qtquick2, just like it's done for QtQuick 1. All tools, examples, and tests that use QtQuick C++ API have gotten "QT += quick" or "QT += quick-private" added to their .pro file. A few additional internal QtDeclarative classes had to be exported (via Q_DECLARATIVE_PRIVATE_EXPORT) since they're needed by the QtQuick 2 implementation. The old header locations (e.g. QtDeclarative/qquickitem.h) will still be supported for some time, but will produce compile-time warnings. (To avoid the QtQuick implementation using the compatibility headers (since QtDeclarative's includepath comes first), a few include statements were modified, e.g. from "#include <qsgnode.h>" to "#include <QtQuick/qsgnode.h>".) There's a change in qtbase that automatically adds QtQuick to the module list if QtDeclarative is used. Together with the compatibility headers, this should help reduce the migration pain for existing projects. In theory, simply getting an existing QtDeclarative-based project to compile and link shouldn't require any changes for now -- but porting to the new scheme is of course recommended, and will eventually become mandatory. Task-number: QTBUG-22889 Reviewed-by: Lars Knoll <lars.knoll@nokia.com> Change-Id: Ia52be9373172ba2f37e7623231ecb060316c96a7 Reviewed-by: Kent Hansen <kent.hansen@nokia.com> Reviewed-by: Sergio Ahumada <sergio.ahumada@nokia.com>
2011-11-23 14:14:07 +00:00
#include <QtQuick/QQuickView>
#include <private/qguiapplication_p.h>
#include <limits.h>
#include <QtGui/QMouseEvent>
Say hello to QtQuick module This change moves the QtQuick 2 types and C++ API (including SceneGraph) to a new module (AKA library), QtQuick. 99% of this change is moving files from src/declarative to src/quick, and from tests/auto/declarative to tests/auto/qtquick2. The loading of QtQuick 2 ("import QtQuick 2.0") is now delegated to a plugin, src/imports/qtquick2, just like it's done for QtQuick 1. All tools, examples, and tests that use QtQuick C++ API have gotten "QT += quick" or "QT += quick-private" added to their .pro file. A few additional internal QtDeclarative classes had to be exported (via Q_DECLARATIVE_PRIVATE_EXPORT) since they're needed by the QtQuick 2 implementation. The old header locations (e.g. QtDeclarative/qquickitem.h) will still be supported for some time, but will produce compile-time warnings. (To avoid the QtQuick implementation using the compatibility headers (since QtDeclarative's includepath comes first), a few include statements were modified, e.g. from "#include <qsgnode.h>" to "#include <QtQuick/qsgnode.h>".) There's a change in qtbase that automatically adds QtQuick to the module list if QtDeclarative is used. Together with the compatibility headers, this should help reduce the migration pain for existing projects. In theory, simply getting an existing QtDeclarative-based project to compile and link shouldn't require any changes for now -- but porting to the new scheme is of course recommended, and will eventually become mandatory. Task-number: QTBUG-22889 Reviewed-by: Lars Knoll <lars.knoll@nokia.com> Change-Id: Ia52be9373172ba2f37e7623231ecb060316c96a7 Reviewed-by: Kent Hansen <kent.hansen@nokia.com> Reviewed-by: Sergio Ahumada <sergio.ahumada@nokia.com>
2011-11-23 14:14:07 +00:00
#include "../../shared/util.h"
#include "testhttpserver.h"
DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
#define SERVER_PORT 14459
#define SERVER_ADDR "http://127.0.0.1:14459"
Q_DECLARE_METATYPE(QQuickText::TextFormat)
QT_BEGIN_NAMESPACE
extern void qt_setQtEnableTestFont(bool value);
QT_END_NAMESPACE
class tst_qquicktext : public QQmlDataTest
{
Q_OBJECT
public:
tst_qquicktext();
private slots:
void text();
void width();
void wrap();
void elide();
void multilineElide_data();
void multilineElide();
void implicitElide_data();
void implicitElide();
void textFormat();
void alignments_data();
void alignments();
void baseUrl();
void embeddedImages_data();
void embeddedImages();
void lineCount();
void lineHeight();
// ### these tests may be trivial
void horizontalAlignment();
void horizontalAlignment_RightToLeft();
void verticalAlignment();
void hAlignImplicitWidth();
void font();
void style();
void color();
void smooth();
// QQuickFontValueType
void weight();
void underline();
void overline();
void strikeout();
void capitalization();
void letterSpacing();
void wordSpacing();
void clickLink_data();
void clickLink();
void implicitSize_data();
void implicitSize();
void contentSize();
void implicitSizeBinding_data();
void implicitSizeBinding();
void geometryChanged();
void boundingRect_data();
void boundingRect();
void clipRect();
void lineLaidOut();
void lineLaidOutRelayout();
void imgTagsBaseUrl_data();
void imgTagsBaseUrl();
void imgTagsAlign_data();
void imgTagsAlign();
void imgTagsMultipleImages();
void imgTagsElide();
void imgTagsUpdates();
void imgTagsError();
void fontSizeMode_data();
void fontSizeMode();
void fontSizeModeMultiline_data();
void fontSizeModeMultiline();
void multilengthStrings_data();
void multilengthStrings();
void fontFormatSizes_data();
void fontFormatSizes();
void baselineOffset_data();
void baselineOffset();
void htmlLists();
void htmlLists_data();
private:
QStringList standard;
QStringList richText;
QStringList horizontalAlignmentmentStrings;
QStringList verticalAlignmentmentStrings;
QList<Qt::Alignment> verticalAlignmentments;
QList<Qt::Alignment> horizontalAlignmentments;
QStringList styleStrings;
QList<QQuickText::TextStyle> styles;
QStringList colorStrings;
QQmlEngine engine;
QQuickView *createView(const QString &filename);
int numberOfNonWhitePixels(int fromX, int toX, const QImage &image);
};
tst_qquicktext::tst_qquicktext()
{
standard << "the quick brown fox jumped over the lazy dog"
<< "the quick brown fox\n jumped over the lazy dog";
richText << "<i>the <b>quick</b> brown <a href=\\\"http://www.google.com\\\">fox</a> jumped over the <b>lazy</b> dog</i>"
<< "<i>the <b>quick</b> brown <a href=\\\"http://www.google.com\\\">fox</a><br>jumped over the <b>lazy</b> dog</i>";
horizontalAlignmentmentStrings << "AlignLeft"
<< "AlignRight"
<< "AlignHCenter";
verticalAlignmentmentStrings << "AlignTop"
<< "AlignBottom"
<< "AlignVCenter";
horizontalAlignmentments << Qt::AlignLeft
<< Qt::AlignRight
<< Qt::AlignHCenter;
verticalAlignmentments << Qt::AlignTop
<< Qt::AlignBottom
<< Qt::AlignVCenter;
styleStrings << "Normal"
<< "Outline"
<< "Raised"
<< "Sunken";
styles << QQuickText::Normal
<< QQuickText::Outline
<< QQuickText::Raised
<< QQuickText::Sunken;
colorStrings << "aliceblue"
<< "antiquewhite"
<< "aqua"
<< "darkkhaki"
<< "darkolivegreen"
<< "dimgray"
<< "palevioletred"
<< "lightsteelblue"
<< "#000000"
<< "#AAAAAA"
<< "#FFFFFF"
<< "#2AC05F";
//
// need a different test to do alpha channel test
// << "#AA0011DD"
// << "#00F16B11";
//
qt_setQtEnableTestFont(true);
}
QQuickView *tst_qquicktext::createView(const QString &filename)
{
QQuickView *window = new QQuickView(0);
window->setSource(QUrl::fromLocalFile(filename));
return window;
}
void tst_qquicktext::text()
{
{
QQmlComponent textComponent(&engine);
textComponent.setData("import QtQuick 2.0\nText { text: \"\" }", QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QVERIFY(textObject != 0);
QCOMPARE(textObject->text(), QString(""));
QVERIFY(textObject->width() == 0);
delete textObject;
}
for (int i = 0; i < standard.size(); i++)
{
QString componentStr = "import QtQuick 2.0\nText { text: \"" + standard.at(i) + "\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QVERIFY(textObject != 0);
QCOMPARE(textObject->text(), standard.at(i));
QVERIFY(textObject->width() > 0);
delete textObject;
}
for (int i = 0; i < richText.size(); i++)
{
QString componentStr = "import QtQuick 2.0\nText { text: \"" + richText.at(i) + "\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QVERIFY(textObject != 0);
QString expected = richText.at(i);
QCOMPARE(textObject->text(), expected.replace("\\\"", "\""));
QVERIFY(textObject->width() > 0);
delete textObject;
}
}
void tst_qquicktext::width()
{
// uses Font metrics to find the width for standard and document to find the width for rich
{
QQmlComponent textComponent(&engine);
textComponent.setData("import QtQuick 2.0\nText { text: \"\" }", QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QVERIFY(textObject != 0);
QCOMPARE(textObject->width(), 0.);
delete textObject;
}
bool requiresUnhintedMetrics = !qmlDisableDistanceField();
for (int i = 0; i < standard.size(); i++)
{
QVERIFY(!Qt::mightBeRichText(standard.at(i))); // self-test
QFont f;
qreal metricWidth = 0.0;
if (requiresUnhintedMetrics) {
QString s = standard.at(i);
s.replace(QLatin1Char('\n'), QChar::LineSeparator);
QTextLayout layout(s);
layout.setFlags(Qt::TextExpandTabs | Qt::TextShowMnemonic);
{
QTextOption option;
option.setUseDesignMetrics(true);
layout.setTextOption(option);
}
layout.beginLayout();
forever {
QTextLine line = layout.createLine();
if (!line.isValid())
break;
}
layout.endLayout();
metricWidth = layout.boundingRect().width();
} else {
QFontMetricsF fm(f);
metricWidth = fm.size(Qt::TextExpandTabs && Qt::TextShowMnemonic, standard.at(i)).width();
}
QString componentStr = "import QtQuick 2.0\nText { text: \"" + standard.at(i) + "\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QVERIFY(textObject != 0);
QVERIFY(textObject->boundingRect().width() > 0);
QCOMPARE(textObject->width(), qreal(metricWidth));
QVERIFY(textObject->textFormat() == QQuickText::AutoText); // setting text doesn't change format
delete textObject;
}
for (int i = 0; i < richText.size(); i++)
{
QVERIFY(Qt::mightBeRichText(richText.at(i))); // self-test
QString componentStr = "import QtQuick 2.0\nText { text: \"" + richText.at(i) + "\"; textFormat: Text.RichText }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QVERIFY(textObject != 0);
QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
QVERIFY(textPrivate != 0);
QVERIFY(textPrivate->extra.isAllocated());
QTextDocument *doc = textPrivate->extra->doc;
QVERIFY(doc != 0);
QCOMPARE(int(textObject->width()), int(doc->idealWidth()));
QVERIFY(textObject->textFormat() == QQuickText::RichText);
delete textObject;
}
}
void tst_qquicktext::wrap()
{
int textHeight = 0;
// for specified width and wrap set true
{
QQmlComponent textComponent(&engine);
textComponent.setData("import QtQuick 2.0\nText { text: \"Hello\"; wrapMode: Text.WordWrap; width: 300 }", QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
textHeight = textObject->height();
QVERIFY(textObject != 0);
QVERIFY(textObject->wrapMode() == QQuickText::WordWrap);
QCOMPARE(textObject->width(), 300.);
delete textObject;
}
for (int i = 0; i < standard.size(); i++)
{
QString componentStr = "import QtQuick 2.0\nText { wrapMode: Text.WordWrap; width: 30; text: \"" + standard.at(i) + "\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QVERIFY(textObject != 0);
QCOMPARE(textObject->width(), 30.);
QVERIFY(textObject->height() > textHeight);
int oldHeight = textObject->height();
textObject->setWidth(100);
QVERIFY(textObject->height() < oldHeight);
delete textObject;
}
for (int i = 0; i < richText.size(); i++)
{
QString componentStr = "import QtQuick 2.0\nText { wrapMode: Text.WordWrap; width: 30; text: \"" + richText.at(i) + "\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QVERIFY(textObject != 0);
QCOMPARE(textObject->width(), 30.);
QVERIFY(textObject->height() > textHeight);
qreal oldHeight = textObject->height();
textObject->setWidth(100);
QVERIFY(textObject->height() < oldHeight);
delete textObject;
}
// richtext again with a fixed height
for (int i = 0; i < richText.size(); i++)
{
QString componentStr = "import QtQuick 2.0\nText { wrapMode: Text.WordWrap; width: 30; height: 50; text: \"" + richText.at(i) + "\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QVERIFY(textObject != 0);
QCOMPARE(textObject->width(), 30.);
QVERIFY(textObject->implicitHeight() > textHeight);
qreal oldHeight = textObject->implicitHeight();
textObject->setWidth(100);
QVERIFY(textObject->implicitHeight() < oldHeight);
delete textObject;
}
}
void tst_qquicktext::elide()
{
for (QQuickText::TextElideMode m = QQuickText::ElideLeft; m<=QQuickText::ElideNone; m=QQuickText::TextElideMode(int(m)+1)) {
const char* elidename[]={"ElideLeft", "ElideRight", "ElideMiddle", "ElideNone"};
QString elide = "elide: Text." + QString(elidename[int(m)]) + ";";
// XXX Poor coverage.
{
QQmlComponent textComponent(&engine);
textComponent.setData(("import QtQuick 2.0\nText { text: \"\"; "+elide+" width: 100 }").toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QCOMPARE(textObject->elideMode(), m);
QCOMPARE(textObject->width(), 100.);
delete textObject;
}
for (int i = 0; i < standard.size(); i++)
{
QString componentStr = "import QtQuick 2.0\nText { "+elide+" width: 100; text: \"" + standard.at(i) + "\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QCOMPARE(textObject->elideMode(), m);
QCOMPARE(textObject->width(), 100.);
if (m != QQuickText::ElideNone && !standard.at(i).contains('\n'))
QVERIFY(textObject->contentWidth() <= textObject->width());
delete textObject;
}
for (int i = 0; i < richText.size(); i++)
{
QString componentStr = "import QtQuick 2.0\nText { "+elide+" width: 100; text: \"" + richText.at(i) + "\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QCOMPARE(textObject->elideMode(), m);
QCOMPARE(textObject->width(), 100.);
if (m != QQuickText::ElideNone && standard.at(i).contains("<br>"))
QVERIFY(textObject->contentWidth() <= textObject->width());
delete textObject;
}
}
}
void tst_qquicktext::multilineElide_data()
{
QTest::addColumn<QQuickText::TextFormat>("format");
QTest::newRow("plain") << QQuickText::PlainText;
QTest::newRow("styled") << QQuickText::StyledText;
}
void tst_qquicktext::multilineElide()
{
QFETCH(QQuickText::TextFormat, format);
QQuickView *window = createView(testFile("multilineelide.qml"));
QQuickText *myText = qobject_cast<QQuickText*>(window->rootObject());
QVERIFY(myText != 0);
myText->setTextFormat(format);
QCOMPARE(myText->lineCount(), 3);
QCOMPARE(myText->truncated(), true);
qreal lineHeight = myText->contentHeight() / 3.;
// Set a valid height greater than the truncated content height and ensure the line count is
// unchanged.
myText->setHeight(200);
QCOMPARE(myText->lineCount(), 3);
QCOMPARE(myText->truncated(), true);
// reduce size and ensure fewer lines are drawn
myText->setHeight(lineHeight * 2);
QCOMPARE(myText->lineCount(), 2);
myText->setHeight(lineHeight);
QCOMPARE(myText->lineCount(), 1);
myText->setHeight(5);
QCOMPARE(myText->lineCount(), 1);
myText->setHeight(lineHeight * 3);
QCOMPARE(myText->lineCount(), 3);
// remove max count and show all lines.
myText->setHeight(1000);
myText->resetMaximumLineCount();
QCOMPARE(myText->truncated(), false);
// reduce size again
myText->setHeight(lineHeight * 2);
QCOMPARE(myText->lineCount(), 2);
QCOMPARE(myText->truncated(), true);
// change line height
myText->setLineHeight(1.1);
QCOMPARE(myText->lineCount(), 1);
delete window;
}
void tst_qquicktext::implicitElide_data()
{
QTest::addColumn<QString>("width");
QTest::addColumn<QString>("initialText");
QTest::addColumn<QString>("text");
QTest::newRow("maximum width, empty")
<< "Math.min(implicitWidth, 100)"
<< "";
QTest::newRow("maximum width, short")
<< "Math.min(implicitWidth, 100)"
<< "the";
QTest::newRow("maximum width, long")
<< "Math.min(implicitWidth, 100)"
<< "the quick brown fox jumped over the lazy dog";
QTest::newRow("reset width, empty")
<< "implicitWidth > 100 ? 100 : undefined"
<< "";
QTest::newRow("reset width, short")
<< "implicitWidth > 100 ? 100 : undefined"
<< "the";
QTest::newRow("reset width, long")
<< "implicitWidth > 100 ? 100 : undefined"
<< "the quick brown fox jumped over the lazy dog";
}
void tst_qquicktext::implicitElide()
{
QFETCH(QString, width);
QFETCH(QString, initialText);
QString componentStr =
"import QtQuick 2.0\n"
"Text {\n"
"width: " + width + "\n"
"text: \"" + initialText + "\"\n"
"elide: Text.ElideRight\n"
"}";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QVERIFY(textObject->contentWidth() <= textObject->width());
textObject->setText("the quick brown fox jumped over");
QVERIFY(textObject->contentWidth() > 0);
QVERIFY(textObject->contentWidth() <= textObject->width());
}
void tst_qquicktext::textFormat()
{
{
QQmlComponent textComponent(&engine);
textComponent.setData("import QtQuick 2.0\nText { text: \"Hello\"; textFormat: Text.RichText }", QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QVERIFY(textObject != 0);
QVERIFY(textObject->textFormat() == QQuickText::RichText);
QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
QVERIFY(textPrivate != 0);
QVERIFY(textPrivate->richText == true);
delete textObject;
}
{
QQmlComponent textComponent(&engine);
textComponent.setData("import QtQuick 2.0\nText { text: \"<b>Hello</b>\" }", QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QVERIFY(textObject != 0);
QVERIFY(textObject->textFormat() == QQuickText::AutoText);
QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
QVERIFY(textPrivate != 0);
QVERIFY(textPrivate->styledText == true);
delete textObject;
}
{
QQmlComponent textComponent(&engine);
textComponent.setData("import QtQuick 2.0\nText { text: \"<b>Hello</b>\"; textFormat: Text.PlainText }", QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QVERIFY(textObject != 0);
QVERIFY(textObject->textFormat() == QQuickText::PlainText);
delete textObject;
}
}
void tst_qquicktext::alignments_data()
{
QTest::addColumn<int>("hAlign");
QTest::addColumn<int>("vAlign");
QTest::addColumn<QString>("expectfile");
QTest::newRow("LT") << int(Qt::AlignLeft) << int(Qt::AlignTop) << testFile("alignments_lt.png");
QTest::newRow("RT") << int(Qt::AlignRight) << int(Qt::AlignTop) << testFile("alignments_rt.png");
QTest::newRow("CT") << int(Qt::AlignHCenter) << int(Qt::AlignTop) << testFile("alignments_ct.png");
QTest::newRow("LB") << int(Qt::AlignLeft) << int(Qt::AlignBottom) << testFile("alignments_lb.png");
QTest::newRow("RB") << int(Qt::AlignRight) << int(Qt::AlignBottom) << testFile("alignments_rb.png");
QTest::newRow("CB") << int(Qt::AlignHCenter) << int(Qt::AlignBottom) << testFile("alignments_cb.png");
QTest::newRow("LC") << int(Qt::AlignLeft) << int(Qt::AlignVCenter) << testFile("alignments_lc.png");
QTest::newRow("RC") << int(Qt::AlignRight) << int(Qt::AlignVCenter) << testFile("alignments_rc.png");
QTest::newRow("CC") << int(Qt::AlignHCenter) << int(Qt::AlignVCenter) << testFile("alignments_cc.png");
}
void tst_qquicktext::alignments()
{
QSKIP("Text alignment pixmap comparison tests will not work with scenegraph");
#if (0)// No widgets in scenegraph
QFETCH(int, hAlign);
QFETCH(int, vAlign);
QFETCH(QString, expectfile);
QQuickView *window = createView(testFile("alignments.qml"));
window->show();
window->requestActivateWindow();
QTest::qWait(50);
QTRY_COMPARE(QGuiApplication::activeWindow(), static_cast<QWidget *>(window));
QObject *ob = window->rootObject();
QVERIFY(ob != 0);
ob->setProperty("horizontalAlignment",hAlign);
ob->setProperty("verticalAlignment",vAlign);
QTRY_COMPARE(ob->property("running").toBool(),false);
QImage actual(window->width(), window->height(), QImage::Format_RGB32);
actual.fill(qRgb(255,255,255));
QPainter p(&actual);
window->render(&p);
QImage expect(expectfile);
if (QGuiApplicationPrivate::graphics_system_name == "raster" || QGuiApplicationPrivate::graphics_system_name == "") {
QCOMPARE(actual,expect);
}
delete window;
#endif
}
//the alignment tests may be trivial o.oa
void tst_qquicktext::horizontalAlignment()
{
//test one align each, and then test if two align fails.
for (int i = 0; i < standard.size(); i++)
{
for (int j=0; j < horizontalAlignmentmentStrings.size(); j++)
{
QString componentStr = "import QtQuick 2.0\nText { horizontalAlignment: \"" + horizontalAlignmentmentStrings.at(j) + "\"; text: \"" + standard.at(i) + "\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QCOMPARE((int)textObject->hAlign(), (int)horizontalAlignmentments.at(j));
delete textObject;
}
}
for (int i = 0; i < richText.size(); i++)
{
for (int j=0; j < horizontalAlignmentmentStrings.size(); j++)
{
QString componentStr = "import QtQuick 2.0\nText { horizontalAlignment: \"" + horizontalAlignmentmentStrings.at(j) + "\"; text: \"" + richText.at(i) + "\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QCOMPARE((int)textObject->hAlign(), (int)horizontalAlignmentments.at(j));
delete textObject;
}
}
}
void tst_qquicktext::horizontalAlignment_RightToLeft()
{
QQuickView *window = createView(testFile("horizontalAlignment_RightToLeft.qml"));
QQuickText *text = window->rootObject()->findChild<QQuickText*>("text");
QVERIFY(text != 0);
window->show();
QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(text);
QVERIFY(textPrivate != 0);
QTRY_VERIFY(textPrivate->layout.lineCount());
// implicit alignment should follow the reading direction of RTL text
QCOMPARE(text->hAlign(), QQuickText::AlignRight);
QCOMPARE(text->effectiveHAlign(), text->hAlign());
QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > window->width()/2);
// explicitly left aligned text
text->setHAlign(QQuickText::AlignLeft);
QCOMPARE(text->hAlign(), QQuickText::AlignLeft);
QCOMPARE(text->effectiveHAlign(), text->hAlign());
QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < window->width()/2);
// explicitly right aligned text
text->setHAlign(QQuickText::AlignRight);
QCOMPARE(text->hAlign(), QQuickText::AlignRight);
QCOMPARE(text->effectiveHAlign(), text->hAlign());
QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > window->width()/2);
// change to rich text
QString textString = text->text();
text->setText(QString("<i>") + textString + QString("</i>"));
text->setTextFormat(QQuickText::RichText);
text->resetHAlign();
// implicitly aligned rich text should follow the reading direction of text
QCOMPARE(text->hAlign(), QQuickText::AlignRight);
QCOMPARE(text->effectiveHAlign(), text->hAlign());
QVERIFY(textPrivate->extra.isAllocated());
QVERIFY(textPrivate->extra->doc->defaultTextOption().alignment() & Qt::AlignLeft);
// explicitly left aligned rich text
text->setHAlign(QQuickText::AlignLeft);
QCOMPARE(text->hAlign(), QQuickText::AlignLeft);
QCOMPARE(text->effectiveHAlign(), text->hAlign());
QVERIFY(textPrivate->extra->doc->defaultTextOption().alignment() & Qt::AlignRight);
// explicitly right aligned rich text
text->setHAlign(QQuickText::AlignRight);
QCOMPARE(text->hAlign(), QQuickText::AlignRight);
QCOMPARE(text->effectiveHAlign(), text->hAlign());
QVERIFY(textPrivate->extra->doc->defaultTextOption().alignment() & Qt::AlignLeft);
text->setText(textString);
text->setTextFormat(QQuickText::PlainText);
// explicitly center aligned
text->setHAlign(QQuickText::AlignHCenter);
QCOMPARE(text->hAlign(), QQuickText::AlignHCenter);
QCOMPARE(text->effectiveHAlign(), text->hAlign());
QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < window->width()/2);
QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().right() > window->width()/2);
// reseted alignment should go back to following the text reading direction
text->resetHAlign();
QCOMPARE(text->hAlign(), QQuickText::AlignRight);
QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > window->width()/2);
// mirror the text item
QQuickItemPrivate::get(text)->setLayoutMirror(true);
// mirrored implicit alignment should continue to follow the reading direction of the text
QCOMPARE(text->hAlign(), QQuickText::AlignRight);
QCOMPARE(text->effectiveHAlign(), QQuickText::AlignRight);
QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > window->width()/2);
// mirrored explicitly right aligned behaves as left aligned
text->setHAlign(QQuickText::AlignRight);
QCOMPARE(text->hAlign(), QQuickText::AlignRight);
QCOMPARE(text->effectiveHAlign(), QQuickText::AlignLeft);
QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < window->width()/2);
// mirrored explicitly left aligned behaves as right aligned
text->setHAlign(QQuickText::AlignLeft);
QCOMPARE(text->hAlign(), QQuickText::AlignLeft);
QCOMPARE(text->effectiveHAlign(), QQuickText::AlignRight);
QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > window->width()/2);
// disable mirroring
QQuickItemPrivate::get(text)->setLayoutMirror(false);
text->resetHAlign();
// English text should be implicitly left aligned
text->setText("Hello world!");
QCOMPARE(text->hAlign(), QQuickText::AlignLeft);
QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < window->width()/2);
// empty text with implicit alignment follows the system locale-based
// keyboard input direction from QInputMethod::inputDirection()
text->setText("");
QCOMPARE(text->hAlign(), qApp->inputMethod()->inputDirection() == Qt::LeftToRight ?
QQuickText::AlignLeft : QQuickText::AlignRight);
text->setHAlign(QQuickText::AlignRight);
QCOMPARE(text->hAlign(), QQuickText::AlignRight);
delete window;
// alignment of Text with no text set to it
QString componentStr = "import QtQuick 2.0\nText {}";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QCOMPARE(textObject->hAlign(), qApp->inputMethod()->inputDirection() == Qt::LeftToRight ?
QQuickText::AlignLeft : QQuickText::AlignRight);
delete textObject;
}
int tst_qquicktext::numberOfNonWhitePixels(int fromX, int toX, const QImage &image)
{
int pixels = 0;
for (int x = fromX; x < toX; ++x) {
for (int y = 0; y < image.height(); ++y) {
if (image.pixel(x, y) != qRgb(255, 255, 255))
pixels++;
}
}
return pixels;
}
void tst_qquicktext::hAlignImplicitWidth()
{
QQuickView view(testFileUrl("hAlignImplicitWidth.qml"));
view.show();
view.requestActivateWindow();
QVERIFY(QTest::qWaitForWindowActive(&view));
QQuickText *text = view.rootObject()->findChild<QQuickText*>("textItem");
QVERIFY(text != 0);
{
// Left Align
QImage image = view.grabWindow();
int left = numberOfNonWhitePixels(0, image.width() / 3, image);
int mid = numberOfNonWhitePixels(image.width() / 3, 2 * image.width() / 3, image);
int right = numberOfNonWhitePixels( 2 * image.width() / 3, image.width(), image);
QVERIFY(left > mid);
QVERIFY(mid > right);
}
{
// HCenter Align
text->setHAlign(QQuickText::AlignHCenter);
QImage image = view.grabWindow();
int left = numberOfNonWhitePixels(0, image.width() / 3, image);
int mid = numberOfNonWhitePixels(image.width() / 3, 2 * image.width() / 3, image);
int right = numberOfNonWhitePixels( 2 * image.width() / 3, image.width(), image);
QVERIFY(left < mid);
QVERIFY(mid > right);
}
{
// Right Align
text->setHAlign(QQuickText::AlignRight);
QImage image = view.grabWindow();
int left = numberOfNonWhitePixels(0, image.width() / 3, image);
int mid = numberOfNonWhitePixels(image.width() / 3, 2 * image.width() / 3, image);
int right = numberOfNonWhitePixels( 2 * image.width() / 3, image.width(), image);
QVERIFY(left < mid);
QVERIFY(mid < right);
}
}
void tst_qquicktext::verticalAlignment()
{
//test one align each, and then test if two align fails.
for (int i = 0; i < standard.size(); i++)
{
for (int j=0; j < verticalAlignmentmentStrings.size(); j++)
{
QString componentStr = "import QtQuick 2.0\nText { verticalAlignment: \"" + verticalAlignmentmentStrings.at(j) + "\"; text: \"" + standard.at(i) + "\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QVERIFY(textObject != 0);
QCOMPARE((int)textObject->vAlign(), (int)verticalAlignmentments.at(j));
delete textObject;
}
}
for (int i = 0; i < richText.size(); i++)
{
for (int j=0; j < verticalAlignmentmentStrings.size(); j++)
{
QString componentStr = "import QtQuick 2.0\nText { verticalAlignment: \"" + verticalAlignmentmentStrings.at(j) + "\"; text: \"" + richText.at(i) + "\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QVERIFY(textObject != 0);
QCOMPARE((int)textObject->vAlign(), (int)verticalAlignmentments.at(j));
delete textObject;
}
}
}
void tst_qquicktext::font()
{
//test size, then bold, then italic, then family
{
QString componentStr = "import QtQuick 2.0\nText { font.pointSize: 40; text: \"Hello World\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QCOMPARE(textObject->font().pointSize(), 40);
QCOMPARE(textObject->font().bold(), false);
QCOMPARE(textObject->font().italic(), false);
delete textObject;
}
{
QString componentStr = "import QtQuick 2.0\nText { font.pixelSize: 40; text: \"Hello World\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QCOMPARE(textObject->font().pixelSize(), 40);
QCOMPARE(textObject->font().bold(), false);
QCOMPARE(textObject->font().italic(), false);
delete textObject;
}
{
QString componentStr = "import QtQuick 2.0\nText { font.bold: true; text: \"Hello World\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QCOMPARE(textObject->font().bold(), true);
QCOMPARE(textObject->font().italic(), false);
delete textObject;
}
{
QString componentStr = "import QtQuick 2.0\nText { font.italic: true; text: \"Hello World\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QCOMPARE(textObject->font().italic(), true);
QCOMPARE(textObject->font().bold(), false);
delete textObject;
}
{
QString componentStr = "import QtQuick 2.0\nText { font.family: \"Helvetica\"; text: \"Hello World\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QCOMPARE(textObject->font().family(), QString("Helvetica"));
QCOMPARE(textObject->font().bold(), false);
QCOMPARE(textObject->font().italic(), false);
delete textObject;
}
{
QString componentStr = "import QtQuick 2.0\nText { font.family: \"\"; text: \"Hello World\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QCOMPARE(textObject->font().family(), QString(""));
delete textObject;
}
}
void tst_qquicktext::style()
{
//test style
for (int i = 0; i < styles.size(); i++)
{
QString componentStr = "import QtQuick 2.0\nText { style: \"" + styleStrings.at(i) + "\"; styleColor: \"white\"; text: \"Hello World\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QCOMPARE((int)textObject->style(), (int)styles.at(i));
QCOMPARE(textObject->styleColor(), QColor("white"));
delete textObject;
}
QString componentStr = "import QtQuick 2.0\nText { text: \"Hello World\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QRectF brPre = textObject->boundingRect();
textObject->setStyle(QQuickText::Outline);
QRectF brPost = textObject->boundingRect();
QVERIFY(brPre.width() < brPost.width());
QVERIFY(brPre.height() < brPost.height());
delete textObject;
}
void tst_qquicktext::color()
{
//test style
for (int i = 0; i < colorStrings.size(); i++)
{
QString componentStr = "import QtQuick 2.0\nText { color: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QCOMPARE(textObject->color(), QColor(colorStrings.at(i)));
QCOMPARE(textObject->styleColor(), QColor("black"));
QCOMPARE(textObject->linkColor(), QColor("blue"));
delete textObject;
}
for (int i = 0; i < colorStrings.size(); i++)
{
QString componentStr = "import QtQuick 2.0\nText { styleColor: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QCOMPARE(textObject->styleColor(), QColor(colorStrings.at(i)));
// default color to black?
QCOMPARE(textObject->color(), QColor("black"));
QCOMPARE(textObject->linkColor(), QColor("blue"));
delete textObject;
}
for (int i = 0; i < colorStrings.size(); i++)
{
QString componentStr = "import QtQuick 2.0\nText { linkColor: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QCOMPARE(textObject->styleColor(), QColor("black"));
QCOMPARE(textObject->color(), QColor("black"));
QCOMPARE(textObject->linkColor(), QColor(colorStrings.at(i)));
delete textObject;
}
for (int i = 0; i < colorStrings.size(); i++)
{
for (int j = 0; j < colorStrings.size(); j++)
{
QString componentStr = "import QtQuick 2.0\nText { "
"color: \"" + colorStrings.at(i) + "\"; "
"styleColor: \"" + colorStrings.at(j) + "\"; "
"linkColor: \"" + colorStrings.at(j) + "\"; "
"text: \"Hello World\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QCOMPARE(textObject->color(), QColor(colorStrings.at(i)));
QCOMPARE(textObject->styleColor(), QColor(colorStrings.at(j)));
QCOMPARE(textObject->linkColor(), QColor(colorStrings.at(j)));
delete textObject;
}
}
{
QString colorStr = "#AA001234";
QColor testColor("#001234");
testColor.setAlpha(170);
QString componentStr = "import QtQuick 2.0\nText { color: \"" + colorStr + "\"; text: \"Hello World\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QCOMPARE(textObject->color(), testColor);
delete textObject;
} {
QString colorStr = "#001234";
QColor testColor(colorStr);
QString componentStr = "import QtQuick 2.0\nText { color: \"" + colorStr + "\"; text: \"Hello World\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QScopedPointer<QObject> object(textComponent.create());
QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
QSignalSpy spy(textObject, SIGNAL(colorChanged()));
QCOMPARE(textObject->color(), testColor);
textObject->setColor(testColor);
QCOMPARE(textObject->color(), testColor);
QCOMPARE(spy.count(), 0);
testColor = QColor("black");
textObject->setColor(testColor);
QCOMPARE(textObject->color(), testColor);
QCOMPARE(spy.count(), 1);
} {
QString colorStr = "#001234";
QColor testColor(colorStr);
QString componentStr = "import QtQuick 2.0\nText { styleColor: \"" + colorStr + "\"; text: \"Hello World\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QScopedPointer<QObject> object(textComponent.create());
QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
QSignalSpy spy(textObject, SIGNAL(styleColorChanged()));
QCOMPARE(textObject->styleColor(), testColor);
textObject->setStyleColor(testColor);
QCOMPARE(textObject->styleColor(), testColor);
QCOMPARE(spy.count(), 0);
testColor = QColor("black");
textObject->setStyleColor(testColor);
QCOMPARE(textObject->styleColor(), testColor);
QCOMPARE(spy.count(), 1);
} {
QString colorStr = "#001234";
QColor testColor(colorStr);
QString componentStr = "import QtQuick 2.0\nText { linkColor: \"" + colorStr + "\"; text: \"Hello World\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QScopedPointer<QObject> object(textComponent.create());
QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
QSignalSpy spy(textObject, SIGNAL(linkColorChanged()));
QCOMPARE(textObject->linkColor(), testColor);
textObject->setLinkColor(testColor);
QCOMPARE(textObject->linkColor(), testColor);
QCOMPARE(spy.count(), 0);
testColor = QColor("black");
textObject->setLinkColor(testColor);
QCOMPARE(textObject->linkColor(), testColor);
QCOMPARE(spy.count(), 1);
}
}
void tst_qquicktext::smooth()
{
for (int i = 0; i < standard.size(); i++)
{
{
QString componentStr = "import QtQuick 2.0\nText { smooth: false; text: \"" + standard.at(i) + "\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QCOMPARE(textObject->smooth(), false);
delete textObject;
}
{
QString componentStr = "import QtQuick 2.0\nText { text: \"" + standard.at(i) + "\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QCOMPARE(textObject->smooth(), true);
delete textObject;
}
}
for (int i = 0; i < richText.size(); i++)
{
{
QString componentStr = "import QtQuick 2.0\nText { smooth: false; text: \"" + richText.at(i) + "\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QCOMPARE(textObject->smooth(), false);
delete textObject;
}
{
QString componentStr = "import QtQuick 2.0\nText { text: \"" + richText.at(i) + "\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QCOMPARE(textObject->smooth(), true);
delete textObject;
}
}
}
void tst_qquicktext::weight()
{
{
QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QVERIFY(textObject != 0);
QCOMPARE((int)textObject->font().weight(), (int)QQuickFontValueType::Normal);
delete textObject;
}
{
QString componentStr = "import QtQuick 2.0\nText { font.weight: \"Bold\"; text: \"Hello world!\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QVERIFY(textObject != 0);
QCOMPARE((int)textObject->font().weight(), (int)QQuickFontValueType::Bold);
delete textObject;
}
}
void tst_qquicktext::underline()
{
QQuickView view(testFileUrl("underline.qml"));
view.show();
view.requestActivateWindow();
QVERIFY(QTest::qWaitForWindowActive(&view));
QQuickText *textObject = view.rootObject()->findChild<QQuickText*>("myText");
QVERIFY(textObject != 0);
QCOMPARE(textObject->font().overline(), false);
QCOMPARE(textObject->font().underline(), true);
QCOMPARE(textObject->font().strikeOut(), false);
}
void tst_qquicktext::overline()
{
QQuickView view(testFileUrl("overline.qml"));
view.show();
view.requestActivateWindow();
QVERIFY(QTest::qWaitForWindowActive(&view));
QQuickText *textObject = view.rootObject()->findChild<QQuickText*>("myText");
QVERIFY(textObject != 0);
QCOMPARE(textObject->font().overline(), true);
QCOMPARE(textObject->font().underline(), false);
QCOMPARE(textObject->font().strikeOut(), false);
}
void tst_qquicktext::strikeout()
{
QQuickView view(testFileUrl("strikeout.qml"));
view.show();
view.requestActivateWindow();
QVERIFY(QTest::qWaitForWindowActive(&view));
QQuickText *textObject = view.rootObject()->findChild<QQuickText*>("myText");
QVERIFY(textObject != 0);
QCOMPARE(textObject->font().overline(), false);
QCOMPARE(textObject->font().underline(), false);
QCOMPARE(textObject->font().strikeOut(), true);
}
void tst_qquicktext::capitalization()
{
{
QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QVERIFY(textObject != 0);
QCOMPARE((int)textObject->font().capitalization(), (int)QQuickFontValueType::MixedCase);
delete textObject;
}
{
QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"AllUppercase\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QVERIFY(textObject != 0);
QCOMPARE((int)textObject->font().capitalization(), (int)QQuickFontValueType::AllUppercase);
delete textObject;
}
{
QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"AllLowercase\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QVERIFY(textObject != 0);
QCOMPARE((int)textObject->font().capitalization(), (int)QQuickFontValueType::AllLowercase);
delete textObject;
}
{
QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"SmallCaps\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QVERIFY(textObject != 0);
QCOMPARE((int)textObject->font().capitalization(), (int)QQuickFontValueType::SmallCaps);
delete textObject;
}
{
QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"Capitalize\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QVERIFY(textObject != 0);
QCOMPARE((int)textObject->font().capitalization(), (int)QQuickFontValueType::Capitalize);
delete textObject;
}
}
void tst_qquicktext::letterSpacing()
{
{
QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QVERIFY(textObject != 0);
QCOMPARE(textObject->font().letterSpacing(), 0.0);
delete textObject;
}
{
QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.letterSpacing: -2 }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QVERIFY(textObject != 0);
QCOMPARE(textObject->font().letterSpacing(), -2.);
delete textObject;
}
{
QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.letterSpacing: 3 }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QVERIFY(textObject != 0);
QCOMPARE(textObject->font().letterSpacing(), 3.);
delete textObject;
}
}
void tst_qquicktext::wordSpacing()
{
{
QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QVERIFY(textObject != 0);
QCOMPARE(textObject->font().wordSpacing(), 0.0);
delete textObject;
}
{
QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.wordSpacing: -50 }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QVERIFY(textObject != 0);
QCOMPARE(textObject->font().wordSpacing(), -50.);
delete textObject;
}
{
QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.wordSpacing: 200 }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QVERIFY(textObject != 0);
QCOMPARE(textObject->font().wordSpacing(), 200.);
delete textObject;
}
}
class EventSender : public QQuickItem
{
public:
void sendEvent(QMouseEvent *event) {
if (event->type() == QEvent::MouseButtonPress)
mousePressEvent(event);
else if (event->type() == QEvent::MouseButtonRelease)
mouseReleaseEvent(event);
else if (event->type() == QEvent::MouseMove)
mouseMoveEvent(event);
else
qWarning() << "Trying to send unsupported event type";
}
};
class LinkTest : public QObject
{
Q_OBJECT
public:
LinkTest() {}
QString link;
public slots:
void linkClicked(QString l) { link = l; }
};
class TextMetrics
{
public:
TextMetrics(const QString &text, Qt::TextElideMode elideMode = Qt::ElideNone)
{
QString adjustedText = text;
adjustedText.replace(QLatin1Char('\n'), QChar(QChar::LineSeparator));
if (elideMode == Qt::ElideLeft)
adjustedText = QChar(0x2026) + adjustedText;
else if (elideMode == Qt::ElideRight)
adjustedText = adjustedText + QChar(0x2026);
layout.setText(adjustedText);
QTextOption option;
option.setUseDesignMetrics(true);
layout.setTextOption(option);
layout.beginLayout();
qreal height = 0;
QTextLine line = layout.createLine();
while (line.isValid()) {
line.setLineWidth(FLT_MAX);
line.setPosition(QPointF(0, height));
height += line.height();
line = layout.createLine();
}
layout.endLayout();
}
qreal width() const { return layout.maximumWidth(); }
QRectF characterRectangle(
int position,
int hAlign = Qt::AlignLeft,
int vAlign = Qt::AlignTop,
const QSizeF &bounds = QSizeF(240, 320)) const
{
qreal dy = 0;
switch (vAlign) {
case Qt::AlignBottom:
dy = bounds.height() - layout.boundingRect().height();
break;
case Qt::AlignVCenter:
dy = (bounds.height() - layout.boundingRect().height()) / 2;
break;
default:
break;
}
for (int i = 0; i < layout.lineCount(); ++i) {
QTextLine line = layout.lineAt(i);
if (position >= line.textStart() + line.textLength())
continue;
qreal dx = 0;
switch (hAlign) {
case Qt::AlignRight:
dx = bounds.width() - line.naturalTextWidth();
break;
case Qt::AlignHCenter:
dx = (bounds.width() - line.naturalTextWidth()) / 2;
break;
default:
break;
}
QRectF rect;
rect.setLeft(dx + line.cursorToX(position, QTextLine::Leading));
rect.setRight(dx + line.cursorToX(position, QTextLine::Trailing));
rect.setTop(dy + line.y());
rect.setBottom(dy + line.y() + line.height());
return rect;
}
return QRectF();
}
QTextLayout layout;
};
typedef QVector<QPointF> PointVector;
Q_DECLARE_METATYPE(PointVector);
void tst_qquicktext::clickLink_data()
{
QTest::addColumn<QString>("text");
QTest::addColumn<qreal>("width");
QTest::addColumn<QString>("bindings");
QTest::addColumn<PointVector>("mousePositions");
QTest::addColumn<QString>("link");
const QString singleLineText = "this text has a <a href=\\\"http://qt-project.org/single\\\">link</a> in it";
const QString singleLineLink = "http://qt-project.org/single";
const QString multipleLineText = "this text<br/>has <a href=\\\"http://qt-project.org/multiple\\\">multiple<br/>lines</a> in it";
const QString multipleLineLink = "http://qt-project.org/multiple";
const QString nestedText = "this text has a <a href=\\\"http://qt-project.org/outer\\\">nested <a href=\\\"http://qt-project.org/inner\\\">link</a> in it</a>";
const QString outerLink = "http://qt-project.org/outer";
const QString innerLink = "http://qt-project.org/inner";
{
const TextMetrics metrics("this text has a link in it");
QTest::newRow("click on link")
<< singleLineText << 240.
<< ""
<< (PointVector() << metrics.characterRectangle(18).center())
<< singleLineLink;
QTest::newRow("click on text")
<< singleLineText << 240.
<< ""
<< (PointVector() << metrics.characterRectangle(13).center())
<< QString();
QTest::newRow("drag within link")
<< singleLineText << 240.
<< ""
<< (PointVector()
<< metrics.characterRectangle(17).center()
<< metrics.characterRectangle(19).center())
<< singleLineLink;
QTest::newRow("drag away from link")
<< singleLineText << 240.
<< ""
<< (PointVector()
<< metrics.characterRectangle(18).center()
<< metrics.characterRectangle(13).center())
<< QString();
QTest::newRow("drag on to link")
<< singleLineText << 240.
<< ""
<< (PointVector()
<< metrics.characterRectangle(13).center()
<< metrics.characterRectangle(18).center())
<< QString();
QTest::newRow("click on bottom right aligned link")
<< singleLineText << 240.
<< "horizontalAlignment: Text.AlignRight; verticalAlignment: Text.AlignBottom"
<< (PointVector() << metrics.characterRectangle(18, Qt::AlignRight, Qt::AlignBottom).center())
<< singleLineLink;
QTest::newRow("click on center aligned link")
<< singleLineText << 240.
<< "horizontalAlignment: Text.AlignHCenter; verticalAlignment: Text.AlignVCenter"
<< (PointVector() << metrics.characterRectangle(18, Qt::AlignHCenter, Qt::AlignVCenter).center())
<< singleLineLink;
QTest::newRow("click on rich text link")
<< singleLineText << 240.
<< "textFormat: Text.RichText"
<< (PointVector() << metrics.characterRectangle(18).center())
<< singleLineLink;
QTest::newRow("click on rich text")
<< singleLineText << 240.
<< "textFormat: Text.RichText"
<< (PointVector() << metrics.characterRectangle(13).center())
<< QString();
QTest::newRow("click on bottom right aligned rich text link")
<< singleLineText << 240.
<< "textFormat: Text.RichText; horizontalAlignment: Text.AlignRight; verticalAlignment: Text.AlignBottom"
<< (PointVector() << metrics.characterRectangle(18, Qt::AlignRight, Qt::AlignBottom).center())
<< singleLineLink;
QTest::newRow("click on center aligned rich text link")
<< singleLineText << 240.
<< "textFormat: Text.RichText; horizontalAlignment: Text.AlignHCenter; verticalAlignment: Text.AlignVCenter"
<< (PointVector() << metrics.characterRectangle(18, Qt::AlignHCenter, Qt::AlignVCenter).center())
<< singleLineLink;
} {
const TextMetrics metrics("this text has a li", Qt::ElideRight);
QTest::newRow("click on right elided link")
<< singleLineText << metrics.width() + 2
<< "elide: Text.ElideRight"
<< (PointVector() << metrics.characterRectangle(17).center())
<< singleLineLink;
} {
const TextMetrics metrics("ink in it", Qt::ElideLeft);
QTest::newRow("click on left elided link")
<< singleLineText << metrics.width() + 2
<< "elide: Text.ElideLeft"
<< (PointVector() << metrics.characterRectangle(2).center())
<< singleLineLink;
} {
const TextMetrics metrics("this text\nhas multiple\nlines in it");
QTest::newRow("click on second line")
<< multipleLineText << 240.
<< ""
<< (PointVector() << metrics.characterRectangle(18).center())
<< multipleLineLink;
QTest::newRow("click on third line")
<< multipleLineText << 240.
<< ""
<< (PointVector() << metrics.characterRectangle(25).center())
<< multipleLineLink;
QTest::newRow("drag from second line to third")
<< multipleLineText << 240.
<< ""
<< (PointVector()
<< metrics.characterRectangle(18).center()
<< metrics.characterRectangle(25).center())
<< multipleLineLink;
QTest::newRow("click on rich text second line")
<< multipleLineText << 240.
<< "textFormat: Text.RichText"
<< (PointVector() << metrics.characterRectangle(18).center())
<< multipleLineLink;
QTest::newRow("click on rich text third line")
<< multipleLineText << 240.
<< "textFormat: Text.RichText"
<< (PointVector() << metrics.characterRectangle(25).center())
<< multipleLineLink;
QTest::newRow("drag rich text from second line to third")
<< multipleLineText << 240.
<< "textFormat: Text.RichText"
<< (PointVector()
<< metrics.characterRectangle(18).center()
<< metrics.characterRectangle(25).center())
<< multipleLineLink;
} {
const TextMetrics metrics("this text has a nested link in it");
QTest::newRow("click on left outer link")
<< nestedText << 240.
<< ""
<< (PointVector() << metrics.characterRectangle(22).center())
<< outerLink;
QTest::newRow("click on right outer link")
<< nestedText << 240.
<< ""
<< (PointVector() << metrics.characterRectangle(27).center())
<< outerLink;
QTest::newRow("click on inner link left")
<< nestedText << 240.
<< ""
<< (PointVector() << metrics.characterRectangle(23).center())
<< innerLink;
QTest::newRow("click on inner link right")
<< nestedText << 240.
<< ""
<< (PointVector() << metrics.characterRectangle(26).center())
<< innerLink;
QTest::newRow("drag from inner to outer link")
<< nestedText << 240.
<< ""
<< (PointVector()
<< metrics.characterRectangle(25).center()
<< metrics.characterRectangle(30).center())
<< QString();
QTest::newRow("drag from outer to inner link")
<< nestedText << 240.
<< ""
<< (PointVector()
<< metrics.characterRectangle(30).center()
<< metrics.characterRectangle(25).center())
<< QString();
QTest::newRow("click on left outer rich text link")
<< nestedText << 240.
<< "textFormat: Text.RichText"
<< (PointVector() << metrics.characterRectangle(22).center())
<< outerLink;
QTest::newRow("click on right outer rich text link")
<< nestedText << 240.
<< "textFormat: Text.RichText"
<< (PointVector() << metrics.characterRectangle(27).center())
<< outerLink;
QTest::newRow("click on inner rich text link left")
<< nestedText << 240.
<< "textFormat: Text.RichText"
<< (PointVector() << metrics.characterRectangle(23).center())
<< innerLink;
QTest::newRow("click on inner rich text link right")
<< nestedText << 240.
<< "textFormat: Text.RichText"
<< (PointVector() << metrics.characterRectangle(26).center())
<< innerLink;
QTest::newRow("drag from inner to outer rich text link")
<< nestedText << 240.
<< "textFormat: Text.RichText"
<< (PointVector()
<< metrics.characterRectangle(25).center()
<< metrics.characterRectangle(30).center())
<< QString();
QTest::newRow("drag from outer to inner rich text link")
<< nestedText << 240.
<< "textFormat: Text.RichText"
<< (PointVector()
<< metrics.characterRectangle(30).center()
<< metrics.characterRectangle(25).center())
<< QString();
}
}
void tst_qquicktext::clickLink()
{
QFETCH(QString, text);
QFETCH(qreal, width);
QFETCH(QString, bindings);
QFETCH(PointVector, mousePositions);
QFETCH(QString, link);
QString componentStr =
"import QtQuick 2.0\nText {\n"
"width: " + QString::number(width) + "\n"
"height: 320\n"
"text: \"" + text + "\"\n"
"" + bindings + "\n"
"}";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QVERIFY(textObject != 0);
LinkTest test;
QObject::connect(textObject, SIGNAL(linkActivated(QString)), &test, SLOT(linkClicked(QString)));
QVERIFY(mousePositions.count() > 0);
QPointF mousePosition = mousePositions.first();
{
QMouseEvent me(QEvent::MouseButtonPress, mousePosition, Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
static_cast<EventSender*>(static_cast<QQuickItem*>(textObject))->sendEvent(&me);
}
for (int i = 1; i < mousePositions.count(); ++i) {
mousePosition = mousePositions.at(i);
QMouseEvent me(QEvent::MouseMove, mousePosition, Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
static_cast<EventSender*>(static_cast<QQuickItem*>(textObject))->sendEvent(&me);
}
{
QMouseEvent me(QEvent::MouseButtonRelease, mousePosition, Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
static_cast<EventSender*>(static_cast<QQuickItem*>(textObject))->sendEvent(&me);
}
QCOMPARE(test.link, link);
delete textObject;
}
void tst_qquicktext::baseUrl()
{
QUrl localUrl("file:///tests/text.qml");
QUrl remoteUrl("http://qt.nokia.com/test.qml");
QQmlComponent textComponent(&engine);
textComponent.setData("import QtQuick 2.0\n Text {}", localUrl);
QQuickText *textObject = qobject_cast<QQuickText *>(textComponent.create());
QCOMPARE(textObject->baseUrl(), localUrl);
QSignalSpy spy(textObject, SIGNAL(baseUrlChanged()));
textObject->setBaseUrl(localUrl);
QCOMPARE(textObject->baseUrl(), localUrl);
QCOMPARE(spy.count(), 0);
textObject->setBaseUrl(remoteUrl);
QCOMPARE(textObject->baseUrl(), remoteUrl);
QCOMPARE(spy.count(), 1);
textObject->resetBaseUrl();
QCOMPARE(textObject->baseUrl(), localUrl);
QCOMPARE(spy.count(), 2);
}
void tst_qquicktext::embeddedImages_data()
{
QTest::addColumn<QUrl>("qmlfile");
QTest::addColumn<QString>("error");
QTest::newRow("local") << testFileUrl("embeddedImagesLocal.qml") << "";
QTest::newRow("local-error") << testFileUrl("embeddedImagesLocalError.qml")
<< testFileUrl("embeddedImagesLocalError.qml").toString()+":3:1: QML Text: Cannot open: " + testFileUrl("http/notexists.png").toString();
QTest::newRow("local") << testFileUrl("embeddedImagesLocalRelative.qml") << "";
QTest::newRow("remote") << testFileUrl("embeddedImagesRemote.qml") << "";
QTest::newRow("remote-error") << testFileUrl("embeddedImagesRemoteError.qml")
<< testFileUrl("embeddedImagesRemoteError.qml").toString()+":3:1: QML Text: Error downloading " SERVER_ADDR "/notexists.png - server replied: Not found";
QTest::newRow("remote") << testFileUrl("embeddedImagesRemoteRelative.qml") << "";
}
void tst_qquicktext::embeddedImages()
{
// Tests QTBUG-9900
QFETCH(QUrl, qmlfile);
QFETCH(QString, error);
TestHTTPServer server(SERVER_PORT);
server.serveDirectory(testFile("http"));
if (!error.isEmpty())
QTest::ignoreMessage(QtWarningMsg, error.toLatin1());
QQuickView *view = new QQuickView(qmlfile);
view->show();
view->requestActivateWindow();
QVERIFY(QTest::qWaitForWindowActive(view));
QQuickText *textObject = qobject_cast<QQuickText*>(view->rootObject());
QVERIFY(textObject != 0);
QTRY_COMPARE(textObject->resourcesLoading(), 0);
QPixmap pm(testFile("http/exists.png"));
if (error.isEmpty()) {
QCOMPARE(textObject->width(), double(pm.width()));
QCOMPARE(textObject->height(), double(pm.height()));
} else {
QVERIFY(16 != pm.width()); // check test is effective
QCOMPARE(textObject->width(), 16.0); // default size of QTextDocument broken image icon
QCOMPARE(textObject->height(), 16.0);
}
delete view;
}
void tst_qquicktext::lineCount()
{
QQuickView *window = createView(testFile("lineCount.qml"));
QQuickText *myText = window->rootObject()->findChild<QQuickText*>("myText");
QVERIFY(myText != 0);
QVERIFY(myText->lineCount() > 1);
QVERIFY(!myText->truncated());
QCOMPARE(myText->maximumLineCount(), INT_MAX);
myText->setMaximumLineCount(2);
QCOMPARE(myText->lineCount(), 2);
QCOMPARE(myText->truncated(), true);
QCOMPARE(myText->maximumLineCount(), 2);
myText->resetMaximumLineCount();
QCOMPARE(myText->maximumLineCount(), INT_MAX);
QCOMPARE(myText->truncated(), false);
myText->setElideMode(QQuickText::ElideRight);
myText->setMaximumLineCount(2);
QCOMPARE(myText->lineCount(), 2);
QCOMPARE(myText->truncated(), true);
QCOMPARE(myText->maximumLineCount(), 2);
delete window;
}
void tst_qquicktext::lineHeight()
{
QQuickView *window = createView(testFile("lineHeight.qml"));
QQuickText *myText = window->rootObject()->findChild<QQuickText*>("myText");
QVERIFY(myText != 0);
QVERIFY(myText->lineHeight() == 1);
QVERIFY(myText->lineHeightMode() == QQuickText::ProportionalHeight);
qreal h = myText->height();
myText->setLineHeight(1.5);
QCOMPARE(myText->height(), qreal(qCeil(h)) * 1.5);
myText->setLineHeightMode(QQuickText::FixedHeight);
myText->setLineHeight(20);
QCOMPARE(myText->height(), myText->lineCount() * 20.0);
myText->setText("Lorem ipsum sit <b>amet</b>, consectetur adipiscing elit. Integer felis nisl, varius in pretium nec, venenatis non erat. Proin lobortis interdum dictum.");
myText->setLineHeightMode(QQuickText::ProportionalHeight);
myText->setLineHeight(1.0);
qreal h2 = myText->height();
myText->setLineHeight(2.0);
QVERIFY(myText->height() == h2 * 2.0);
myText->setLineHeightMode(QQuickText::FixedHeight);
myText->setLineHeight(10);
QCOMPARE(myText->height(), myText->lineCount() * 10.0);
delete window;
}
void tst_qquicktext::implicitSize_data()
{
QTest::addColumn<QString>("text");
QTest::addColumn<QString>("width");
QTest::addColumn<QString>("wrap");
QTest::addColumn<QString>("elide");
QTest::addColumn<QString>("format");
QTest::newRow("plain") << "The quick red fox jumped over the lazy brown dog" << "50" << "Text.NoWrap" << "Text.ElideNone" << "Text.PlainText";
QTest::newRow("richtext") << "<b>The quick red fox jumped over the lazy brown dog</b>" <<" 50" << "Text.NoWrap" << "Text.ElideNone" << "Text.RichText";
QTest::newRow("styledtext") << "<b>The quick red fox jumped over the lazy brown dog</b>" <<" 50" << "Text.NoWrap" << "Text.ElideNone" << "Text.StyledText";
QTest::newRow("plain, 0 width") << "The quick red fox jumped over the lazy brown dog" << "0" << "Text.NoWrap" << "Text.ElideNone" << "Text.PlainText";
QTest::newRow("plain, elide") << "The quick red fox jumped over the lazy brown dog" << "50" << "Text.NoWrap" << "Text.ElideRight" << "Text.PlainText";
QTest::newRow("plain, 0 width, elide") << "The quick red fox jumped over the lazy brown dog" << "0" << "Text.NoWrap" << "Text.ElideRight" << "Text.PlainText";
QTest::newRow("richtext, 0 width") << "<b>The quick red fox jumped over the lazy brown dog</b>" <<" 0" << "Text.NoWrap" << "Text.ElideNone" << "Text.RichText";
QTest::newRow("styledtext, 0 width") << "<b>The quick red fox jumped over the lazy brown dog</b>" <<" 0" << "Text.NoWrap" << "Text.ElideNone" << "Text.StyledText";
QTest::newRow("plain_wrap") << "The quick red fox jumped over the lazy brown dog" << "50" << "Text.Wrap" << "Text.ElideNone" << "Text.PlainText";
QTest::newRow("richtext_wrap") << "<b>The quick red fox jumped over the lazy brown dog</b>" << "50" << "Text.Wrap" << "Text.ElideNone" << "Text.RichText";
QTest::newRow("styledtext_wrap") << "<b>The quick red fox jumped over the lazy brown dog</b>" << "50" << "Text.Wrap" << "Text.ElideNone" << "Text.StyledText";
QTest::newRow("plain_wrap, 0 width") << "The quick red fox jumped over the lazy brown dog" << "0" << "Text.Wrap" << "Text.ElideNone" << "Text.PlainText";
QTest::newRow("plain_wrap, elide") << "The quick red fox jumped over the lazy brown dog" << "50" << "Text.Wrap" << "Text.ElideRight" << "Text.PlainText";
QTest::newRow("plain_wrap, 0 width, elide") << "The quick red fox jumped over the lazy brown dog" << "0" << "Text.Wrap" << "Text.ElideRight" << "Text.PlainText";
QTest::newRow("richtext_wrap, 0 width") << "<b>The quick red fox jumped over the lazy brown dog</b>" << "0" << "Text.Wrap" << "Text.ElideNone" << "Text.RichText";
QTest::newRow("styledtext_wrap, 0 width") << "<b>The quick red fox jumped over the lazy brown dog</b>" << "0" << "Text.Wrap" << "Text.ElideNone" << "Text.StyledText";
}
void tst_qquicktext::implicitSize()
{
QFETCH(QString, text);
QFETCH(QString, width);
QFETCH(QString, format);
QFETCH(QString, wrap);
QFETCH(QString, elide);
QString componentStr = "import QtQuick 2.0\nText { "
"property real iWidth: implicitWidth; "
"text: \"" + text + "\"; "
"width: " + width + "; "
"textFormat: " + format + "; "
"wrapMode: " + wrap + "; "
"elide: " + elide + "; "
"maximumLineCount: 2 }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QVERIFY(textObject->width() < textObject->implicitWidth());
QVERIFY(textObject->height() == textObject->implicitHeight());
QCOMPARE(textObject->property("iWidth").toReal(), textObject->implicitWidth());
textObject->resetWidth();
QVERIFY(textObject->width() == textObject->implicitWidth());
QVERIFY(textObject->height() == textObject->implicitHeight());
delete textObject;
}
void tst_qquicktext::contentSize()
{
QString componentStr = "import QtQuick 2.0\nText { width: 75; height: 16; font.pixelSize: 10 }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QScopedPointer<QObject> object(textComponent.create());
QQuickText *textObject = qobject_cast<QQuickText *>(object.data());
QSignalSpy spy(textObject, SIGNAL(contentSizeChanged()));
textObject->setText("The quick red fox jumped over the lazy brown dog");
QVERIFY(textObject->contentWidth() > textObject->width());
QVERIFY(textObject->contentHeight() < textObject->height());
QCOMPARE(spy.count(), 1);
textObject->setWrapMode(QQuickText::WordWrap);
QVERIFY(textObject->contentWidth() <= textObject->width());
QVERIFY(textObject->contentHeight() > textObject->height());
QCOMPARE(spy.count(), 2);
textObject->setElideMode(QQuickText::ElideRight);
QVERIFY(textObject->contentWidth() <= textObject->width());
QVERIFY(textObject->contentHeight() < textObject->height());
QCOMPARE(spy.count(), 3);
int spyCount = 3;
qreal elidedWidth = textObject->contentWidth();
textObject->setText("The quickredfoxjumpedoverthe lazy brown dog");
QVERIFY(textObject->contentWidth() <= textObject->width());
QVERIFY(textObject->contentHeight() < textObject->height());
// this text probably won't have the same elided width, but it's not guaranteed.
if (textObject->contentWidth() != elidedWidth)
QCOMPARE(spy.count(), ++spyCount);
else
QCOMPARE(spy.count(), spyCount);
textObject->setElideMode(QQuickText::ElideNone);
QVERIFY(textObject->contentWidth() > textObject->width());
QVERIFY(textObject->contentHeight() > textObject->height());
QCOMPARE(spy.count(), ++spyCount);
}
void tst_qquicktext::geometryChanged()
{
// Test that text is re-laid out when the geometry of the item by verifying changes in content
// size. Implicit width is also tested as that in combination with item geometry provides a
// reference for expected content sizes.
QString componentStr = "import QtQuick 2.0\nText { font.family: \"__Qt__Box__Engine__\"; font.pixelSize: 10 }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QScopedPointer<QObject> object(textComponent.create());
QQuickText *textObject = qobject_cast<QQuickText *>(object.data());
const qreal implicitHeight = textObject->implicitHeight();
const qreal widths[] = { 100, 2000, 3000, -100, 100 };
const qreal heights[] = { implicitHeight, 2000, 3000, -implicitHeight, implicitHeight };
QCOMPARE(textObject->implicitWidth(), 0.);
QVERIFY(implicitHeight > 0.);
QCOMPARE(textObject->width(), textObject->implicitWidth());
QCOMPARE(textObject->height(), implicitHeight);
QCOMPARE(textObject->contentWidth(), textObject->implicitWidth());
QCOMPARE(textObject->contentHeight(), implicitHeight);
textObject->setText("The quick red fox jumped over the lazy brown dog");
const qreal implicitWidth = textObject->implicitWidth();
QVERIFY(implicitWidth > 0.);
QCOMPARE(textObject->implicitHeight(), implicitHeight);
QCOMPARE(textObject->width(), textObject->implicitWidth());
QCOMPARE(textObject->height(), textObject->implicitHeight());
QCOMPARE(textObject->contentWidth(), textObject->implicitWidth());
QCOMPARE(textObject->contentHeight(), textObject->implicitHeight());
// Changing the geometry with no eliding, or wrapping doesn't change the content size.
for (int i = 0; i < 5; ++i) {
textObject->setWidth(widths[i]);
QCOMPARE(textObject->implicitWidth(), implicitWidth);
QCOMPARE(textObject->implicitHeight(), implicitHeight);
QCOMPARE(textObject->width(), widths[i]);
QCOMPARE(textObject->height(), implicitHeight);
QCOMPARE(textObject->contentWidth(), implicitWidth);
QCOMPARE(textObject->contentHeight(), implicitHeight);
}
// With eliding enabled the content width is bounded to the item width, but is never
// larger than the implicit width.
textObject->setElideMode(QQuickText::ElideRight);
QCOMPARE(textObject->implicitWidth(), implicitWidth);
QCOMPARE(textObject->implicitHeight(), implicitHeight);
QCOMPARE(textObject->width(), 100.);
QCOMPARE(textObject->height(), implicitHeight);
QVERIFY(textObject->contentWidth() <= 100.);
QCOMPARE(textObject->contentHeight(), implicitHeight);
textObject->setWidth(2000.);
QCOMPARE(textObject->implicitWidth(), implicitWidth);
QCOMPARE(textObject->implicitHeight(), implicitHeight);
QCOMPARE(textObject->width(), 2000.);
QCOMPARE(textObject->height(), implicitHeight);
QCOMPARE(textObject->contentWidth(), implicitWidth);
QCOMPARE(textObject->contentHeight(), implicitHeight);
textObject->setWidth(3000.);
QCOMPARE(textObject->implicitWidth(), implicitWidth);
QCOMPARE(textObject->implicitHeight(), implicitHeight);
QCOMPARE(textObject->width(), 3000.);
QCOMPARE(textObject->height(), implicitHeight);
QCOMPARE(textObject->contentWidth(), implicitWidth);
QCOMPARE(textObject->contentHeight(), implicitHeight);
textObject->setWidth(-100);
QCOMPARE(textObject->implicitWidth(), implicitWidth);
QCOMPARE(textObject->implicitHeight(), implicitHeight);
QCOMPARE(textObject->width(), -100.);
QCOMPARE(textObject->height(), implicitHeight);
QCOMPARE(textObject->contentWidth(), 0.);
QCOMPARE(textObject->contentHeight(), implicitHeight);
textObject->setWidth(100.);
QCOMPARE(textObject->implicitWidth(), implicitWidth);
QCOMPARE(textObject->implicitHeight(), implicitHeight);
QCOMPARE(textObject->width(), 100.);
QCOMPARE(textObject->height(), implicitHeight);
QVERIFY(textObject->contentWidth() <= 100.);
QCOMPARE(textObject->contentHeight(), implicitHeight);
// With wrapping enabled the implicit height changes with the width.
textObject->setElideMode(QQuickText::ElideNone);
textObject->setWrapMode(QQuickText::Wrap);
const qreal wrappedImplicitHeight = textObject->implicitHeight();
QVERIFY(wrappedImplicitHeight > implicitHeight);
QCOMPARE(textObject->implicitWidth(), implicitWidth);
QCOMPARE(textObject->width(), 100.);
QCOMPARE(textObject->height(), wrappedImplicitHeight);
QVERIFY(textObject->contentWidth() <= 100.);
QCOMPARE(textObject->contentHeight(), wrappedImplicitHeight);
textObject->setWidth(2000.);
QCOMPARE(textObject->implicitWidth(), implicitWidth);
QCOMPARE(textObject->implicitHeight(), implicitHeight);
QCOMPARE(textObject->width(), 2000.);
QCOMPARE(textObject->height(), implicitHeight);
QCOMPARE(textObject->contentWidth(), implicitWidth);
QCOMPARE(textObject->contentHeight(), implicitHeight);
textObject->setWidth(3000.);
QCOMPARE(textObject->implicitWidth(), implicitWidth);
QCOMPARE(textObject->implicitHeight(), implicitHeight);
QCOMPARE(textObject->width(), 3000.);
QCOMPARE(textObject->height(), implicitHeight);
QCOMPARE(textObject->contentWidth(), implicitWidth);
QCOMPARE(textObject->contentHeight(), implicitHeight);
textObject->setWidth(-100);
QCOMPARE(textObject->implicitWidth(), implicitWidth);
QCOMPARE(textObject->implicitHeight(), implicitHeight);
QCOMPARE(textObject->width(), -100.);
QCOMPARE(textObject->height(), implicitHeight);
QCOMPARE(textObject->contentWidth(), implicitWidth); // 0 or negative width item won't wrap.
QCOMPARE(textObject->contentHeight(), implicitHeight);
textObject->setWidth(100.);
QCOMPARE(textObject->implicitWidth(), implicitWidth);
QCOMPARE(textObject->implicitHeight(), wrappedImplicitHeight);
QCOMPARE(textObject->width(), 100.);
QCOMPARE(textObject->height(), wrappedImplicitHeight);
QVERIFY(textObject->contentWidth() <= 100.);
QCOMPARE(textObject->contentHeight(), wrappedImplicitHeight);
// With no eliding or maximum line count the content height is the same as the implicit height.
for (int i = 0; i < 5; ++i) {
textObject->setHeight(heights[i]);
QCOMPARE(textObject->implicitWidth(), implicitWidth);
QCOMPARE(textObject->implicitHeight(), wrappedImplicitHeight);
QCOMPARE(textObject->width(), 100.);
QCOMPARE(textObject->height(), heights[i]);
QVERIFY(textObject->contentWidth() <= 100.);
QCOMPARE(textObject->contentHeight(), wrappedImplicitHeight);
}
// The implicit height is unaffected by eliding but the content height will change.
textObject->setElideMode(QQuickText::ElideRight);
QCOMPARE(textObject->implicitWidth(), implicitWidth);
QCOMPARE(textObject->implicitHeight(), wrappedImplicitHeight);
QCOMPARE(textObject->width(), 100.);
QCOMPARE(textObject->height(), implicitHeight);
QVERIFY(textObject->contentWidth() <= 100.);
QCOMPARE(textObject->contentHeight(), implicitHeight);
textObject->setHeight(2000);
QCOMPARE(textObject->implicitWidth(), implicitWidth);
QCOMPARE(textObject->implicitHeight(), wrappedImplicitHeight);
QCOMPARE(textObject->width(), 100.);
QCOMPARE(textObject->height(), 2000.);
QVERIFY(textObject->contentWidth() <= 100.);
QCOMPARE(textObject->contentHeight(), wrappedImplicitHeight);
textObject->setHeight(3000);
QCOMPARE(textObject->implicitWidth(), implicitWidth);
QCOMPARE(textObject->implicitHeight(), wrappedImplicitHeight);
QCOMPARE(textObject->width(), 100.);
QCOMPARE(textObject->height(), 3000.);
QVERIFY(textObject->contentWidth() <= 100.);
QCOMPARE(textObject->contentHeight(), wrappedImplicitHeight);
textObject->setHeight(-implicitHeight);
QCOMPARE(textObject->implicitWidth(), implicitWidth);
QCOMPARE(textObject->implicitHeight(), wrappedImplicitHeight);
QCOMPARE(textObject->width(), 100.);
QCOMPARE(textObject->height(), -implicitHeight);
QVERIFY(textObject->contentWidth() <= 0.);
QCOMPARE(textObject->contentHeight(), implicitHeight); // content height is never less than font height. seems a little odd in this instance.
textObject->setHeight(implicitHeight);
QCOMPARE(textObject->implicitWidth(), implicitWidth);
QCOMPARE(textObject->implicitHeight(), wrappedImplicitHeight);
QCOMPARE(textObject->width(), 100.);
QCOMPARE(textObject->height(), implicitHeight);
QVERIFY(textObject->contentWidth() <= 100.);
QCOMPARE(textObject->contentHeight(), implicitHeight);
// Varying the height with a maximum line count but no eliding won't affect the content height.
textObject->setElideMode(QQuickText::ElideNone);
textObject->setMaximumLineCount(2);
textObject->resetHeight();
const qreal maxLineCountImplicitHeight = textObject->implicitHeight();
QVERIFY(maxLineCountImplicitHeight > implicitHeight);
QVERIFY(maxLineCountImplicitHeight < wrappedImplicitHeight);
QCOMPARE(textObject->implicitWidth(), implicitWidth);
QCOMPARE(textObject->width(), 100.);
QCOMPARE(textObject->height(), maxLineCountImplicitHeight);
QVERIFY(textObject->contentWidth() <= 100.);
QCOMPARE(textObject->contentHeight(), maxLineCountImplicitHeight);
for (int i = 0; i < 5; ++i) {
textObject->setHeight(heights[i]);
QCOMPARE(textObject->implicitWidth(), implicitWidth);
QCOMPARE(textObject->implicitHeight(), maxLineCountImplicitHeight);
QCOMPARE(textObject->width(), 100.);
QCOMPARE(textObject->height(), heights[i]);
QVERIFY(textObject->contentWidth() <= 100.);
QCOMPARE(textObject->contentHeight(), maxLineCountImplicitHeight);
}
// Varying the width with a maximum line count won't increase the implicit height beyond the
// height of the maximum number of lines.
textObject->setWidth(2000.);
QCOMPARE(textObject->implicitWidth(), implicitWidth);
QCOMPARE(textObject->implicitHeight(), implicitHeight);
QCOMPARE(textObject->width(), 2000.);
QCOMPARE(textObject->height(), implicitHeight);
QCOMPARE(textObject->contentWidth(), implicitWidth);
QCOMPARE(textObject->contentHeight(), implicitHeight);
textObject->setWidth(3000.);
QCOMPARE(textObject->implicitWidth(), implicitWidth);
QCOMPARE(textObject->implicitHeight(), implicitHeight);
QCOMPARE(textObject->width(), 3000.);
QCOMPARE(textObject->height(), implicitHeight);
QCOMPARE(textObject->contentWidth(), implicitWidth);
QCOMPARE(textObject->contentHeight(), implicitHeight);
textObject->setWidth(-100);
QCOMPARE(textObject->implicitWidth(), implicitWidth);
QCOMPARE(textObject->implicitHeight(), implicitHeight);
QCOMPARE(textObject->width(), -100.);
QCOMPARE(textObject->height(), implicitHeight);
QCOMPARE(textObject->contentWidth(), implicitWidth); // 0 or negative width item won't wrap.
QCOMPARE(textObject->contentHeight(), implicitHeight);
textObject->setWidth(50.);
QCOMPARE(textObject->implicitWidth(), implicitWidth);
QCOMPARE(textObject->implicitHeight(), maxLineCountImplicitHeight);
QCOMPARE(textObject->width(), 50.);
QCOMPARE(textObject->height(), implicitHeight);
QVERIFY(textObject->contentWidth() <= 50.);
QCOMPARE(textObject->contentHeight(), maxLineCountImplicitHeight);
textObject->setWidth(100.);
QCOMPARE(textObject->implicitWidth(), implicitWidth);
QCOMPARE(textObject->implicitHeight(), maxLineCountImplicitHeight);
QCOMPARE(textObject->width(), 100.);
QCOMPARE(textObject->height(), implicitHeight);
QVERIFY(textObject->contentWidth() <= 100.);
QCOMPARE(textObject->contentHeight(), maxLineCountImplicitHeight);
}
void tst_qquicktext::implicitSizeBinding_data()
{
implicitSize_data();
}
void tst_qquicktext::implicitSizeBinding()
{
QFETCH(QString, text);
QFETCH(QString, wrap);
QFETCH(QString, format);
QString componentStr = "import QtQuick 2.0\nText { text: \"" + text + "\"; width: implicitWidth; height: implicitHeight; wrapMode: " + wrap + "; textFormat: " + format + " }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QScopedPointer<QObject> object(textComponent.create());
QQuickText *textObject = qobject_cast<QQuickText *>(object.data());
QCOMPARE(textObject->width(), textObject->implicitWidth());
QCOMPARE(textObject->height(), textObject->implicitHeight());
textObject->resetWidth();
QCOMPARE(textObject->width(), textObject->implicitWidth());
QCOMPARE(textObject->height(), textObject->implicitHeight());
textObject->resetHeight();
QCOMPARE(textObject->width(), textObject->implicitWidth());
QCOMPARE(textObject->height(), textObject->implicitHeight());
}
void tst_qquicktext::boundingRect_data()
{
QTest::addColumn<QString>("format");
QTest::newRow("PlainText") << "Text.PlainText";
QTest::newRow("StyledText") << "Text.StyledText";
QTest::newRow("RichText") << "Text.RichText";
}
void tst_qquicktext::boundingRect()
{
QFETCH(QString, format);
QQmlComponent component(&engine);
component.setData("import QtQuick 2.0\n Text { textFormat:" + format.toUtf8() + "}", QUrl());
QScopedPointer<QObject> object(component.create());
QQuickText *text = qobject_cast<QQuickText *>(object.data());
QVERIFY(text);
QCOMPARE(text->boundingRect().x(), qreal(0));
QCOMPARE(text->boundingRect().y(), qreal(0));
QCOMPARE(text->boundingRect().width(), qreal(0));
QCOMPARE(text->boundingRect().height(), qreal(qCeil(QFontMetricsF(text->font()).height())));
text->setText("Hello World");
QTextLayout layout(text->text());
layout.setFont(text->font());
if (!qmlDisableDistanceField()) {
QTextOption option;
option.setUseDesignMetrics(true);
layout.setTextOption(option);
}
layout.beginLayout();
QTextLine line = layout.createLine();
layout.endLayout();
QCOMPARE(text->boundingRect().x(), qreal(0));
QCOMPARE(text->boundingRect().y(), qreal(0));
QCOMPARE(text->boundingRect().width(), line.naturalTextWidth());
QCOMPARE(text->boundingRect().height(), line.height());
// the size of the bounding rect shouldn't be bounded by the size of item.
text->setWidth(text->width() / 2);
QCOMPARE(text->boundingRect().x(), qreal(0));
QCOMPARE(text->boundingRect().y(), qreal(0));
QCOMPARE(text->boundingRect().width(), line.naturalTextWidth());
QCOMPARE(text->boundingRect().height(), line.height());
text->setHeight(text->height() * 2);
QCOMPARE(text->boundingRect().x(), qreal(0));
QCOMPARE(text->boundingRect().y(), qreal(0));
QCOMPARE(text->boundingRect().width(), line.naturalTextWidth());
QCOMPARE(text->boundingRect().height(), line.height());
text->setHAlign(QQuickText::AlignRight);
QCOMPARE(text->boundingRect().x(), text->width() - line.naturalTextWidth());
QCOMPARE(text->boundingRect().y(), qreal(0));
QCOMPARE(text->boundingRect().width(), line.naturalTextWidth());
QCOMPARE(text->boundingRect().height(), line.height());
text->setWrapMode(QQuickText::Wrap);
QCOMPARE(text->boundingRect().right(), text->width());
QCOMPARE(text->boundingRect().y(), qreal(0));
QVERIFY(text->boundingRect().width() < line.naturalTextWidth());
QVERIFY(text->boundingRect().height() > line.height());
text->setVAlign(QQuickText::AlignBottom);
QCOMPARE(text->boundingRect().right(), text->width());
QCOMPARE(text->boundingRect().bottom(), text->height());
QVERIFY(text->boundingRect().width() < line.naturalTextWidth());
QVERIFY(text->boundingRect().height() > line.height());
}
void tst_qquicktext::clipRect()
{
QQmlComponent component(&engine);
component.setData("import QtQuick 2.0\n Text {}", QUrl());
QScopedPointer<QObject> object(component.create());
QQuickText *text = qobject_cast<QQuickText *>(object.data());
QVERIFY(text);
QTextLayout layout;
layout.setFont(text->font());
QCOMPARE(text->clipRect().x(), qreal(0));
QCOMPARE(text->clipRect().y(), qreal(0));
QCOMPARE(text->clipRect().width(), text->width());
QCOMPARE(text->clipRect().height(), text->height());
text->setText("Hello World");
QCOMPARE(text->clipRect().x(), qreal(0));
QCOMPARE(text->clipRect().y(), qreal(0));
QCOMPARE(text->clipRect().width(), text->width());
QCOMPARE(text->clipRect().height(), text->height());
// Clip rect follows the item not content dimensions.
text->setWidth(text->width() / 2);
QCOMPARE(text->clipRect().x(), qreal(0));
QCOMPARE(text->clipRect().y(), qreal(0));
QCOMPARE(text->clipRect().width(), text->width());
QCOMPARE(text->clipRect().height(), text->height());
text->setHeight(text->height() * 2);
QCOMPARE(text->clipRect().x(), qreal(0));
QCOMPARE(text->clipRect().y(), qreal(0));
QCOMPARE(text->clipRect().width(), text->width());
QCOMPARE(text->clipRect().height(), text->height());
// Setting a style adds a small amount of padding to the clip rect.
text->setStyle(QQuickText::Outline);
QCOMPARE(text->clipRect().x(), qreal(-1));
QCOMPARE(text->clipRect().y(), qreal(0));
QCOMPARE(text->clipRect().width(), text->width() + 2);
QCOMPARE(text->clipRect().height(), text->height() + 2);
}
void tst_qquicktext::lineLaidOut()
{
QQuickView *window = createView(testFile("lineLayout.qml"));
QQuickText *myText = window->rootObject()->findChild<QQuickText*>("myText");
QVERIFY(myText != 0);
QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(myText);
QVERIFY(textPrivate != 0);
QVERIFY(!textPrivate->extra.isAllocated());
for (int i = 0; i < textPrivate->layout.lineCount(); ++i) {
QRectF r = textPrivate->layout.lineAt(i).rect();
QVERIFY(r.width() == i * 15);
if (i >= 30)
QVERIFY(r.x() == r.width() + 30);
if (i >= 60) {
QVERIFY(r.x() == r.width() * 2 + 60);
QVERIFY(r.height() == 20);
}
}
delete window;
}
void tst_qquicktext::lineLaidOutRelayout()
{
QQuickView *window = createView(testFile("lineLayoutRelayout.qml"));
window->show();
window->requestActivateWindow();
QVERIFY(QTest::qWaitForWindowActive(window));
QQuickText *myText = window->rootObject()->findChild<QQuickText*>("myText");
QVERIFY(myText != 0);
QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(myText);
QVERIFY(textPrivate != 0);
QVERIFY(!textPrivate->extra.isAllocated());
qreal maxH = 0;
for (int i = 0; i < textPrivate->layout.lineCount(); ++i) {
QRectF r = textPrivate->layout.lineAt(i).rect();
if (r.x() == 0) {
QCOMPARE(r.y(), i * r.height());
maxH = qMax(maxH, r.y() + r.height());
} else {
QCOMPARE(r.x(), myText->width() / 2);
QCOMPARE(r.y(), (i * r.height()) - maxH);
}
}
delete window;
}
void tst_qquicktext::imgTagsBaseUrl_data()
{
QTest::addColumn<QUrl>("src");
QTest::addColumn<QUrl>("baseUrl");
QTest::addColumn<QUrl>("contextUrl");
QTest::addColumn<qreal>("imgHeight");
QTest::newRow("absolute local")
<< testFileUrl("images/heart200.png")
<< QUrl()
<< QUrl()
<< 181.;
QTest::newRow("relative local context 1")
<< QUrl("images/heart200.png")
<< QUrl()
<< testFileUrl("/app.qml")
<< 181.;
QTest::newRow("relative local context 2")
<< QUrl("heart200.png")
<< QUrl()
<< testFileUrl("images/app.qml")
<< 181.;
QTest::newRow("relative local base 1")
<< QUrl("images/heart200.png")
<< testFileUrl("")
<< testFileUrl("nonexistant/app.qml")
<< 181.;
QTest::newRow("relative local base 2")
<< QUrl("heart200.png")
<< testFileUrl("images/")
<< testFileUrl("nonexistant/app.qml")
<< 181.;
QTest::newRow("base relative to local context")
<< QUrl("heart200.png")
<< testFileUrl("images/")
<< testFileUrl("/app.qml")
<< 181.;
QTest::newRow("absolute remote")
<< QUrl(SERVER_ADDR "/images/heart200.png")
<< QUrl()
<< QUrl()
<< 181.;
QTest::newRow("relative remote base 1")
<< QUrl("images/heart200.png")
<< QUrl(SERVER_ADDR "/")
<< testFileUrl("nonexistant/app.qml")
<< 181.;
QTest::newRow("relative remote base 2")
<< QUrl("heart200.png")
<< QUrl(SERVER_ADDR "/images/")
<< testFileUrl("nonexistant/app.qml")
<< 181.;
}
void tst_qquicktext::imgTagsBaseUrl()
{
QFETCH(QUrl, src);
QFETCH(QUrl, baseUrl);
QFETCH(QUrl, contextUrl);
QFETCH(qreal, imgHeight);
TestHTTPServer server(SERVER_PORT);
server.serveDirectory(testFile(""));
QByteArray baseUrlFragment;
if (!baseUrl.isEmpty())
baseUrlFragment = "; baseUrl: \"" + baseUrl.toEncoded() + "\"";
QByteArray componentStr = "import QtQuick 2.0\nText { text: \"This is a test <img src=\\\"" + src.toEncoded() + "\\\">\"" + baseUrlFragment + " }";
QQmlComponent component(&engine);
component.setData(componentStr, contextUrl);
QScopedPointer<QObject> object(component.create());
QQuickText *textObject = qobject_cast<QQuickText *>(object.data());
QVERIFY(textObject);
QCoreApplication::processEvents();
QTRY_COMPARE(textObject->height(), imgHeight);
}
void tst_qquicktext::imgTagsAlign_data()
{
QTest::addColumn<QString>("src");
QTest::addColumn<int>("imgHeight");
QTest::addColumn<QString>("align");
QTest::newRow("heart-bottom") << "data/images/heart200.png" << 181 << "bottom";
QTest::newRow("heart-middle") << "data/images/heart200.png" << 181 << "middle";
QTest::newRow("heart-top") << "data/images/heart200.png" << 181 << "top";
QTest::newRow("starfish-bottom") << "data/images/starfish_2.png" << 217 << "bottom";
QTest::newRow("starfish-middle") << "data/images/starfish_2.png" << 217 << "middle";
QTest::newRow("starfish-top") << "data/images/starfish_2.png" << 217 << "top";
}
void tst_qquicktext::imgTagsAlign()
{
QFETCH(QString, src);
QFETCH(int, imgHeight);
QFETCH(QString, align);
QString componentStr = "import QtQuick 2.0\nText { text: \"This is a test <img src=\\\"" + src + "\\\" align=\\\"" + align + "\\\"> of image.\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QVERIFY(textObject != 0);
QVERIFY(textObject->height() == imgHeight);
QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
QVERIFY(textPrivate != 0);
QRectF br = textPrivate->layout.boundingRect();
if (align == "bottom")
QVERIFY(br.y() == imgHeight - br.height());
else if (align == "middle")
QVERIFY(br.y() == imgHeight / 2.0 - br.height() / 2.0);
else if (align == "top")
QVERIFY(br.y() == 0);
delete textObject;
}
void tst_qquicktext::imgTagsMultipleImages()
{
QString componentStr = "import QtQuick 2.0\nText { text: \"This is a starfish<img src=\\\"data/images/starfish_2.png\\\" width=\\\"60\\\" height=\\\"60\\\" > and another one<img src=\\\"data/images/heart200.png\\\" width=\\\"85\\\" height=\\\"85\\\">.\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QVERIFY(textObject != 0);
QVERIFY(textObject->height() == 85);
QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
QVERIFY(textPrivate != 0);
QVERIFY(textPrivate->visibleImgTags.count() == 2);
delete textObject;
}
void tst_qquicktext::imgTagsElide()
{
QQuickView *window = createView(testFile("imgTagsElide.qml"));
QQuickText *myText = window->rootObject()->findChild<QQuickText*>("myText");
QVERIFY(myText != 0);
QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(myText);
QVERIFY(textPrivate != 0);
QVERIFY(textPrivate->visibleImgTags.count() == 0);
myText->setMaximumLineCount(20);
QTRY_VERIFY(textPrivate->visibleImgTags.count() == 1);
delete myText;
delete window;
}
void tst_qquicktext::imgTagsUpdates()
{
QQuickView *window = createView(testFile("imgTagsUpdates.qml"));
QQuickText *myText = window->rootObject()->findChild<QQuickText*>("myText");
QVERIFY(myText != 0);
QSignalSpy spy(myText, SIGNAL(contentSizeChanged()));
QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(myText);
QVERIFY(textPrivate != 0);
myText->setText("This is a heart<img src=\"images/heart200.png\">.");
QVERIFY(textPrivate->visibleImgTags.count() == 1);
QVERIFY(spy.count() == 1);
myText->setMaximumLineCount(2);
myText->setText("This is another heart<img src=\"images/heart200.png\">.");
QTRY_VERIFY(textPrivate->visibleImgTags.count() == 1);
// if maximumLineCount is set and the img tag doesn't have an explicit size
// we relayout twice.
QVERIFY(spy.count() == 3);
delete myText;
delete window;
}
void tst_qquicktext::imgTagsError()
{
QString componentStr = "import QtQuick 2.0\nText { text: \"This is a starfish<img src=\\\"data/images/starfish_2.pn\\\" width=\\\"60\\\" height=\\\"60\\\">.\" }";
QQmlComponent textComponent(&engine);
QTest::ignoreMessage(QtWarningMsg, "file::2:1: QML Text: Cannot open: file:data/images/starfish_2.pn");
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
QVERIFY(textObject != 0);
delete textObject;
}
void tst_qquicktext::fontSizeMode_data()
{
QTest::addColumn<QString>("text");
QTest::newRow("plain") << "The quick red fox jumped over the lazy brown dog";
QTest::newRow("styled") << "<b>The quick red fox jumped over the lazy brown dog</b>";
}
void tst_qquicktext::fontSizeMode()
{
QFETCH(QString, text);
QScopedPointer<QQuickView> window(createView(testFile("fontSizeMode.qml")));
window->show();
QQuickText *myText = window->rootObject()->findChild<QQuickText*>("myText");
QVERIFY(myText != 0);
myText->setText(text);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
qreal originalWidth = myText->contentWidth();
qreal originalHeight = myText->contentHeight();
// The original text unwrapped should exceed the width of the item.
QVERIFY(originalWidth > myText->width());
QVERIFY(originalHeight < myText->height());
QFont font = myText->font();
font.setPixelSize(64);
myText->setFont(font);
myText->setFontSizeMode(QQuickText::HorizontalFit);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
// Font size reduced to fit within the width of the item.
qreal horizontalFitWidth = myText->contentWidth();
qreal horizontalFitHeight = myText->contentHeight();
QVERIFY(horizontalFitWidth <= myText->width() + 2); // rounding
QVERIFY(horizontalFitHeight <= myText->height() + 2);
// Elide won't affect the size with HorizontalFit.
myText->setElideMode(QQuickText::ElideRight);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
QVERIFY(!myText->truncated());
QCOMPARE(myText->contentWidth(), horizontalFitWidth);
QCOMPARE(myText->contentHeight(), horizontalFitHeight);
myText->setElideMode(QQuickText::ElideLeft);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
QVERIFY(!myText->truncated());
QCOMPARE(myText->contentWidth(), horizontalFitWidth);
QCOMPARE(myText->contentHeight(), horizontalFitHeight);
myText->setElideMode(QQuickText::ElideMiddle);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
QVERIFY(!myText->truncated());
QCOMPARE(myText->contentWidth(), horizontalFitWidth);
QCOMPARE(myText->contentHeight(), horizontalFitHeight);
myText->setElideMode(QQuickText::ElideNone);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
myText->setFontSizeMode(QQuickText::VerticalFit);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
// Font size increased to fill the height of the item.
qreal verticalFitHeight = myText->contentHeight();
QVERIFY(myText->contentWidth() > myText->width());
QVERIFY(verticalFitHeight <= myText->height() + 2);
QVERIFY(verticalFitHeight > originalHeight);
// Elide won't affect the height of a single line with VerticalFit but will crop the width.
myText->setElideMode(QQuickText::ElideRight);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
QVERIFY(myText->truncated());
QVERIFY(myText->contentWidth() <= myText->width() + 2);
QCOMPARE(myText->contentHeight(), verticalFitHeight);
myText->setElideMode(QQuickText::ElideLeft);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
QVERIFY(myText->truncated());
QVERIFY(myText->contentWidth() <= myText->width() + 2);
QCOMPARE(myText->contentHeight(), verticalFitHeight);
myText->setElideMode(QQuickText::ElideMiddle);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
QVERIFY(myText->truncated());
QVERIFY(myText->contentWidth() <= myText->width() + 2);
QCOMPARE(myText->contentHeight(), verticalFitHeight);
myText->setElideMode(QQuickText::ElideNone);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
myText->setFontSizeMode(QQuickText::Fit);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
// Should be the same as HorizontalFit with no wrapping.
QCOMPARE(myText->contentWidth(), horizontalFitWidth);
QCOMPARE(myText->contentHeight(), horizontalFitHeight);
// Elide won't affect the size with Fit.
myText->setElideMode(QQuickText::ElideRight);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
QVERIFY(!myText->truncated());
QCOMPARE(myText->contentWidth(), horizontalFitWidth);
QCOMPARE(myText->contentHeight(), horizontalFitHeight);
myText->setElideMode(QQuickText::ElideLeft);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
QVERIFY(!myText->truncated());
QCOMPARE(myText->contentWidth(), horizontalFitWidth);
QCOMPARE(myText->contentHeight(), horizontalFitHeight);
myText->setElideMode(QQuickText::ElideMiddle);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
QVERIFY(!myText->truncated());
QCOMPARE(myText->contentWidth(), horizontalFitWidth);
QCOMPARE(myText->contentHeight(), horizontalFitHeight);
myText->setElideMode(QQuickText::ElideNone);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
myText->setFontSizeMode(QQuickText::FixedSize);
myText->setWrapMode(QQuickText::Wrap);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
originalWidth = myText->contentWidth();
originalHeight = myText->contentHeight();
// The original text wrapped should exceed the height of the item.
QVERIFY(originalWidth <= myText->width() + 2);
QVERIFY(originalHeight > myText->height());
myText->setFontSizeMode(QQuickText::HorizontalFit);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
// HorizontalFit should reduce the font size to minimize wrapping, which brings it back to the
// same size as without text wrapping.
QCOMPARE(myText->contentWidth(), horizontalFitWidth);
QCOMPARE(myText->contentHeight(), horizontalFitHeight);
// Elide won't affect the size with HorizontalFit.
myText->setElideMode(QQuickText::ElideRight);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
QVERIFY(!myText->truncated());
QCOMPARE(myText->contentWidth(), horizontalFitWidth);
QCOMPARE(myText->contentHeight(), horizontalFitHeight);
myText->setElideMode(QQuickText::ElideNone);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
myText->setFontSizeMode(QQuickText::VerticalFit);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
// VerticalFit should reduce the size to the wrapped text within the vertical height.
verticalFitHeight = myText->contentHeight();
qreal verticalFitWidth = myText->contentWidth();
QVERIFY(myText->contentWidth() <= myText->width() + 2);
QVERIFY(verticalFitHeight <= myText->height() + 2);
QVERIFY(verticalFitHeight < originalHeight);
// Elide won't affect the height or width of a wrapped text with VerticalFit.
myText->setElideMode(QQuickText::ElideRight);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
QVERIFY(!myText->truncated());
QCOMPARE(myText->contentWidth(), verticalFitWidth);
QCOMPARE(myText->contentHeight(), verticalFitHeight);
myText->setElideMode(QQuickText::ElideNone);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
myText->setFontSizeMode(QQuickText::Fit);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
// Should be the same as VerticalFit with wrapping.
QCOMPARE(myText->contentWidth(), verticalFitWidth);
QCOMPARE(myText->contentHeight(), verticalFitHeight);
// Elide won't affect the size with Fit.
myText->setElideMode(QQuickText::ElideRight);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
QVERIFY(!myText->truncated());
QCOMPARE(myText->contentWidth(), verticalFitWidth);
QCOMPARE(myText->contentHeight(), verticalFitHeight);
myText->setElideMode(QQuickText::ElideNone);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
myText->setFontSizeMode(QQuickText::FixedSize);
myText->setMaximumLineCount(2);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
// The original text wrapped should exceed the height of the item.
QVERIFY(originalWidth <= myText->width() + 2);
QVERIFY(originalHeight > myText->height());
myText->setFontSizeMode(QQuickText::HorizontalFit);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
// HorizontalFit should reduce the font size to minimize wrapping, which brings it back to the
// same size as without text wrapping.
QCOMPARE(myText->contentWidth(), horizontalFitWidth);
QCOMPARE(myText->contentHeight(), horizontalFitHeight);
// Elide won't affect the size with HorizontalFit.
myText->setElideMode(QQuickText::ElideRight);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
QVERIFY(!myText->truncated());
QCOMPARE(myText->contentWidth(), horizontalFitWidth);
QCOMPARE(myText->contentHeight(), horizontalFitHeight);
myText->setElideMode(QQuickText::ElideNone);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
myText->setFontSizeMode(QQuickText::VerticalFit);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
// VerticalFit should reduce the size to the wrapped text within the vertical height.
verticalFitHeight = myText->contentHeight();
verticalFitWidth = myText->contentWidth();
QVERIFY(myText->contentWidth() <= myText->width() + 2);
QVERIFY(verticalFitHeight <= myText->height() + 2);
QVERIFY(verticalFitHeight < originalHeight);
// Elide won't affect the height or width of a wrapped text with VerticalFit.
myText->setElideMode(QQuickText::ElideRight);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
QVERIFY(!myText->truncated());
QCOMPARE(myText->contentWidth(), verticalFitWidth);
QCOMPARE(myText->contentHeight(), verticalFitHeight);
myText->setElideMode(QQuickText::ElideNone);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
myText->setFontSizeMode(QQuickText::Fit);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
// Should be the same as VerticalFit with wrapping.
QCOMPARE(myText->contentWidth(), verticalFitWidth);
QCOMPARE(myText->contentHeight(), verticalFitHeight);
// Elide won't affect the size with Fit.
myText->setElideMode(QQuickText::ElideRight);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
QVERIFY(!myText->truncated());
QCOMPARE(myText->contentWidth(), verticalFitWidth);
QCOMPARE(myText->contentHeight(), verticalFitHeight);
myText->setElideMode(QQuickText::ElideNone);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
}
void tst_qquicktext::fontSizeModeMultiline_data()
{
QTest::addColumn<QString>("text");
QTest::newRow("plain") << "The quick red fox jumped\n over the lazy brown dog";
QTest::newRow("styledtext") << "<b>The quick red fox jumped<br/> over the lazy brown dog</b>";
}
void tst_qquicktext::fontSizeModeMultiline()
{
QFETCH(QString, text);
QScopedPointer<QQuickView> window(createView(testFile("fontSizeMode.qml")));
window->show();
QQuickText *myText = window->rootObject()->findChild<QQuickText*>("myText");
QVERIFY(myText != 0);
myText->setText(text);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
qreal originalWidth = myText->contentWidth();
qreal originalHeight = myText->contentHeight();
QCOMPARE(myText->lineCount(), 2);
// The original text unwrapped should exceed the width and height of the item.
QVERIFY(originalWidth > myText->width());
QVERIFY(originalHeight > myText->height());
QFont font = myText->font();
font.setPixelSize(64);
myText->setFont(font);
myText->setFontSizeMode(QQuickText::HorizontalFit);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
// Font size reduced to fit within the width of the item.
QCOMPARE(myText->lineCount(), 2);
qreal horizontalFitWidth = myText->contentWidth();
qreal horizontalFitHeight = myText->contentHeight();
QVERIFY(horizontalFitWidth <= myText->width() + 2); // rounding
QVERIFY(horizontalFitHeight > myText->height());
// Right eliding will remove the last line
myText->setElideMode(QQuickText::ElideRight);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
QVERIFY(myText->truncated());
QCOMPARE(myText->lineCount(), 1);
QVERIFY(myText->contentWidth() <= myText->width() + 2);
QVERIFY(myText->contentHeight() <= myText->height() + 2);
// Left or middle eliding wont have any effect.
myText->setElideMode(QQuickText::ElideLeft);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
QVERIFY(!myText->truncated());
QCOMPARE(myText->contentWidth(), horizontalFitWidth);
QCOMPARE(myText->contentHeight(), horizontalFitHeight);
myText->setElideMode(QQuickText::ElideMiddle);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
QVERIFY(!myText->truncated());
QCOMPARE(myText->contentWidth(), horizontalFitWidth);
QCOMPARE(myText->contentHeight(), horizontalFitHeight);
myText->setElideMode(QQuickText::ElideNone);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
myText->setFontSizeMode(QQuickText::VerticalFit);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
// Font size reduced to fit within the height of the item.
qreal verticalFitWidth = myText->contentWidth();
qreal verticalFitHeight = myText->contentHeight();
QVERIFY(verticalFitWidth <= myText->width() + 2);
QVERIFY(verticalFitHeight <= myText->height() + 2);
// Elide will have no effect.
myText->setElideMode(QQuickText::ElideRight);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
QVERIFY(!myText->truncated());
QVERIFY(myText->contentWidth() <= myText->width() + 2);
QCOMPARE(myText->contentWidth(), verticalFitWidth);
QCOMPARE(myText->contentHeight(), verticalFitHeight);
myText->setElideMode(QQuickText::ElideLeft);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
QVERIFY(!myText->truncated());
QCOMPARE(myText->contentWidth(), verticalFitWidth);
QCOMPARE(myText->contentHeight(), verticalFitHeight);
myText->setElideMode(QQuickText::ElideMiddle);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
QVERIFY(!myText->truncated());
QCOMPARE(myText->contentWidth(), verticalFitWidth);
QCOMPARE(myText->contentHeight(), verticalFitHeight);
myText->setElideMode(QQuickText::ElideNone);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
myText->setFontSizeMode(QQuickText::Fit);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
// Should be the same as VerticalFit with no wrapping.
QCOMPARE(myText->contentWidth(), verticalFitWidth);
QCOMPARE(myText->contentHeight(), verticalFitHeight);
// Elide won't affect the size with Fit.
myText->setElideMode(QQuickText::ElideRight);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
QVERIFY(!myText->truncated());
QCOMPARE(myText->contentWidth(), verticalFitWidth);
QCOMPARE(myText->contentHeight(), verticalFitHeight);
myText->setElideMode(QQuickText::ElideLeft);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
QVERIFY(!myText->truncated());
QCOMPARE(myText->contentWidth(), verticalFitWidth);
QCOMPARE(myText->contentHeight(), verticalFitHeight);
myText->setElideMode(QQuickText::ElideMiddle);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
QVERIFY(!myText->truncated());
QCOMPARE(myText->contentWidth(), verticalFitWidth);
QCOMPARE(myText->contentHeight(), verticalFitHeight);
myText->setElideMode(QQuickText::ElideNone);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
myText->setFontSizeMode(QQuickText::FixedSize);
myText->setWrapMode(QQuickText::Wrap);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
originalWidth = myText->contentWidth();
originalHeight = myText->contentHeight();
// The original text wrapped should exceed the height of the item.
QVERIFY(originalWidth <= myText->width() + 2);
QVERIFY(originalHeight > myText->height());
myText->setFontSizeMode(QQuickText::HorizontalFit);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
// HorizontalFit should reduce the font size to minimize wrapping, which brings it back to the
// same size as without text wrapping.
QCOMPARE(myText->contentWidth(), horizontalFitWidth);
QCOMPARE(myText->contentHeight(), horizontalFitHeight);
// Text will be elided vertically with HorizontalFit
myText->setElideMode(QQuickText::ElideRight);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
QVERIFY(myText->truncated());
QVERIFY(myText->contentWidth() <= myText->width() + 2);
QVERIFY(myText->contentHeight() <= myText->height() + 2);
myText->setElideMode(QQuickText::ElideNone);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
myText->setFontSizeMode(QQuickText::VerticalFit);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
// VerticalFit should reduce the size to the wrapped text within the vertical height.
verticalFitHeight = myText->contentHeight();
verticalFitWidth = myText->contentWidth();
QVERIFY(myText->contentWidth() <= myText->width() + 2);
QVERIFY(verticalFitHeight <= myText->height() + 2);
QVERIFY(verticalFitHeight < originalHeight);
// Elide won't affect the height or width of a wrapped text with VerticalFit.
myText->setElideMode(QQuickText::ElideRight);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
QVERIFY(!myText->truncated());
QCOMPARE(myText->contentWidth(), verticalFitWidth);
QCOMPARE(myText->contentHeight(), verticalFitHeight);
myText->setElideMode(QQuickText::ElideNone);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
myText->setFontSizeMode(QQuickText::Fit);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
// Should be the same as VerticalFit with wrapping.
QCOMPARE(myText->contentWidth(), verticalFitWidth);
QCOMPARE(myText->contentHeight(), verticalFitHeight);
// Elide won't affect the size with Fit.
myText->setElideMode(QQuickText::ElideRight);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
QVERIFY(!myText->truncated());
QCOMPARE(myText->contentWidth(), verticalFitWidth);
QCOMPARE(myText->contentHeight(), verticalFitHeight);
myText->setElideMode(QQuickText::ElideNone);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
myText->setFontSizeMode(QQuickText::FixedSize);
myText->setMaximumLineCount(2);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
// The original text wrapped should exceed the height of the item.
QVERIFY(originalWidth <= myText->width() + 2);
QVERIFY(originalHeight > myText->height());
myText->setFontSizeMode(QQuickText::HorizontalFit);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
// HorizontalFit should reduce the font size to minimize wrapping, which brings it back to the
// same size as without text wrapping.
QCOMPARE(myText->contentWidth(), horizontalFitWidth);
QCOMPARE(myText->contentHeight(), horizontalFitHeight);
// Elide won't affect the size with HorizontalFit.
myText->setElideMode(QQuickText::ElideRight);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
QVERIFY(myText->truncated());
QVERIFY(myText->contentWidth() <= myText->width() + 2);
QVERIFY(myText->contentHeight() <= myText->height() + 2);
myText->setElideMode(QQuickText::ElideNone);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
myText->setFontSizeMode(QQuickText::VerticalFit);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
// VerticalFit should reduce the size to the wrapped text within the vertical height.
verticalFitHeight = myText->contentHeight();
verticalFitWidth = myText->contentWidth();
QVERIFY(myText->contentWidth() <= myText->width() + 2);
QVERIFY(verticalFitHeight <= myText->height() + 2);
QVERIFY(verticalFitHeight < originalHeight);
// Elide won't affect the height or width of a wrapped text with VerticalFit.
myText->setElideMode(QQuickText::ElideRight);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
QVERIFY(!myText->truncated());
QCOMPARE(myText->contentWidth(), verticalFitWidth);
QCOMPARE(myText->contentHeight(), verticalFitHeight);
myText->setElideMode(QQuickText::ElideNone);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
myText->setFontSizeMode(QQuickText::Fit);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
// Should be the same as VerticalFit with wrapping.
QCOMPARE(myText->contentWidth(), verticalFitWidth);
QCOMPARE(myText->contentHeight(), verticalFitHeight);
// Elide won't affect the size with Fit.
myText->setElideMode(QQuickText::ElideRight);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
QVERIFY(!myText->truncated());
QCOMPARE(myText->contentWidth(), verticalFitWidth);
QCOMPARE(myText->contentHeight(), verticalFitHeight);
myText->setElideMode(QQuickText::ElideNone);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
}
void tst_qquicktext::multilengthStrings_data()
{
QTest::addColumn<QString>("source");
QTest::newRow("No Wrap") << testFile("multilengthStrings.qml");
QTest::newRow("Wrap") << testFile("multilengthStringsWrapped.qml");
}
void tst_qquicktext::multilengthStrings()
{
QFETCH(QString, source);
QScopedPointer<QQuickView> window(createView(source));
window->show();
QQuickText *myText = window->rootObject()->findChild<QQuickText*>("myText");
QVERIFY(myText != 0);
const QString longText = "the quick brown fox jumped over the lazy dog";
const QString mediumText = "the brown fox jumped over the dog";
const QString shortText = "fox jumped dog";
myText->setText(longText);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
const qreal longWidth = myText->contentWidth();
const qreal longHeight = myText->contentHeight();
myText->setText(mediumText);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
const qreal mediumWidth = myText->contentWidth();
const qreal mediumHeight = myText->contentHeight();
myText->setText(shortText);
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
const qreal shortWidth = myText->contentWidth();
const qreal shortHeight = myText->contentHeight();
myText->setElideMode(QQuickText::ElideRight);
myText->setText(longText + QLatin1Char('\x9c') + mediumText + QLatin1Char('\x9c') + shortText);
myText->setSize(QSizeF(longWidth, longHeight));
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
QCOMPARE(myText->contentWidth(), longWidth);
QCOMPARE(myText->contentHeight(), longHeight);
QCOMPARE(myText->truncated(), false);
myText->setSize(QSizeF(mediumWidth, mediumHeight));
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
QCOMPARE(myText->contentWidth(), mediumWidth);
QCOMPARE(myText->contentHeight(), mediumHeight);
QCOMPARE(myText->truncated(), true);
myText->setSize(QSizeF(shortWidth, shortHeight));
QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
QCOMPARE(myText->contentWidth(), shortWidth);
QCOMPARE(myText->contentHeight(), shortHeight);
QCOMPARE(myText->truncated(), true);
}
void tst_qquicktext::fontFormatSizes_data()
{
QTest::addColumn<QString>("text");
QTest::addColumn<QString>("textWithTag");
QTest::addColumn<bool>("fontIsBigger");
QTest::newRow("fs1") << "Hello world!" << "Hello <font size=\"1\">world</font>!" << false;
QTest::newRow("fs2") << "Hello world!" << "Hello <font size=\"2\">world</font>!" << false;
QTest::newRow("fs3") << "Hello world!" << "Hello <font size=\"3\">world</font>!" << false;
QTest::newRow("fs4") << "Hello world!" << "Hello <font size=\"4\">world</font>!" << true;
QTest::newRow("fs5") << "Hello world!" << "Hello <font size=\"5\">world</font>!" << true;
QTest::newRow("fs6") << "Hello world!" << "Hello <font size=\"6\">world</font>!" << true;
QTest::newRow("fs7") << "Hello world!" << "Hello <font size=\"7\">world</font>!" << true;
QTest::newRow("h1") << "This is<br/>a font<br/> size test." << "This is <h1>a font</h1> size test." << true;
QTest::newRow("h2") << "This is<br/>a font<br/> size test." << "This is <h2>a font</h2> size test." << true;
QTest::newRow("h3") << "This is<br/>a font<br/> size test." << "This is <h3>a font</h3> size test." << true;
QTest::newRow("h4") << "This is<br/>a font<br/> size test." << "This is <h4>a font</h4> size test." << true;
QTest::newRow("h5") << "This is<br/>a font<br/> size test." << "This is <h5>a font</h5> size test." << false;
QTest::newRow("h6") << "This is<br/>a font<br/> size test." << "This is <h6>a font</h6> size test." << false;
}
void tst_qquicktext::fontFormatSizes()
{
QFETCH(QString, text);
QFETCH(QString, textWithTag);
QFETCH(bool, fontIsBigger);
QQuickView *view = new QQuickView;
{
view->setSource(testFileUrl("pointFontSizes.qml"));
view->show();
QQuickText *qtext = view->rootObject()->findChild<QQuickText*>("text");
QQuickText *qtextWithTag = view->rootObject()->findChild<QQuickText*>("textWithTag");
QVERIFY(qtext != 0);
QVERIFY(qtextWithTag != 0);
qtext->setText(text);
qtextWithTag->setText(textWithTag);
for (int size = 6; size < 100; size += 4) {
view->rootObject()->setProperty("pointSize", size);
if (fontIsBigger)
QVERIFY(qtext->height() <= qtextWithTag->height());
else
QVERIFY(qtext->height() >= qtextWithTag->height());
}
}
{
view->setSource(testFileUrl("pixelFontSizes.qml"));
QQuickText *qtext = view->rootObject()->findChild<QQuickText*>("text");
QQuickText *qtextWithTag = view->rootObject()->findChild<QQuickText*>("textWithTag");
QVERIFY(qtext != 0);
QVERIFY(qtextWithTag != 0);
qtext->setText(text);
qtextWithTag->setText(textWithTag);
for (int size = 6; size < 100; size += 4) {
view->rootObject()->setProperty("pixelSize", size);
if (fontIsBigger)
QVERIFY(qtext->height() <= qtextWithTag->height());
else
QVERIFY(qtext->height() >= qtextWithTag->height());
}
}
delete view;
}
typedef qreal (*ExpectedBaseline)(QQuickText *item);
Q_DECLARE_METATYPE(ExpectedBaseline)
static qreal expectedBaselineTop(QQuickText *item)
{
QFontMetricsF fm(item->font());
return fm.ascent();
}
static qreal expectedBaselineBottom(QQuickText *item)
{
QFontMetricsF fm(item->font());
return item->height() - item->contentHeight() + fm.ascent();
}
static qreal expectedBaselineCenter(QQuickText *item)
{
QFontMetricsF fm(item->font());
return ((item->height() - item->contentHeight()) / 2) + fm.ascent();
}
static qreal expectedBaselineBold(QQuickText *item)
{
QFont font = item->font();
font.setBold(true);
QFontMetricsF fm(font);
return fm.ascent();
}
static qreal expectedBaselineImage(QQuickText *item)
{
QFontMetricsF fm(item->font());
// The line is positioned so the bottom of the line is aligned with the bottom of the image,
// or image height - line height and the baseline is line position + ascent. Because
// QTextLine's height is rounded up this can give slightly different results to image height
// - descent.
return 181 - qCeil(fm.height()) + fm.ascent();
}
static qreal expectedBaselineCustom(QQuickText *item)
{
QFontMetricsF fm(item->font());
return 16 + fm.ascent();
}
static qreal expectedBaselineScaled(QQuickText *item)
{
QFont font = item->font();
QTextLayout layout(item->text().replace(QLatin1Char('\n'), QChar::LineSeparator));
do {
layout.setFont(font);
qreal width = 0;
layout.beginLayout();
for (QTextLine line = layout.createLine(); line.isValid(); line = layout.createLine()) {
line.setLineWidth(FLT_MAX);
width = qMax(line.naturalTextWidth(), width);
}
layout.endLayout();
if (width < item->width()) {
QFontMetricsF fm(layout.font());
return fm.ascent();
}
font.setPointSize(font.pointSize() - 1);
} while (font.pointSize() > 0);
return 0;
}
static qreal expectedBaselineFixedBottom(QQuickText *item)
{
QFontMetricsF fm(item->font());
qreal dy = item->text().contains(QLatin1Char('\n'))
? 160
: 180;
return dy + fm.ascent();
}
static qreal expectedBaselineProportionalBottom(QQuickText *item)
{
QFontMetricsF fm(item->font());
qreal dy = item->text().contains(QLatin1Char('\n'))
? 200 - (qCeil(fm.height()) * 3)
: 200 - (qCeil(fm.height()) * 1.5);
return dy + fm.ascent();
}
void tst_qquicktext::baselineOffset_data()
{
qRegisterMetaType<ExpectedBaseline>();
QTest::addColumn<QString>("text");
QTest::addColumn<QString>("wrappedText");
QTest::addColumn<QByteArray>("bindings");
QTest::addColumn<ExpectedBaseline>("expectedBaseline");
QTest::addColumn<ExpectedBaseline>("expectedBaselineEmpty");
QTest::newRow("top align")
<< "hello world"
<< "hello\nworld"
<< QByteArray("height: 200; verticalAlignment: Text.AlignTop")
<< &expectedBaselineTop
<< &expectedBaselineTop;
QTest::newRow("bottom align")
<< "hello world"
<< "hello\nworld"
<< QByteArray("height: 200; verticalAlignment: Text.AlignBottom")
<< &expectedBaselineBottom
<< &expectedBaselineBottom;
QTest::newRow("center align")
<< "hello world"
<< "hello\nworld"
<< QByteArray("height: 200; verticalAlignment: Text.AlignVCenter")
<< &expectedBaselineCenter
<< &expectedBaselineCenter;
QTest::newRow("bold")
<< "<b>hello world</b>"
<< "<b>hello<br/>world</b>"
<< QByteArray("height: 200")
<< &expectedBaselineTop
<< &expectedBaselineBold;
QTest::newRow("richText")
<< "<b>hello world</b>"
<< "<b>hello<br/>world</b>"
<< QByteArray("height: 200; textFormat: Text.RichText")
<< &expectedBaselineTop
<< &expectedBaselineTop;
QTest::newRow("elided")
<< "hello world"
<< "hello\nworld"
<< QByteArray("width: 20; height: 8; elide: Text.ElideRight")
<< &expectedBaselineTop
<< &expectedBaselineTop;
QTest::newRow("elided bottom align")
<< "hello world"
<< "hello\nworld!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
<< QByteArray("width: 200; height: 200; elide: Text.ElideRight; verticalAlignment: Text.AlignBottom")
<< &expectedBaselineBottom
<< &expectedBaselineBottom;
QTest::newRow("image")
<< "hello <img src=\"images/heart200.png\" /> world"
<< "hello <img src=\"images/heart200.png\" /><br/>world"
<< QByteArray("height: 200\n; baseUrl: \"") + testFileUrl("reference").toEncoded() + QByteArray("\"")
<< &expectedBaselineImage
<< &expectedBaselineTop;
QTest::newRow("customLine")
<< "hello world"
<< "hello\nworld"
<< QByteArray("height: 200; onLineLaidOut: line.y += 16")
<< &expectedBaselineCustom
<< &expectedBaselineCustom;
QTest::newRow("scaled font")
<< "hello world"
<< "hello\nworld"
<< QByteArray("width: 200; minimumPointSize: 1; font.pointSize: 64; fontSizeMode: Text.HorizontalFit")
<< &expectedBaselineScaled
<< &expectedBaselineTop;
QTest::newRow("fixed line height top align")
<< "hello world"
<< "hello\nworld"
<< QByteArray("height: 200; lineHeightMode: Text.FixedHeight; lineHeight: 20; verticalAlignment: Text.AlignTop")
<< &expectedBaselineTop
<< &expectedBaselineTop;
QTest::newRow("fixed line height bottom align")
<< "hello world"
<< "hello\nworld"
<< QByteArray("height: 200; lineHeightMode: Text.FixedHeight; lineHeight: 20; verticalAlignment: Text.AlignBottom")
<< &expectedBaselineFixedBottom
<< &expectedBaselineFixedBottom;
QTest::newRow("proportional line height top align")
<< "hello world"
<< "hello\nworld"
<< QByteArray("height: 200; lineHeightMode: Text.ProportionalHeight; lineHeight: 1.5; verticalAlignment: Text.AlignTop")
<< &expectedBaselineTop
<< &expectedBaselineTop;
QTest::newRow("proportional line height bottom align")
<< "hello world"
<< "hello\nworld"
<< QByteArray("height: 200; lineHeightMode: Text.ProportionalHeight; lineHeight: 1.5; verticalAlignment: Text.AlignBottom")
<< &expectedBaselineProportionalBottom
<< &expectedBaselineProportionalBottom;
}
void tst_qquicktext::baselineOffset()
{
QFETCH(QString, text);
QFETCH(QString, wrappedText);
QFETCH(QByteArray, bindings);
QFETCH(ExpectedBaseline, expectedBaseline);
QFETCH(ExpectedBaseline, expectedBaselineEmpty);
QQmlComponent component(&engine);
component.setData(
"import QtQuick 2.0\n"
"Text {\n"
+ bindings + "\n"
"}", QUrl());
QScopedPointer<QObject> object(component.create());
QQuickText *item = qobject_cast<QQuickText *>(object.data());
QVERIFY(item);
{
qreal baseline = expectedBaselineEmpty(item);
QCOMPARE(item->baselineOffset(), baseline);
item->setText(text);
if (expectedBaseline != expectedBaselineEmpty)
baseline = expectedBaseline(item);
QCOMPARE(item->baselineOffset(), baseline);
item->setText(wrappedText);
QCOMPARE(item->baselineOffset(), expectedBaseline(item));
}
QFont font = item->font();
font.setPointSize(font.pointSize() + 8);
{
QCOMPARE(item->baselineOffset(), expectedBaseline(item));
item->setText(text);
qreal baseline = expectedBaseline(item);
QCOMPARE(item->baselineOffset(), baseline);
item->setText(QString());
if (expectedBaselineEmpty != expectedBaseline)
baseline = expectedBaselineEmpty(item);
QCOMPARE(item->baselineOffset(), baseline);
}
}
void tst_qquicktext::htmlLists()
{
QFETCH(QString, text);
QFETCH(int, nbLines);
QQuickView *view = createView(testFile("htmlLists.qml"));
QQuickText *textObject = view->rootObject()->findChild<QQuickText*>("myText");
QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
QVERIFY(textPrivate != 0);
QVERIFY(textPrivate->extra.isAllocated());
QVERIFY(textObject != 0);
textObject->setText(text);
view->show();
view->requestActivateWindow();
QVERIFY(QTest::qWaitForWindowActive(view));
QCOMPARE(textPrivate->extra->doc->lineCount(), nbLines);
delete view;
}
void tst_qquicktext::htmlLists_data()
{
QTest::addColumn<QString>("text");
QTest::addColumn<int>("nbLines");
QTest::newRow("ordered list") << "<ol><li>one<li>two<li>three" << 3;
QTest::newRow("ordered list closed") << "<ol><li>one</li></ol>" << 1;
QTest::newRow("ordered list alpha") << "<ol type=\"a\"><li>one</li><li>two</li></ol>" << 2;
QTest::newRow("ordered list upper alpha") << "<ol type=\"A\"><li>one</li><li>two</li></ol>" << 2;
QTest::newRow("ordered list roman") << "<ol type=\"i\"><li>one</li><li>two</li></ol>" << 2;
QTest::newRow("ordered list upper roman") << "<ol type=\"I\"><li>one</li><li>two</li></ol>" << 2;
QTest::newRow("ordered list bad") << "<ol type=\"z\"><li>one</li><li>two</li></ol>" << 2;
QTest::newRow("unordered list") << "<ul><li>one<li>two" << 2;
QTest::newRow("unordered list closed") << "<ul><li>one</li><li>two</li></ul>" << 2;
QTest::newRow("unordered list disc") << "<ul type=\"disc\"><li>one</li><li>two</li></ul>" << 2;
QTest::newRow("unordered list square") << "<ul type=\"square\"><li>one</li><li>two</li></ul>" << 2;
QTest::newRow("unordered list bad") << "<ul type=\"bad\"><li>one</li><li>two</li></ul>" << 2;
}
QTEST_MAIN(tst_qquicktext)
#include "tst_qquicktext.moc"