Rename Qt Quick-specific classes to QQuick*
[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     QEXPECT_FAIL("", "Most likely a side-effect of QTBUG-21489", Abort);
1687     view.setWindowState(Qt::WindowNoState);
1688     QCOMPARE(edit.isCursorVisible(), false);
1689     QCOMPARE(spy.count(), 6);
1690
1691     view.requestActivateWindow();
1692     QCOMPARE(edit.isCursorVisible(), true);
1693     QCOMPARE(spy.count(), 7);
1694
1695     // on mac, setActiveWindow(0) on mac does not deactivate the current application
1696     // (you have to switch to a different app or hide the current app to trigger this)
1697 #if !defined(Q_WS_MAC)
1698     // on mac, setActiveWindow(0) on mac does not deactivate the current application
1699     // (you have to switch to a different app or hide the current app to trigger this)
1700 //    QApplication::setActiveWindow(0);
1701 //    QTRY_COMPARE(QApplication::focusWindow(), static_cast<QWidget *>(0));
1702 //    QCOMPARE(edit.isCursorVisible(), false);
1703 //    QCOMPARE(spy.count(), 8);
1704
1705 //    view.requestActivateWindow();
1706 //    QTest::qWaitForWindowShown(&view);
1707 //    QTRY_COMPARE(view.windowState(), Qt::WindowActive);
1708 //    QCOMPARE(edit.isCursorVisible(), true);
1709 //    QCOMPARE(spy.count(), 9);
1710 #endif
1711 }
1712
1713 void tst_qquicktextedit::delegateLoading_data()
1714 {
1715     QTest::addColumn<QString>("qmlfile");
1716     QTest::addColumn<QString>("error");
1717
1718     // import installed
1719     QTest::newRow("pass") << "cursorHttpTestPass.qml" << "";
1720     QTest::newRow("fail1") << "cursorHttpTestFail1.qml" << "http://localhost:42332/FailItem.qml: Remote host closed the connection ";
1721     QTest::newRow("fail2") << "cursorHttpTestFail2.qml" << "http://localhost:42332/ErrItem.qml:4:5: Fungus is not a type ";
1722 }
1723
1724 void tst_qquicktextedit::delegateLoading()
1725 {
1726     QFETCH(QString, qmlfile);
1727     QFETCH(QString, error);
1728
1729     TestHTTPServer server(42332);
1730     server.serveDirectory(TESTDATA("httpfail"), TestHTTPServer::Disconnect);
1731     server.serveDirectory(TESTDATA("httpslow"), TestHTTPServer::Delay);
1732     server.serveDirectory(TESTDATA("http"));
1733
1734     QQuickView view(QUrl(QLatin1String("http://localhost:42332/") + qmlfile));
1735     view.show();
1736     view.requestActivateWindow();
1737
1738     if (!error.isEmpty()) {
1739         QTest::ignoreMessage(QtWarningMsg, error.toUtf8());
1740         QTRY_VERIFY(view.status()==QQuickView::Error);
1741         QTRY_VERIFY(!view.rootObject()); // there is fail item inside this test
1742     } else {
1743         QTRY_VERIFY(view.rootObject());//Wait for loading to finish.
1744         QQuickTextEdit *textEditObject = view.rootObject()->findChild<QQuickTextEdit*>("textEditObject");
1745         //    view.rootObject()->dumpObjectTree();
1746         QVERIFY(textEditObject != 0);
1747         textEditObject->setFocus(true);
1748         QQuickItem *delegate;
1749         delegate = view.rootObject()->findChild<QQuickItem*>("delegateOkay");
1750         QVERIFY(delegate);
1751         delegate = view.rootObject()->findChild<QQuickItem*>("delegateSlow");
1752         QVERIFY(delegate);
1753
1754         delete delegate;
1755     }
1756
1757
1758     //A test should be added here with a component which is ready but component.create() returns null
1759     //Not sure how to accomplish this with QQuickTextEdits cursor delegate
1760     //###This was only needed for code coverage, and could be a case of overzealous defensive programming
1761     //delegate = view.rootObject()->findChild<QQuickItem*>("delegateErrorB");
1762     //QVERIFY(!delegate);
1763 }
1764
1765 /*
1766 TextEdit element should only handle left/right keys until the cursor reaches
1767 the extent of the text, then they should ignore the keys.
1768 */
1769 void tst_qquicktextedit::navigation()
1770 {
1771     QQuickView canvas(QUrl::fromLocalFile(TESTDATA("navigation.qml")));
1772     canvas.show();
1773     canvas.requestActivateWindow();
1774
1775     QVERIFY(canvas.rootObject() != 0);
1776
1777     QQuickItem *input = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(canvas.rootObject()->property("myInput")));
1778
1779     QVERIFY(input != 0);
1780     QTRY_VERIFY(input->hasActiveFocus() == true);
1781     simulateKey(&canvas, Qt::Key_Left);
1782     QVERIFY(input->hasActiveFocus() == false);
1783     simulateKey(&canvas, Qt::Key_Right);
1784     QVERIFY(input->hasActiveFocus() == true);
1785     simulateKey(&canvas, Qt::Key_Right);
1786     QVERIFY(input->hasActiveFocus() == true);
1787     simulateKey(&canvas, Qt::Key_Right);
1788     QVERIFY(input->hasActiveFocus() == false);
1789     simulateKey(&canvas, Qt::Key_Left);
1790     QVERIFY(input->hasActiveFocus() == true);
1791 }
1792
1793 void tst_qquicktextedit::copyAndPaste() {
1794 #ifndef QT_NO_CLIPBOARD
1795
1796 #ifdef Q_WS_MAC
1797     {
1798         PasteboardRef pasteboard;
1799         OSStatus status = PasteboardCreate(0, &pasteboard);
1800         if (status == noErr)
1801             CFRelease(pasteboard);
1802         else
1803             QSKIP("This machine doesn't support the clipboard");
1804     }
1805 #endif
1806
1807     QString componentStr = "import QtQuick 2.0\nTextEdit { text: \"Hello world!\" }";
1808     QDeclarativeComponent textEditComponent(&engine);
1809     textEditComponent.setData(componentStr.toLatin1(), QUrl());
1810     QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit*>(textEditComponent.create());
1811     QVERIFY(textEdit != 0);
1812
1813     // copy and paste
1814     QCOMPARE(textEdit->text().length(), 12);
1815     textEdit->select(0, textEdit->text().length());;
1816     textEdit->copy();
1817     QCOMPARE(textEdit->selectedText(), QString("Hello world!"));
1818     QCOMPARE(textEdit->selectedText().length(), 12);
1819     textEdit->setCursorPosition(0);
1820     QVERIFY(textEdit->canPaste());
1821     textEdit->paste();
1822     QCOMPARE(textEdit->text(), QString("Hello world!Hello world!"));
1823     QCOMPARE(textEdit->text().length(), 24);
1824
1825     // canPaste
1826     QVERIFY(textEdit->canPaste());
1827     textEdit->setReadOnly(true);
1828     QVERIFY(!textEdit->canPaste());
1829     textEdit->setReadOnly(false);
1830     QVERIFY(textEdit->canPaste());
1831
1832     // QTBUG-12339
1833     // test that document and internal text attribute are in sync
1834     QQuickItemPrivate* pri = QQuickItemPrivate::get(textEdit);
1835     QQuickTextEditPrivate *editPrivate = static_cast<QQuickTextEditPrivate*>(pri);
1836     QCOMPARE(textEdit->text(), editPrivate->text);
1837
1838     // select word
1839     textEdit->setCursorPosition(0);
1840     textEdit->selectWord();
1841     QCOMPARE(textEdit->selectedText(), QString("Hello"));
1842
1843     // select all and cut
1844     textEdit->selectAll();
1845     textEdit->cut();
1846     QCOMPARE(textEdit->text().length(), 0);
1847     textEdit->paste();
1848     QCOMPARE(textEdit->text(), QString("Hello world!Hello world!"));
1849     QCOMPARE(textEdit->text().length(), 24);
1850 #endif
1851 }
1852
1853 void tst_qquicktextedit::canPaste() {
1854 #ifndef QT_NO_CLIPBOARD
1855
1856     QGuiApplication::clipboard()->setText("Some text");
1857
1858     QString componentStr = "import QtQuick 2.0\nTextEdit { text: \"Hello world!\" }";
1859     QDeclarativeComponent textEditComponent(&engine);
1860     textEditComponent.setData(componentStr.toLatin1(), QUrl());
1861     QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit*>(textEditComponent.create());
1862     QVERIFY(textEdit != 0);
1863
1864     // check initial value - QTBUG-17765
1865     QTextControl tc;
1866     QCOMPARE(textEdit->canPaste(), tc.canPaste());
1867
1868 #endif
1869 }
1870
1871 void tst_qquicktextedit::canPasteEmpty() {
1872 #ifndef QT_NO_CLIPBOARD
1873
1874     QGuiApplication::clipboard()->clear();
1875
1876     QString componentStr = "import QtQuick 2.0\nTextEdit { text: \"Hello world!\" }";
1877     QDeclarativeComponent textEditComponent(&engine);
1878     textEditComponent.setData(componentStr.toLatin1(), QUrl());
1879     QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit*>(textEditComponent.create());
1880     QVERIFY(textEdit != 0);
1881
1882     // check initial value - QTBUG-17765
1883     QTextControl tc;
1884     QCOMPARE(textEdit->canPaste(), tc.canPaste());
1885
1886 #endif
1887 }
1888
1889 void tst_qquicktextedit::readOnly()
1890 {
1891     QQuickView canvas(QUrl::fromLocalFile(TESTDATA("readOnly.qml")));
1892     canvas.show();
1893     canvas.requestActivateWindow();
1894
1895     QVERIFY(canvas.rootObject() != 0);
1896
1897     QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(qvariant_cast<QObject *>(canvas.rootObject()->property("myInput")));
1898
1899     QVERIFY(edit != 0);
1900     QTRY_VERIFY(edit->hasActiveFocus() == true);
1901     QVERIFY(edit->isReadOnly() == true);
1902     QString initial = edit->text();
1903     for (int k=Qt::Key_0; k<=Qt::Key_Z; k++)
1904         simulateKey(&canvas, k);
1905     simulateKey(&canvas, Qt::Key_Return);
1906     simulateKey(&canvas, Qt::Key_Space);
1907     simulateKey(&canvas, Qt::Key_Escape);
1908     QCOMPARE(edit->text(), initial);
1909
1910     edit->setCursorPosition(3);
1911     edit->setReadOnly(false);
1912     QCOMPARE(edit->isReadOnly(), false);
1913     QCOMPARE(edit->cursorPosition(), edit->text().length());
1914 }
1915
1916 void tst_qquicktextedit::simulateKey(QQuickView *view, int key, Qt::KeyboardModifiers modifiers)
1917 {
1918     QKeyEvent press(QKeyEvent::KeyPress, key, modifiers);
1919     QKeyEvent release(QKeyEvent::KeyRelease, key, modifiers);
1920
1921     QGuiApplication::sendEvent(view, &press);
1922     QGuiApplication::sendEvent(view, &release);
1923 }
1924
1925
1926 #ifndef QTBUG_21691
1927 class MyInputContext : public QInputContext
1928 {
1929 public:
1930     MyInputContext() : updateReceived(false), eventType(QEvent::None) {}
1931     ~MyInputContext() {}
1932
1933     QString identifierName() { return QString(); }
1934     QString language() { return QString(); }
1935
1936     void reset() {}
1937
1938     bool isComposing() const { return false; }
1939
1940     void update() { updateReceived = true; }
1941
1942     void sendPreeditText(const QString &text, int cursor)
1943     {
1944         QList<QInputMethodEvent::Attribute> attributes;
1945         attributes.append(QInputMethodEvent::Attribute(
1946                 QInputMethodEvent::Cursor, cursor, text.length(), QVariant()));
1947
1948         QInputMethodEvent event(text, attributes);
1949         sendEvent(event);
1950     }
1951
1952     void mouseHandler(int x, QMouseEvent *event)
1953     {
1954         cursor = x;
1955         eventType = event->type();
1956         eventPosition = event->pos();
1957         eventGlobalPosition = event->globalPos();
1958         eventButton = event->button();
1959         eventButtons = event->buttons();
1960         eventModifiers = event->modifiers();
1961     }
1962
1963     bool updateReceived;
1964     int cursor;
1965     QEvent::Type eventType;
1966     QPoint eventPosition;
1967     QPoint eventGlobalPosition;
1968     Qt::MouseButton eventButton;
1969     Qt::MouseButtons eventButtons;
1970     Qt::KeyboardModifiers eventModifiers;
1971 };
1972 #endif
1973
1974 void tst_qquicktextedit::textInput()
1975 {
1976     QQuickView view(QUrl::fromLocalFile(TESTDATA("inputMethodEvent.qml")));
1977     view.show();
1978     view.requestActivateWindow();
1979     QTest::qWaitForWindowShown(&view);
1980     QTRY_COMPARE(&view, qGuiApp->focusWindow());
1981     QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(view.rootObject());
1982     QVERIFY(edit);
1983     QVERIFY(edit->hasActiveFocus() == true);
1984
1985     // test that input method event is committed
1986     QInputMethodEvent event;
1987     event.setCommitString( "Hello world!", 0, 0);
1988     QGuiApplication::sendEvent(&view, &event);
1989     QEXPECT_FAIL("", "QTBUG-21689", Abort);
1990     QCOMPARE(edit->text(), QString("Hello world!"));
1991
1992     // QTBUG-12339
1993     // test that document and internal text attribute are in sync
1994     QQuickTextEditPrivate *editPrivate = static_cast<QQuickTextEditPrivate*>(QQuickItemPrivate::get(edit));
1995     QCOMPARE(editPrivate->text, QString("Hello world!"));
1996 }
1997
1998 void tst_qquicktextedit::openInputPanel()
1999 {
2000     QQuickView view(QUrl::fromLocalFile(TESTDATA("openInputPanel.qml")));
2001     view.show();
2002     view.requestActivateWindow();
2003     QTest::qWaitForWindowShown(&view);
2004     QTRY_COMPARE(&view, qGuiApp->focusWindow());
2005
2006     QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(view.rootObject());
2007     QVERIFY(edit);
2008
2009     // check default values
2010     QVERIFY(edit->focusOnPress());
2011     QVERIFY(!edit->hasActiveFocus());
2012     qDebug() << &edit << qApp->inputPanel()->inputItem();
2013     QCOMPARE(qApp->inputPanel()->inputItem(), static_cast<QObject*>(0));
2014     QEXPECT_FAIL("", "QTBUG-21946", Abort);
2015     QCOMPARE(qApp->inputPanel()->visible(), false);
2016
2017     // input panel should open on focus
2018     QPoint centerPoint(view.width()/2, view.height()/2);
2019     Qt::KeyboardModifiers noModifiers = 0;
2020     QTest::mousePress(&view, Qt::LeftButton, noModifiers, centerPoint);
2021     QGuiApplication::processEvents();
2022     QVERIFY(edit->hasActiveFocus());
2023     QCOMPARE(qApp->inputPanel()->inputItem(), edit);
2024     QCOMPARE(qApp->inputPanel()->visible(), true);
2025     QTest::mouseRelease(&view, Qt::LeftButton, noModifiers, centerPoint);
2026
2027     // input panel should be re-opened when pressing already focused TextEdit
2028     qApp->inputPanel()->hide();
2029     QCOMPARE(qApp->inputPanel()->visible(), false);
2030     QVERIFY(edit->hasActiveFocus());
2031     QTest::mousePress(&view, Qt::LeftButton, noModifiers, centerPoint);
2032     QGuiApplication::processEvents();
2033     QCOMPARE(qApp->inputPanel()->visible(), true);
2034     QTest::mouseRelease(&view, Qt::LeftButton, noModifiers, centerPoint);
2035
2036     // input panel should stay visible if focus is lost to another text editor
2037     QSignalSpy inputPanelVisibilitySpy(qApp->inputPanel(), SIGNAL(visibleChanged()));
2038     QQuickTextEdit anotherEdit;
2039     anotherEdit.setParentItem(view.rootObject());
2040     anotherEdit.setFocus(true);
2041     QCOMPARE(qApp->inputPanel()->visible(), true);
2042     QCOMPARE(qApp->inputPanel()->inputItem(), qobject_cast<QObject*>(&anotherEdit));
2043     QCOMPARE(inputPanelVisibilitySpy.count(), 0);
2044
2045     anotherEdit.setFocus(false);
2046     QCOMPARE(qApp->inputPanel()->inputItem(), static_cast<QObject*>(0));
2047     QCOMPARE(view.activeFocusItem(), view.rootItem());
2048     anotherEdit.setFocus(true);
2049
2050     // input item should be null if focus is lost to an item that doesn't accept inputs
2051     QQuickItem item;
2052     item.setParentItem(view.rootObject());
2053     item.setFocus(true);
2054     QCOMPARE(qApp->inputPanel()->inputItem(), static_cast<QObject*>(0));
2055     QCOMPARE(view.activeFocusItem(), &item);
2056
2057     qApp->inputPanel()->hide();
2058
2059     // input panel should not be opened if TextEdit is read only
2060     edit->setReadOnly(true);
2061     edit->setFocus(true);
2062     QCOMPARE(qApp->inputPanel()->visible(), false);
2063     QTest::mousePress(&view, Qt::LeftButton, noModifiers, centerPoint);
2064     QTest::mouseRelease(&view, Qt::LeftButton, noModifiers, centerPoint);
2065     QGuiApplication::processEvents();
2066     QCOMPARE(qApp->inputPanel()->visible(), false);
2067
2068     // input panel should not be opened if focusOnPress is set to false
2069     edit->setFocusOnPress(false);
2070     edit->setFocus(false);
2071     edit->setFocus(true);
2072     QCOMPARE(qApp->inputPanel()->visible(), false);
2073     QTest::mousePress(&view, Qt::LeftButton, noModifiers, centerPoint);
2074     QTest::mouseRelease(&view, Qt::LeftButton, noModifiers, centerPoint);
2075     QCOMPARE(qApp->inputPanel()->visible(), false);
2076
2077     // input panel should open when openSoftwareInputPanel is called
2078     edit->openSoftwareInputPanel();
2079     QCOMPARE(qApp->inputPanel()->visible(), true);
2080
2081     // input panel should close when closeSoftwareInputPanel is called
2082     edit->closeSoftwareInputPanel();
2083     QCOMPARE(qApp->inputPanel()->visible(), false);
2084 }
2085
2086 void tst_qquicktextedit::geometrySignals()
2087 {
2088     QDeclarativeComponent component(&engine, TESTDATA("geometrySignals.qml"));
2089     QObject *o = component.create();
2090     QVERIFY(o);
2091     QCOMPARE(o->property("bindingWidth").toInt(), 400);
2092     QCOMPARE(o->property("bindingHeight").toInt(), 500);
2093     delete o;
2094 }
2095
2096 void tst_qquicktextedit::pastingRichText_QTBUG_14003()
2097 {
2098 #ifndef QT_NO_CLIPBOARD
2099     QString componentStr = "import QtQuick 2.0\nTextEdit { textFormat: TextEdit.PlainText }";
2100     QDeclarativeComponent component(&engine);
2101     component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
2102     QQuickTextEdit *obj = qobject_cast<QQuickTextEdit*>(component.create());
2103
2104     QTRY_VERIFY(obj != 0);
2105     QTRY_VERIFY(obj->textFormat() == QQuickTextEdit::PlainText);
2106
2107     QMimeData *mData = new QMimeData;
2108     mData->setHtml("<font color=\"red\">Hello</font>");
2109     QGuiApplication::clipboard()->setMimeData(mData);
2110
2111     obj->paste();
2112     QTRY_VERIFY(obj->text() == "");
2113     QTRY_VERIFY(obj->textFormat() == QQuickTextEdit::PlainText);
2114 #endif
2115 }
2116
2117 void tst_qquicktextedit::implicitSize_data()
2118 {
2119     QTest::addColumn<QString>("text");
2120     QTest::addColumn<QString>("wrap");
2121     QTest::newRow("plain") << "The quick red fox jumped over the lazy brown dog" << "TextEdit.NoWrap";
2122     QTest::newRow("richtext") << "<b>The quick red fox jumped over the lazy brown dog</b>" << "TextEdit.NoWrap";
2123     QTest::newRow("plain_wrap") << "The quick red fox jumped over the lazy brown dog" << "TextEdit.Wrap";
2124     QTest::newRow("richtext_wrap") << "<b>The quick red fox jumped over the lazy brown dog</b>" << "TextEdit.Wrap";
2125 }
2126
2127 void tst_qquicktextedit::implicitSize()
2128 {
2129     QFETCH(QString, text);
2130     QFETCH(QString, wrap);
2131     QString componentStr = "import QtQuick 2.0\nTextEdit { text: \"" + text + "\"; width: 50; wrapMode: " + wrap + " }";
2132     QDeclarativeComponent textComponent(&engine);
2133     textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
2134     QQuickTextEdit *textObject = qobject_cast<QQuickTextEdit*>(textComponent.create());
2135
2136     QVERIFY(textObject->width() < textObject->implicitWidth());
2137     QVERIFY(textObject->height() == textObject->implicitHeight());
2138
2139     textObject->resetWidth();
2140     QVERIFY(textObject->width() == textObject->implicitWidth());
2141     QVERIFY(textObject->height() == textObject->implicitHeight());
2142 }
2143
2144 void tst_qquicktextedit::testQtQuick11Attributes()
2145 {
2146     QFETCH(QString, code);
2147     QFETCH(QString, warning);
2148     QFETCH(QString, error);
2149
2150     QDeclarativeEngine engine;
2151     QObject *obj;
2152
2153     QDeclarativeComponent valid(&engine);
2154     valid.setData("import QtQuick 2.0; TextEdit { " + code.toUtf8() + " }", QUrl(""));
2155     obj = valid.create();
2156     QVERIFY(obj);
2157     QVERIFY(valid.errorString().isEmpty());
2158     delete obj;
2159
2160     QDeclarativeComponent invalid(&engine);
2161     invalid.setData("import QtQuick 1.0; TextEdit { " + code.toUtf8() + " }", QUrl(""));
2162     QTest::ignoreMessage(QtWarningMsg, warning.toUtf8());
2163     obj = invalid.create();
2164     QCOMPARE(invalid.errorString(), error);
2165     delete obj;
2166 }
2167
2168 void tst_qquicktextedit::testQtQuick11Attributes_data()
2169 {
2170     QTest::addColumn<QString>("code");
2171     QTest::addColumn<QString>("warning");
2172     QTest::addColumn<QString>("error");
2173
2174     QTest::newRow("canPaste") << "property bool foo: canPaste"
2175         << "<Unknown File>:1: ReferenceError: Can't find variable: canPaste"
2176         << "";
2177
2178     QTest::newRow("lineCount") << "property int foo: lineCount"
2179         << "<Unknown File>:1: ReferenceError: Can't find variable: lineCount"
2180         << "";
2181
2182     QTest::newRow("moveCursorSelection") << "Component.onCompleted: moveCursorSelection(0, TextEdit.SelectCharacters)"
2183         << "<Unknown File>:1: ReferenceError: Can't find variable: moveCursorSelection"
2184         << "";
2185
2186     QTest::newRow("deselect") << "Component.onCompleted: deselect()"
2187         << "<Unknown File>:1: ReferenceError: Can't find variable: deselect"
2188         << "";
2189
2190     QTest::newRow("onLinkActivated") << "onLinkActivated: {}"
2191         << "QDeclarativeComponent: Component is not ready"
2192         << ":1 \"TextEdit.onLinkActivated\" is not available in QtQuick 1.0.\n";
2193 }
2194
2195 void tst_qquicktextedit::preeditMicroFocus()
2196 {
2197 #ifdef QTBUG_21691
2198     QEXPECT_FAIL("", QTBUG_21691_MESSAGE, Abort);
2199     QVERIFY(false);
2200 #else
2201     QString preeditText = "super";
2202
2203     QQuickView view(QUrl::fromLocalFile(TESTDATA("inputMethodEvent.qml")));
2204     view.show();
2205     view.requestActivateWindow();
2206     QTest::qWaitForWindowShown(&view);
2207
2208     QTRY_COMPARE(&view, qGuiApp->focusWindow());
2209     QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(view.rootObject());
2210     QVERIFY(edit);
2211
2212     QSignalSpy cursorRectangleSpy(edit, SIGNAL(cursorRectangleChanged()));
2213
2214     QRect currentRect;
2215     QRect previousRect = edit->inputMethodQuery(Qt::ImCursorRectangle).toRect();
2216
2217     // Verify that the micro focus rect is positioned the same for position 0 as
2218     // it would be if there was no preedit text.
2219     ic.updateReceived = false;
2220     ic.sendPreeditText(preeditText, 0);
2221     currentRect = edit->inputMethodQuery(Qt::ImCursorRectangle).toRect();
2222     QCOMPARE(currentRect, previousRect);
2223 #if defined(Q_WS_X11) || defined(Q_WS_QWS)
2224     QCOMPARE(ic.updateReceived, false); // The cursor position hasn't changed.
2225 #endif
2226     QCOMPARE(cursorRectangleSpy.count(), 0);
2227
2228     // Verify that the micro focus rect moves to the left as the cursor position
2229     // is incremented.
2230     for (int i = 1; i <= 5; ++i) {
2231         ic.updateReceived = false;
2232         ic.sendPreeditText(preeditText, i);
2233         currentRect = edit->inputMethodQuery(Qt::ImCursorRectangle).toRect();
2234         QVERIFY(previousRect.left() < currentRect.left());
2235 #if defined(Q_WS_X11) || defined(Q_WS_QWS)
2236         QCOMPARE(ic.updateReceived, true);
2237 #endif
2238         QVERIFY(cursorRectangleSpy.count() > 0);
2239         cursorRectangleSpy.clear();
2240         previousRect = currentRect;
2241     }
2242
2243     // Verify that if there is no preedit cursor then the micro focus rect is the
2244     // same as it would be if it were positioned at the end of the preedit text.
2245     ic.sendPreeditText(preeditText, 0);
2246     ic.updateReceived = false;
2247     ic.sendEvent(QInputMethodEvent(preeditText, QList<QInputMethodEvent::Attribute>()));
2248     currentRect = edit->inputMethodQuery(Qt::ImCursorRectangle).toRect();
2249     QCOMPARE(currentRect, previousRect);
2250 #if defined(Q_WS_X11) || defined(Q_WS_QWS)
2251     QCOMPARE(ic.updateReceived, true);
2252 #endif
2253     QVERIFY(cursorRectangleSpy.count() > 0);
2254 #endif
2255 }
2256
2257 void tst_qquicktextedit::inputContextMouseHandler()
2258 {
2259
2260 #ifdef QTBUG_21691
2261     QEXPECT_FAIL("", QTBUG_21691_MESSAGE, Abort);
2262     QVERIFY(false);
2263 #else
2264     QString text = "supercalifragisiticexpialidocious!";
2265
2266     QQuickView view(QUrl::fromLocalFile(TESTDATA("inputContext.qml")));
2267     MyInputContext ic;
2268     // QQuickCanvas won't set the Qt::WA_InputMethodEnabled flag unless a suitable item has focus
2269     // and QWidget won't allow an input context to be set when the flag is not set.
2270     view.setAttribute(Qt::WA_InputMethodEnabled, true);
2271     view.setInputContext(&ic);
2272     view.setAttribute(Qt::WA_InputMethodEnabled, false);
2273     view.show();
2274     view.requestActivateWindow();
2275     QTest::qWaitForWindowShown(&view);
2276
2277     QTRY_COMPARE(&view, qGuiApp->focusWindow());
2278     QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(view.rootObject());
2279     QVERIFY(edit);
2280     edit->setCursorPosition(12);
2281
2282     QFontMetricsF fm(edit->font());
2283     const qreal y = fm.height() / 2;
2284
2285     QPoint position2 = edit->mapToScene(QPointF(fm.width(text.mid(0, 2)), y)).toPoint();
2286     QPoint position8 = edit->mapToScene(QPointF(fm.width(text.mid(0, 8)), y)).toPoint();
2287     QPoint position20 = edit->mapToScene(QPointF(fm.width(text.mid(0, 20)), y)).toPoint();
2288     QPoint position27 = edit->mapToScene(QPointF(fm.width(text.mid(0, 27)), y)).toPoint();
2289     QPoint globalPosition2 = view.mapToGlobal(position2);
2290     QPoint globalposition8 = view.mapToGlobal(position8);
2291     QPoint globalposition20 = view.mapToGlobal(position20);
2292     QPoint globalposition27 = view.mapToGlobal(position27);
2293
2294     ic.sendEvent(QInputMethodEvent(text.mid(12), QList<QInputMethodEvent::Attribute>()));
2295
2296     QTest::mouseDClick(&view, Qt::LeftButton, Qt::NoModifier, position2);
2297     QCOMPARE(ic.eventType, QEvent::MouseButtonDblClick);
2298     QCOMPARE(ic.eventPosition, position2);
2299     QCOMPARE(ic.eventGlobalPosition, globalPosition2);
2300     QCOMPARE(ic.eventButton, Qt::LeftButton);
2301     QCOMPARE(ic.eventModifiers, Qt::NoModifier);
2302     QVERIFY(ic.cursor < 0);
2303     ic.eventType = QEvent::None;
2304
2305     QTest::mousePress(&view, Qt::LeftButton, Qt::NoModifier, position2);
2306     QCOMPARE(ic.eventType, QEvent::MouseButtonPress);
2307     QCOMPARE(ic.eventPosition, position2);
2308     QCOMPARE(ic.eventGlobalPosition, globalPosition2);
2309     QCOMPARE(ic.eventButton, Qt::LeftButton);
2310     QCOMPARE(ic.eventModifiers, Qt::NoModifier);
2311     QVERIFY(ic.cursor < 0);
2312     ic.eventType = QEvent::None;
2313
2314     {   QMouseEvent mv(QEvent::MouseMove, position8, globalposition8, Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
2315         QGuiApplication::sendEvent(&view, &mv); }
2316     QCOMPARE(ic.eventType, QEvent::None);
2317
2318     {   QMouseEvent mv(QEvent::MouseMove, position27, globalposition27, Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
2319         QGuiApplication::sendEvent(&view, &mv); }
2320     QCOMPARE(ic.eventType, QEvent::MouseMove);
2321     QCOMPARE(ic.eventPosition, position27);
2322         QCOMPARE(ic.eventGlobalPosition, globalposition27);
2323     QCOMPARE(ic.eventButton, Qt::LeftButton);
2324     QCOMPARE(ic.eventModifiers, Qt::NoModifier);
2325     QVERIFY(ic.cursor >= 14 && ic.cursor <= 16);    // 15 is expected but some platforms may be off by one.
2326     ic.eventType = QEvent::None;
2327
2328     QTest::mouseRelease(&view, Qt::LeftButton, Qt::NoModifier, position27);
2329     QCOMPARE(ic.eventType, QEvent::MouseButtonRelease);
2330     QCOMPARE(ic.eventPosition, position27);
2331     QCOMPARE(ic.eventGlobalPosition, globalposition27);
2332     QCOMPARE(ic.eventButton, Qt::LeftButton);
2333     QCOMPARE(ic.eventModifiers, Qt::NoModifier);
2334     QVERIFY(ic.cursor >= 14 && ic.cursor <= 16);
2335     ic.eventType = QEvent::None;
2336
2337     // And in the other direction.
2338     QTest::mouseDClick(&view, Qt::LeftButton, Qt::ControlModifier, position27);
2339     QCOMPARE(ic.eventType, QEvent::MouseButtonDblClick);
2340     QCOMPARE(ic.eventPosition, position27);
2341     QCOMPARE(ic.eventGlobalPosition, globalposition27);
2342     QCOMPARE(ic.eventButton, Qt::LeftButton);
2343     QCOMPARE(ic.eventModifiers, Qt::ControlModifier);
2344     QVERIFY(ic.cursor >= 14 && ic.cursor <= 16);
2345     ic.eventType = QEvent::None;
2346
2347     QTest::mousePress(&view, Qt::RightButton, Qt::ControlModifier, position27);
2348     QCOMPARE(ic.eventType, QEvent::MouseButtonPress);
2349     QCOMPARE(ic.eventPosition, position27);
2350     QCOMPARE(ic.eventGlobalPosition, globalposition27);
2351     QCOMPARE(ic.eventButton, Qt::RightButton);
2352     QCOMPARE(ic.eventModifiers, Qt::ControlModifier);
2353     QVERIFY(ic.cursor >= 14 && ic.cursor <= 16);
2354     ic.eventType = QEvent::None;
2355
2356     {   QMouseEvent mv(QEvent::MouseMove, position20, globalposition20, Qt::RightButton, Qt::RightButton,Qt::ControlModifier);
2357         QGuiApplication::sendEvent(&view, &mv); }
2358     QCOMPARE(ic.eventType, QEvent::MouseMove);
2359     QCOMPARE(ic.eventPosition, position20);
2360     QCOMPARE(ic.eventGlobalPosition, globalposition20);
2361     QCOMPARE(ic.eventButton, Qt::RightButton);
2362     QCOMPARE(ic.eventModifiers, Qt::ControlModifier);
2363     QVERIFY(ic.cursor >= 7 && ic.cursor <= 9);
2364     ic.eventType = QEvent::None;
2365
2366     {   QMouseEvent mv(QEvent::MouseMove, position2, globalPosition2, Qt::RightButton, Qt::RightButton,Qt::ControlModifier);
2367         QGuiApplication::sendEvent(&view, &mv); }
2368     QCOMPARE(ic.eventType, QEvent::None);
2369
2370     QTest::mouseRelease(&view, Qt::RightButton, Qt::ControlModifier, position2);
2371     QCOMPARE(ic.eventType, QEvent::MouseButtonRelease);
2372     QCOMPARE(ic.eventPosition, position2);
2373     QCOMPARE(ic.eventGlobalPosition, globalPosition2);
2374     QCOMPARE(ic.eventButton, Qt::RightButton);
2375     QCOMPARE(ic.eventModifiers, Qt::ControlModifier);
2376     QVERIFY(ic.cursor < 0);
2377     ic.eventType = QEvent::None;
2378 #endif
2379 }
2380
2381 void tst_qquicktextedit::inputMethodComposing()
2382 {
2383     QString text = "supercalifragisiticexpialidocious!";
2384
2385     QQuickView view(QUrl::fromLocalFile(TESTDATA("inputContext.qml")));
2386     view.show();
2387     view.requestActivateWindow();
2388     QTest::qWaitForWindowShown(&view);
2389     QTRY_COMPARE(&view, qGuiApp->focusWindow());
2390     QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(view.rootObject());
2391     QVERIFY(edit);
2392     QSignalSpy spy(edit, SIGNAL(inputMethodComposingChanged()));
2393     edit->setCursorPosition(12);
2394
2395     QCOMPARE(edit->isInputMethodComposing(), false);
2396
2397     {
2398         QInputMethodEvent event(text.mid(3), QList<QInputMethodEvent::Attribute>());
2399         QGuiApplication::sendEvent(edit, &event);
2400     }
2401
2402     QCOMPARE(edit->isInputMethodComposing(), true);
2403     QCOMPARE(spy.count(), 1);
2404
2405     {
2406         QInputMethodEvent event(text.mid(12), QList<QInputMethodEvent::Attribute>());
2407         QGuiApplication::sendEvent(edit, &event);
2408     }
2409     QCOMPARE(spy.count(), 1);
2410
2411     {
2412         QInputMethodEvent event;
2413         QGuiApplication::sendEvent(edit, &event);
2414     }
2415     QCOMPARE(edit->isInputMethodComposing(), false);
2416     QCOMPARE(spy.count(), 2);
2417 }
2418
2419 void tst_qquicktextedit::cursorRectangleSize()
2420 {
2421     QQuickView *canvas = new QQuickView(QUrl::fromLocalFile(TESTDATA("CursorRect.qml")));
2422     QVERIFY(canvas->rootObject() != 0);
2423     canvas->show();
2424     canvas->requestActivateWindow();
2425     QTest::qWaitForWindowShown(canvas);
2426
2427     QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit *>(canvas->rootObject());
2428     QVERIFY(textEdit != 0);
2429     textEdit->setFocus(Qt::OtherFocusReason);
2430     QRectF cursorRect = textEdit->positionToRectangle(textEdit->cursorPosition());
2431     QRectF microFocusFromScene = canvas->inputMethodQuery(Qt::ImCursorRectangle).toRectF();
2432     QInputMethodQueryEvent event(Qt::ImCursorRectangle);
2433     qApp->sendEvent(qApp->inputPanel()->inputItem(), &event);
2434
2435     QRectF microFocusFromApp = event.value(Qt::ImCursorRectangle).toRectF();
2436
2437     QCOMPARE(microFocusFromScene.size(), cursorRect.size());
2438     QCOMPARE(microFocusFromApp.size(), cursorRect.size());
2439
2440     delete canvas;
2441 }
2442
2443 void tst_qquicktextedit::emptytags_QTBUG_22058()
2444 {
2445     QQuickView canvas(QUrl::fromLocalFile(TESTDATA("qtbug-22058.qml")));
2446     QVERIFY(canvas.rootObject() != 0);
2447
2448     canvas.show();
2449     canvas.requestActivateWindow();
2450     QTest::qWaitForWindowShown(&canvas);
2451     QQuickTextEdit *input = qobject_cast<QQuickTextEdit *>(qvariant_cast<QObject *>(canvas.rootObject()->property("inputField")));
2452     QVERIFY(input->hasActiveFocus());
2453
2454     QInputMethodEvent event("", QList<QInputMethodEvent::Attribute>());
2455     event.setCommitString("<b>Bold<");
2456     QGuiApplication::sendEvent(input, &event);
2457     QCOMPARE(input->text(), QString("<b>Bold<"));
2458     event.setCommitString(">");
2459     QEXPECT_FAIL("", "Entering empty tags into a TextEdit asserts - QTBUG-22058", Abort);
2460     QVERIFY(false);
2461     QGuiApplication::sendEvent(input, &event);
2462     QCOMPARE(input->text(), QString("<b>Bold<>"));
2463 }
2464
2465 QTEST_MAIN(tst_qquicktextedit)
2466
2467 #include "tst_qquicktextedit.moc"