Use QGuiApplication, not QApplication, in tests
[profile/ivi/qtdeclarative.git] / tests / auto / qtquick2 / qquicktext / tst_qquicktext.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the test suite of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 #include <qtest.h>
42 #include <QTextDocument>
43 #include <QtDeclarative/qdeclarativeengine.h>
44 #include <QtDeclarative/qdeclarativecomponent.h>
45 #include <QtQuick/private/qquicktext_p.h>
46 #include <private/qquicktext_p_p.h>
47 #include <private/qdeclarativevaluetype_p.h>
48 #include <QFontMetrics>
49 #include <QGraphicsSceneMouseEvent>
50 #include <qmath.h>
51 #include <QtQuick/QQuickView>
52 #include <private/qapplication_p.h>
53 #include <limits.h>
54 #include <QtGui/QMouseEvent>
55 #include "../../shared/util.h"
56 #include "testhttpserver.h"
57
58 DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
59
60 class tst_qquicktext : public QDeclarativeDataTest
61 {
62     Q_OBJECT
63 public:
64     tst_qquicktext();
65
66 private slots:
67     void text();
68     void width();
69     void wrap();
70     void elide();
71     void multilineElide();
72     void textFormat();
73
74     void alignments_data();
75     void alignments();
76
77     void embeddedImages_data();
78     void embeddedImages();
79
80     void lineCount();
81     void lineHeight();
82
83     // ### these tests may be trivial
84     void horizontalAlignment();
85     void horizontalAlignment_RightToLeft();
86     void verticalAlignment();
87     void font();
88     void style();
89     void color();
90     void smooth();
91
92     // QDeclarativeFontValueType
93     void weight();
94     void underline();
95     void overline();
96     void strikeout();
97     void capitalization();
98     void letterSpacing();
99     void wordSpacing();
100
101     void clickLink();
102
103     void implicitSize_data();
104     void implicitSize();
105
106     void lineLaidOut();
107
108
109 private:
110     QStringList standard;
111     QStringList richText;
112
113     QStringList horizontalAlignmentmentStrings;
114     QStringList verticalAlignmentmentStrings;
115
116     QList<Qt::Alignment> verticalAlignmentments;
117     QList<Qt::Alignment> horizontalAlignmentments;
118
119     QStringList styleStrings;
120     QList<QQuickText::TextStyle> styles;
121
122     QStringList colorStrings;
123
124     QDeclarativeEngine engine;
125
126     QQuickView *createView(const QString &filename);
127 };
128
129 tst_qquicktext::tst_qquicktext()
130 {
131     standard << "the quick brown fox jumped over the lazy dog"
132             << "the quick brown fox\n jumped over the lazy dog";
133
134     richText << "<i>the <b>quick</b> brown <a href=\\\"http://www.google.com\\\">fox</a> jumped over the <b>lazy</b> dog</i>"
135             << "<i>the <b>quick</b> brown <a href=\\\"http://www.google.com\\\">fox</a><br>jumped over the <b>lazy</b> dog</i>";
136
137     horizontalAlignmentmentStrings << "AlignLeft"
138             << "AlignRight"
139             << "AlignHCenter";
140
141     verticalAlignmentmentStrings << "AlignTop"
142             << "AlignBottom"
143             << "AlignVCenter";
144
145     horizontalAlignmentments << Qt::AlignLeft
146             << Qt::AlignRight
147             << Qt::AlignHCenter;
148
149     verticalAlignmentments << Qt::AlignTop
150             << Qt::AlignBottom
151             << Qt::AlignVCenter;
152
153     styleStrings << "Normal"
154             << "Outline"
155             << "Raised"
156             << "Sunken";
157
158     styles << QQuickText::Normal
159             << QQuickText::Outline
160             << QQuickText::Raised
161             << QQuickText::Sunken;
162
163     colorStrings << "aliceblue"
164             << "antiquewhite"
165             << "aqua"
166             << "darkkhaki"
167             << "darkolivegreen"
168             << "dimgray"
169             << "palevioletred"
170             << "lightsteelblue"
171             << "#000000"
172             << "#AAAAAA"
173             << "#FFFFFF"
174             << "#2AC05F";
175     //
176     // need a different test to do alpha channel test
177     // << "#AA0011DD"
178     // << "#00F16B11";
179     //
180 }
181
182 QQuickView *tst_qquicktext::createView(const QString &filename)
183 {
184     QQuickView *canvas = new QQuickView(0);
185
186     canvas->setSource(QUrl::fromLocalFile(filename));
187     return canvas;
188 }
189
190 void tst_qquicktext::text()
191 {
192     {
193         QDeclarativeComponent textComponent(&engine);
194         textComponent.setData("import QtQuick 2.0\nText { text: \"\" }", QUrl::fromLocalFile(""));
195         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
196
197         QVERIFY(textObject != 0);
198         QCOMPARE(textObject->text(), QString(""));
199         QVERIFY(textObject->width() == 0);
200
201         delete textObject;
202     }
203
204     for (int i = 0; i < standard.size(); i++)
205     {
206         QString componentStr = "import QtQuick 2.0\nText { text: \"" + standard.at(i) + "\" }";
207         QDeclarativeComponent textComponent(&engine);
208         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
209
210         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
211
212         QVERIFY(textObject != 0);
213         QCOMPARE(textObject->text(), standard.at(i));
214         QVERIFY(textObject->width() > 0);
215
216         delete textObject;
217     }
218
219     for (int i = 0; i < richText.size(); i++)
220     {
221         QString componentStr = "import QtQuick 2.0\nText { text: \"" + richText.at(i) + "\" }";
222         QDeclarativeComponent textComponent(&engine);
223         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
224         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
225
226         QVERIFY(textObject != 0);
227         QString expected = richText.at(i);
228         QCOMPARE(textObject->text(), expected.replace("\\\"", "\""));
229         QVERIFY(textObject->width() > 0);
230
231         delete textObject;
232     }
233 }
234
235 void tst_qquicktext::width()
236 {
237     // uses Font metrics to find the width for standard and document to find the width for rich
238     {
239         QDeclarativeComponent textComponent(&engine);
240         textComponent.setData("import QtQuick 2.0\nText { text: \"\" }", QUrl::fromLocalFile(""));
241         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
242
243         QVERIFY(textObject != 0);
244         QCOMPARE(textObject->width(), 0.);
245
246         delete textObject;
247     }
248
249     bool requiresUnhintedMetrics = !qmlDisableDistanceField();
250
251     for (int i = 0; i < standard.size(); i++)
252     {
253         QVERIFY(!Qt::mightBeRichText(standard.at(i))); // self-test
254
255         QFont f;
256         qreal metricWidth = 0.0;
257
258         if (requiresUnhintedMetrics) {
259             QString s = standard.at(i);
260             s.replace(QLatin1Char('\n'), QChar::LineSeparator);
261
262             QTextLayout layout(s);
263             layout.setFlags(Qt::TextExpandTabs | Qt::TextShowMnemonic);
264             {
265                 QTextOption option;
266                 option.setUseDesignMetrics(true);
267                 layout.setTextOption(option);
268             }
269
270             layout.beginLayout();
271             forever {
272                 QTextLine line = layout.createLine();
273                 if (!line.isValid())
274                     break;
275             }
276
277             layout.endLayout();
278
279             metricWidth = qCeil(layout.boundingRect().width());
280         } else {
281             QFontMetricsF fm(f);
282             qreal metricWidth = fm.size(Qt::TextExpandTabs && Qt::TextShowMnemonic, standard.at(i)).width();
283             metricWidth = qCeil(metricWidth);
284         }
285
286         QString componentStr = "import QtQuick 2.0\nText { text: \"" + standard.at(i) + "\" }";
287         QDeclarativeComponent textComponent(&engine);
288         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
289         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
290
291         QVERIFY(textObject != 0);
292         QVERIFY(textObject->boundingRect().width() > 0);
293         QCOMPARE(textObject->width(), qreal(metricWidth));
294         QVERIFY(textObject->textFormat() == QQuickText::AutoText); // setting text doesn't change format
295
296         delete textObject;
297     }
298
299     for (int i = 0; i < richText.size(); i++)
300     {
301         QVERIFY(Qt::mightBeRichText(richText.at(i))); // self-test
302
303         QString componentStr = "import QtQuick 2.0\nText { text: \"" + richText.at(i) + "\"; textFormat: Text.RichText }";
304         QDeclarativeComponent textComponent(&engine);
305         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
306         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
307         QVERIFY(textObject != 0);
308
309         QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
310         QVERIFY(textPrivate != 0);
311
312         QTextDocument *doc = textPrivate->textDocument();
313         QVERIFY(doc != 0);
314
315         QCOMPARE(int(textObject->width()), int(doc->idealWidth()));
316         QVERIFY(textObject->textFormat() == QQuickText::RichText);
317
318         delete textObject;
319     }
320 }
321
322 void tst_qquicktext::wrap()
323 {
324     int textHeight = 0;
325     // for specified width and wrap set true
326     {
327         QDeclarativeComponent textComponent(&engine);
328         textComponent.setData("import QtQuick 2.0\nText { text: \"Hello\"; wrapMode: Text.WordWrap; width: 300 }", QUrl::fromLocalFile(""));
329         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
330         textHeight = textObject->height();
331
332         QVERIFY(textObject != 0);
333         QVERIFY(textObject->wrapMode() == QQuickText::WordWrap);
334         QCOMPARE(textObject->width(), 300.);
335
336         delete textObject;
337     }
338
339     for (int i = 0; i < standard.size(); i++)
340     {
341         QString componentStr = "import QtQuick 2.0\nText { wrapMode: Text.WordWrap; width: 30; text: \"" + standard.at(i) + "\" }";
342         QDeclarativeComponent textComponent(&engine);
343         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
344         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
345
346         QVERIFY(textObject != 0);
347         QCOMPARE(textObject->width(), 30.);
348         QVERIFY(textObject->height() > textHeight);
349
350         int oldHeight = textObject->height();
351         textObject->setWidth(100);
352         QVERIFY(textObject->height() < oldHeight);
353
354         delete textObject;
355     }
356
357     for (int i = 0; i < richText.size(); i++)
358     {
359         QString componentStr = "import QtQuick 2.0\nText { wrapMode: Text.WordWrap; width: 30; text: \"" + richText.at(i) + "\" }";
360         QDeclarativeComponent textComponent(&engine);
361         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
362         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
363
364         QVERIFY(textObject != 0);
365         QCOMPARE(textObject->width(), 30.);
366         QVERIFY(textObject->height() > textHeight);
367
368         qreal oldHeight = textObject->height();
369         textObject->setWidth(100);
370         QVERIFY(textObject->height() < oldHeight);
371
372         delete textObject;
373     }
374
375     // richtext again with a fixed height
376     for (int i = 0; i < richText.size(); i++)
377     {
378         QString componentStr = "import QtQuick 2.0\nText { wrapMode: Text.WordWrap; width: 30; height: 50; text: \"" + richText.at(i) + "\" }";
379         QDeclarativeComponent textComponent(&engine);
380         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
381         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
382
383         QVERIFY(textObject != 0);
384         QCOMPARE(textObject->width(), 30.);
385         QVERIFY(textObject->implicitHeight() > textHeight);
386
387         qreal oldHeight = textObject->implicitHeight();
388         textObject->setWidth(100);
389         QVERIFY(textObject->implicitHeight() < oldHeight);
390
391         delete textObject;
392     }
393 }
394
395 void tst_qquicktext::elide()
396 {
397     for (QQuickText::TextElideMode m = QQuickText::ElideLeft; m<=QQuickText::ElideNone; m=QQuickText::TextElideMode(int(m)+1)) {
398         const char* elidename[]={"ElideLeft", "ElideRight", "ElideMiddle", "ElideNone"};
399         QString elide = "elide: Text." + QString(elidename[int(m)]) + ";";
400
401         // XXX Poor coverage.
402
403         {
404             QDeclarativeComponent textComponent(&engine);
405             textComponent.setData(("import QtQuick 2.0\nText { text: \"\"; "+elide+" width: 100 }").toLatin1(), QUrl::fromLocalFile(""));
406             QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
407
408             QCOMPARE(textObject->elideMode(), m);
409             QCOMPARE(textObject->width(), 100.);
410
411             delete textObject;
412         }
413
414         for (int i = 0; i < standard.size(); i++)
415         {
416             QString componentStr = "import QtQuick 2.0\nText { "+elide+" width: 100; text: \"" + standard.at(i) + "\" }";
417             QDeclarativeComponent textComponent(&engine);
418             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
419             QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
420
421             QCOMPARE(textObject->elideMode(), m);
422             QCOMPARE(textObject->width(), 100.);
423
424             delete textObject;
425         }
426
427         // richtext - does nothing
428         for (int i = 0; i < richText.size(); i++)
429         {
430             QString componentStr = "import QtQuick 2.0\nText { "+elide+" width: 100; text: \"" + richText.at(i) + "\" }";
431             QDeclarativeComponent textComponent(&engine);
432             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
433             QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
434
435             QCOMPARE(textObject->elideMode(), m);
436             QCOMPARE(textObject->width(), 100.);
437
438             delete textObject;
439         }
440     }
441 }
442
443 void tst_qquicktext::multilineElide()
444 {
445     QQuickView *canvas = createView(testFile("multilineelide.qml"));
446
447     QQuickText *myText = qobject_cast<QQuickText*>(canvas->rootObject());
448     QVERIFY(myText != 0);
449
450     QCOMPARE(myText->lineCount(), 3);
451     QCOMPARE(myText->truncated(), true);
452
453     qreal lineHeight = myText->paintedHeight() / 3.;
454
455     // reduce size and ensure fewer lines are drawn
456     myText->setHeight(lineHeight * 2);
457     QCOMPARE(myText->lineCount(), 2);
458
459     myText->setHeight(lineHeight);
460     QCOMPARE(myText->lineCount(), 1);
461
462     myText->setHeight(5);
463     QCOMPARE(myText->lineCount(), 1);
464
465     myText->setHeight(lineHeight * 3);
466     QCOMPARE(myText->lineCount(), 3);
467
468     // remove max count and show all lines.
469     myText->setHeight(1000);
470     myText->resetMaximumLineCount();
471
472     QCOMPARE(myText->truncated(), false);
473
474     // reduce size again
475     myText->setHeight(lineHeight * 2);
476     QCOMPARE(myText->lineCount(), 2);
477     QCOMPARE(myText->truncated(), true);
478
479     // change line height
480     myText->setLineHeight(1.1);
481     QCOMPARE(myText->lineCount(), 1);
482
483     delete canvas;
484 }
485
486 void tst_qquicktext::textFormat()
487 {
488     {
489         QDeclarativeComponent textComponent(&engine);
490         textComponent.setData("import QtQuick 2.0\nText { text: \"Hello\"; textFormat: Text.RichText }", QUrl::fromLocalFile(""));
491         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
492
493         QVERIFY(textObject != 0);
494         QVERIFY(textObject->textFormat() == QQuickText::RichText);
495
496         QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
497         QVERIFY(textPrivate != 0);
498         QVERIFY(textPrivate->richText == true);
499
500         delete textObject;
501     }
502     {
503         QDeclarativeComponent textComponent(&engine);
504         textComponent.setData("import QtQuick 2.0\nText { text: \"<b>Hello</b>\" }", QUrl::fromLocalFile(""));
505         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
506
507         QVERIFY(textObject != 0);
508         QVERIFY(textObject->textFormat() == QQuickText::AutoText);
509
510         QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
511         QVERIFY(textPrivate != 0);
512         QVERIFY(textPrivate->styledText == true);
513
514         delete textObject;
515     }
516     {
517         QDeclarativeComponent textComponent(&engine);
518         textComponent.setData("import QtQuick 2.0\nText { text: \"<b>Hello</b>\"; textFormat: Text.PlainText }", QUrl::fromLocalFile(""));
519         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
520
521         QVERIFY(textObject != 0);
522         QVERIFY(textObject->textFormat() == QQuickText::PlainText);
523
524         delete textObject;
525     }
526 }
527
528
529 void tst_qquicktext::alignments_data()
530 {
531     QTest::addColumn<int>("hAlign");
532     QTest::addColumn<int>("vAlign");
533     QTest::addColumn<QString>("expectfile");
534
535     QTest::newRow("LT") << int(Qt::AlignLeft) << int(Qt::AlignTop) << testFile("alignments_lt.png");
536     QTest::newRow("RT") << int(Qt::AlignRight) << int(Qt::AlignTop) << testFile("alignments_rt.png");
537     QTest::newRow("CT") << int(Qt::AlignHCenter) << int(Qt::AlignTop) << testFile("alignments_ct.png");
538
539     QTest::newRow("LB") << int(Qt::AlignLeft) << int(Qt::AlignBottom) << testFile("alignments_lb.png");
540     QTest::newRow("RB") << int(Qt::AlignRight) << int(Qt::AlignBottom) << testFile("alignments_rb.png");
541     QTest::newRow("CB") << int(Qt::AlignHCenter) << int(Qt::AlignBottom) << testFile("alignments_cb.png");
542
543     QTest::newRow("LC") << int(Qt::AlignLeft) << int(Qt::AlignVCenter) << testFile("alignments_lc.png");
544     QTest::newRow("RC") << int(Qt::AlignRight) << int(Qt::AlignVCenter) << testFile("alignments_rc.png");
545     QTest::newRow("CC") << int(Qt::AlignHCenter) << int(Qt::AlignVCenter) << testFile("alignments_cc.png");
546 }
547
548
549 void tst_qquicktext::alignments()
550 {
551     QSKIP("Text alignment pixmap comparison tests will not work with scenegraph");
552 #if (0)// No widgets in scenegraph
553     QFETCH(int, hAlign);
554     QFETCH(int, vAlign);
555     QFETCH(QString, expectfile);
556
557     QQuickView *canvas = createView(testFile("alignments.qml"));
558     canvas->show();
559     canvas->requestActivateWindow();
560     QTest::qWait(50);
561     QTRY_COMPARE(QGuiApplication::activeWindow(), static_cast<QWidget *>(canvas));
562
563     QObject *ob = canvas->rootObject();
564     QVERIFY(ob != 0);
565     ob->setProperty("horizontalAlignment",hAlign);
566     ob->setProperty("verticalAlignment",vAlign);
567     QTRY_COMPARE(ob->property("running").toBool(),false);
568     QImage actual(canvas->width(), canvas->height(), QImage::Format_RGB32);
569     actual.fill(qRgb(255,255,255));
570     QPainter p(&actual);
571     canvas->render(&p);
572
573     QImage expect(expectfile);
574     if (QGuiApplicationPrivate::graphics_system_name == "raster" || QGuiApplicationPrivate::graphics_system_name == "") {
575         QCOMPARE(actual,expect);
576     }
577     delete canvas;
578 #endif
579 }
580
581 //the alignment tests may be trivial o.oa
582 void tst_qquicktext::horizontalAlignment()
583 {
584     //test one align each, and then test if two align fails.
585
586     for (int i = 0; i < standard.size(); i++)
587     {
588         for (int j=0; j < horizontalAlignmentmentStrings.size(); j++)
589         {
590             QString componentStr = "import QtQuick 2.0\nText { horizontalAlignment: \"" + horizontalAlignmentmentStrings.at(j) + "\"; text: \"" + standard.at(i) + "\" }";
591             QDeclarativeComponent textComponent(&engine);
592             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
593             QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
594
595             QCOMPARE((int)textObject->hAlign(), (int)horizontalAlignmentments.at(j));
596
597             delete textObject;
598         }
599     }
600
601     for (int i = 0; i < richText.size(); i++)
602     {
603         for (int j=0; j < horizontalAlignmentmentStrings.size(); j++)
604         {
605             QString componentStr = "import QtQuick 2.0\nText { horizontalAlignment: \"" + horizontalAlignmentmentStrings.at(j) + "\"; text: \"" + richText.at(i) + "\" }";
606             QDeclarativeComponent textComponent(&engine);
607             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
608             QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
609
610             QCOMPARE((int)textObject->hAlign(), (int)horizontalAlignmentments.at(j));
611
612             delete textObject;
613         }
614     }
615
616 }
617
618 void tst_qquicktext::horizontalAlignment_RightToLeft()
619 {
620     QQuickView *canvas = createView(testFile("horizontalAlignment_RightToLeft.qml"));
621     QQuickText *text = canvas->rootObject()->findChild<QQuickText*>("text");
622     QVERIFY(text != 0);
623     canvas->show();
624
625     QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(text);
626     QVERIFY(textPrivate != 0);
627
628     QTRY_VERIFY(textPrivate->layout.lineCount());
629
630     // implicit alignment should follow the reading direction of RTL text
631     QCOMPARE(text->hAlign(), QQuickText::AlignRight);
632     QCOMPARE(text->effectiveHAlign(), text->hAlign());
633     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > canvas->width()/2);
634
635     // explicitly left aligned text
636     text->setHAlign(QQuickText::AlignLeft);
637     QCOMPARE(text->hAlign(), QQuickText::AlignLeft);
638     QCOMPARE(text->effectiveHAlign(), text->hAlign());
639     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < canvas->width()/2);
640
641     // explicitly right aligned text
642     text->setHAlign(QQuickText::AlignRight);
643     QCOMPARE(text->hAlign(), QQuickText::AlignRight);
644     QCOMPARE(text->effectiveHAlign(), text->hAlign());
645     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > canvas->width()/2);
646
647     // change to rich text
648     QString textString = text->text();
649     text->setText(QString("<i>") + textString + QString("</i>"));
650     text->setTextFormat(QQuickText::RichText);
651     text->resetHAlign();
652
653     // implicitly aligned rich text should follow the reading direction of text
654     QCOMPARE(text->hAlign(), QQuickText::AlignRight);
655     QCOMPARE(text->effectiveHAlign(), text->hAlign());
656     QVERIFY(textPrivate->textDocument()->defaultTextOption().alignment() & Qt::AlignLeft);
657
658     // explicitly left aligned rich text
659     text->setHAlign(QQuickText::AlignLeft);
660     QCOMPARE(text->hAlign(), QQuickText::AlignLeft);
661     QCOMPARE(text->effectiveHAlign(), text->hAlign());
662     QVERIFY(textPrivate->textDocument()->defaultTextOption().alignment() & Qt::AlignRight);
663
664     // explicitly right aligned rich text
665     text->setHAlign(QQuickText::AlignRight);
666     QCOMPARE(text->hAlign(), QQuickText::AlignRight);
667     QCOMPARE(text->effectiveHAlign(), text->hAlign());
668     QVERIFY(textPrivate->textDocument()->defaultTextOption().alignment() & Qt::AlignLeft);
669
670     text->setText(textString);
671     text->setTextFormat(QQuickText::PlainText);
672
673     // explicitly center aligned
674     text->setHAlign(QQuickText::AlignHCenter);
675     QCOMPARE(text->hAlign(), QQuickText::AlignHCenter);
676     QCOMPARE(text->effectiveHAlign(), text->hAlign());
677     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < canvas->width()/2);
678     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().right() > canvas->width()/2);
679
680     // reseted alignment should go back to following the text reading direction
681     text->resetHAlign();
682     QCOMPARE(text->hAlign(), QQuickText::AlignRight);
683     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > canvas->width()/2);
684
685     // mirror the text item
686     QQuickItemPrivate::get(text)->setLayoutMirror(true);
687
688     // mirrored implicit alignment should continue to follow the reading direction of the text
689     QCOMPARE(text->hAlign(), QQuickText::AlignRight);
690     QCOMPARE(text->effectiveHAlign(), QQuickText::AlignRight);
691     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > canvas->width()/2);
692
693     // mirrored explicitly right aligned behaves as left aligned
694     text->setHAlign(QQuickText::AlignRight);
695     QCOMPARE(text->hAlign(), QQuickText::AlignRight);
696     QCOMPARE(text->effectiveHAlign(), QQuickText::AlignLeft);
697     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < canvas->width()/2);
698
699     // mirrored explicitly left aligned behaves as right aligned
700     text->setHAlign(QQuickText::AlignLeft);
701     QCOMPARE(text->hAlign(), QQuickText::AlignLeft);
702     QCOMPARE(text->effectiveHAlign(), QQuickText::AlignRight);
703     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > canvas->width()/2);
704
705     // disable mirroring
706     QQuickItemPrivate::get(text)->setLayoutMirror(false);
707     text->resetHAlign();
708
709     // English text should be implicitly left aligned
710     text->setText("Hello world!");
711     QCOMPARE(text->hAlign(), QQuickText::AlignLeft);
712     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < canvas->width()/2);
713
714     // empty text with implicit alignment follows the system locale-based
715     // keyboard input direction from QInputPanel::inputDirection()
716     text->setText("");
717     QCOMPARE(text->hAlign(), qApp->inputPanel()->inputDirection() == Qt::LeftToRight ?
718                                   QQuickText::AlignLeft : QQuickText::AlignRight);
719     text->setHAlign(QQuickText::AlignRight);
720     QCOMPARE(text->hAlign(), QQuickText::AlignRight);
721
722     delete canvas;
723
724     // alignment of Text with no text set to it
725     QString componentStr = "import QtQuick 2.0\nText {}";
726     QDeclarativeComponent textComponent(&engine);
727     textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
728     QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
729     QCOMPARE(textObject->hAlign(), qApp->inputPanel()->inputDirection() == Qt::LeftToRight ?
730                                   QQuickText::AlignLeft : QQuickText::AlignRight);
731     delete textObject;
732 }
733
734 void tst_qquicktext::verticalAlignment()
735 {
736     //test one align each, and then test if two align fails.
737
738     for (int i = 0; i < standard.size(); i++)
739     {
740         for (int j=0; j < verticalAlignmentmentStrings.size(); j++)
741         {
742             QString componentStr = "import QtQuick 2.0\nText { verticalAlignment: \"" + verticalAlignmentmentStrings.at(j) + "\"; text: \"" + standard.at(i) + "\" }";
743             QDeclarativeComponent textComponent(&engine);
744             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
745             QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
746
747             QVERIFY(textObject != 0);
748             QCOMPARE((int)textObject->vAlign(), (int)verticalAlignmentments.at(j));
749
750             delete textObject;
751         }
752     }
753
754     for (int i = 0; i < richText.size(); i++)
755     {
756         for (int j=0; j < verticalAlignmentmentStrings.size(); j++)
757         {
758             QString componentStr = "import QtQuick 2.0\nText { verticalAlignment: \"" + verticalAlignmentmentStrings.at(j) + "\"; text: \"" + richText.at(i) + "\" }";
759             QDeclarativeComponent textComponent(&engine);
760             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
761             QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
762
763             QVERIFY(textObject != 0);
764             QCOMPARE((int)textObject->vAlign(), (int)verticalAlignmentments.at(j));
765
766             delete textObject;
767         }
768     }
769
770 }
771
772 void tst_qquicktext::font()
773 {
774     //test size, then bold, then italic, then family
775     {
776         QString componentStr = "import QtQuick 2.0\nText { font.pointSize: 40; text: \"Hello World\" }";
777         QDeclarativeComponent textComponent(&engine);
778         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
779         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
780
781         QCOMPARE(textObject->font().pointSize(), 40);
782         QCOMPARE(textObject->font().bold(), false);
783         QCOMPARE(textObject->font().italic(), false);
784
785         delete textObject;
786     }
787
788     {
789         QString componentStr = "import QtQuick 2.0\nText { font.pixelSize: 40; text: \"Hello World\" }";
790         QDeclarativeComponent textComponent(&engine);
791         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
792         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
793
794         QCOMPARE(textObject->font().pixelSize(), 40);
795         QCOMPARE(textObject->font().bold(), false);
796         QCOMPARE(textObject->font().italic(), false);
797
798         delete textObject;
799     }
800
801     {
802         QString componentStr = "import QtQuick 2.0\nText { font.bold: true; text: \"Hello World\" }";
803         QDeclarativeComponent textComponent(&engine);
804         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
805         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
806
807         QCOMPARE(textObject->font().bold(), true);
808         QCOMPARE(textObject->font().italic(), false);
809
810         delete textObject;
811     }
812
813     {
814         QString componentStr = "import QtQuick 2.0\nText { font.italic: true; text: \"Hello World\" }";
815         QDeclarativeComponent textComponent(&engine);
816         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
817         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
818
819         QCOMPARE(textObject->font().italic(), true);
820         QCOMPARE(textObject->font().bold(), false);
821
822         delete textObject;
823     }
824
825     {
826         QString componentStr = "import QtQuick 2.0\nText { font.family: \"Helvetica\"; text: \"Hello World\" }";
827         QDeclarativeComponent textComponent(&engine);
828         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
829         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
830
831         QCOMPARE(textObject->font().family(), QString("Helvetica"));
832         QCOMPARE(textObject->font().bold(), false);
833         QCOMPARE(textObject->font().italic(), false);
834
835         delete textObject;
836     }
837
838     {
839         QString componentStr = "import QtQuick 2.0\nText { font.family: \"\"; text: \"Hello World\" }";
840         QDeclarativeComponent textComponent(&engine);
841         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
842         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
843
844         QCOMPARE(textObject->font().family(), QString(""));
845
846         delete textObject;
847     }
848 }
849
850 void tst_qquicktext::style()
851 {
852     //test style
853     for (int i = 0; i < styles.size(); i++)
854     {
855         QString componentStr = "import QtQuick 2.0\nText { style: \"" + styleStrings.at(i) + "\"; styleColor: \"white\"; text: \"Hello World\" }";
856         QDeclarativeComponent textComponent(&engine);
857         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
858         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
859
860         QCOMPARE((int)textObject->style(), (int)styles.at(i));
861         QCOMPARE(textObject->styleColor(), QColor("white"));
862
863         delete textObject;
864     }
865     QString componentStr = "import QtQuick 2.0\nText { text: \"Hello World\" }";
866     QDeclarativeComponent textComponent(&engine);
867     textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
868     QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
869
870     QRectF brPre = textObject->boundingRect();
871     textObject->setStyle(QQuickText::Outline);
872     QRectF brPost = textObject->boundingRect();
873
874     QVERIFY(brPre.width() < brPost.width());
875     QVERIFY(brPre.height() < brPost.height());
876
877     delete textObject;
878 }
879
880 void tst_qquicktext::color()
881 {
882     //test style
883     for (int i = 0; i < colorStrings.size(); i++)
884     {
885         QString componentStr = "import QtQuick 2.0\nText { color: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
886         QDeclarativeComponent textComponent(&engine);
887         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
888         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
889
890         QCOMPARE(textObject->color(), QColor(colorStrings.at(i)));
891         QCOMPARE(textObject->styleColor(), QColor());
892
893         delete textObject;
894     }
895
896     for (int i = 0; i < colorStrings.size(); i++)
897     {
898         QString componentStr = "import QtQuick 2.0\nText { styleColor: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
899         QDeclarativeComponent textComponent(&engine);
900         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
901         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
902
903         QCOMPARE(textObject->styleColor(), QColor(colorStrings.at(i)));
904         // default color to black?
905         QCOMPARE(textObject->color(), QColor("black"));
906
907         delete textObject;
908     }
909
910     for (int i = 0; i < colorStrings.size(); i++)
911     {
912         for (int j = 0; j < colorStrings.size(); j++)
913         {
914             QString componentStr = "import QtQuick 2.0\nText { color: \"" + colorStrings.at(i) + "\"; styleColor: \"" + colorStrings.at(j) + "\"; text: \"Hello World\" }";
915             QDeclarativeComponent textComponent(&engine);
916             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
917             QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
918
919             QCOMPARE(textObject->color(), QColor(colorStrings.at(i)));
920             QCOMPARE(textObject->styleColor(), QColor(colorStrings.at(j)));
921
922             delete textObject;
923         }
924     }
925     {
926         QString colorStr = "#AA001234";
927         QColor testColor("#001234");
928         testColor.setAlpha(170);
929
930         QString componentStr = "import QtQuick 2.0\nText { color: \"" + colorStr + "\"; text: \"Hello World\" }";
931         QDeclarativeComponent textComponent(&engine);
932         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
933         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
934
935         QCOMPARE(textObject->color(), testColor);
936
937         delete textObject;
938     }
939 }
940
941 void tst_qquicktext::smooth()
942 {
943     for (int i = 0; i < standard.size(); i++)
944     {
945         {
946             QString componentStr = "import QtQuick 2.0\nText { smooth: true; text: \"" + standard.at(i) + "\" }";
947             QDeclarativeComponent textComponent(&engine);
948             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
949             QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
950             QCOMPARE(textObject->smooth(), true);
951
952             delete textObject;
953         }
954         {
955             QString componentStr = "import QtQuick 2.0\nText { text: \"" + standard.at(i) + "\" }";
956             QDeclarativeComponent textComponent(&engine);
957             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
958             QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
959             QCOMPARE(textObject->smooth(), false);
960
961             delete textObject;
962         }
963     }
964     for (int i = 0; i < richText.size(); i++)
965     {
966         {
967             QString componentStr = "import QtQuick 2.0\nText { smooth: true; text: \"" + richText.at(i) + "\" }";
968             QDeclarativeComponent textComponent(&engine);
969             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
970             QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
971             QCOMPARE(textObject->smooth(), true);
972
973             delete textObject;
974         }
975         {
976             QString componentStr = "import QtQuick 2.0\nText { text: \"" + richText.at(i) + "\" }";
977             QDeclarativeComponent textComponent(&engine);
978             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
979             QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
980             QCOMPARE(textObject->smooth(), false);
981
982             delete textObject;
983         }
984     }
985 }
986
987 void tst_qquicktext::weight()
988 {
989     {
990         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
991         QDeclarativeComponent textComponent(&engine);
992         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
993         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
994
995         QVERIFY(textObject != 0);
996         QCOMPARE((int)textObject->font().weight(), (int)QDeclarativeFontValueType::Normal);
997
998         delete textObject;
999     }
1000     {
1001         QString componentStr = "import QtQuick 2.0\nText { font.weight: \"Bold\"; text: \"Hello world!\" }";
1002         QDeclarativeComponent textComponent(&engine);
1003         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1004         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1005
1006         QVERIFY(textObject != 0);
1007         QCOMPARE((int)textObject->font().weight(), (int)QDeclarativeFontValueType::Bold);
1008
1009         delete textObject;
1010     }
1011 }
1012
1013 void tst_qquicktext::underline()
1014 {
1015     {
1016         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1017         QDeclarativeComponent textComponent(&engine);
1018         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1019         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1020
1021         QVERIFY(textObject != 0);
1022         QCOMPARE(textObject->font().underline(), false);
1023
1024         delete textObject;
1025     }
1026     {
1027         QString componentStr = "import QtQuick 2.0\nText { font.underline: true; text: \"Hello world!\" }";
1028         QDeclarativeComponent textComponent(&engine);
1029         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1030         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1031
1032         QVERIFY(textObject != 0);
1033         QCOMPARE(textObject->font().underline(), true);
1034
1035         delete textObject;
1036     }
1037 }
1038
1039 void tst_qquicktext::overline()
1040 {
1041     {
1042         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1043         QDeclarativeComponent textComponent(&engine);
1044         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1045         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1046
1047         QVERIFY(textObject != 0);
1048         QCOMPARE(textObject->font().overline(), false);
1049
1050         delete textObject;
1051     }
1052     {
1053         QString componentStr = "import QtQuick 2.0\nText { font.overline: true; text: \"Hello world!\" }";
1054         QDeclarativeComponent textComponent(&engine);
1055         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1056         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1057
1058         QVERIFY(textObject != 0);
1059         QCOMPARE(textObject->font().overline(), true);
1060
1061         delete textObject;
1062     }
1063 }
1064
1065 void tst_qquicktext::strikeout()
1066 {
1067     {
1068         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1069         QDeclarativeComponent textComponent(&engine);
1070         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1071         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1072
1073         QVERIFY(textObject != 0);
1074         QCOMPARE(textObject->font().strikeOut(), false);
1075
1076         delete textObject;
1077     }
1078     {
1079         QString componentStr = "import QtQuick 2.0\nText { font.strikeout: true; text: \"Hello world!\" }";
1080         QDeclarativeComponent textComponent(&engine);
1081         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1082         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1083
1084         QVERIFY(textObject != 0);
1085         QCOMPARE(textObject->font().strikeOut(), true);
1086
1087         delete textObject;
1088     }
1089 }
1090
1091 void tst_qquicktext::capitalization()
1092 {
1093     {
1094         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1095         QDeclarativeComponent textComponent(&engine);
1096         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1097         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1098
1099         QVERIFY(textObject != 0);
1100         QCOMPARE((int)textObject->font().capitalization(), (int)QDeclarativeFontValueType::MixedCase);
1101
1102         delete textObject;
1103     }
1104     {
1105         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"AllUppercase\" }";
1106         QDeclarativeComponent textComponent(&engine);
1107         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1108         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1109
1110         QVERIFY(textObject != 0);
1111         QCOMPARE((int)textObject->font().capitalization(), (int)QDeclarativeFontValueType::AllUppercase);
1112
1113         delete textObject;
1114     }
1115     {
1116         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"AllLowercase\" }";
1117         QDeclarativeComponent textComponent(&engine);
1118         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1119         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1120
1121         QVERIFY(textObject != 0);
1122         QCOMPARE((int)textObject->font().capitalization(), (int)QDeclarativeFontValueType::AllLowercase);
1123
1124         delete textObject;
1125     }
1126     {
1127         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"SmallCaps\" }";
1128         QDeclarativeComponent textComponent(&engine);
1129         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1130         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1131
1132         QVERIFY(textObject != 0);
1133         QCOMPARE((int)textObject->font().capitalization(), (int)QDeclarativeFontValueType::SmallCaps);
1134
1135         delete textObject;
1136     }
1137     {
1138         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"Capitalize\" }";
1139         QDeclarativeComponent textComponent(&engine);
1140         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1141         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1142
1143         QVERIFY(textObject != 0);
1144         QCOMPARE((int)textObject->font().capitalization(), (int)QDeclarativeFontValueType::Capitalize);
1145
1146         delete textObject;
1147     }
1148 }
1149
1150 void tst_qquicktext::letterSpacing()
1151 {
1152     {
1153         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1154         QDeclarativeComponent textComponent(&engine);
1155         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1156         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1157
1158         QVERIFY(textObject != 0);
1159         QCOMPARE(textObject->font().letterSpacing(), 0.0);
1160
1161         delete textObject;
1162     }
1163     {
1164         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.letterSpacing: -2 }";
1165         QDeclarativeComponent textComponent(&engine);
1166         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1167         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1168
1169         QVERIFY(textObject != 0);
1170         QCOMPARE(textObject->font().letterSpacing(), -2.);
1171
1172         delete textObject;
1173     }
1174     {
1175         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.letterSpacing: 3 }";
1176         QDeclarativeComponent textComponent(&engine);
1177         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1178         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1179
1180         QVERIFY(textObject != 0);
1181         QCOMPARE(textObject->font().letterSpacing(), 3.);
1182
1183         delete textObject;
1184     }
1185 }
1186
1187 void tst_qquicktext::wordSpacing()
1188 {
1189     {
1190         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1191         QDeclarativeComponent textComponent(&engine);
1192         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1193         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1194
1195         QVERIFY(textObject != 0);
1196         QCOMPARE(textObject->font().wordSpacing(), 0.0);
1197
1198         delete textObject;
1199     }
1200     {
1201         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.wordSpacing: -50 }";
1202         QDeclarativeComponent textComponent(&engine);
1203         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1204         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1205
1206         QVERIFY(textObject != 0);
1207         QCOMPARE(textObject->font().wordSpacing(), -50.);
1208
1209         delete textObject;
1210     }
1211     {
1212         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.wordSpacing: 200 }";
1213         QDeclarativeComponent textComponent(&engine);
1214         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1215         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1216
1217         QVERIFY(textObject != 0);
1218         QCOMPARE(textObject->font().wordSpacing(), 200.);
1219
1220         delete textObject;
1221     }
1222 }
1223
1224
1225
1226
1227 class EventSender : public QQuickItem
1228 {
1229 public:
1230     void sendEvent(QMouseEvent *event) {
1231         if (event->type() == QEvent::MouseButtonPress)
1232             mousePressEvent(event);
1233         else if (event->type() == QEvent::MouseButtonRelease)
1234             mouseReleaseEvent(event);
1235         else
1236             qWarning() << "Trying to send unsupported event type";
1237     }
1238 };
1239
1240 class LinkTest : public QObject
1241 {
1242     Q_OBJECT
1243 public:
1244     LinkTest() {}
1245
1246     QString link;
1247
1248 public slots:
1249     void linkClicked(QString l) { link = l; }
1250 };
1251
1252 void tst_qquicktext::clickLink()
1253 {
1254     {
1255         QString componentStr = "import QtQuick 2.0\nText { text: \"<a href=\\\"http://qt.nokia.com\\\">Hello world!</a>\" }";
1256         QDeclarativeComponent textComponent(&engine);
1257         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1258         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1259
1260         QVERIFY(textObject != 0);
1261
1262         LinkTest test;
1263         QObject::connect(textObject, SIGNAL(linkActivated(QString)), &test, SLOT(linkClicked(QString)));
1264
1265         {
1266             QMouseEvent me(QEvent::MouseButtonPress,QPointF(textObject->x()/2, textObject->y()/2), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
1267             static_cast<EventSender*>(static_cast<QQuickItem*>(textObject))->sendEvent(&me);
1268
1269         }
1270
1271         {
1272             QMouseEvent me(QEvent::MouseButtonRelease,QPointF(textObject->x()/2, textObject->y()/2), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
1273             static_cast<EventSender*>(static_cast<QQuickItem*>(textObject))->sendEvent(&me);
1274
1275         }
1276
1277
1278         QCOMPARE(test.link, QLatin1String("http://qt.nokia.com"));
1279
1280         delete textObject;
1281     }
1282 }
1283
1284 void tst_qquicktext::embeddedImages_data()
1285 {
1286     QTest::addColumn<QUrl>("qmlfile");
1287     QTest::addColumn<QString>("error");
1288     QTest::newRow("local") << testFileUrl("embeddedImagesLocal.qml") << "";
1289     QTest::newRow("local-error") << testFileUrl("embeddedImagesLocalError.qml")
1290         << testFileUrl("embeddedImagesLocalError.qml").toString()+":3:1: QML Text: Cannot open: " + testFileUrl("http/notexists.png").toString();
1291     QTest::newRow("remote") << testFileUrl("embeddedImagesRemote.qml") << "";
1292     QTest::newRow("remote-error") << testFileUrl("embeddedImagesRemoteError.qml")
1293         << testFileUrl("embeddedImagesRemoteError.qml").toString()+":3:1: QML Text: Error downloading http://127.0.0.1:14453/notexists.png - server replied: Not found";
1294 }
1295
1296 void tst_qquicktext::embeddedImages()
1297 {
1298     // Tests QTBUG-9900
1299
1300     QFETCH(QUrl, qmlfile);
1301     QFETCH(QString, error);
1302
1303     TestHTTPServer server(14453);
1304     server.serveDirectory(testFile("http"));
1305
1306     if (!error.isEmpty())
1307         QTest::ignoreMessage(QtWarningMsg, error.toLatin1());
1308
1309     QDeclarativeComponent textComponent(&engine, qmlfile);
1310     QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1311
1312     QVERIFY(textObject != 0);
1313
1314     QTRY_COMPARE(textObject->resourcesLoading(), 0);
1315
1316     QPixmap pm(testFile("http/exists.png"));
1317     if (error.isEmpty()) {
1318         QCOMPARE(textObject->width(), double(pm.width()));
1319         QCOMPARE(textObject->height(), double(pm.height()));
1320     } else {
1321         QVERIFY(16 != pm.width()); // check test is effective
1322         QCOMPARE(textObject->width(), 16.0); // default size of QTextDocument broken image icon
1323         QCOMPARE(textObject->height(), 16.0);
1324     }
1325
1326     delete textObject;
1327 }
1328
1329 void tst_qquicktext::lineCount()
1330 {
1331     QQuickView *canvas = createView(testFile("lineCount.qml"));
1332
1333     QQuickText *myText = canvas->rootObject()->findChild<QQuickText*>("myText");
1334     QVERIFY(myText != 0);
1335
1336     QVERIFY(myText->lineCount() > 1);
1337     QVERIFY(!myText->truncated());
1338     QCOMPARE(myText->maximumLineCount(), INT_MAX);
1339
1340     myText->setMaximumLineCount(2);
1341     QCOMPARE(myText->lineCount(), 2);
1342     QCOMPARE(myText->truncated(), true);
1343     QCOMPARE(myText->maximumLineCount(), 2);
1344
1345     myText->resetMaximumLineCount();
1346     QCOMPARE(myText->maximumLineCount(), INT_MAX);
1347     QCOMPARE(myText->truncated(), false);
1348
1349     myText->setElideMode(QQuickText::ElideRight);
1350     myText->setMaximumLineCount(2);
1351     QCOMPARE(myText->lineCount(), 2);
1352     QCOMPARE(myText->truncated(), true);
1353     QCOMPARE(myText->maximumLineCount(), 2);
1354
1355     delete canvas;
1356 }
1357
1358 void tst_qquicktext::lineHeight()
1359 {
1360     QQuickView *canvas = createView(testFile("lineHeight.qml"));
1361
1362     QQuickText *myText = canvas->rootObject()->findChild<QQuickText*>("myText");
1363     QVERIFY(myText != 0);
1364
1365     QVERIFY(myText->lineHeight() == 1);
1366     QVERIFY(myText->lineHeightMode() == QQuickText::ProportionalHeight);
1367
1368     qreal h = myText->height();
1369     myText->setLineHeight(1.5);
1370     QVERIFY(myText->height() == qCeil(h * 1.5));
1371
1372     myText->setLineHeightMode(QQuickText::FixedHeight);
1373     myText->setLineHeight(20);
1374     QCOMPARE(myText->height(), myText->lineCount() * 20.0);
1375
1376     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.");
1377     myText->setLineHeightMode(QQuickText::ProportionalHeight);
1378     myText->setLineHeight(1.0);
1379
1380     qreal h2 = myText->height();
1381     myText->setLineHeight(2.0);
1382     QVERIFY(myText->height() == h2 * 2.0);
1383
1384     myText->setLineHeightMode(QQuickText::FixedHeight);
1385     myText->setLineHeight(10);
1386     QCOMPARE(myText->height(), myText->lineCount() * 10.0);
1387
1388     delete canvas;
1389 }
1390
1391 void tst_qquicktext::implicitSize_data()
1392 {
1393     QTest::addColumn<QString>("text");
1394     QTest::addColumn<QString>("wrap");
1395     QTest::newRow("plain") << "The quick red fox jumped over the lazy brown dog" << "Text.NoWrap";
1396     QTest::newRow("richtext") << "<b>The quick red fox jumped over the lazy brown dog</b>" << "Text.NoWrap";
1397     QTest::newRow("plain_wrap") << "The quick red fox jumped over the lazy brown dog" << "Text.Wrap";
1398     QTest::newRow("richtext_wrap") << "<b>The quick red fox jumped over the lazy brown dog</b>" << "Text.Wrap";
1399 }
1400
1401 void tst_qquicktext::implicitSize()
1402 {
1403     QFETCH(QString, text);
1404     QFETCH(QString, wrap);
1405     QString componentStr = "import QtQuick 2.0\nText { text: \"" + text + "\"; width: 50; wrapMode: " + wrap + " }";
1406     QDeclarativeComponent textComponent(&engine);
1407     textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1408     QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1409
1410     QVERIFY(textObject->width() < textObject->implicitWidth());
1411     QVERIFY(textObject->height() == textObject->implicitHeight());
1412
1413     textObject->resetWidth();
1414     QVERIFY(textObject->width() == textObject->implicitWidth());
1415     QVERIFY(textObject->height() == textObject->implicitHeight());
1416
1417     delete textObject;
1418 }
1419
1420 void tst_qquicktext::lineLaidOut()
1421 {
1422     QQuickView *canvas = createView(testFile("lineLayout.qml"));
1423
1424     QQuickText *myText = canvas->rootObject()->findChild<QQuickText*>("myText");
1425     QVERIFY(myText != 0);
1426
1427     QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(myText);
1428     QVERIFY(textPrivate != 0);
1429
1430     QTextDocument *doc = textPrivate->textDocument();
1431     QVERIFY(doc == 0);
1432
1433 #if defined(Q_OS_MAC)
1434     QVERIFY(myText->lineCount() == textPrivate->linesRects.count());
1435 #endif
1436
1437     for (int i = 0; i < textPrivate->layout.lineCount(); ++i) {
1438         QRectF r = textPrivate->layout.lineAt(i).rect();
1439         QVERIFY(r.width() == i * 15);
1440         if (i >= 30)
1441             QVERIFY(r.x() == r.width() + 30);
1442         if (i >= 60) {
1443             QVERIFY(r.x() == r.width() * 2 + 60);
1444             QVERIFY(r.height() == 20);
1445         }
1446     }
1447
1448     delete canvas;
1449 }
1450
1451 QTEST_MAIN(tst_qquicktext)
1452
1453 #include "tst_qquicktext.moc"