86c33a64d8c852b6b44e925882127cc906c4c935
[profile/ivi/qtdeclarative.git] / tests / auto / declarative / qquicktextedit / tst_qquicktextedit.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 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 <QtTest/QSignalSpy>
43 #include "../shared/testhttpserver.h"
44 #include <math.h>
45 #include <QFile>
46 #include <QTextDocument>
47 #include <QtDeclarative/qdeclarativeengine.h>
48 #include <QtDeclarative/qdeclarativecontext.h>
49 #include <QtDeclarative/qdeclarativeexpression.h>
50 #include <QtDeclarative/qdeclarativecomponent.h>
51 #include <QtGui/qguiapplication.h>
52 #include <private/qquicktextedit_p.h>
53 #include <private/qquicktextedit_p_p.h>
54 #include <private/qsgdistancefieldglyphcache_p.h>
55 #include <QFontMetrics>
56 #include <QQuickView>
57 #include <QDir>
58 #include <QStyle>
59 #include <QInputContext>
60 #include <QInputPanel>
61 #include <QClipboard>
62 #include <QMimeData>
63 #include <private/qtextcontrol_p.h>
64 #include "../shared/util.h"
65
66 #ifdef Q_WS_MAC
67 #include <Carbon/Carbon.h>
68 #endif
69
70 #define QTBUG_21691
71 #define QTBUG_21691_MESSAGE "QTBUG-21691: The test needs to be rewritten to not use QInputContext"
72
73 Q_DECLARE_METATYPE(QQuickTextEdit::SelectionMode)
74 DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
75
76 QString createExpectedFileIfNotFound(const QString& filebasename, const QImage& actual)
77 {
78     // XXX This will be replaced by some clever persistent platform image store.
79     QString persistent_dir = TESTDATA("");
80     QString arch = "unknown-architecture"; // QTest needs to help with this.
81
82     QString expectfile = persistent_dir + QDir::separator() + filebasename + "-" + arch + ".png";
83
84     if (!QFile::exists(expectfile)) {
85         actual.save(expectfile);
86         qWarning() << "created" << expectfile;
87     }
88
89     return expectfile;
90 }
91
92
93 class tst_qquicktextedit : public QObject
94
95 {
96     Q_OBJECT
97 public:
98     tst_qquicktextedit();
99
100 private slots:
101     void initTestCase();
102     void cleanupTestCase();
103     void text();
104     void width();
105     void wrap();
106     void textFormat();
107     void alignments();
108     void alignments_data();
109
110     // ### these tests may be trivial
111     void hAlign();
112     void hAlign_RightToLeft();
113     void vAlign();
114     void font();
115     void color();
116     void textMargin();
117     void persistentSelection();
118     void focusOnPress();
119     void selection();
120     void isRightToLeft_data();
121     void isRightToLeft();
122     void keySelection();
123     void moveCursorSelection_data();
124     void moveCursorSelection();
125     void moveCursorSelectionSequence_data();
126     void moveCursorSelectionSequence();
127     void mouseSelection_data();
128     void mouseSelection();
129     void mouseSelectionMode_data();
130     void mouseSelectionMode();
131     void dragMouseSelection();
132     void inputMethodHints();
133
134     void positionAt();
135
136     void cursorDelegate();
137     void cursorVisible();
138     void delegateLoading_data();
139     void delegateLoading();
140     void navigation();
141     void readOnly();
142     void copyAndPaste();
143     void canPaste();
144     void canPasteEmpty();
145     void textInput();
146     void openInputPanel();
147     void geometrySignals();
148     void pastingRichText_QTBUG_14003();
149     void implicitSize_data();
150     void implicitSize();
151     void testQtQuick11Attributes();
152     void testQtQuick11Attributes_data();
153
154     void preeditMicroFocus();
155     void inputContextMouseHandler();
156     void inputMethodComposing();
157     void cursorRectangleSize();
158
159     void emptytags_QTBUG_22058();
160
161 private:
162     void simulateKey(QQuickView *, int key, Qt::KeyboardModifiers modifiers = 0);
163
164     QStringList standard;
165     QStringList richText;
166
167     QStringList hAlignmentStrings;
168     QStringList vAlignmentStrings;
169
170     QList<Qt::Alignment> vAlignments;
171     QList<Qt::Alignment> hAlignments;
172
173     QStringList colorStrings;
174
175     QDeclarativeEngine engine;
176 };
177 void tst_qquicktextedit::initTestCase()
178 {
179 }
180
181 void tst_qquicktextedit::cleanupTestCase()
182 {
183
184 }
185 tst_qquicktextedit::tst_qquicktextedit()
186 {
187     standard << "the quick brown fox jumped over the lazy dog"
188              << "the quick brown fox\n jumped over the lazy dog"
189              << "Hello, world!"
190              << "!dlrow ,olleH";
191
192     richText << "<i>the <b>quick</b> brown <a href=\\\"http://www.google.com\\\">fox</a> jumped over the <b>lazy</b> dog</i>"
193              << "<i>the <b>quick</b> brown <a href=\\\"http://www.google.com\\\">fox</a><br>jumped over the <b>lazy</b> dog</i>";
194
195     hAlignmentStrings << "AlignLeft"
196                       << "AlignRight"
197                       << "AlignHCenter";
198
199     vAlignmentStrings << "AlignTop"
200                       << "AlignBottom"
201                       << "AlignVCenter";
202
203     hAlignments << Qt::AlignLeft
204                 << Qt::AlignRight
205                 << Qt::AlignHCenter;
206
207     vAlignments << Qt::AlignTop
208                 << Qt::AlignBottom
209                 << Qt::AlignVCenter;
210
211     colorStrings << "aliceblue"
212                  << "antiquewhite"
213                  << "aqua"
214                  << "darkkhaki"
215                  << "darkolivegreen"
216                  << "dimgray"
217                  << "palevioletred"
218                  << "lightsteelblue"
219                  << "#000000"
220                  << "#AAAAAA"
221                  << "#FFFFFF"
222                  << "#2AC05F";
223                  //
224                  // need a different test to do alpha channel test
225                  // << "#AA0011DD"
226                  // << "#00F16B11";
227                  //
228 }
229
230 void tst_qquicktextedit::text()
231 {
232     {
233         QDeclarativeComponent texteditComponent(&engine);
234         texteditComponent.setData("import QtQuick 2.0\nTextEdit {  text: \"\"  }", QUrl());
235         QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
236
237         QVERIFY(textEditObject != 0);
238         QCOMPARE(textEditObject->text(), QString(""));
239     }
240
241     for (int i = 0; i < standard.size(); i++)
242     {
243         QString componentStr = "import QtQuick 2.0\nTextEdit { text: \"" + standard.at(i) + "\" }";
244         QDeclarativeComponent texteditComponent(&engine);
245         texteditComponent.setData(componentStr.toLatin1(), QUrl());
246         QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
247
248         QVERIFY(textEditObject != 0);
249         QCOMPARE(textEditObject->text(), standard.at(i));
250     }
251
252     for (int i = 0; i < richText.size(); i++)
253     {
254         QString componentStr = "import QtQuick 2.0\nTextEdit { text: \"" + richText.at(i) + "\" }";
255         QDeclarativeComponent texteditComponent(&engine);
256         texteditComponent.setData(componentStr.toLatin1(), QUrl());
257         QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
258
259         QVERIFY(textEditObject != 0);
260         QString actual = textEditObject->text();
261         QString expected = richText.at(i);
262         actual.replace(QRegExp(".*<body[^>]*>"),"");
263         actual.replace(QRegExp("(<[^>]*>)+"),"<>");
264         expected.replace(QRegExp("(<[^>]*>)+"),"<>");
265         QCOMPARE(actual.simplified(),expected.simplified());
266     }
267 }
268
269 void tst_qquicktextedit::width()
270 {
271     // uses Font metrics to find the width for standard and document to find the width for rich
272     {
273         QDeclarativeComponent texteditComponent(&engine);
274         texteditComponent.setData("import QtQuick 2.0\nTextEdit {  text: \"\" }", QUrl());
275         QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
276
277         QVERIFY(textEditObject != 0);
278         QCOMPARE(textEditObject->width(), 0.0);
279     }
280
281     bool requiresUnhintedMetrics = !qmlDisableDistanceField();
282
283     for (int i = 0; i < standard.size(); i++)
284     {
285         QFont f;
286         qreal metricWidth = 0.0;
287
288         if (requiresUnhintedMetrics) {
289             QString s = standard.at(i);
290             s.replace(QLatin1Char('\n'), QChar::LineSeparator);
291
292             QTextLayout layout(s);
293             layout.setFlags(Qt::TextExpandTabs | Qt::TextShowMnemonic);
294             {
295                 QTextOption option;
296                 option.setUseDesignMetrics(true);
297                 layout.setTextOption(option);
298             }
299
300             layout.beginLayout();
301             forever {
302                 QTextLine line = layout.createLine();
303                 if (!line.isValid())
304                     break;
305             }
306
307             layout.endLayout();
308
309             metricWidth = ceil(layout.boundingRect().width());
310         } else {
311             QFontMetricsF fm(f);
312             metricWidth = fm.size(Qt::TextExpandTabs | Qt::TextShowMnemonic, standard.at(i)).width();
313             metricWidth = ceil(metricWidth);
314         }
315
316         QString componentStr = "import QtQuick 2.0\nTextEdit { text: \"" + standard.at(i) + "\" }";
317         QDeclarativeComponent texteditComponent(&engine);
318         texteditComponent.setData(componentStr.toLatin1(), QUrl());
319         QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
320
321         QVERIFY(textEditObject != 0);
322         QCOMPARE(textEditObject->width(), qreal(metricWidth));
323     }
324
325     for (int i = 0; i < richText.size(); i++)
326     {
327         QTextDocument document;
328         document.setHtml(richText.at(i));
329         document.setDocumentMargin(0);
330         if (requiresUnhintedMetrics)
331             document.setUseDesignMetrics(true);
332
333         int documentWidth = ceil(document.idealWidth());
334
335         QString componentStr = "import QtQuick 2.0\nTextEdit { text: \"" + richText.at(i) + "\" }";
336         QDeclarativeComponent texteditComponent(&engine);
337         texteditComponent.setData(componentStr.toLatin1(), QUrl());
338         QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
339
340         QVERIFY(textEditObject != 0);
341         QCOMPARE(textEditObject->width(), qreal(documentWidth));
342     }
343 }
344
345 void tst_qquicktextedit::wrap()
346 {
347     // for specified width and wrap set true
348     {
349         QDeclarativeComponent texteditComponent(&engine);
350         texteditComponent.setData("import QtQuick 2.0\nTextEdit {  text: \"\"; wrapMode: TextEdit.WordWrap; width: 300 }", QUrl());
351         QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
352
353         QVERIFY(textEditObject != 0);
354         QCOMPARE(textEditObject->width(), 300.);
355     }
356
357     for (int i = 0; i < standard.size(); i++)
358     {
359         QString componentStr = "import QtQuick 2.0\nTextEdit {  wrapMode: TextEdit.WordWrap; width: 300; text: \"" + standard.at(i) + "\" }";
360         QDeclarativeComponent texteditComponent(&engine);
361         texteditComponent.setData(componentStr.toLatin1(), QUrl());
362         QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
363
364         QVERIFY(textEditObject != 0);
365         QCOMPARE(textEditObject->width(), 300.);
366     }
367
368     for (int i = 0; i < richText.size(); i++)
369     {
370         QString componentStr = "import QtQuick 2.0\nTextEdit {  wrapMode: TextEdit.WordWrap; width: 300; text: \"" + richText.at(i) + "\" }";
371         QDeclarativeComponent texteditComponent(&engine);
372         texteditComponent.setData(componentStr.toLatin1(), QUrl());
373         QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
374
375         QVERIFY(textEditObject != 0);
376         QCOMPARE(textEditObject->width(), 300.);
377     }
378
379 }
380
381 void tst_qquicktextedit::textFormat()
382 {
383     {
384         QDeclarativeComponent textComponent(&engine);
385         textComponent.setData("import QtQuick 2.0\nTextEdit { text: \"Hello\"; textFormat: Text.RichText }", QUrl::fromLocalFile(""));
386         QQuickTextEdit *textObject = qobject_cast<QQuickTextEdit*>(textComponent.create());
387
388         QVERIFY(textObject != 0);
389         QVERIFY(textObject->textFormat() == QQuickTextEdit::RichText);
390     }
391     {
392         QDeclarativeComponent textComponent(&engine);
393         textComponent.setData("import QtQuick 2.0\nTextEdit { text: \"<b>Hello</b>\"; textFormat: Text.PlainText }", QUrl::fromLocalFile(""));
394         QQuickTextEdit *textObject = qobject_cast<QQuickTextEdit*>(textComponent.create());
395
396         QVERIFY(textObject != 0);
397         QVERIFY(textObject->textFormat() == QQuickTextEdit::PlainText);
398     }
399 }
400
401 void tst_qquicktextedit::alignments_data()
402 {
403     QTest::addColumn<int>("hAlign");
404     QTest::addColumn<int>("vAlign");
405     QTest::addColumn<QString>("expectfile");
406
407     QTest::newRow("LT") << int(Qt::AlignLeft) << int(Qt::AlignTop) << "alignments_lt";
408     QTest::newRow("RT") << int(Qt::AlignRight) << int(Qt::AlignTop) << "alignments_rt";
409     QTest::newRow("CT") << int(Qt::AlignHCenter) << int(Qt::AlignTop) << "alignments_ct";
410
411     QTest::newRow("LB") << int(Qt::AlignLeft) << int(Qt::AlignBottom) << "alignments_lb";
412     QTest::newRow("RB") << int(Qt::AlignRight) << int(Qt::AlignBottom) << "alignments_rb";
413     QTest::newRow("CB") << int(Qt::AlignHCenter) << int(Qt::AlignBottom) << "alignments_cb";
414
415     QTest::newRow("LC") << int(Qt::AlignLeft) << int(Qt::AlignVCenter) << "alignments_lc";
416     QTest::newRow("RC") << int(Qt::AlignRight) << int(Qt::AlignVCenter) << "alignments_rc";
417     QTest::newRow("CC") << int(Qt::AlignHCenter) << int(Qt::AlignVCenter) << "alignments_cc";
418 }
419
420
421 void tst_qquicktextedit::alignments()
422 {
423     QSKIP("Image comparison of text is almost guaranteed to fail during development");
424
425     QFETCH(int, hAlign);
426     QFETCH(int, vAlign);
427     QFETCH(QString, expectfile);
428
429     QQuickView canvas(QUrl::fromLocalFile(TESTDATA("alignments.qml")));
430
431     canvas.show();
432     canvas.requestActivateWindow();
433     QTest::qWaitForWindowShown(&canvas);
434     QTRY_COMPARE(&canvas, qGuiApp->focusWindow());
435
436     QObject *ob = canvas.rootObject();
437     QVERIFY(ob != 0);
438     ob->setProperty("horizontalAlignment",hAlign);
439     ob->setProperty("verticalAlignment",vAlign);
440     QTRY_COMPARE(ob->property("running").toBool(),false);
441     QImage actual = canvas.grabFrameBuffer();
442
443     expectfile = createExpectedFileIfNotFound(expectfile, actual);
444
445     QImage expect(expectfile);
446
447     QCOMPARE(actual,expect);
448 }
449
450
451 //the alignment tests may be trivial o.oa
452 void tst_qquicktextedit::hAlign()
453 {
454     //test one align each, and then test if two align fails.
455
456     for (int i = 0; i < standard.size(); i++)
457     {
458         for (int j=0; j < hAlignmentStrings.size(); j++)
459         {
460             QString componentStr = "import QtQuick 2.0\nTextEdit {  horizontalAlignment: \"" + hAlignmentStrings.at(j) + "\"; text: \"" + standard.at(i) + "\" }";
461             QDeclarativeComponent texteditComponent(&engine);
462             texteditComponent.setData(componentStr.toLatin1(), QUrl());
463             QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
464
465             QVERIFY(textEditObject != 0);
466             QCOMPARE((int)textEditObject->hAlign(), (int)hAlignments.at(j));
467         }
468     }
469
470     for (int i = 0; i < richText.size(); i++)
471     {
472         for (int j=0; j < hAlignmentStrings.size(); j++)
473         {
474             QString componentStr = "import QtQuick 2.0\nTextEdit {  horizontalAlignment: \"" + hAlignmentStrings.at(j) + "\"; text: \"" + richText.at(i) + "\" }";
475             QDeclarativeComponent texteditComponent(&engine);
476             texteditComponent.setData(componentStr.toLatin1(), QUrl());
477             QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
478
479             QVERIFY(textEditObject != 0);
480             QCOMPARE((int)textEditObject->hAlign(), (int)hAlignments.at(j));
481         }
482     }
483
484 }
485
486 void tst_qquicktextedit::hAlign_RightToLeft()
487 {
488     QQuickView canvas(QUrl::fromLocalFile(TESTDATA("horizontalAlignment_RightToLeft.qml")));
489     QQuickTextEdit *textEdit = canvas.rootObject()->findChild<QQuickTextEdit*>("text");
490     QVERIFY(textEdit != 0);
491     canvas.show();
492
493     const QString rtlText = textEdit->text();
494
495     // implicit alignment should follow the reading direction of text
496     QCOMPARE(textEdit->hAlign(), QQuickTextEdit::AlignRight);
497     QVERIFY(textEdit->positionToRectangle(0).x() > canvas.width()/2);
498
499     // explicitly left aligned
500     textEdit->setHAlign(QQuickTextEdit::AlignLeft);
501     QCOMPARE(textEdit->hAlign(), QQuickTextEdit::AlignLeft);
502     QVERIFY(textEdit->positionToRectangle(0).x() < canvas.width()/2);
503
504     // explicitly right aligned
505     textEdit->setHAlign(QQuickTextEdit::AlignRight);
506     QCOMPARE(textEdit->hAlign(), QQuickTextEdit::AlignRight);
507     QVERIFY(textEdit->positionToRectangle(0).x() > canvas.width()/2);
508
509     QString textString = textEdit->text();
510     textEdit->setText(QString("<i>") + textString + QString("</i>"));
511     textEdit->resetHAlign();
512
513     // implicitly aligned rich text should follow the reading direction of RTL text
514     QCOMPARE(textEdit->hAlign(), QQuickTextEdit::AlignRight);
515     QCOMPARE(textEdit->effectiveHAlign(), textEdit->hAlign());
516     QVERIFY(textEdit->positionToRectangle(0).x() > canvas.width()/2);
517
518     // explicitly left aligned rich text
519     textEdit->setHAlign(QQuickTextEdit::AlignLeft);
520     QCOMPARE(textEdit->hAlign(), QQuickTextEdit::AlignLeft);
521     QCOMPARE(textEdit->effectiveHAlign(), textEdit->hAlign());
522     QVERIFY(textEdit->positionToRectangle(0).x() < canvas.width()/2);
523
524     // explicitly right aligned rich text
525     textEdit->setHAlign(QQuickTextEdit::AlignRight);
526     QCOMPARE(textEdit->hAlign(), QQuickTextEdit::AlignRight);
527     QCOMPARE(textEdit->effectiveHAlign(), textEdit->hAlign());
528     QVERIFY(textEdit->positionToRectangle(0).x() > canvas.width()/2);
529
530     textEdit->setText(textString);
531
532     // explicitly center aligned
533     textEdit->setHAlign(QQuickTextEdit::AlignHCenter);
534     QCOMPARE(textEdit->hAlign(), QQuickTextEdit::AlignHCenter);
535     QVERIFY(textEdit->positionToRectangle(0).x() > canvas.width()/2);
536
537     // reseted alignment should go back to following the text reading direction
538     textEdit->resetHAlign();
539     QCOMPARE(textEdit->hAlign(), QQuickTextEdit::AlignRight);
540     QVERIFY(textEdit->positionToRectangle(0).x() > canvas.width()/2);
541
542     // mirror the text item
543     QQuickItemPrivate::get(textEdit)->setLayoutMirror(true);
544
545     // mirrored implicit alignment should continue to follow the reading direction of the text
546     QCOMPARE(textEdit->hAlign(), QQuickTextEdit::AlignRight);
547     QCOMPARE(textEdit->effectiveHAlign(), QQuickTextEdit::AlignRight);
548     QVERIFY(textEdit->positionToRectangle(0).x() > canvas.width()/2);
549
550     // mirrored explicitly right aligned behaves as left aligned
551     textEdit->setHAlign(QQuickTextEdit::AlignRight);
552     QCOMPARE(textEdit->hAlign(), QQuickTextEdit::AlignRight);
553     QCOMPARE(textEdit->effectiveHAlign(), QQuickTextEdit::AlignLeft);
554     QVERIFY(textEdit->positionToRectangle(0).x() < canvas.width()/2);
555
556     // mirrored explicitly left aligned behaves as right aligned
557     textEdit->setHAlign(QQuickTextEdit::AlignLeft);
558     QCOMPARE(textEdit->hAlign(), QQuickTextEdit::AlignLeft);
559     QCOMPARE(textEdit->effectiveHAlign(), QQuickTextEdit::AlignRight);
560     QVERIFY(textEdit->positionToRectangle(0).x() > canvas.width()/2);
561
562     // disable mirroring
563     QQuickItemPrivate::get(textEdit)->setLayoutMirror(false);
564     textEdit->resetHAlign();
565
566     // English text should be implicitly left aligned
567     textEdit->setText("Hello world!");
568     QCOMPARE(textEdit->hAlign(), QQuickTextEdit::AlignLeft);
569     QVERIFY(textEdit->positionToRectangle(0).x() < canvas.width()/2);
570
571     canvas.requestActivateWindow();
572     QTest::qWaitForWindowShown(&canvas);
573     QTRY_COMPARE(&canvas, qGuiApp->focusWindow());
574
575     textEdit->setText(QString());
576     { QInputMethodEvent ev(rtlText, QList<QInputMethodEvent::Attribute>()); QGuiApplication::sendEvent(&canvas, &ev); }
577     QEXPECT_FAIL("", "QTBUG-21691", Abort);
578     QCOMPARE(textEdit->hAlign(), QQuickTextEdit::AlignRight);
579     { QInputMethodEvent ev("Hello world!", QList<QInputMethodEvent::Attribute>()); QGuiApplication::sendEvent(&canvas, &ev); }
580     QCOMPARE(textEdit->hAlign(), QQuickTextEdit::AlignLeft);
581
582 #ifndef Q_OS_MAC    // QTBUG-18040
583     // empty text with implicit alignment follows the system locale-based
584     // keyboard input direction from QGuiApplication::keyboardInputDirection
585     textEdit->setText("");
586     QCOMPARE(textEdit->hAlign(), QGuiApplication::keyboardInputDirection() == Qt::LeftToRight ?
587                                   QQuickTextEdit::AlignLeft : QQuickTextEdit::AlignRight);
588     if (QGuiApplication::keyboardInputDirection() == Qt::LeftToRight)
589         QVERIFY(textEdit->positionToRectangle(0).x() < canvas.width()/2);
590     else
591         QVERIFY(textEdit->positionToRectangle(0).x() > canvas.width()/2);
592     textEdit->setHAlign(QQuickTextEdit::AlignRight);
593     QCOMPARE(textEdit->hAlign(), QQuickTextEdit::AlignRight);
594     QVERIFY(textEdit->positionToRectangle(0).x() > canvas.width()/2);
595 #endif
596
597 #ifndef Q_OS_MAC    // QTBUG-18040
598     // alignment of TextEdit with no text set to it
599     QString componentStr = "import QtQuick 2.0\nTextEdit {}";
600     QDeclarativeComponent textComponent(&engine);
601     textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
602     QQuickTextEdit *textObject = qobject_cast<QQuickTextEdit*>(textComponent.create());
603     QCOMPARE(textObject->hAlign(), QGuiApplication::keyboardInputDirection() == Qt::LeftToRight ?
604                                   QQuickTextEdit::AlignLeft : QQuickTextEdit::AlignRight);
605     delete textObject;
606 #endif
607 }
608
609 void tst_qquicktextedit::vAlign()
610 {
611     //test one align each, and then test if two align fails.
612
613     for (int i = 0; i < standard.size(); i++)
614     {
615         for (int j=0; j < vAlignmentStrings.size(); j++)
616         {
617             QString componentStr = "import QtQuick 2.0\nTextEdit {  verticalAlignment: \"" + vAlignmentStrings.at(j) + "\"; text: \"" + standard.at(i) + "\" }";
618             QDeclarativeComponent texteditComponent(&engine);
619             texteditComponent.setData(componentStr.toLatin1(), QUrl());
620             QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
621
622             QVERIFY(textEditObject != 0);
623             QCOMPARE((int)textEditObject->vAlign(), (int)vAlignments.at(j));
624         }
625     }
626
627     for (int i = 0; i < richText.size(); i++)
628     {
629         for (int j=0; j < vAlignmentStrings.size(); j++)
630         {
631             QString componentStr = "import QtQuick 2.0\nTextEdit {  verticalAlignment: \"" + vAlignmentStrings.at(j) + "\"; text: \"" + richText.at(i) + "\" }";
632             QDeclarativeComponent texteditComponent(&engine);
633             texteditComponent.setData(componentStr.toLatin1(), QUrl());
634             QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
635
636             QVERIFY(textEditObject != 0);
637             QCOMPARE((int)textEditObject->vAlign(), (int)vAlignments.at(j));
638         }
639     }
640
641 }
642
643 void tst_qquicktextedit::font()
644 {
645     //test size, then bold, then italic, then family
646     {
647         QString componentStr = "import QtQuick 2.0\nTextEdit {  font.pointSize: 40; text: \"Hello World\" }";
648         QDeclarativeComponent texteditComponent(&engine);
649         texteditComponent.setData(componentStr.toLatin1(), QUrl());
650         QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
651
652         QVERIFY(textEditObject != 0);
653         QCOMPARE(textEditObject->font().pointSize(), 40);
654         QCOMPARE(textEditObject->font().bold(), false);
655         QCOMPARE(textEditObject->font().italic(), false);
656     }
657
658     {
659         QString componentStr = "import QtQuick 2.0\nTextEdit {  font.bold: true; text: \"Hello World\" }";
660         QDeclarativeComponent texteditComponent(&engine);
661         texteditComponent.setData(componentStr.toLatin1(), QUrl());
662         QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
663
664         QVERIFY(textEditObject != 0);
665         QCOMPARE(textEditObject->font().bold(), true);
666         QCOMPARE(textEditObject->font().italic(), false);
667     }
668
669     {
670         QString componentStr = "import QtQuick 2.0\nTextEdit {  font.italic: true; text: \"Hello World\" }";
671         QDeclarativeComponent texteditComponent(&engine);
672         texteditComponent.setData(componentStr.toLatin1(), QUrl());
673         QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
674
675         QVERIFY(textEditObject != 0);
676         QCOMPARE(textEditObject->font().italic(), true);
677         QCOMPARE(textEditObject->font().bold(), false);
678     }
679
680     {
681         QString componentStr = "import QtQuick 2.0\nTextEdit {  font.family: \"Helvetica\"; text: \"Hello World\" }";
682         QDeclarativeComponent texteditComponent(&engine);
683         texteditComponent.setData(componentStr.toLatin1(), QUrl());
684         QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
685
686         QVERIFY(textEditObject != 0);
687         QCOMPARE(textEditObject->font().family(), QString("Helvetica"));
688         QCOMPARE(textEditObject->font().bold(), false);
689         QCOMPARE(textEditObject->font().italic(), false);
690     }
691
692     {
693         QString componentStr = "import QtQuick 2.0\nTextEdit {  font.family: \"\"; text: \"Hello World\" }";
694         QDeclarativeComponent texteditComponent(&engine);
695         texteditComponent.setData(componentStr.toLatin1(), QUrl());
696         QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
697
698         QVERIFY(textEditObject != 0);
699         QCOMPARE(textEditObject->font().family(), QString(""));
700     }
701 }
702
703 void tst_qquicktextedit::color()
704 {
705     //test initial color
706     {
707         QString componentStr = "import QtQuick 2.0\nTextEdit { text: \"Hello World\" }";
708         QDeclarativeComponent texteditComponent(&engine);
709         texteditComponent.setData(componentStr.toLatin1(), QUrl());
710         QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
711
712         QQuickTextEditPrivate *textEditPrivate = static_cast<QQuickTextEditPrivate*>(QQuickItemPrivate::get(textEditObject));
713
714         QVERIFY(textEditObject);
715         QVERIFY(textEditPrivate);
716         QVERIFY(textEditPrivate->control);
717
718         QPalette pal = textEditPrivate->control->palette();
719         QCOMPARE(textEditPrivate->color, QColor("black"));
720         QCOMPARE(textEditPrivate->color, pal.color(QPalette::Text));
721     }
722     //test normal
723     for (int i = 0; i < colorStrings.size(); i++)
724     {
725         QString componentStr = "import QtQuick 2.0\nTextEdit {  color: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
726         QDeclarativeComponent texteditComponent(&engine);
727         texteditComponent.setData(componentStr.toLatin1(), QUrl());
728         QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
729         //qDebug() << "textEditObject: " << textEditObject->color() << "vs. " << QColor(colorStrings.at(i));
730         QVERIFY(textEditObject != 0);
731         QCOMPARE(textEditObject->color(), QColor(colorStrings.at(i)));
732     }
733
734     //test selection
735     for (int i = 0; i < colorStrings.size(); i++)
736     {
737         QString componentStr = "import QtQuick 2.0\nTextEdit {  selectionColor: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
738         QDeclarativeComponent texteditComponent(&engine);
739         texteditComponent.setData(componentStr.toLatin1(), QUrl());
740         QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
741         QVERIFY(textEditObject != 0);
742         QCOMPARE(textEditObject->selectionColor(), QColor(colorStrings.at(i)));
743     }
744
745     //test selected text
746     for (int i = 0; i < colorStrings.size(); i++)
747     {
748         QString componentStr = "import QtQuick 2.0\nTextEdit {  selectedTextColor: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
749         QDeclarativeComponent texteditComponent(&engine);
750         texteditComponent.setData(componentStr.toLatin1(), QUrl());
751         QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
752         QVERIFY(textEditObject != 0);
753         QCOMPARE(textEditObject->selectedTextColor(), QColor(colorStrings.at(i)));
754     }
755
756     {
757         QString colorStr = "#AA001234";
758         QColor testColor("#001234");
759         testColor.setAlpha(170);
760
761         QString componentStr = "import QtQuick 2.0\nTextEdit {  color: \"" + colorStr + "\"; text: \"Hello World\" }";
762         QDeclarativeComponent texteditComponent(&engine);
763         texteditComponent.setData(componentStr.toLatin1(), QUrl());
764         QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
765
766         QVERIFY(textEditObject != 0);
767         QCOMPARE(textEditObject->color(), testColor);
768     }
769 }
770
771 void tst_qquicktextedit::textMargin()
772 {
773     for (qreal i=0; i<=10; i+=0.3) {
774         QString componentStr = "import QtQuick 2.0\nTextEdit {  textMargin: " + QString::number(i) + "; text: \"Hello World\" }";
775         QDeclarativeComponent texteditComponent(&engine);
776         texteditComponent.setData(componentStr.toLatin1(), QUrl());
777         QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
778         QVERIFY(textEditObject != 0);
779         QCOMPARE(textEditObject->textMargin(), i);
780     }
781 }
782
783 void tst_qquicktextedit::persistentSelection()
784 {
785     {
786         QString componentStr = "import QtQuick 2.0\nTextEdit {  persistentSelection: true; text: \"Hello World\" }";
787         QDeclarativeComponent texteditComponent(&engine);
788         texteditComponent.setData(componentStr.toLatin1(), QUrl());
789         QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
790         QVERIFY(textEditObject != 0);
791         QCOMPARE(textEditObject->persistentSelection(), true);
792     }
793
794     {
795         QString componentStr = "import QtQuick 2.0\nTextEdit {  persistentSelection: false; text: \"Hello World\" }";
796         QDeclarativeComponent texteditComponent(&engine);
797         texteditComponent.setData(componentStr.toLatin1(), QUrl());
798         QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
799         QVERIFY(textEditObject != 0);
800         QCOMPARE(textEditObject->persistentSelection(), false);
801     }
802 }
803
804 void tst_qquicktextedit::focusOnPress()
805 {
806     {
807         QString componentStr = "import QtQuick 2.0\nTextEdit {  activeFocusOnPress: true; text: \"Hello World\" }";
808         QDeclarativeComponent texteditComponent(&engine);
809         texteditComponent.setData(componentStr.toLatin1(), QUrl());
810         QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
811         QVERIFY(textEditObject != 0);
812         QCOMPARE(textEditObject->focusOnPress(), true);
813     }
814
815     {
816         QString componentStr = "import QtQuick 2.0\nTextEdit {  activeFocusOnPress: false; text: \"Hello World\" }";
817         QDeclarativeComponent texteditComponent(&engine);
818         texteditComponent.setData(componentStr.toLatin1(), QUrl());
819         QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
820         QVERIFY(textEditObject != 0);
821         QCOMPARE(textEditObject->focusOnPress(), false);
822     }
823 }
824
825 void tst_qquicktextedit::selection()
826 {
827     QString testStr = standard[0];//TODO: What should happen for multiline/rich text?
828     QString componentStr = "import QtQuick 2.0\nTextEdit {  text: \""+ testStr +"\"; }";
829     QDeclarativeComponent texteditComponent(&engine);
830     texteditComponent.setData(componentStr.toLatin1(), QUrl());
831     QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
832     QVERIFY(textEditObject != 0);
833
834
835     //Test selection follows cursor
836     for (int i=0; i<= testStr.size(); i++) {
837         textEditObject->setCursorPosition(i);
838         QCOMPARE(textEditObject->cursorPosition(), i);
839         QCOMPARE(textEditObject->selectionStart(), i);
840         QCOMPARE(textEditObject->selectionEnd(), i);
841         QVERIFY(textEditObject->selectedText().isNull());
842     }
843
844     textEditObject->setCursorPosition(0);
845     QVERIFY(textEditObject->cursorPosition() == 0);
846     QVERIFY(textEditObject->selectionStart() == 0);
847     QVERIFY(textEditObject->selectionEnd() == 0);
848     QVERIFY(textEditObject->selectedText().isNull());
849
850     // Verify invalid positions are ignored.
851     textEditObject->setCursorPosition(-1);
852     QVERIFY(textEditObject->cursorPosition() == 0);
853     QVERIFY(textEditObject->selectionStart() == 0);
854     QVERIFY(textEditObject->selectionEnd() == 0);
855     QVERIFY(textEditObject->selectedText().isNull());
856
857     textEditObject->setCursorPosition(textEditObject->text().count()+1);
858     QVERIFY(textEditObject->cursorPosition() == 0);
859     QVERIFY(textEditObject->selectionStart() == 0);
860     QVERIFY(textEditObject->selectionEnd() == 0);
861     QVERIFY(textEditObject->selectedText().isNull());
862
863     //Test selection
864     for (int i=0; i<= testStr.size(); i++) {
865         textEditObject->select(0,i);
866         QCOMPARE(testStr.mid(0,i), textEditObject->selectedText());
867     }
868     for (int i=0; i<= testStr.size(); i++) {
869         textEditObject->select(i,testStr.size());
870         QCOMPARE(testStr.mid(i,testStr.size()-i), textEditObject->selectedText());
871     }
872
873     textEditObject->setCursorPosition(0);
874     QVERIFY(textEditObject->cursorPosition() == 0);
875     QVERIFY(textEditObject->selectionStart() == 0);
876     QVERIFY(textEditObject->selectionEnd() == 0);
877     QVERIFY(textEditObject->selectedText().isNull());
878
879     //Test Error Ignoring behaviour
880     textEditObject->setCursorPosition(0);
881     QVERIFY(textEditObject->selectedText().isNull());
882     textEditObject->select(-10,0);
883     QVERIFY(textEditObject->selectedText().isNull());
884     textEditObject->select(100,101);
885     QVERIFY(textEditObject->selectedText().isNull());
886     textEditObject->select(0,-10);
887     QVERIFY(textEditObject->selectedText().isNull());
888     textEditObject->select(0,100);
889     QVERIFY(textEditObject->selectedText().isNull());
890     textEditObject->select(0,10);
891     QVERIFY(textEditObject->selectedText().size() == 10);
892     textEditObject->select(-10,0);
893     QVERIFY(textEditObject->selectedText().size() == 10);
894     textEditObject->select(100,101);
895     QVERIFY(textEditObject->selectedText().size() == 10);
896     textEditObject->select(0,-10);
897     QVERIFY(textEditObject->selectedText().size() == 10);
898     textEditObject->select(0,100);
899     QVERIFY(textEditObject->selectedText().size() == 10);
900
901     textEditObject->deselect();
902     QVERIFY(textEditObject->selectedText().isNull());
903     textEditObject->select(0,10);
904     QVERIFY(textEditObject->selectedText().size() == 10);
905     textEditObject->deselect();
906     QVERIFY(textEditObject->selectedText().isNull());
907 }
908
909 void tst_qquicktextedit::isRightToLeft_data()
910 {
911     QTest::addColumn<QString>("text");
912     QTest::addColumn<bool>("emptyString");
913     QTest::addColumn<bool>("firstCharacter");
914     QTest::addColumn<bool>("lastCharacter");
915     QTest::addColumn<bool>("middleCharacter");
916     QTest::addColumn<bool>("startString");
917     QTest::addColumn<bool>("midString");
918     QTest::addColumn<bool>("endString");
919
920     const quint16 arabic_str[] = { 0x0638, 0x0643, 0x00646, 0x0647, 0x0633, 0x0638, 0x0643, 0x00646, 0x0647, 0x0633, 0x0647};
921     QTest::newRow("Empty") << "" << false << false << false << false << false << false << false;
922     QTest::newRow("Neutral") << "23244242" << false << false << false << false << false << false << false;
923     QTest::newRow("LTR") << "Hello world" << false << false << false << false << false << false << false;
924     QTest::newRow("RTL") << QString::fromUtf16(arabic_str, 11) << false << true << true << true << true << true << true;
925     QTest::newRow("Bidi RTL + LTR + RTL") << QString::fromUtf16(arabic_str, 11) + QString("Hello world") + QString::fromUtf16(arabic_str, 11) << false << true << true << false << true << true << true;
926     QTest::newRow("Bidi LTR + RTL + LTR") << QString("Hello world") + QString::fromUtf16(arabic_str, 11) + QString("Hello world") << false << false << false << true << false << false << false;
927 }
928
929 void tst_qquicktextedit::isRightToLeft()
930 {
931     QFETCH(QString, text);
932     QFETCH(bool, emptyString);
933     QFETCH(bool, firstCharacter);
934     QFETCH(bool, lastCharacter);
935     QFETCH(bool, middleCharacter);
936     QFETCH(bool, startString);
937     QFETCH(bool, midString);
938     QFETCH(bool, endString);
939
940     QQuickTextEdit textEdit;
941     textEdit.setText(text);
942
943     // first test that the right string is delivered to the QString::isRightToLeft()
944     QCOMPARE(textEdit.isRightToLeft(0,0), text.mid(0,0).isRightToLeft());
945     QCOMPARE(textEdit.isRightToLeft(0,1), text.mid(0,1).isRightToLeft());
946     QCOMPARE(textEdit.isRightToLeft(text.count()-2, text.count()-1), text.mid(text.count()-2, text.count()-1).isRightToLeft());
947     QCOMPARE(textEdit.isRightToLeft(text.count()/2, text.count()/2 + 1), text.mid(text.count()/2, text.count()/2 + 1).isRightToLeft());
948     QCOMPARE(textEdit.isRightToLeft(0,text.count()/4), text.mid(0,text.count()/4).isRightToLeft());
949     QCOMPARE(textEdit.isRightToLeft(text.count()/4,3*text.count()/4), text.mid(text.count()/4,3*text.count()/4).isRightToLeft());
950     if (text.isEmpty())
951         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML TextEdit: isRightToLeft(start, end) called with the end property being smaller than the start.");
952     QCOMPARE(textEdit.isRightToLeft(3*text.count()/4,text.count()-1), text.mid(3*text.count()/4,text.count()-1).isRightToLeft());
953
954     // then test that the feature actually works
955     QCOMPARE(textEdit.isRightToLeft(0,0), emptyString);
956     QCOMPARE(textEdit.isRightToLeft(0,1), firstCharacter);
957     QCOMPARE(textEdit.isRightToLeft(text.count()-2, text.count()-1), lastCharacter);
958     QCOMPARE(textEdit.isRightToLeft(text.count()/2, text.count()/2 + 1), middleCharacter);
959     QCOMPARE(textEdit.isRightToLeft(0,text.count()/4), startString);
960     QCOMPARE(textEdit.isRightToLeft(text.count()/4,3*text.count()/4), midString);
961     if (text.isEmpty())
962         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML TextEdit: isRightToLeft(start, end) called with the end property being smaller than the start.");
963     QCOMPARE(textEdit.isRightToLeft(3*text.count()/4,text.count()-1), endString);
964 }
965
966 void tst_qquicktextedit::keySelection()
967 {
968     QQuickView canvas(QUrl::fromLocalFile(TESTDATA("navigation.qml")));
969     canvas.show();
970     canvas.requestActivateWindow();
971     QTest::qWaitForWindowShown(&canvas);
972     QTRY_COMPARE(&canvas, qGuiApp->focusWindow());
973     canvas.requestActivateWindow();
974
975     QVERIFY(canvas.rootObject() != 0);
976
977     QQuickTextEdit *input = qobject_cast<QQuickTextEdit *>(qvariant_cast<QObject *>(canvas.rootObject()->property("myInput")));
978
979     QVERIFY(input != 0);
980     QTRY_VERIFY(input->hasActiveFocus() == true);
981
982     QSignalSpy spy(input, SIGNAL(selectionChanged()));
983
984     simulateKey(&canvas, Qt::Key_Right, Qt::ShiftModifier);
985     QVERIFY(input->hasActiveFocus() == true);
986     QCOMPARE(input->selectedText(), QString("a"));
987     QCOMPARE(spy.count(), 1);
988     simulateKey(&canvas, Qt::Key_Right);
989     QVERIFY(input->hasActiveFocus() == true);
990     QCOMPARE(input->selectedText(), QString());
991     QCOMPARE(spy.count(), 2);
992     simulateKey(&canvas, Qt::Key_Right);
993     QVERIFY(input->hasActiveFocus() == false);
994     QCOMPARE(input->selectedText(), QString());
995     QCOMPARE(spy.count(), 2);
996
997     simulateKey(&canvas, Qt::Key_Left);
998     QVERIFY(input->hasActiveFocus() == true);
999     QCOMPARE(spy.count(), 2);
1000     simulateKey(&canvas, Qt::Key_Left, Qt::ShiftModifier);
1001     QVERIFY(input->hasActiveFocus() == true);
1002     QCOMPARE(input->selectedText(), QString("a"));
1003     QCOMPARE(spy.count(), 3);
1004     simulateKey(&canvas, Qt::Key_Left);
1005     QVERIFY(input->hasActiveFocus() == true);
1006     QCOMPARE(input->selectedText(), QString());
1007     QCOMPARE(spy.count(), 4);
1008     simulateKey(&canvas, Qt::Key_Left);
1009     QVERIFY(input->hasActiveFocus() == false);
1010     QCOMPARE(input->selectedText(), QString());
1011     QCOMPARE(spy.count(), 4);
1012 }
1013
1014 void tst_qquicktextedit::moveCursorSelection_data()
1015 {
1016     QTest::addColumn<QString>("testStr");
1017     QTest::addColumn<int>("cursorPosition");
1018     QTest::addColumn<int>("movePosition");
1019     QTest::addColumn<QQuickTextEdit::SelectionMode>("mode");
1020     QTest::addColumn<int>("selectionStart");
1021     QTest::addColumn<int>("selectionEnd");
1022     QTest::addColumn<bool>("reversible");
1023
1024     QTest::newRow("(t)he|characters")
1025             << standard[0] << 0 << 1 << QQuickTextEdit::SelectCharacters << 0 << 1 << true;
1026     QTest::newRow("do(g)|characters")
1027             << standard[0] << 43 << 44 << QQuickTextEdit::SelectCharacters << 43 << 44 << true;
1028     QTest::newRow("jum(p)ed|characters")
1029             << standard[0] << 23 << 24 << QQuickTextEdit::SelectCharacters << 23 << 24 << true;
1030     QTest::newRow("jumped( )over|characters")
1031             << standard[0] << 26 << 27 << QQuickTextEdit::SelectCharacters << 26 << 27 << true;
1032     QTest::newRow("(the )|characters")
1033             << standard[0] << 0 << 4 << QQuickTextEdit::SelectCharacters << 0 << 4 << true;
1034     QTest::newRow("( dog)|characters")
1035             << standard[0] << 40 << 44 << QQuickTextEdit::SelectCharacters << 40 << 44 << true;
1036     QTest::newRow("( jumped )|characters")
1037             << standard[0] << 19 << 27 << QQuickTextEdit::SelectCharacters << 19 << 27 << true;
1038     QTest::newRow("th(e qu)ick|characters")
1039             << standard[0] << 2 << 6 << QQuickTextEdit::SelectCharacters << 2 << 6 << true;
1040     QTest::newRow("la(zy d)og|characters")
1041             << standard[0] << 38 << 42 << QQuickTextEdit::SelectCharacters << 38 << 42 << true;
1042     QTest::newRow("jum(ped ov)er|characters")
1043             << standard[0] << 23 << 29 << QQuickTextEdit::SelectCharacters << 23 << 29 << true;
1044     QTest::newRow("()the|characters")
1045             << standard[0] << 0 << 0 << QQuickTextEdit::SelectCharacters << 0 << 0 << true;
1046     QTest::newRow("dog()|characters")
1047             << standard[0] << 44 << 44 << QQuickTextEdit::SelectCharacters << 44 << 44 << true;
1048     QTest::newRow("jum()ped|characters")
1049             << standard[0] << 23 << 23 << QQuickTextEdit::SelectCharacters << 23 << 23 << true;
1050
1051     QTest::newRow("<(t)he>|words")
1052             << standard[0] << 0 << 1 << QQuickTextEdit::SelectWords << 0 << 3 << true;
1053     QTest::newRow("<do(g)>|words")
1054             << standard[0] << 43 << 44 << QQuickTextEdit::SelectWords << 41 << 44 << true;
1055     QTest::newRow("<jum(p)ed>|words")
1056             << standard[0] << 23 << 24 << QQuickTextEdit::SelectWords << 20 << 26 << true;
1057     QTest::newRow("<jumped( )>over|words")
1058             << standard[0] << 26 << 27 << QQuickTextEdit::SelectWords << 20 << 27 << false;
1059     QTest::newRow("jumped<( )over>|words,reversed")
1060             << standard[0] << 27 << 26 << QQuickTextEdit::SelectWords << 26 << 31 << false;
1061     QTest::newRow("<(the )>quick|words")
1062             << standard[0] << 0 << 4 << QQuickTextEdit::SelectWords << 0 << 4 << false;
1063     QTest::newRow("<(the )quick>|words,reversed")
1064             << standard[0] << 4 << 0 << QQuickTextEdit::SelectWords << 0 << 9 << false;
1065     QTest::newRow("<lazy( dog)>|words")
1066             << standard[0] << 40 << 44 << QQuickTextEdit::SelectWords << 36 << 44 << false;
1067     QTest::newRow("lazy<( dog)>|words,reversed")
1068             << standard[0] << 44 << 40 << QQuickTextEdit::SelectWords << 40 << 44 << false;
1069     QTest::newRow("<fox( jumped )>over|words")
1070             << standard[0] << 19 << 27 << QQuickTextEdit::SelectWords << 16 << 27 << false;
1071     QTest::newRow("fox<( jumped )over>|words,reversed")
1072             << standard[0] << 27 << 19 << QQuickTextEdit::SelectWords << 19 << 31 << false;
1073     QTest::newRow("<th(e qu)ick>|words")
1074             << standard[0] << 2 << 6 << QQuickTextEdit::SelectWords << 0 << 9 << true;
1075     QTest::newRow("<la(zy d)og|words>")
1076             << standard[0] << 38 << 42 << QQuickTextEdit::SelectWords << 36 << 44 << true;
1077     QTest::newRow("<jum(ped ov)er>|words")
1078             << standard[0] << 23 << 29 << QQuickTextEdit::SelectWords << 20 << 31 << true;
1079     QTest::newRow("<()>the|words")
1080             << standard[0] << 0 << 0 << QQuickTextEdit::SelectWords << 0 << 0 << true;
1081     QTest::newRow("dog<()>|words")
1082             << standard[0] << 44 << 44 << QQuickTextEdit::SelectWords << 44 << 44 << true;
1083     QTest::newRow("jum<()>ped|words")
1084             << standard[0] << 23 << 23 << QQuickTextEdit::SelectWords << 23 << 23 << true;
1085
1086     QTest::newRow("Hello<(,)> |words")
1087             << standard[2] << 5 << 6 << QQuickTextEdit::SelectWords << 5 << 6 << true;
1088     QTest::newRow("Hello<(, )>world|words")
1089             << standard[2] << 5 << 7 << QQuickTextEdit::SelectWords << 5 << 7 << false;
1090     QTest::newRow("Hello<(, )world>|words,reversed")
1091             << standard[2] << 7 << 5 << QQuickTextEdit::SelectWords << 5 << 12 << false;
1092     QTest::newRow("<Hel(lo, )>world|words")
1093             << standard[2] << 3 << 7 << QQuickTextEdit::SelectWords << 0 << 7 << false;
1094     QTest::newRow("<Hel(lo, )world>|words,reversed")
1095             << standard[2] << 7 << 3 << QQuickTextEdit::SelectWords << 0 << 12 << false;
1096     QTest::newRow("<Hel(lo)>,|words")
1097             << standard[2] << 3 << 5 << QQuickTextEdit::SelectWords << 0 << 5 << true;
1098     QTest::newRow("Hello<()>,|words")
1099             << standard[2] << 5 << 5 << QQuickTextEdit::SelectWords << 5 << 5 << true;
1100     QTest::newRow("Hello,<()>|words")
1101             << standard[2] << 6 << 6 << QQuickTextEdit::SelectWords << 6 << 6 << true;
1102     QTest::newRow("Hello<,( )>world|words")
1103             << standard[2] << 6 << 7 << QQuickTextEdit::SelectWords << 5 << 7 << false;
1104     QTest::newRow("Hello,<( )world>|words,reversed")
1105             << standard[2] << 7 << 6 << QQuickTextEdit::SelectWords << 6 << 12 << false;
1106     QTest::newRow("Hello<,( world)>|words")
1107             << standard[2] << 6 << 12 << QQuickTextEdit::SelectWords << 5 << 12 << false;
1108     QTest::newRow("Hello,<( world)>|words,reversed")
1109             << standard[2] << 12 << 6 << QQuickTextEdit::SelectWords << 6 << 12 << false;
1110     QTest::newRow("Hello<,( world!)>|words")
1111             << standard[2] << 6 << 13 << QQuickTextEdit::SelectWords << 5 << 13 << false;
1112     QTest::newRow("Hello,<( world!)>|words,reversed")
1113             << standard[2] << 13 << 6 << QQuickTextEdit::SelectWords << 6 << 13 << false;
1114     QTest::newRow("Hello<(, world!)>|words")
1115             << standard[2] << 5 << 13 << QQuickTextEdit::SelectWords << 5 << 13 << true;
1116     QTest::newRow("world<(!)>|words")
1117             << standard[2] << 12 << 13 << QQuickTextEdit::SelectWords << 12 << 13 << true;
1118     QTest::newRow("world!<()>)|words")
1119             << standard[2] << 13 << 13 << QQuickTextEdit::SelectWords << 13 << 13 << true;
1120     QTest::newRow("world<()>!)|words")
1121             << standard[2] << 12 << 12 << QQuickTextEdit::SelectWords << 12 << 12 << true;
1122
1123     QTest::newRow("<(,)>olleH |words")
1124             << standard[3] << 7 << 8 << QQuickTextEdit::SelectWords << 7 << 8 << true;
1125     QTest::newRow("<dlrow( ,)>olleH|words")
1126             << standard[3] << 6 << 8 << QQuickTextEdit::SelectWords << 1 << 8 << false;
1127     QTest::newRow("dlrow<( ,)>olleH|words,reversed")
1128             << standard[3] << 8 << 6 << QQuickTextEdit::SelectWords << 6 << 8 << false;
1129     QTest::newRow("<dlrow( ,ol)leH>|words")
1130             << standard[3] << 6 << 10 << QQuickTextEdit::SelectWords << 1 << 13 << false;
1131     QTest::newRow("dlrow<( ,ol)leH>|words,reversed")
1132             << standard[3] << 10 << 6 << QQuickTextEdit::SelectWords << 6 << 13 << false;
1133     QTest::newRow(",<(ol)leH>,|words")
1134             << standard[3] << 8 << 10 << QQuickTextEdit::SelectWords << 8 << 13 << true;
1135     QTest::newRow(",<()>olleH|words")
1136             << standard[3] << 8 << 8 << QQuickTextEdit::SelectWords << 8 << 8 << true;
1137     QTest::newRow("<()>,olleH|words")
1138             << standard[3] << 7 << 7 << QQuickTextEdit::SelectWords << 7 << 7 << true;
1139     QTest::newRow("<dlrow( )>,olleH|words")
1140             << standard[3] << 6 << 7 << QQuickTextEdit::SelectWords << 1 << 7 << false;
1141     QTest::newRow("dlrow<( ),>olleH|words,reversed")
1142             << standard[3] << 7 << 6 << QQuickTextEdit::SelectWords << 6 << 8 << false;
1143     QTest::newRow("<(dlrow )>,olleH|words")
1144             << standard[3] << 1 << 7 << QQuickTextEdit::SelectWords << 1 << 7 << false;
1145     QTest::newRow("<(dlrow ),>olleH|words,reversed")
1146             << standard[3] << 7 << 1 << QQuickTextEdit::SelectWords << 1 << 8 << false;
1147     QTest::newRow("<(!dlrow )>,olleH|words")
1148             << standard[3] << 0 << 7 << QQuickTextEdit::SelectWords << 0 << 7 << false;
1149     QTest::newRow("<(!dlrow ),>olleH|words,reversed")
1150             << standard[3] << 7 << 0 << QQuickTextEdit::SelectWords << 0 << 8 << false;
1151     QTest::newRow("(!dlrow ,)olleH|words")
1152             << standard[3] << 0 << 8 << QQuickTextEdit::SelectWords << 0 << 8 << true;
1153     QTest::newRow("<(!)>dlrow|words")
1154             << standard[3] << 0 << 1 << QQuickTextEdit::SelectWords << 0 << 1 << true;
1155     QTest::newRow("<()>!dlrow|words")
1156             << standard[3] << 0 << 0 << QQuickTextEdit::SelectWords << 0 << 0 << true;
1157     QTest::newRow("!<()>dlrow|words")
1158             << standard[3] << 1 << 1 << QQuickTextEdit::SelectWords << 1 << 1 << true;
1159 }
1160
1161 void tst_qquicktextedit::moveCursorSelection()
1162 {
1163     QFETCH(QString, testStr);
1164     QFETCH(int, cursorPosition);
1165     QFETCH(int, movePosition);
1166     QFETCH(QQuickTextEdit::SelectionMode, mode);
1167     QFETCH(int, selectionStart);
1168     QFETCH(int, selectionEnd);
1169     QFETCH(bool, reversible);
1170
1171     QString componentStr = "import QtQuick 2.0\nTextEdit {  text: \""+ testStr +"\"; }";
1172     QDeclarativeComponent textinputComponent(&engine);
1173     textinputComponent.setData(componentStr.toLatin1(), QUrl());
1174     QQuickTextEdit *texteditObject = qobject_cast<QQuickTextEdit*>(textinputComponent.create());
1175     QVERIFY(texteditObject != 0);
1176
1177     texteditObject->setCursorPosition(cursorPosition);
1178     texteditObject->moveCursorSelection(movePosition, mode);
1179
1180     QCOMPARE(texteditObject->selectedText(), testStr.mid(selectionStart, selectionEnd - selectionStart));
1181     QCOMPARE(texteditObject->selectionStart(), selectionStart);
1182     QCOMPARE(texteditObject->selectionEnd(), selectionEnd);
1183
1184     if (reversible) {
1185         texteditObject->setCursorPosition(movePosition);
1186         texteditObject->moveCursorSelection(cursorPosition, mode);
1187
1188         QCOMPARE(texteditObject->selectedText(), testStr.mid(selectionStart, selectionEnd - selectionStart));
1189         QCOMPARE(texteditObject->selectionStart(), selectionStart);
1190         QCOMPARE(texteditObject->selectionEnd(), selectionEnd);
1191     }
1192 }
1193
1194 void tst_qquicktextedit::moveCursorSelectionSequence_data()
1195 {
1196     QTest::addColumn<QString>("testStr");
1197     QTest::addColumn<int>("cursorPosition");
1198     QTest::addColumn<int>("movePosition1");
1199     QTest::addColumn<int>("movePosition2");
1200     QTest::addColumn<int>("selection1Start");
1201     QTest::addColumn<int>("selection1End");
1202     QTest::addColumn<int>("selection2Start");
1203     QTest::addColumn<int>("selection2End");
1204
1205     QTest::newRow("the {<quick( bro)wn> f^ox} jumped|ltr")
1206             << standard[0]
1207             << 9 << 13 << 17
1208             << 4 << 15
1209             << 4 << 19;
1210     QTest::newRow("the quick<( {bro)wn> f^ox} jumped|rtl")
1211             << standard[0]
1212             << 13 << 9 << 17
1213             << 9 << 15
1214             << 10 << 19;
1215     QTest::newRow("the {<quick( bro)wn> ^}fox jumped|ltr")
1216             << standard[0]
1217             << 9 << 13 << 16
1218             << 4 << 15
1219             << 4 << 16;
1220     QTest::newRow("the quick<( {bro)wn> ^}fox jumped|rtl")
1221             << standard[0]
1222             << 13 << 9 << 16
1223             << 9 << 15
1224             << 10 << 16;
1225     QTest::newRow("the {<quick( bro)wn^>} fox jumped|ltr")
1226             << standard[0]
1227             << 9 << 13 << 15
1228             << 4 << 15
1229             << 4 << 15;
1230     QTest::newRow("the quick<( {bro)wn^>} f^ox jumped|rtl")
1231             << standard[0]
1232             << 13 << 9 << 15
1233             << 9 << 15
1234             << 10 << 15;
1235     QTest::newRow("the {<quick() ^}bro)wn> fox|ltr")
1236             << standard[0]
1237             << 9 << 13 << 10
1238             << 4 << 15
1239             << 4 << 10;
1240     QTest::newRow("the quick<(^ {^bro)wn>} fox|rtl")
1241             << standard[0]
1242             << 13 << 9 << 10
1243             << 9 << 15
1244             << 10 << 15;
1245     QTest::newRow("the {<quick^}( bro)wn> fox|ltr")
1246             << standard[0]
1247             << 9 << 13 << 9
1248             << 4 << 15
1249             << 4 << 9;
1250     QTest::newRow("the quick{<(^ bro)wn>} fox|rtl")
1251             << standard[0]
1252             << 13 << 9 << 9
1253             << 9 << 15
1254             << 9 << 15;
1255     QTest::newRow("the {<qui^ck}( bro)wn> fox|ltr")
1256             << standard[0]
1257             << 9 << 13 << 7
1258             << 4 << 15
1259             << 4 << 9;
1260     QTest::newRow("the {<qui^ck}( bro)wn> fox|rtl")
1261             << standard[0]
1262             << 13 << 9 << 7
1263             << 9 << 15
1264             << 4 << 15;
1265     QTest::newRow("the {<^quick}( bro)wn> fox|ltr")
1266             << standard[0]
1267             << 9 << 13 << 4
1268             << 4 << 15
1269             << 4 << 9;
1270     QTest::newRow("the {<^quick}( bro)wn> fox|rtl")
1271             << standard[0]
1272             << 13 << 9 << 4
1273             << 9 << 15
1274             << 4 << 15;
1275     QTest::newRow("the{^ <quick}( bro)wn> fox|ltr")
1276             << standard[0]
1277             << 9 << 13 << 3
1278             << 4 << 15
1279             << 3 << 9;
1280     QTest::newRow("the{^ <quick}( bro)wn> fox|rtl")
1281             << standard[0]
1282             << 13 << 9 << 3
1283             << 9 << 15
1284             << 3 << 15;
1285     QTest::newRow("{t^he <quick}( bro)wn> fox|ltr")
1286             << standard[0]
1287             << 9 << 13 << 1
1288             << 4 << 15
1289             << 0 << 9;
1290     QTest::newRow("{t^he <quick}( bro)wn> fox|rtl")
1291             << standard[0]
1292             << 13 << 9 << 1
1293             << 9 << 15
1294             << 0 << 15;
1295
1296     QTest::newRow("{<He(ll)o>, w^orld}!|ltr")
1297             << standard[2]
1298             << 2 << 4 << 8
1299             << 0 << 5
1300             << 0 << 12;
1301     QTest::newRow("{<He(ll)o>, w^orld}!|rtl")
1302             << standard[2]
1303             << 4 << 2 << 8
1304             << 0 << 5
1305             << 0 << 12;
1306
1307     QTest::newRow("!{dlro^w ,<o(ll)eH>}|ltr")
1308             << standard[3]
1309             << 9 << 11 << 5
1310             << 8 << 13
1311             << 1 << 13;
1312     QTest::newRow("!{dlro^w ,<o(ll)eH>}|rtl")
1313             << standard[3]
1314             << 11 << 9 << 5
1315             << 8 << 13
1316             << 1 << 13;
1317 }
1318
1319 void tst_qquicktextedit::moveCursorSelectionSequence()
1320 {
1321     QFETCH(QString, testStr);
1322     QFETCH(int, cursorPosition);
1323     QFETCH(int, movePosition1);
1324     QFETCH(int, movePosition2);
1325     QFETCH(int, selection1Start);
1326     QFETCH(int, selection1End);
1327     QFETCH(int, selection2Start);
1328     QFETCH(int, selection2End);
1329
1330     QString componentStr = "import QtQuick 2.0\nTextEdit {  text: \""+ testStr +"\"; }";
1331     QDeclarativeComponent texteditComponent(&engine);
1332     texteditComponent.setData(componentStr.toLatin1(), QUrl());
1333     QQuickTextEdit *texteditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
1334     QVERIFY(texteditObject != 0);
1335
1336     texteditObject->setCursorPosition(cursorPosition);
1337
1338     texteditObject->moveCursorSelection(movePosition1, QQuickTextEdit::SelectWords);
1339     QCOMPARE(texteditObject->selectedText(), testStr.mid(selection1Start, selection1End - selection1Start));
1340     QCOMPARE(texteditObject->selectionStart(), selection1Start);
1341     QCOMPARE(texteditObject->selectionEnd(), selection1End);
1342
1343     texteditObject->moveCursorSelection(movePosition2, QQuickTextEdit::SelectWords);
1344     QCOMPARE(texteditObject->selectedText(), testStr.mid(selection2Start, selection2End - selection2Start));
1345     QCOMPARE(texteditObject->selectionStart(), selection2Start);
1346     QCOMPARE(texteditObject->selectionEnd(), selection2End);
1347 }
1348
1349
1350 void tst_qquicktextedit::mouseSelection_data()
1351 {
1352     QTest::addColumn<QString>("qmlfile");
1353     QTest::addColumn<int>("from");
1354     QTest::addColumn<int>("to");
1355     QTest::addColumn<QString>("selectedText");
1356
1357     // import installed
1358     QTest::newRow("on") << TESTDATA("mouseselection_true.qml") << 4 << 9 << "45678";
1359     QTest::newRow("off") << TESTDATA("mouseselection_false.qml") << 4 << 9 << QString();
1360     QTest::newRow("default") << TESTDATA("mouseselection_default.qml") << 4 << 9 << QString();
1361     QTest::newRow("off word selection") << TESTDATA("mouseselection_false_words.qml") << 4 << 9 << QString();
1362     QTest::newRow("on word selection (4,9)") << TESTDATA("mouseselection_true_words.qml") << 4 << 9 << "0123456789";
1363     QTest::newRow("on word selection (2,13)") << TESTDATA("mouseselection_true_words.qml") << 2 << 13 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1364     QTest::newRow("on word selection (2,30)") << TESTDATA("mouseselection_true_words.qml") << 2 << 30 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1365     QTest::newRow("on word selection (9,13)") << TESTDATA("mouseselection_true_words.qml") << 9 << 13 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1366     QTest::newRow("on word selection (9,30)") << TESTDATA("mouseselection_true_words.qml") << 9 << 30 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1367     QTest::newRow("on word selection (13,2)") << TESTDATA("mouseselection_true_words.qml") << 13 << 2 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1368     QTest::newRow("on word selection (20,2)") << TESTDATA("mouseselection_true_words.qml") << 20 << 2 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1369     QTest::newRow("on word selection (12,9)") << TESTDATA("mouseselection_true_words.qml") << 12 << 9 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1370     QTest::newRow("on word selection (30,9)") << TESTDATA("mouseselection_true_words.qml") << 30 << 9 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1371 }
1372
1373 void tst_qquicktextedit::mouseSelection()
1374 {
1375     QFETCH(QString, qmlfile);
1376     QFETCH(int, from);
1377     QFETCH(int, to);
1378     QFETCH(QString, selectedText);
1379
1380     QQuickView canvas(QUrl::fromLocalFile(qmlfile));
1381
1382     canvas.show();
1383     canvas.requestActivateWindow();
1384     QTest::qWaitForWindowShown(&canvas);
1385     QTRY_COMPARE(&canvas, qGuiApp->focusWindow());
1386
1387     QVERIFY(canvas.rootObject() != 0);
1388     QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit *>(canvas.rootObject());
1389     QVERIFY(textEditObject != 0);
1390
1391     // press-and-drag-and-release from x1 to x2
1392     QPoint p1 = textEditObject->positionToRectangle(from).center().toPoint();
1393     QPoint p2 = textEditObject->positionToRectangle(to).center().toPoint();
1394     QTest::mousePress(&canvas, Qt::LeftButton, 0, p1);
1395     QTest::mouseMove(&canvas, p2);
1396     QTest::mouseRelease(&canvas, Qt::LeftButton, 0, p2);
1397     QTest::qWait(50);
1398     QTRY_COMPARE(textEditObject->selectedText(), selectedText);
1399
1400     // Clicking and shift to clicking between the same points should select the same text.
1401     textEditObject->setCursorPosition(0);
1402     QTest::mouseClick(&canvas, Qt::LeftButton, Qt::NoModifier, p1);
1403     QTest::mouseClick(&canvas, Qt::LeftButton, Qt::ShiftModifier, p2);
1404     QTest::qWait(50);
1405     if (!selectedText.isEmpty())
1406         QEXPECT_FAIL("", "QTBUG-21743", Continue);
1407     QTRY_COMPARE(textEditObject->selectedText(), selectedText);
1408 }
1409
1410 void tst_qquicktextedit::dragMouseSelection()
1411 {
1412     QString qmlfile = TESTDATA("mouseselection_true.qml");
1413
1414     QQuickView canvas(QUrl::fromLocalFile(qmlfile));
1415
1416     canvas.show();
1417     canvas.requestActivateWindow();
1418     QTest::qWaitForWindowShown(&canvas);
1419     QTRY_COMPARE(&canvas, qGuiApp->focusWindow());
1420
1421     QVERIFY(canvas.rootObject() != 0);
1422     QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit *>(canvas.rootObject());
1423     QVERIFY(textEditObject != 0);
1424
1425     // press-and-drag-and-release from x1 to x2
1426     int x1 = 10;
1427     int x2 = 70;
1428     int y = textEditObject->height()/2;
1429     QTest::mousePress(&canvas, Qt::LeftButton, 0, QPoint(x1,y));
1430     QTest::mouseMove(&canvas, QPoint(x2, y));
1431     QTest::mouseRelease(&canvas, Qt::LeftButton, 0, QPoint(x2,y));
1432     QTest::qWait(300);
1433     QString str1;
1434     QTRY_VERIFY((str1 = textEditObject->selectedText()).length() > 3);
1435
1436     // press and drag the current selection.
1437     x1 = 40;
1438     x2 = 100;
1439     QTest::mousePress(&canvas, Qt::LeftButton, 0, QPoint(x1,y));
1440     QTest::mouseMove(&canvas, QPoint(x2, y));
1441     QTest::mouseRelease(&canvas, Qt::LeftButton, 0, QPoint(x2,y));
1442     QTest::qWait(300);
1443     QString str2;
1444     QTRY_VERIFY((str2 = textEditObject->selectedText()).length() > 3);
1445
1446     QVERIFY(str1 != str2); // Verify the second press and drag is a new selection and not the first moved.
1447 }
1448
1449 void tst_qquicktextedit::mouseSelectionMode_data()
1450 {
1451     QTest::addColumn<QString>("qmlfile");
1452     QTest::addColumn<bool>("selectWords");
1453
1454     // import installed
1455     QTest::newRow("SelectWords") << TESTDATA("mouseselectionmode_words.qml") << true;
1456     QTest::newRow("SelectCharacters") << TESTDATA("mouseselectionmode_characters.qml") << false;
1457     QTest::newRow("default") << TESTDATA("mouseselectionmode_default.qml") << false;
1458 }
1459
1460 void tst_qquicktextedit::mouseSelectionMode()
1461 {
1462     QFETCH(QString, qmlfile);
1463     QFETCH(bool, selectWords);
1464
1465     QString text = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1466
1467     QQuickView canvas(QUrl::fromLocalFile(qmlfile));
1468
1469     canvas.show();
1470     canvas.requestActivateWindow();
1471     QTest::qWaitForWindowShown(&canvas);
1472     QTRY_COMPARE(&canvas, qGuiApp->focusWindow());
1473
1474     QVERIFY(canvas.rootObject() != 0);
1475     QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit *>(canvas.rootObject());
1476     QVERIFY(textEditObject != 0);
1477
1478     // press-and-drag-and-release from x1 to x2
1479     int x1 = 10;
1480     int x2 = 70;
1481     int y = textEditObject->height()/2;
1482     QTest::mousePress(&canvas, Qt::LeftButton, 0, QPoint(x1,y));
1483     QTest::mouseMove(&canvas, QPoint(x2, y));
1484     //QTest::mouseMove(canvas, QPoint(x2,y)); // doesn't work
1485 //    QMouseEvent mv(QEvent::MouseMove, QPoint(x2,y), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
1486 //    QGuiApplication::sendEvent(&canvas, &mv);
1487     QTest::mouseRelease(&canvas, Qt::LeftButton, 0, QPoint(x2,y));
1488     QString str = textEditObject->selectedText();
1489     if (selectWords) {
1490         QTRY_COMPARE(textEditObject->selectedText(), text);
1491     } else {
1492         QTRY_VERIFY(textEditObject->selectedText().length() > 3);
1493         QVERIFY(str != text);
1494     }
1495 }
1496
1497 void tst_qquicktextedit::inputMethodHints()
1498 {
1499     QQuickView canvas(QUrl::fromLocalFile(TESTDATA("inputmethodhints.qml")));
1500     canvas.show();
1501     canvas.requestActivateWindow();
1502
1503     QVERIFY(canvas.rootObject() != 0);
1504     QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit *>(canvas.rootObject());
1505     QVERIFY(textEditObject != 0);
1506     QVERIFY(textEditObject->inputMethodHints() & Qt::ImhNoPredictiveText);
1507     textEditObject->setInputMethodHints(Qt::ImhUppercaseOnly);
1508     QVERIFY(textEditObject->inputMethodHints() & Qt::ImhUppercaseOnly);
1509 }
1510
1511 void tst_qquicktextedit::positionAt()
1512 {
1513     QQuickView canvas(QUrl::fromLocalFile(TESTDATA("positionAt.qml")));
1514     QVERIFY(canvas.rootObject() != 0);
1515     canvas.show();
1516     canvas.requestActivateWindow();
1517     canvas.requestActivateWindow();
1518     QTest::qWaitForWindowShown(&canvas);
1519
1520     QQuickTextEdit *texteditObject = qobject_cast<QQuickTextEdit *>(canvas.rootObject());
1521     QVERIFY(texteditObject != 0);
1522
1523     QFontMetrics fm(texteditObject->font());
1524     const int y0 = fm.height() / 2;
1525     const int y1 = fm.height() * 3 / 2;
1526
1527     int pos = texteditObject->positionAt(texteditObject->width()/2, y0);
1528     int width = 0;
1529     if (!qmlDisableDistanceField()) {
1530         QTextLayout layout(texteditObject->text().left(pos));
1531
1532         {
1533             QTextOption option;
1534             option.setUseDesignMetrics(true);
1535             layout.setTextOption(option);
1536         }
1537
1538         layout.beginLayout();
1539         QTextLine line = layout.createLine();
1540         layout.endLayout();
1541
1542         width = ceil(line.horizontalAdvance());
1543
1544     } else {
1545         width = fm.width(texteditObject->text().left(pos));
1546     }
1547
1548
1549     int diff = abs(int(width-texteditObject->width()/2));
1550
1551     QEXPECT_FAIL("", "QTBUG-21689", Abort);
1552     // some tollerance for different fonts.
1553 #ifdef Q_OS_LINUX
1554     QVERIFY(diff < 2);
1555 #else
1556     QVERIFY(diff < 5);
1557 #endif
1558
1559     const qreal x0 = texteditObject->positionToRectangle(pos).x();
1560     const qreal x1 = texteditObject->positionToRectangle(pos + 1).x();
1561
1562     QString preeditText = texteditObject->text().mid(0, pos);
1563     texteditObject->setText(texteditObject->text().mid(pos));
1564     texteditObject->setCursorPosition(0);
1565
1566     QInputMethodEvent inputEvent(preeditText, QList<QInputMethodEvent::Attribute>());
1567     QGuiApplication::sendEvent(&canvas, &inputEvent);
1568
1569     // Check all points within the preedit text return the same position.
1570     QCOMPARE(texteditObject->positionAt(0, y0), 0);
1571     QCOMPARE(texteditObject->positionAt(x0 / 2, y0), 0);
1572     QCOMPARE(texteditObject->positionAt(x0, y0), 0);
1573
1574     // Verify positioning returns to normal after the preedit text.
1575     QCOMPARE(texteditObject->positionAt(x1, y0), 1);
1576     QCOMPARE(texteditObject->positionToRectangle(1).x(), x1);
1577
1578     QVERIFY(texteditObject->positionAt(x0 / 2, y1) > 0);
1579 }
1580
1581 void tst_qquicktextedit::cursorDelegate()
1582 {
1583     QQuickView view(QUrl::fromLocalFile(TESTDATA("cursorTest.qml")));
1584     view.show();
1585     view.requestActivateWindow();
1586     QQuickTextEdit *textEditObject = view.rootObject()->findChild<QQuickTextEdit*>("textEditObject");
1587     QVERIFY(textEditObject != 0);
1588     QVERIFY(textEditObject->findChild<QQuickItem*>("cursorInstance"));
1589     //Test Delegate gets created
1590     textEditObject->setFocus(true);
1591     QQuickItem* delegateObject = textEditObject->findChild<QQuickItem*>("cursorInstance");
1592     QVERIFY(delegateObject);
1593     QCOMPARE(delegateObject->property("localProperty").toString(), QString("Hello"));
1594     //Test Delegate gets moved
1595     for (int i=0; i<= textEditObject->text().length(); i++) {
1596         textEditObject->setCursorPosition(i);
1597         QCOMPARE(textEditObject->cursorRectangle().x(), qRound(delegateObject->x()));
1598         QCOMPARE(textEditObject->cursorRectangle().y(), qRound(delegateObject->y()));
1599     }
1600     // Clear preedit text;
1601     QInputMethodEvent event;
1602     QGuiApplication::sendEvent(&view, &event);
1603
1604
1605     // Test delegate gets moved on mouse press.
1606     textEditObject->setSelectByMouse(true);
1607     textEditObject->setCursorPosition(0);
1608     const QPoint point1 = textEditObject->positionToRectangle(5).center().toPoint();
1609     QTest::mouseClick(&view, Qt::LeftButton, 0, point1);
1610     QTest::qWait(50);
1611     QTRY_VERIFY(textEditObject->cursorPosition() != 0);
1612     QCOMPARE(textEditObject->cursorRectangle().x(), qRound(delegateObject->x()));
1613     QCOMPARE(textEditObject->cursorRectangle().y(), qRound(delegateObject->y()));
1614
1615     // Test delegate gets moved on mouse drag
1616     textEditObject->setCursorPosition(0);
1617     const QPoint point2 = textEditObject->positionToRectangle(10).center().toPoint();
1618     QTest::mousePress(&view, Qt::LeftButton, 0, point1);
1619     QMouseEvent mv(QEvent::MouseMove, point2, Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
1620     QGuiApplication::sendEvent(&view, &mv);
1621     QTest::mouseRelease(&view, Qt::LeftButton, 0, point2);
1622     QTest::qWait(50);
1623     QTRY_COMPARE(textEditObject->cursorRectangle().x(), qRound(delegateObject->x()));
1624     QCOMPARE(textEditObject->cursorRectangle().y(), qRound(delegateObject->y()));
1625
1626     textEditObject->setReadOnly(true);
1627     textEditObject->setCursorPosition(0);
1628     QTest::mouseClick(&view, Qt::LeftButton, 0, textEditObject->positionToRectangle(5).center().toPoint());
1629     QTest::qWait(50);
1630     QTRY_VERIFY(textEditObject->cursorPosition() != 0);
1631     QCOMPARE(textEditObject->cursorRectangle().x(), qRound(delegateObject->x()));
1632     QCOMPARE(textEditObject->cursorRectangle().y(), qRound(delegateObject->y()));
1633
1634     textEditObject->setCursorPosition(0);
1635     QTest::mouseClick(&view, Qt::LeftButton, 0, textEditObject->positionToRectangle(5).center().toPoint());
1636     QTest::qWait(50);
1637     QTRY_VERIFY(textEditObject->cursorPosition() != 0);
1638     QCOMPARE(textEditObject->cursorRectangle().x(), qRound(delegateObject->x()));
1639     QCOMPARE(textEditObject->cursorRectangle().y(), qRound(delegateObject->y()));
1640
1641     textEditObject->setCursorPosition(0);
1642     QCOMPARE(textEditObject->cursorRectangle().x(), qRound(delegateObject->x()));
1643     QCOMPARE(textEditObject->cursorRectangle().y(), qRound(delegateObject->y()));
1644     //Test Delegate gets deleted
1645     textEditObject->setCursorDelegate(0);
1646     QVERIFY(!textEditObject->findChild<QQuickItem*>("cursorInstance"));
1647 }
1648
1649 void tst_qquicktextedit::cursorVisible()
1650 {
1651     QQuickView view(QUrl::fromLocalFile(TESTDATA("cursorVisible.qml")));
1652     view.show();
1653     view.requestActivateWindow();
1654     QTest::qWaitForWindowShown(&view);
1655     QTRY_COMPARE(&view, qGuiApp->focusWindow());
1656
1657     QQuickTextEdit edit;
1658     QSignalSpy spy(&edit, SIGNAL(cursorVisibleChanged(bool)));
1659
1660     QCOMPARE(edit.isCursorVisible(), false);
1661
1662     edit.setCursorVisible(true);
1663     QCOMPARE(edit.isCursorVisible(), true);
1664     QCOMPARE(spy.count(), 1);
1665
1666     edit.setCursorVisible(false);
1667     QCOMPARE(edit.isCursorVisible(), false);
1668     QCOMPARE(spy.count(), 2);
1669
1670     edit.setFocus(true);
1671     QCOMPARE(edit.isCursorVisible(), false);
1672     QCOMPARE(spy.count(), 2);
1673
1674     edit.setParentItem(view.rootObject());
1675     QCOMPARE(edit.isCursorVisible(), true);
1676     QCOMPARE(spy.count(), 3);
1677
1678     edit.setFocus(false);
1679     QCOMPARE(edit.isCursorVisible(), false);
1680     QCOMPARE(spy.count(), 4);
1681
1682     edit.setFocus(true);
1683     QCOMPARE(edit.isCursorVisible(), true);
1684     QCOMPARE(spy.count(), 5);
1685
1686     QQuickView alternateView;
1687     alternateView.show();
1688     alternateView.requestActivateWindow();
1689     QTest::qWaitForWindowShown(&alternateView);
1690
1691     QCOMPARE(edit.isCursorVisible(), false);
1692     QCOMPARE(spy.count(), 6);
1693
1694     view.requestActivateWindow();
1695     QTest::qWaitForWindowShown(&view);
1696     QCOMPARE(edit.isCursorVisible(), true);
1697     QCOMPARE(spy.count(), 7);
1698 }
1699
1700 void tst_qquicktextedit::delegateLoading_data()
1701 {
1702     QTest::addColumn<QString>("qmlfile");
1703     QTest::addColumn<QString>("error");
1704
1705     // import installed
1706     QTest::newRow("pass") << "cursorHttpTestPass.qml" << "";
1707     QTest::newRow("fail1") << "cursorHttpTestFail1.qml" << "http://localhost:42332/FailItem.qml: Remote host closed the connection ";
1708     QTest::newRow("fail2") << "cursorHttpTestFail2.qml" << "http://localhost:42332/ErrItem.qml:4:5: Fungus is not a type ";
1709 }
1710
1711 void tst_qquicktextedit::delegateLoading()
1712 {
1713     QFETCH(QString, qmlfile);
1714     QFETCH(QString, error);
1715
1716     TestHTTPServer server(42332);
1717     server.serveDirectory(TESTDATA("httpfail"), TestHTTPServer::Disconnect);
1718     server.serveDirectory(TESTDATA("httpslow"), TestHTTPServer::Delay);
1719     server.serveDirectory(TESTDATA("http"));
1720
1721     QQuickView view(QUrl(QLatin1String("http://localhost:42332/") + qmlfile));
1722     view.show();
1723     view.requestActivateWindow();
1724
1725     if (!error.isEmpty()) {
1726         QTest::ignoreMessage(QtWarningMsg, error.toUtf8());
1727         QTRY_VERIFY(view.status()==QQuickView::Error);
1728         QTRY_VERIFY(!view.rootObject()); // there is fail item inside this test
1729     } else {
1730         QTRY_VERIFY(view.rootObject());//Wait for loading to finish.
1731         QQuickTextEdit *textEditObject = view.rootObject()->findChild<QQuickTextEdit*>("textEditObject");
1732         //    view.rootObject()->dumpObjectTree();
1733         QVERIFY(textEditObject != 0);
1734         textEditObject->setFocus(true);
1735         QQuickItem *delegate;
1736         delegate = view.rootObject()->findChild<QQuickItem*>("delegateOkay");
1737         QVERIFY(delegate);
1738         delegate = view.rootObject()->findChild<QQuickItem*>("delegateSlow");
1739         QVERIFY(delegate);
1740
1741         delete delegate;
1742     }
1743
1744
1745     //A test should be added here with a component which is ready but component.create() returns null
1746     //Not sure how to accomplish this with QQuickTextEdits cursor delegate
1747     //###This was only needed for code coverage, and could be a case of overzealous defensive programming
1748     //delegate = view.rootObject()->findChild<QQuickItem*>("delegateErrorB");
1749     //QVERIFY(!delegate);
1750 }
1751
1752 /*
1753 TextEdit element should only handle left/right keys until the cursor reaches
1754 the extent of the text, then they should ignore the keys.
1755 */
1756 void tst_qquicktextedit::navigation()
1757 {
1758     QQuickView canvas(QUrl::fromLocalFile(TESTDATA("navigation.qml")));
1759     canvas.show();
1760     canvas.requestActivateWindow();
1761
1762     QVERIFY(canvas.rootObject() != 0);
1763
1764     QQuickItem *input = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(canvas.rootObject()->property("myInput")));
1765
1766     QVERIFY(input != 0);
1767     QTRY_VERIFY(input->hasActiveFocus() == true);
1768     simulateKey(&canvas, Qt::Key_Left);
1769     QVERIFY(input->hasActiveFocus() == false);
1770     simulateKey(&canvas, Qt::Key_Right);
1771     QVERIFY(input->hasActiveFocus() == true);
1772     simulateKey(&canvas, Qt::Key_Right);
1773     QVERIFY(input->hasActiveFocus() == true);
1774     simulateKey(&canvas, Qt::Key_Right);
1775     QVERIFY(input->hasActiveFocus() == false);
1776     simulateKey(&canvas, Qt::Key_Left);
1777     QVERIFY(input->hasActiveFocus() == true);
1778 }
1779
1780 void tst_qquicktextedit::copyAndPaste() {
1781 #ifndef QT_NO_CLIPBOARD
1782
1783 #ifdef Q_WS_MAC
1784     {
1785         PasteboardRef pasteboard;
1786         OSStatus status = PasteboardCreate(0, &pasteboard);
1787         if (status == noErr)
1788             CFRelease(pasteboard);
1789         else
1790             QSKIP("This machine doesn't support the clipboard");
1791     }
1792 #endif
1793
1794     QString componentStr = "import QtQuick 2.0\nTextEdit { text: \"Hello world!\" }";
1795     QDeclarativeComponent textEditComponent(&engine);
1796     textEditComponent.setData(componentStr.toLatin1(), QUrl());
1797     QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit*>(textEditComponent.create());
1798     QVERIFY(textEdit != 0);
1799
1800     // copy and paste
1801     QCOMPARE(textEdit->text().length(), 12);
1802     textEdit->select(0, textEdit->text().length());;
1803     textEdit->copy();
1804     QCOMPARE(textEdit->selectedText(), QString("Hello world!"));
1805     QCOMPARE(textEdit->selectedText().length(), 12);
1806     textEdit->setCursorPosition(0);
1807     QVERIFY(textEdit->canPaste());
1808     textEdit->paste();
1809     QCOMPARE(textEdit->text(), QString("Hello world!Hello world!"));
1810     QCOMPARE(textEdit->text().length(), 24);
1811
1812     // canPaste
1813     QVERIFY(textEdit->canPaste());
1814     textEdit->setReadOnly(true);
1815     QVERIFY(!textEdit->canPaste());
1816     textEdit->setReadOnly(false);
1817     QVERIFY(textEdit->canPaste());
1818
1819     // QTBUG-12339
1820     // test that document and internal text attribute are in sync
1821     QQuickItemPrivate* pri = QQuickItemPrivate::get(textEdit);
1822     QQuickTextEditPrivate *editPrivate = static_cast<QQuickTextEditPrivate*>(pri);
1823     QCOMPARE(textEdit->text(), editPrivate->text);
1824
1825     // select word
1826     textEdit->setCursorPosition(0);
1827     textEdit->selectWord();
1828     QCOMPARE(textEdit->selectedText(), QString("Hello"));
1829
1830     // select all and cut
1831     textEdit->selectAll();
1832     textEdit->cut();
1833     QCOMPARE(textEdit->text().length(), 0);
1834     textEdit->paste();
1835     QCOMPARE(textEdit->text(), QString("Hello world!Hello world!"));
1836     QCOMPARE(textEdit->text().length(), 24);
1837 #endif
1838 }
1839
1840 void tst_qquicktextedit::canPaste() {
1841 #ifndef QT_NO_CLIPBOARD
1842
1843     QGuiApplication::clipboard()->setText("Some text");
1844
1845     QString componentStr = "import QtQuick 2.0\nTextEdit { text: \"Hello world!\" }";
1846     QDeclarativeComponent textEditComponent(&engine);
1847     textEditComponent.setData(componentStr.toLatin1(), QUrl());
1848     QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit*>(textEditComponent.create());
1849     QVERIFY(textEdit != 0);
1850
1851     // check initial value - QTBUG-17765
1852     QTextControl tc;
1853     QCOMPARE(textEdit->canPaste(), tc.canPaste());
1854
1855 #endif
1856 }
1857
1858 void tst_qquicktextedit::canPasteEmpty() {
1859 #ifndef QT_NO_CLIPBOARD
1860
1861     QGuiApplication::clipboard()->clear();
1862
1863     QString componentStr = "import QtQuick 2.0\nTextEdit { text: \"Hello world!\" }";
1864     QDeclarativeComponent textEditComponent(&engine);
1865     textEditComponent.setData(componentStr.toLatin1(), QUrl());
1866     QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit*>(textEditComponent.create());
1867     QVERIFY(textEdit != 0);
1868
1869     // check initial value - QTBUG-17765
1870     QTextControl tc;
1871     QCOMPARE(textEdit->canPaste(), tc.canPaste());
1872
1873 #endif
1874 }
1875
1876 void tst_qquicktextedit::readOnly()
1877 {
1878     QQuickView canvas(QUrl::fromLocalFile(TESTDATA("readOnly.qml")));
1879     canvas.show();
1880     canvas.requestActivateWindow();
1881
1882     QVERIFY(canvas.rootObject() != 0);
1883
1884     QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(qvariant_cast<QObject *>(canvas.rootObject()->property("myInput")));
1885
1886     QVERIFY(edit != 0);
1887     QTRY_VERIFY(edit->hasActiveFocus() == true);
1888     QVERIFY(edit->isReadOnly() == true);
1889     QString initial = edit->text();
1890     for (int k=Qt::Key_0; k<=Qt::Key_Z; k++)
1891         simulateKey(&canvas, k);
1892     simulateKey(&canvas, Qt::Key_Return);
1893     simulateKey(&canvas, Qt::Key_Space);
1894     simulateKey(&canvas, Qt::Key_Escape);
1895     QCOMPARE(edit->text(), initial);
1896
1897     edit->setCursorPosition(3);
1898     edit->setReadOnly(false);
1899     QCOMPARE(edit->isReadOnly(), false);
1900     QCOMPARE(edit->cursorPosition(), edit->text().length());
1901 }
1902
1903 void tst_qquicktextedit::simulateKey(QQuickView *view, int key, Qt::KeyboardModifiers modifiers)
1904 {
1905     QKeyEvent press(QKeyEvent::KeyPress, key, modifiers);
1906     QKeyEvent release(QKeyEvent::KeyRelease, key, modifiers);
1907
1908     QGuiApplication::sendEvent(view, &press);
1909     QGuiApplication::sendEvent(view, &release);
1910 }
1911
1912
1913 #ifndef QTBUG_21691
1914 class MyInputContext : public QInputContext
1915 {
1916 public:
1917     MyInputContext() : updateReceived(false), eventType(QEvent::None) {}
1918     ~MyInputContext() {}
1919
1920     QString identifierName() { return QString(); }
1921     QString language() { return QString(); }
1922
1923     void reset() {}
1924
1925     bool isComposing() const { return false; }
1926
1927     void update() { updateReceived = true; }
1928
1929     void sendPreeditText(const QString &text, int cursor)
1930     {
1931         QList<QInputMethodEvent::Attribute> attributes;
1932         attributes.append(QInputMethodEvent::Attribute(
1933                 QInputMethodEvent::Cursor, cursor, text.length(), QVariant()));
1934
1935         QInputMethodEvent event(text, attributes);
1936         sendEvent(event);
1937     }
1938
1939     void mouseHandler(int x, QMouseEvent *event)
1940     {
1941         cursor = x;
1942         eventType = event->type();
1943         eventPosition = event->pos();
1944         eventGlobalPosition = event->globalPos();
1945         eventButton = event->button();
1946         eventButtons = event->buttons();
1947         eventModifiers = event->modifiers();
1948     }
1949
1950     bool updateReceived;
1951     int cursor;
1952     QEvent::Type eventType;
1953     QPoint eventPosition;
1954     QPoint eventGlobalPosition;
1955     Qt::MouseButton eventButton;
1956     Qt::MouseButtons eventButtons;
1957     Qt::KeyboardModifiers eventModifiers;
1958 };
1959 #endif
1960
1961 void tst_qquicktextedit::textInput()
1962 {
1963     QQuickView view(QUrl::fromLocalFile(TESTDATA("inputMethodEvent.qml")));
1964     view.show();
1965     view.requestActivateWindow();
1966     QTest::qWaitForWindowShown(&view);
1967     QTRY_COMPARE(&view, qGuiApp->focusWindow());
1968     QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(view.rootObject());
1969     QVERIFY(edit);
1970     QVERIFY(edit->hasActiveFocus() == true);
1971
1972     // test that input method event is committed
1973     QInputMethodEvent event;
1974     event.setCommitString( "Hello world!", 0, 0);
1975     QGuiApplication::sendEvent(&view, &event);
1976     QEXPECT_FAIL("", "QTBUG-21689", Abort);
1977     QCOMPARE(edit->text(), QString("Hello world!"));
1978
1979     // QTBUG-12339
1980     // test that document and internal text attribute are in sync
1981     QQuickTextEditPrivate *editPrivate = static_cast<QQuickTextEditPrivate*>(QQuickItemPrivate::get(edit));
1982     QCOMPARE(editPrivate->text, QString("Hello world!"));
1983 }
1984
1985 void tst_qquicktextedit::openInputPanel()
1986 {
1987     QQuickView view(QUrl::fromLocalFile(TESTDATA("openInputPanel.qml")));
1988     view.show();
1989     view.requestActivateWindow();
1990     QTest::qWaitForWindowShown(&view);
1991     QTRY_COMPARE(&view, qGuiApp->focusWindow());
1992
1993     QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(view.rootObject());
1994     QVERIFY(edit);
1995
1996     // check default values
1997     QVERIFY(edit->focusOnPress());
1998     QVERIFY(!edit->hasActiveFocus());
1999     qDebug() << &edit << qApp->inputPanel()->inputItem();
2000     QCOMPARE(qApp->inputPanel()->inputItem(), static_cast<QObject*>(0));
2001     QEXPECT_FAIL("", "QTBUG-21946", Abort);
2002     QCOMPARE(qApp->inputPanel()->visible(), false);
2003
2004     // input panel should open on focus
2005     QPoint centerPoint(view.width()/2, view.height()/2);
2006     Qt::KeyboardModifiers noModifiers = 0;
2007     QTest::mousePress(&view, Qt::LeftButton, noModifiers, centerPoint);
2008     QGuiApplication::processEvents();
2009     QVERIFY(edit->hasActiveFocus());
2010     QCOMPARE(qApp->inputPanel()->inputItem(), edit);
2011     QCOMPARE(qApp->inputPanel()->visible(), true);
2012     QTest::mouseRelease(&view, Qt::LeftButton, noModifiers, centerPoint);
2013
2014     // input panel should be re-opened when pressing already focused TextEdit
2015     qApp->inputPanel()->hide();
2016     QCOMPARE(qApp->inputPanel()->visible(), false);
2017     QVERIFY(edit->hasActiveFocus());
2018     QTest::mousePress(&view, Qt::LeftButton, noModifiers, centerPoint);
2019     QGuiApplication::processEvents();
2020     QCOMPARE(qApp->inputPanel()->visible(), true);
2021     QTest::mouseRelease(&view, Qt::LeftButton, noModifiers, centerPoint);
2022
2023     // input panel should stay visible if focus is lost to another text editor
2024     QSignalSpy inputPanelVisibilitySpy(qApp->inputPanel(), SIGNAL(visibleChanged()));
2025     QQuickTextEdit anotherEdit;
2026     anotherEdit.setParentItem(view.rootObject());
2027     anotherEdit.setFocus(true);
2028     QCOMPARE(qApp->inputPanel()->visible(), true);
2029     QCOMPARE(qApp->inputPanel()->inputItem(), qobject_cast<QObject*>(&anotherEdit));
2030     QCOMPARE(inputPanelVisibilitySpy.count(), 0);
2031
2032     anotherEdit.setFocus(false);
2033     QCOMPARE(qApp->inputPanel()->inputItem(), static_cast<QObject*>(0));
2034     QCOMPARE(view.activeFocusItem(), view.rootItem());
2035     anotherEdit.setFocus(true);
2036
2037     // input item should be null if focus is lost to an item that doesn't accept inputs
2038     QQuickItem item;
2039     item.setParentItem(view.rootObject());
2040     item.setFocus(true);
2041     QCOMPARE(qApp->inputPanel()->inputItem(), static_cast<QObject*>(0));
2042     QCOMPARE(view.activeFocusItem(), &item);
2043
2044     qApp->inputPanel()->hide();
2045
2046     // input panel should not be opened if TextEdit is read only
2047     edit->setReadOnly(true);
2048     edit->setFocus(true);
2049     QCOMPARE(qApp->inputPanel()->visible(), false);
2050     QTest::mousePress(&view, Qt::LeftButton, noModifiers, centerPoint);
2051     QTest::mouseRelease(&view, Qt::LeftButton, noModifiers, centerPoint);
2052     QGuiApplication::processEvents();
2053     QCOMPARE(qApp->inputPanel()->visible(), false);
2054
2055     // input panel should not be opened if focusOnPress is set to false
2056     edit->setFocusOnPress(false);
2057     edit->setFocus(false);
2058     edit->setFocus(true);
2059     QCOMPARE(qApp->inputPanel()->visible(), false);
2060     QTest::mousePress(&view, Qt::LeftButton, noModifiers, centerPoint);
2061     QTest::mouseRelease(&view, Qt::LeftButton, noModifiers, centerPoint);
2062     QCOMPARE(qApp->inputPanel()->visible(), false);
2063
2064     // input panel should open when openSoftwareInputPanel is called
2065     edit->openSoftwareInputPanel();
2066     QCOMPARE(qApp->inputPanel()->visible(), true);
2067
2068     // input panel should close when closeSoftwareInputPanel is called
2069     edit->closeSoftwareInputPanel();
2070     QCOMPARE(qApp->inputPanel()->visible(), false);
2071 }
2072
2073 void tst_qquicktextedit::geometrySignals()
2074 {
2075     QDeclarativeComponent component(&engine, TESTDATA("geometrySignals.qml"));
2076     QObject *o = component.create();
2077     QVERIFY(o);
2078     QCOMPARE(o->property("bindingWidth").toInt(), 400);
2079     QCOMPARE(o->property("bindingHeight").toInt(), 500);
2080     delete o;
2081 }
2082
2083 void tst_qquicktextedit::pastingRichText_QTBUG_14003()
2084 {
2085 #ifndef QT_NO_CLIPBOARD
2086     QString componentStr = "import QtQuick 2.0\nTextEdit { textFormat: TextEdit.PlainText }";
2087     QDeclarativeComponent component(&engine);
2088     component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
2089     QQuickTextEdit *obj = qobject_cast<QQuickTextEdit*>(component.create());
2090
2091     QTRY_VERIFY(obj != 0);
2092     QTRY_VERIFY(obj->textFormat() == QQuickTextEdit::PlainText);
2093
2094     QMimeData *mData = new QMimeData;
2095     mData->setHtml("<font color=\"red\">Hello</font>");
2096     QGuiApplication::clipboard()->setMimeData(mData);
2097
2098     obj->paste();
2099     QTRY_VERIFY(obj->text() == "");
2100     QTRY_VERIFY(obj->textFormat() == QQuickTextEdit::PlainText);
2101 #endif
2102 }
2103
2104 void tst_qquicktextedit::implicitSize_data()
2105 {
2106     QTest::addColumn<QString>("text");
2107     QTest::addColumn<QString>("wrap");
2108     QTest::newRow("plain") << "The quick red fox jumped over the lazy brown dog" << "TextEdit.NoWrap";
2109     QTest::newRow("richtext") << "<b>The quick red fox jumped over the lazy brown dog</b>" << "TextEdit.NoWrap";
2110     QTest::newRow("plain_wrap") << "The quick red fox jumped over the lazy brown dog" << "TextEdit.Wrap";
2111     QTest::newRow("richtext_wrap") << "<b>The quick red fox jumped over the lazy brown dog</b>" << "TextEdit.Wrap";
2112 }
2113
2114 void tst_qquicktextedit::implicitSize()
2115 {
2116     QFETCH(QString, text);
2117     QFETCH(QString, wrap);
2118     QString componentStr = "import QtQuick 2.0\nTextEdit { text: \"" + text + "\"; width: 50; wrapMode: " + wrap + " }";
2119     QDeclarativeComponent textComponent(&engine);
2120     textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
2121     QQuickTextEdit *textObject = qobject_cast<QQuickTextEdit*>(textComponent.create());
2122
2123     QVERIFY(textObject->width() < textObject->implicitWidth());
2124     QVERIFY(textObject->height() == textObject->implicitHeight());
2125
2126     textObject->resetWidth();
2127     QVERIFY(textObject->width() == textObject->implicitWidth());
2128     QVERIFY(textObject->height() == textObject->implicitHeight());
2129 }
2130
2131 void tst_qquicktextedit::testQtQuick11Attributes()
2132 {
2133     QFETCH(QString, code);
2134     QFETCH(QString, warning);
2135     QFETCH(QString, error);
2136
2137     QDeclarativeEngine engine;
2138     QObject *obj;
2139
2140     QDeclarativeComponent valid(&engine);
2141     valid.setData("import QtQuick 2.0; TextEdit { " + code.toUtf8() + " }", QUrl(""));
2142     obj = valid.create();
2143     QVERIFY(obj);
2144     QVERIFY(valid.errorString().isEmpty());
2145     delete obj;
2146
2147     QDeclarativeComponent invalid(&engine);
2148     invalid.setData("import QtQuick 1.0; TextEdit { " + code.toUtf8() + " }", QUrl(""));
2149     QTest::ignoreMessage(QtWarningMsg, warning.toUtf8());
2150     obj = invalid.create();
2151     QCOMPARE(invalid.errorString(), error);
2152     delete obj;
2153 }
2154
2155 void tst_qquicktextedit::testQtQuick11Attributes_data()
2156 {
2157     QTest::addColumn<QString>("code");
2158     QTest::addColumn<QString>("warning");
2159     QTest::addColumn<QString>("error");
2160
2161     QTest::newRow("canPaste") << "property bool foo: canPaste"
2162         << "<Unknown File>:1: ReferenceError: Can't find variable: canPaste"
2163         << "";
2164
2165     QTest::newRow("lineCount") << "property int foo: lineCount"
2166         << "<Unknown File>:1: ReferenceError: Can't find variable: lineCount"
2167         << "";
2168
2169     QTest::newRow("moveCursorSelection") << "Component.onCompleted: moveCursorSelection(0, TextEdit.SelectCharacters)"
2170         << "<Unknown File>:1: ReferenceError: Can't find variable: moveCursorSelection"
2171         << "";
2172
2173     QTest::newRow("deselect") << "Component.onCompleted: deselect()"
2174         << "<Unknown File>:1: ReferenceError: Can't find variable: deselect"
2175         << "";
2176
2177     QTest::newRow("onLinkActivated") << "onLinkActivated: {}"
2178         << "QDeclarativeComponent: Component is not ready"
2179         << ":1 \"TextEdit.onLinkActivated\" is not available in QtQuick 1.0.\n";
2180 }
2181
2182 void tst_qquicktextedit::preeditMicroFocus()
2183 {
2184 #ifdef QTBUG_21691
2185     QEXPECT_FAIL("", QTBUG_21691_MESSAGE, Abort);
2186     QVERIFY(false);
2187 #else
2188     QString preeditText = "super";
2189
2190     QQuickView view(QUrl::fromLocalFile(TESTDATA("inputMethodEvent.qml")));
2191     view.show();
2192     view.requestActivateWindow();
2193     QTest::qWaitForWindowShown(&view);
2194
2195     QTRY_COMPARE(&view, qGuiApp->focusWindow());
2196     QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(view.rootObject());
2197     QVERIFY(edit);
2198
2199     QSignalSpy cursorRectangleSpy(edit, SIGNAL(cursorRectangleChanged()));
2200
2201     QRect currentRect;
2202     QRect previousRect = edit->inputMethodQuery(Qt::ImCursorRectangle).toRect();
2203
2204     // Verify that the micro focus rect is positioned the same for position 0 as
2205     // it would be if there was no preedit text.
2206     ic.updateReceived = false;
2207     ic.sendPreeditText(preeditText, 0);
2208     currentRect = edit->inputMethodQuery(Qt::ImCursorRectangle).toRect();
2209     QCOMPARE(currentRect, previousRect);
2210 #if defined(Q_WS_X11) || defined(Q_WS_QWS)
2211     QCOMPARE(ic.updateReceived, false); // The cursor position hasn't changed.
2212 #endif
2213     QCOMPARE(cursorRectangleSpy.count(), 0);
2214
2215     // Verify that the micro focus rect moves to the left as the cursor position
2216     // is incremented.
2217     for (int i = 1; i <= 5; ++i) {
2218         ic.updateReceived = false;
2219         ic.sendPreeditText(preeditText, i);
2220         currentRect = edit->inputMethodQuery(Qt::ImCursorRectangle).toRect();
2221         QVERIFY(previousRect.left() < currentRect.left());
2222 #if defined(Q_WS_X11) || defined(Q_WS_QWS)
2223         QCOMPARE(ic.updateReceived, true);
2224 #endif
2225         QVERIFY(cursorRectangleSpy.count() > 0);
2226         cursorRectangleSpy.clear();
2227         previousRect = currentRect;
2228     }
2229
2230     // Verify that if there is no preedit cursor then the micro focus rect is the
2231     // same as it would be if it were positioned at the end of the preedit text.
2232     ic.sendPreeditText(preeditText, 0);
2233     ic.updateReceived = false;
2234     ic.sendEvent(QInputMethodEvent(preeditText, QList<QInputMethodEvent::Attribute>()));
2235     currentRect = edit->inputMethodQuery(Qt::ImCursorRectangle).toRect();
2236     QCOMPARE(currentRect, previousRect);
2237 #if defined(Q_WS_X11) || defined(Q_WS_QWS)
2238     QCOMPARE(ic.updateReceived, true);
2239 #endif
2240     QVERIFY(cursorRectangleSpy.count() > 0);
2241 #endif
2242 }
2243
2244 void tst_qquicktextedit::inputContextMouseHandler()
2245 {
2246
2247 #ifdef QTBUG_21691
2248     QEXPECT_FAIL("", QTBUG_21691_MESSAGE, Abort);
2249     QVERIFY(false);
2250 #else
2251     QString text = "supercalifragisiticexpialidocious!";
2252
2253     QQuickView view(QUrl::fromLocalFile(TESTDATA("inputContext.qml")));
2254     MyInputContext ic;
2255     // QQuickCanvas won't set the Qt::WA_InputMethodEnabled flag unless a suitable item has focus
2256     // and QWidget won't allow an input context to be set when the flag is not set.
2257     view.setAttribute(Qt::WA_InputMethodEnabled, true);
2258     view.setInputContext(&ic);
2259     view.setAttribute(Qt::WA_InputMethodEnabled, false);
2260     view.show();
2261     view.requestActivateWindow();
2262     QTest::qWaitForWindowShown(&view);
2263
2264     QTRY_COMPARE(&view, qGuiApp->focusWindow());
2265     QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(view.rootObject());
2266     QVERIFY(edit);
2267     edit->setCursorPosition(12);
2268
2269     QFontMetricsF fm(edit->font());
2270     const qreal y = fm.height() / 2;
2271
2272     QPoint position2 = edit->mapToScene(QPointF(fm.width(text.mid(0, 2)), y)).toPoint();
2273     QPoint position8 = edit->mapToScene(QPointF(fm.width(text.mid(0, 8)), y)).toPoint();
2274     QPoint position20 = edit->mapToScene(QPointF(fm.width(text.mid(0, 20)), y)).toPoint();
2275     QPoint position27 = edit->mapToScene(QPointF(fm.width(text.mid(0, 27)), y)).toPoint();
2276     QPoint globalPosition2 = view.mapToGlobal(position2);
2277     QPoint globalposition8 = view.mapToGlobal(position8);
2278     QPoint globalposition20 = view.mapToGlobal(position20);
2279     QPoint globalposition27 = view.mapToGlobal(position27);
2280
2281     ic.sendEvent(QInputMethodEvent(text.mid(12), QList<QInputMethodEvent::Attribute>()));
2282
2283     QTest::mouseDClick(&view, Qt::LeftButton, Qt::NoModifier, position2);
2284     QCOMPARE(ic.eventType, QEvent::MouseButtonDblClick);
2285     QCOMPARE(ic.eventPosition, position2);
2286     QCOMPARE(ic.eventGlobalPosition, globalPosition2);
2287     QCOMPARE(ic.eventButton, Qt::LeftButton);
2288     QCOMPARE(ic.eventModifiers, Qt::NoModifier);
2289     QVERIFY(ic.cursor < 0);
2290     ic.eventType = QEvent::None;
2291
2292     QTest::mousePress(&view, Qt::LeftButton, Qt::NoModifier, position2);
2293     QCOMPARE(ic.eventType, QEvent::MouseButtonPress);
2294     QCOMPARE(ic.eventPosition, position2);
2295     QCOMPARE(ic.eventGlobalPosition, globalPosition2);
2296     QCOMPARE(ic.eventButton, Qt::LeftButton);
2297     QCOMPARE(ic.eventModifiers, Qt::NoModifier);
2298     QVERIFY(ic.cursor < 0);
2299     ic.eventType = QEvent::None;
2300
2301     {   QMouseEvent mv(QEvent::MouseMove, position8, globalposition8, Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
2302         QGuiApplication::sendEvent(&view, &mv); }
2303     QCOMPARE(ic.eventType, QEvent::None);
2304
2305     {   QMouseEvent mv(QEvent::MouseMove, position27, globalposition27, Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
2306         QGuiApplication::sendEvent(&view, &mv); }
2307     QCOMPARE(ic.eventType, QEvent::MouseMove);
2308     QCOMPARE(ic.eventPosition, position27);
2309         QCOMPARE(ic.eventGlobalPosition, globalposition27);
2310     QCOMPARE(ic.eventButton, Qt::LeftButton);
2311     QCOMPARE(ic.eventModifiers, Qt::NoModifier);
2312     QVERIFY(ic.cursor >= 14 && ic.cursor <= 16);    // 15 is expected but some platforms may be off by one.
2313     ic.eventType = QEvent::None;
2314
2315     QTest::mouseRelease(&view, Qt::LeftButton, Qt::NoModifier, position27);
2316     QCOMPARE(ic.eventType, QEvent::MouseButtonRelease);
2317     QCOMPARE(ic.eventPosition, position27);
2318     QCOMPARE(ic.eventGlobalPosition, globalposition27);
2319     QCOMPARE(ic.eventButton, Qt::LeftButton);
2320     QCOMPARE(ic.eventModifiers, Qt::NoModifier);
2321     QVERIFY(ic.cursor >= 14 && ic.cursor <= 16);
2322     ic.eventType = QEvent::None;
2323
2324     // And in the other direction.
2325     QTest::mouseDClick(&view, Qt::LeftButton, Qt::ControlModifier, position27);
2326     QCOMPARE(ic.eventType, QEvent::MouseButtonDblClick);
2327     QCOMPARE(ic.eventPosition, position27);
2328     QCOMPARE(ic.eventGlobalPosition, globalposition27);
2329     QCOMPARE(ic.eventButton, Qt::LeftButton);
2330     QCOMPARE(ic.eventModifiers, Qt::ControlModifier);
2331     QVERIFY(ic.cursor >= 14 && ic.cursor <= 16);
2332     ic.eventType = QEvent::None;
2333
2334     QTest::mousePress(&view, Qt::RightButton, Qt::ControlModifier, position27);
2335     QCOMPARE(ic.eventType, QEvent::MouseButtonPress);
2336     QCOMPARE(ic.eventPosition, position27);
2337     QCOMPARE(ic.eventGlobalPosition, globalposition27);
2338     QCOMPARE(ic.eventButton, Qt::RightButton);
2339     QCOMPARE(ic.eventModifiers, Qt::ControlModifier);
2340     QVERIFY(ic.cursor >= 14 && ic.cursor <= 16);
2341     ic.eventType = QEvent::None;
2342
2343     {   QMouseEvent mv(QEvent::MouseMove, position20, globalposition20, Qt::RightButton, Qt::RightButton,Qt::ControlModifier);
2344         QGuiApplication::sendEvent(&view, &mv); }
2345     QCOMPARE(ic.eventType, QEvent::MouseMove);
2346     QCOMPARE(ic.eventPosition, position20);
2347     QCOMPARE(ic.eventGlobalPosition, globalposition20);
2348     QCOMPARE(ic.eventButton, Qt::RightButton);
2349     QCOMPARE(ic.eventModifiers, Qt::ControlModifier);
2350     QVERIFY(ic.cursor >= 7 && ic.cursor <= 9);
2351     ic.eventType = QEvent::None;
2352
2353     {   QMouseEvent mv(QEvent::MouseMove, position2, globalPosition2, Qt::RightButton, Qt::RightButton,Qt::ControlModifier);
2354         QGuiApplication::sendEvent(&view, &mv); }
2355     QCOMPARE(ic.eventType, QEvent::None);
2356
2357     QTest::mouseRelease(&view, Qt::RightButton, Qt::ControlModifier, position2);
2358     QCOMPARE(ic.eventType, QEvent::MouseButtonRelease);
2359     QCOMPARE(ic.eventPosition, position2);
2360     QCOMPARE(ic.eventGlobalPosition, globalPosition2);
2361     QCOMPARE(ic.eventButton, Qt::RightButton);
2362     QCOMPARE(ic.eventModifiers, Qt::ControlModifier);
2363     QVERIFY(ic.cursor < 0);
2364     ic.eventType = QEvent::None;
2365 #endif
2366 }
2367
2368 void tst_qquicktextedit::inputMethodComposing()
2369 {
2370     QString text = "supercalifragisiticexpialidocious!";
2371
2372     QQuickView view(QUrl::fromLocalFile(TESTDATA("inputContext.qml")));
2373     view.show();
2374     view.requestActivateWindow();
2375     QTest::qWaitForWindowShown(&view);
2376     QTRY_COMPARE(&view, qGuiApp->focusWindow());
2377     QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(view.rootObject());
2378     QVERIFY(edit);
2379     QSignalSpy spy(edit, SIGNAL(inputMethodComposingChanged()));
2380     edit->setCursorPosition(12);
2381
2382     QCOMPARE(edit->isInputMethodComposing(), false);
2383
2384     {
2385         QInputMethodEvent event(text.mid(3), QList<QInputMethodEvent::Attribute>());
2386         QGuiApplication::sendEvent(edit, &event);
2387     }
2388
2389     QCOMPARE(edit->isInputMethodComposing(), true);
2390     QCOMPARE(spy.count(), 1);
2391
2392     {
2393         QInputMethodEvent event(text.mid(12), QList<QInputMethodEvent::Attribute>());
2394         QGuiApplication::sendEvent(edit, &event);
2395     }
2396     QCOMPARE(spy.count(), 1);
2397
2398     {
2399         QInputMethodEvent event;
2400         QGuiApplication::sendEvent(edit, &event);
2401     }
2402     QCOMPARE(edit->isInputMethodComposing(), false);
2403     QCOMPARE(spy.count(), 2);
2404 }
2405
2406 void tst_qquicktextedit::cursorRectangleSize()
2407 {
2408     QQuickView *canvas = new QQuickView(QUrl::fromLocalFile(TESTDATA("CursorRect.qml")));
2409     QVERIFY(canvas->rootObject() != 0);
2410     canvas->show();
2411     canvas->requestActivateWindow();
2412     QTest::qWaitForWindowShown(canvas);
2413
2414     QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit *>(canvas->rootObject());
2415     QVERIFY(textEdit != 0);
2416     textEdit->setFocus(Qt::OtherFocusReason);
2417     QRectF cursorRect = textEdit->positionToRectangle(textEdit->cursorPosition());
2418     QRectF microFocusFromScene = canvas->inputMethodQuery(Qt::ImCursorRectangle).toRectF();
2419     QInputMethodQueryEvent event(Qt::ImCursorRectangle);
2420     qApp->sendEvent(qApp->inputPanel()->inputItem(), &event);
2421
2422     QRectF microFocusFromApp = event.value(Qt::ImCursorRectangle).toRectF();
2423
2424     QCOMPARE(microFocusFromScene.size(), cursorRect.size());
2425     QCOMPARE(microFocusFromApp.size(), cursorRect.size());
2426
2427     delete canvas;
2428 }
2429
2430 void tst_qquicktextedit::emptytags_QTBUG_22058()
2431 {
2432     QQuickView canvas(QUrl::fromLocalFile(TESTDATA("qtbug-22058.qml")));
2433     QVERIFY(canvas.rootObject() != 0);
2434
2435     canvas.show();
2436     canvas.requestActivateWindow();
2437     QTest::qWaitForWindowShown(&canvas);
2438     QQuickTextEdit *input = qobject_cast<QQuickTextEdit *>(qvariant_cast<QObject *>(canvas.rootObject()->property("inputField")));
2439     QVERIFY(input->hasActiveFocus());
2440
2441     QInputMethodEvent event("", QList<QInputMethodEvent::Attribute>());
2442     event.setCommitString("<b>Bold<");
2443     QGuiApplication::sendEvent(input, &event);
2444     QCOMPARE(input->text(), QString("<b>Bold<"));
2445     event.setCommitString(">");
2446     QEXPECT_FAIL("", "Entering empty tags into a TextEdit asserts - QTBUG-22058", Abort);
2447     QVERIFY(false);
2448     QGuiApplication::sendEvent(input, &event);
2449     QCOMPARE(input->text(), QString("<b>Bold<>"));
2450 }
2451
2452 QTEST_MAIN(tst_qquicktextedit)
2453
2454 #include "tst_qquicktextedit.moc"