Remove copy of tests/shared/util.h.
[profile/ivi/qtdeclarative.git] / tests / auto / qtquick1 / qdeclarativetextinput / tst_qdeclarativetextinput.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 <QtDeclarative/qdeclarativeengine.h>
44 #include <QFile>
45 #include <QtQuick1/qdeclarativeview.h>
46 #include <QtQuick1/private/qdeclarativetextinput_p.h>
47 #include <QtQuick1/private/qdeclarativetextinput_p_p.h>
48 #include <QDebug>
49 #include <QDir>
50 #include <QStyle>
51 #include <QInputContext>
52 #include <QtWidgets/5.0.0/QtWidgets/private/qapplication_p.h>
53
54 #include "qplatformdefs.h"
55
56 Q_DECLARE_METATYPE(QDeclarative1TextInput::SelectionMode)
57
58 QString createExpectedFileIfNotFound(const QString& filebasename, const QImage& actual)
59 {
60     // XXX This will be replaced by some clever persistent platform image store.
61     QString persistent_dir = SRCDIR "/data";
62     QString arch = "unknown-architecture"; // QTest needs to help with this.
63
64     QString expectfile = persistent_dir + QDir::separator() + filebasename + "-" + arch + ".png";
65
66     if (!QFile::exists(expectfile)) {
67         actual.save(expectfile);
68         qWarning() << "created" << expectfile;
69     }
70
71     return expectfile;
72 }
73
74 class tst_qdeclarativetextinput : public QObject
75
76 {
77     Q_OBJECT
78 public:
79     tst_qdeclarativetextinput();
80
81 private slots:
82
83     void text();
84     void width();
85     void font();
86     void color();
87     void selection();
88     void isRightToLeft_data();
89     void isRightToLeft();
90     void moveCursorSelection_data();
91     void moveCursorSelection();
92     void moveCursorSelectionSequence_data();
93     void moveCursorSelectionSequence();
94     void mouseSelection_data();
95     void mouseSelection();
96     void deferEnableSelectByMouse_data();
97     void deferEnableSelectByMouse();
98     void deferDisableSelectByMouse_data();
99     void deferDisableSelectByMouse();
100     void dragMouseSelection();
101     void mouseSelectionMode_data();
102     void mouseSelectionMode();
103
104     void horizontalAlignment_data();
105     void horizontalAlignment();
106     void horizontalAlignment_RightToLeft();
107
108     void positionAt();
109
110     void maxLength();
111     void masks();
112     void validators();
113     void inputMethods();
114
115     void passwordCharacter();
116     void cursorDelegate();
117     void cursorVisible();
118     void cursorRectangle();
119     void navigation();
120     void navigation_RTL();
121     void copyAndPaste();
122     void canPasteEmpty();
123     void canPaste();
124     void readOnly();
125
126     void openInputPanelOnClick();
127     void openInputPanelOnFocus();
128     void setHAlignClearCache();
129     void focusOutClearSelection();
130
131     void echoMode();
132 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
133     void passwordEchoDelay();
134 #endif
135     void geometrySignals();
136     void testQtQuick11Attributes();
137     void testQtQuick11Attributes_data();
138
139     void preeditAutoScroll();
140     void preeditMicroFocus();
141     void inputContextMouseHandler();
142     void inputMethodComposing();
143     void cursorRectangleSize();
144
145 private:
146     void simulateKey(QDeclarativeView *, int key);
147     QDeclarativeView *createView(const QString &filename);
148
149     QDeclarativeEngine engine;
150     QStringList standard;
151     QStringList colorStrings;
152 };
153
154 tst_qdeclarativetextinput::tst_qdeclarativetextinput()
155 {
156     standard << "the quick brown fox jumped over the lazy dog"
157         << "It's supercalifragisiticexpialidocious!"
158         << "Hello, world!"
159         << "!dlrow ,olleH"
160         << " spacey   text ";
161
162     colorStrings << "aliceblue"
163                  << "antiquewhite"
164                  << "aqua"
165                  << "darkkhaki"
166                  << "darkolivegreen"
167                  << "dimgray"
168                  << "palevioletred"
169                  << "lightsteelblue"
170                  << "#000000"
171                  << "#AAAAAA"
172                  << "#FFFFFF"
173                  << "#2AC05F";
174 }
175
176 void tst_qdeclarativetextinput::text()
177 {
178     {
179         QDeclarativeComponent textinputComponent(&engine);
180         textinputComponent.setData("import QtQuick 1.0\nTextInput {  text: \"\"  }", QUrl());
181         QDeclarative1TextInput *textinputObject = qobject_cast<QDeclarative1TextInput*>(textinputComponent.create());
182
183         QVERIFY(textinputObject != 0);
184         QCOMPARE(textinputObject->text(), QString(""));
185
186         delete textinputObject;
187     }
188
189     for (int i = 0; i < standard.size(); i++)
190     {
191         QString componentStr = "import QtQuick 1.0\nTextInput { text: \"" + standard.at(i) + "\" }";
192         QDeclarativeComponent textinputComponent(&engine);
193         textinputComponent.setData(componentStr.toLatin1(), QUrl());
194         QDeclarative1TextInput *textinputObject = qobject_cast<QDeclarative1TextInput*>(textinputComponent.create());
195
196         QVERIFY(textinputObject != 0);
197         QCOMPARE(textinputObject->text(), standard.at(i));
198
199         delete textinputObject;
200     }
201
202 }
203
204 void tst_qdeclarativetextinput::width()
205 {
206     // uses Font metrics to find the width for standard
207     {
208         QDeclarativeComponent textinputComponent(&engine);
209         textinputComponent.setData("import QtQuick 1.0\nTextInput {  text: \"\" }", QUrl());
210         QDeclarative1TextInput *textinputObject = qobject_cast<QDeclarative1TextInput*>(textinputComponent.create());
211
212         QVERIFY(textinputObject != 0);
213         QCOMPARE(textinputObject->width(), 0.0);
214
215         delete textinputObject;
216     }
217
218     for (int i = 0; i < standard.size(); i++)
219     {
220         QFont f;
221         QFontMetricsF fm(f);
222         qreal metricWidth = fm.width(standard.at(i));
223
224         QString componentStr = "import QtQuick 1.0\nTextInput { text: \"" + standard.at(i) + "\" }";
225         QDeclarativeComponent textinputComponent(&engine);
226         textinputComponent.setData(componentStr.toLatin1(), QUrl());
227         QDeclarative1TextInput *textinputObject = qobject_cast<QDeclarative1TextInput*>(textinputComponent.create());
228
229         QVERIFY(textinputObject != 0);
230         int delta = abs(int(int(textinputObject->width()) - metricWidth));
231         QVERIFY(delta <= 3.0); // As best as we can hope for cross-platform.
232
233         delete textinputObject;
234     }
235 }
236
237 void tst_qdeclarativetextinput::font()
238 {
239     //test size, then bold, then italic, then family
240     { 
241         QString componentStr = "import QtQuick 1.0\nTextInput {  font.pointSize: 40; text: \"Hello World\" }";
242         QDeclarativeComponent textinputComponent(&engine);
243         textinputComponent.setData(componentStr.toLatin1(), QUrl());
244         QDeclarative1TextInput *textinputObject = qobject_cast<QDeclarative1TextInput*>(textinputComponent.create());
245
246         QVERIFY(textinputObject != 0);
247         QCOMPARE(textinputObject->font().pointSize(), 40);
248         QCOMPARE(textinputObject->font().bold(), false);
249         QCOMPARE(textinputObject->font().italic(), false);
250
251         delete textinputObject;
252     }
253
254     { 
255         QString componentStr = "import QtQuick 1.0\nTextInput {  font.bold: true; text: \"Hello World\" }";
256         QDeclarativeComponent textinputComponent(&engine);
257         textinputComponent.setData(componentStr.toLatin1(), QUrl());
258         QDeclarative1TextInput *textinputObject = qobject_cast<QDeclarative1TextInput*>(textinputComponent.create());
259
260         QVERIFY(textinputObject != 0);
261         QCOMPARE(textinputObject->font().bold(), true);
262         QCOMPARE(textinputObject->font().italic(), false);
263
264         delete textinputObject;
265     }
266
267     { 
268         QString componentStr = "import QtQuick 1.0\nTextInput {  font.italic: true; text: \"Hello World\" }";
269         QDeclarativeComponent textinputComponent(&engine);
270         textinputComponent.setData(componentStr.toLatin1(), QUrl());
271         QDeclarative1TextInput *textinputObject = qobject_cast<QDeclarative1TextInput*>(textinputComponent.create());
272
273         QVERIFY(textinputObject != 0);
274         QCOMPARE(textinputObject->font().italic(), true);
275         QCOMPARE(textinputObject->font().bold(), false);
276
277         delete textinputObject;
278     }
279  
280     { 
281         QString componentStr = "import QtQuick 1.0\nTextInput {  font.family: \"Helvetica\"; text: \"Hello World\" }";
282         QDeclarativeComponent textinputComponent(&engine);
283         textinputComponent.setData(componentStr.toLatin1(), QUrl());
284         QDeclarative1TextInput *textinputObject = qobject_cast<QDeclarative1TextInput*>(textinputComponent.create());
285
286         QVERIFY(textinputObject != 0);
287         QCOMPARE(textinputObject->font().family(), QString("Helvetica"));
288         QCOMPARE(textinputObject->font().bold(), false);
289         QCOMPARE(textinputObject->font().italic(), false);
290
291         delete textinputObject;
292     }
293
294     { 
295         QString componentStr = "import QtQuick 1.0\nTextInput {  font.family: \"\"; text: \"Hello World\" }";
296         QDeclarativeComponent textinputComponent(&engine);
297         textinputComponent.setData(componentStr.toLatin1(), QUrl());
298         QDeclarative1TextInput *textinputObject = qobject_cast<QDeclarative1TextInput*>(textinputComponent.create());
299
300         QVERIFY(textinputObject != 0);
301         QCOMPARE(textinputObject->font().family(), QString(""));
302
303         delete textinputObject;
304     }
305 }
306
307 void tst_qdeclarativetextinput::color()
308 {
309     //test color
310     for (int i = 0; i < colorStrings.size(); i++)
311     { 
312         QString componentStr = "import QtQuick 1.0\nTextInput {  color: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
313         QDeclarativeComponent textinputComponent(&engine);
314         textinputComponent.setData(componentStr.toLatin1(), QUrl());
315         QDeclarative1TextInput *textinputObject = qobject_cast<QDeclarative1TextInput*>(textinputComponent.create());
316         QVERIFY(textinputObject != 0);
317         QCOMPARE(textinputObject->color(), QColor(colorStrings.at(i)));
318
319         delete textinputObject;
320     }
321
322     //test selection color
323     for (int i = 0; i < colorStrings.size(); i++)
324     {
325         QString componentStr = "import QtQuick 1.0\nTextInput {  selectionColor: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
326         QDeclarativeComponent textinputComponent(&engine);
327         textinputComponent.setData(componentStr.toLatin1(), QUrl());
328         QDeclarative1TextInput *textinputObject = qobject_cast<QDeclarative1TextInput*>(textinputComponent.create());
329         QVERIFY(textinputObject != 0);
330         QCOMPARE(textinputObject->selectionColor(), QColor(colorStrings.at(i)));
331
332         delete textinputObject;
333     }
334
335     //test selected text color
336     for (int i = 0; i < colorStrings.size(); i++)
337     { 
338         QString componentStr = "import QtQuick 1.0\nTextInput {  selectedTextColor: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
339         QDeclarativeComponent textinputComponent(&engine);
340         textinputComponent.setData(componentStr.toLatin1(), QUrl());
341         QDeclarative1TextInput *textinputObject = qobject_cast<QDeclarative1TextInput*>(textinputComponent.create());
342         QVERIFY(textinputObject != 0);
343         QCOMPARE(textinputObject->selectedTextColor(), QColor(colorStrings.at(i)));
344
345         delete textinputObject;
346     }
347
348     {
349         QString colorStr = "#AA001234";
350         QColor testColor("#001234");
351         testColor.setAlpha(170);
352
353         QString componentStr = "import QtQuick 1.0\nTextInput {  color: \"" + colorStr + "\"; text: \"Hello World\" }";
354         QDeclarativeComponent textinputComponent(&engine);
355         textinputComponent.setData(componentStr.toLatin1(), QUrl());
356         QDeclarative1TextInput *textinputObject = qobject_cast<QDeclarative1TextInput*>(textinputComponent.create());
357
358         QVERIFY(textinputObject != 0);
359         QCOMPARE(textinputObject->color(), testColor);
360
361         delete textinputObject;
362     }
363 }
364
365 void tst_qdeclarativetextinput::selection()
366 {
367     QString testStr = standard[0];
368     QString componentStr = "import QtQuick 1.0\nTextInput {  text: \""+ testStr +"\"; }";
369     QDeclarativeComponent textinputComponent(&engine);
370     textinputComponent.setData(componentStr.toLatin1(), QUrl());
371     QDeclarative1TextInput *textinputObject = qobject_cast<QDeclarative1TextInput*>(textinputComponent.create());
372     QVERIFY(textinputObject != 0);
373
374
375     //Test selection follows cursor
376     for(int i=0; i<= testStr.size(); i++) {
377         textinputObject->setCursorPosition(i);
378         QCOMPARE(textinputObject->cursorPosition(), i);
379         QCOMPARE(textinputObject->selectionStart(), i);
380         QCOMPARE(textinputObject->selectionEnd(), i);
381         QVERIFY(textinputObject->selectedText().isNull());
382     }
383     //Test cursor follows selection
384     for(int i=0; i<= testStr.size(); i++) {
385         textinputObject->select(i,i);
386         QCOMPARE(textinputObject->cursorPosition(), i);
387         QCOMPARE(textinputObject->selectionStart(), i);
388         QCOMPARE(textinputObject->selectionEnd(), i);
389     }
390
391     textinputObject->setCursorPosition(0);
392     QVERIFY(textinputObject->cursorPosition() == 0);
393     QVERIFY(textinputObject->selectionStart() == 0);
394     QVERIFY(textinputObject->selectionEnd() == 0);
395     QVERIFY(textinputObject->selectedText().isNull());
396
397     // Verify invalid positions are ignored.
398     textinputObject->setCursorPosition(-1);
399     QVERIFY(textinputObject->cursorPosition() == 0);
400     QVERIFY(textinputObject->selectionStart() == 0);
401     QVERIFY(textinputObject->selectionEnd() == 0);
402     QVERIFY(textinputObject->selectedText().isNull());
403
404     textinputObject->setCursorPosition(textinputObject->text().count()+1);
405     QVERIFY(textinputObject->cursorPosition() == 0);
406     QVERIFY(textinputObject->selectionStart() == 0);
407     QVERIFY(textinputObject->selectionEnd() == 0);
408     QVERIFY(textinputObject->selectedText().isNull());
409
410     //Test selection
411     for(int i=0; i<= testStr.size(); i++) {
412         textinputObject->select(0,i);
413         QCOMPARE(testStr.mid(0,i), textinputObject->selectedText());
414         QCOMPARE(textinputObject->cursorPosition(), i);
415     }
416     for(int i=0; i<= testStr.size(); i++) {
417         textinputObject->select(i,testStr.size());
418         QCOMPARE(testStr.mid(i,testStr.size()-i), textinputObject->selectedText());
419         QCOMPARE(textinputObject->cursorPosition(), testStr.size());
420     }
421
422     textinputObject->setCursorPosition(0);
423     QVERIFY(textinputObject->cursorPosition() == 0);
424     QVERIFY(textinputObject->selectionStart() == 0);
425     QVERIFY(textinputObject->selectionEnd() == 0);
426     QVERIFY(textinputObject->selectedText().isNull());
427
428     //Test Error Ignoring behaviour
429     textinputObject->setCursorPosition(0);
430     QVERIFY(textinputObject->selectedText().isNull());
431     textinputObject->select(-10,0);
432     QVERIFY(textinputObject->selectedText().isNull());
433     textinputObject->select(100,110);
434     QVERIFY(textinputObject->selectedText().isNull());
435     textinputObject->select(0,-10);
436     QVERIFY(textinputObject->selectedText().isNull());
437     textinputObject->select(0,100);
438     QVERIFY(textinputObject->selectedText().isNull());
439     textinputObject->select(0,10);
440     QVERIFY(textinputObject->selectedText().size() == 10);
441     textinputObject->select(-10,10);
442     QVERIFY(textinputObject->selectedText().size() == 10);
443     textinputObject->select(100,101);
444     QVERIFY(textinputObject->selectedText().size() == 10);
445     textinputObject->select(0,-10);
446     QVERIFY(textinputObject->selectedText().size() == 10);
447     textinputObject->select(0,100);
448     QVERIFY(textinputObject->selectedText().size() == 10);
449
450     textinputObject->deselect();
451     QVERIFY(textinputObject->selectedText().isNull());
452     textinputObject->select(0,10);
453     QVERIFY(textinputObject->selectedText().size() == 10);
454     textinputObject->deselect();
455     QVERIFY(textinputObject->selectedText().isNull());
456
457     delete textinputObject;
458 }
459
460 void tst_qdeclarativetextinput::isRightToLeft_data()
461 {
462     QTest::addColumn<QString>("text");
463     QTest::addColumn<bool>("emptyString");
464     QTest::addColumn<bool>("firstCharacter");
465     QTest::addColumn<bool>("lastCharacter");
466     QTest::addColumn<bool>("middleCharacter");
467     QTest::addColumn<bool>("startString");
468     QTest::addColumn<bool>("midString");
469     QTest::addColumn<bool>("endString");
470
471     const quint16 arabic_str[] = { 0x0638, 0x0643, 0x00646, 0x0647, 0x0633, 0x0638, 0x0643, 0x00646, 0x0647, 0x0633, 0x0647};
472     QTest::newRow("Empty") << "" << false << false << false << false << false << false << false;
473     QTest::newRow("Neutral") << "23244242" << false << false << false << false << false << false << false;
474     QTest::newRow("LTR") << "Hello world" << false << false << false << false << false << false << false;
475     QTest::newRow("RTL") << QString::fromUtf16(arabic_str, 11) << false << true << true << true << true << true << true;
476     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;
477     QTest::newRow("Bidi LTR + RTL + LTR") << QString("Hello world") + QString::fromUtf16(arabic_str, 11) + QString("Hello world") << false << false << false << true << false << false << false;
478 }
479
480 void tst_qdeclarativetextinput::isRightToLeft()
481 {
482     QFETCH(QString, text);
483     QFETCH(bool, emptyString);
484     QFETCH(bool, firstCharacter);
485     QFETCH(bool, lastCharacter);
486     QFETCH(bool, middleCharacter);
487     QFETCH(bool, startString);
488     QFETCH(bool, midString);
489     QFETCH(bool, endString);
490
491     QDeclarative1TextInput textInput;
492     textInput.setText(text);
493
494     // first test that the right string is delivered to the QString::isRightToLeft()
495     QCOMPARE(textInput.isRightToLeft(0,0), text.mid(0,0).isRightToLeft());
496     QCOMPARE(textInput.isRightToLeft(0,1), text.mid(0,1).isRightToLeft());
497     QCOMPARE(textInput.isRightToLeft(text.count()-2, text.count()-1), text.mid(text.count()-2, text.count()-1).isRightToLeft());
498     QCOMPARE(textInput.isRightToLeft(text.count()/2, text.count()/2 + 1), text.mid(text.count()/2, text.count()/2 + 1).isRightToLeft());
499     QCOMPARE(textInput.isRightToLeft(0,text.count()/4), text.mid(0,text.count()/4).isRightToLeft());
500     QCOMPARE(textInput.isRightToLeft(text.count()/4,3*text.count()/4), text.mid(text.count()/4,3*text.count()/4).isRightToLeft());
501     if (text.isEmpty())
502         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML TextInput: isRightToLeft(start, end) called with the end property being smaller than the start.");
503     QCOMPARE(textInput.isRightToLeft(3*text.count()/4,text.count()-1), text.mid(3*text.count()/4,text.count()-1).isRightToLeft());
504
505     // then test that the feature actually works
506     QCOMPARE(textInput.isRightToLeft(0,0), emptyString);
507     QCOMPARE(textInput.isRightToLeft(0,1), firstCharacter);
508     QCOMPARE(textInput.isRightToLeft(text.count()-2, text.count()-1), lastCharacter);
509     QCOMPARE(textInput.isRightToLeft(text.count()/2, text.count()/2 + 1), middleCharacter);
510     QCOMPARE(textInput.isRightToLeft(0,text.count()/4), startString);
511     QCOMPARE(textInput.isRightToLeft(text.count()/4,3*text.count()/4), midString);
512     if (text.isEmpty())
513         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML TextInput: isRightToLeft(start, end) called with the end property being smaller than the start.");
514     QCOMPARE(textInput.isRightToLeft(3*text.count()/4,text.count()-1), endString);
515 }
516
517 void tst_qdeclarativetextinput::moveCursorSelection_data()
518 {
519     QTest::addColumn<QString>("testStr");
520     QTest::addColumn<int>("cursorPosition");
521     QTest::addColumn<int>("movePosition");
522     QTest::addColumn<QDeclarative1TextInput::SelectionMode>("mode");
523     QTest::addColumn<int>("selectionStart");
524     QTest::addColumn<int>("selectionEnd");
525     QTest::addColumn<bool>("reversible");
526
527     // () contains the text selected by the cursor.
528     // <> contains the actual selection.
529
530     QTest::newRow("(t)he|characters")
531             << standard[0] << 0 << 1 << QDeclarative1TextInput::SelectCharacters << 0 << 1 << true;
532     QTest::newRow("do(g)|characters")
533             << standard[0] << 43 << 44 << QDeclarative1TextInput::SelectCharacters << 43 << 44 << true;
534     QTest::newRow("jum(p)ed|characters")
535             << standard[0] << 23 << 24 << QDeclarative1TextInput::SelectCharacters << 23 << 24 << true;
536     QTest::newRow("jumped( )over|characters")
537             << standard[0] << 26 << 27 << QDeclarative1TextInput::SelectCharacters << 26 << 27 << true;
538     QTest::newRow("(the )|characters")
539             << standard[0] << 0 << 4 << QDeclarative1TextInput::SelectCharacters << 0 << 4 << true;
540     QTest::newRow("( dog)|characters")
541             << standard[0] << 40 << 44 << QDeclarative1TextInput::SelectCharacters << 40 << 44 << true;
542     QTest::newRow("( jumped )|characters")
543             << standard[0] << 19 << 27 << QDeclarative1TextInput::SelectCharacters << 19 << 27 << true;
544     QTest::newRow("th(e qu)ick|characters")
545             << standard[0] << 2 << 6 << QDeclarative1TextInput::SelectCharacters << 2 << 6 << true;
546     QTest::newRow("la(zy d)og|characters")
547             << standard[0] << 38 << 42 << QDeclarative1TextInput::SelectCharacters << 38 << 42 << true;
548     QTest::newRow("jum(ped ov)er|characters")
549             << standard[0] << 23 << 29 << QDeclarative1TextInput::SelectCharacters << 23 << 29 << true;
550     QTest::newRow("()the|characters")
551             << standard[0] << 0 << 0 << QDeclarative1TextInput::SelectCharacters << 0 << 0 << true;
552     QTest::newRow("dog()|characters")
553             << standard[0] << 44 << 44 << QDeclarative1TextInput::SelectCharacters << 44 << 44 << true;
554     QTest::newRow("jum()ped|characters")
555             << standard[0] << 23 << 23 << QDeclarative1TextInput::SelectCharacters << 23 << 23 << true;
556
557     QTest::newRow("<(t)he>|words")
558             << standard[0] << 0 << 1 << QDeclarative1TextInput::SelectWords << 0 << 3 << true;
559     QTest::newRow("<do(g)>|words")
560             << standard[0] << 43 << 44 << QDeclarative1TextInput::SelectWords << 41 << 44 << true;
561     QTest::newRow("<jum(p)ed>|words")
562             << standard[0] << 23 << 24 << QDeclarative1TextInput::SelectWords << 20 << 26 << true;
563     QTest::newRow("<jumped( )>over|words,ltr")
564             << standard[0] << 26 << 27 << QDeclarative1TextInput::SelectWords << 20 << 27 << false;
565     QTest::newRow("jumped<( )over>|words,rtl")
566             << standard[0] << 27 << 26 << QDeclarative1TextInput::SelectWords << 26 << 31 << false;
567     QTest::newRow("<(the )>quick|words,ltr")
568             << standard[0] << 0 << 4 << QDeclarative1TextInput::SelectWords << 0 << 4 << false;
569     QTest::newRow("<(the )quick>|words,rtl")
570             << standard[0] << 4 << 0 << QDeclarative1TextInput::SelectWords << 0 << 9 << false;
571     QTest::newRow("<lazy( dog)>|words,ltr")
572             << standard[0] << 40 << 44 << QDeclarative1TextInput::SelectWords << 36 << 44 << false;
573     QTest::newRow("lazy<( dog)>|words,rtl")
574             << standard[0] << 44 << 40 << QDeclarative1TextInput::SelectWords << 40 << 44 << false;
575     QTest::newRow("<fox( jumped )>over|words,ltr")
576             << standard[0] << 19 << 27 << QDeclarative1TextInput::SelectWords << 16 << 27 << false;
577     QTest::newRow("fox<( jumped )over>|words,rtl")
578             << standard[0] << 27 << 19 << QDeclarative1TextInput::SelectWords << 19 << 31 << false;
579     QTest::newRow("<th(e qu)ick>|words")
580             << standard[0] << 2 << 6 << QDeclarative1TextInput::SelectWords << 0 << 9 << true;
581     QTest::newRow("<la(zy d)og|words>")
582             << standard[0] << 38 << 42 << QDeclarative1TextInput::SelectWords << 36 << 44 << true;
583     QTest::newRow("<jum(ped ov)er>|words")
584             << standard[0] << 23 << 29 << QDeclarative1TextInput::SelectWords << 20 << 31 << true;
585     QTest::newRow("<()>the|words")
586             << standard[0] << 0 << 0 << QDeclarative1TextInput::SelectWords << 0 << 0 << true;
587     QTest::newRow("dog<()>|words")
588             << standard[0] << 44 << 44 << QDeclarative1TextInput::SelectWords << 44 << 44 << true;
589     QTest::newRow("jum<()>ped|words")
590             << standard[0] << 23 << 23 << QDeclarative1TextInput::SelectWords << 23 << 23 << true;
591
592     QTest::newRow("Hello<(,)> |words")
593             << standard[2] << 5 << 6 << QDeclarative1TextInput::SelectWords << 5 << 6 << true;
594     QTest::newRow("Hello<(, )>world|words,ltr")
595             << standard[2] << 5 << 7 << QDeclarative1TextInput::SelectWords << 5 << 7 << false;
596     QTest::newRow("Hello<(, )world>|words,rtl")
597             << standard[2] << 7 << 5 << QDeclarative1TextInput::SelectWords << 5 << 12 << false;
598     QTest::newRow("<Hel(lo, )>world|words,ltr")
599             << standard[2] << 3 << 7 << QDeclarative1TextInput::SelectWords << 0 << 7 << false;
600     QTest::newRow("<Hel(lo, )world>|words,rtl")
601             << standard[2] << 7 << 3 << QDeclarative1TextInput::SelectWords << 0 << 12 << false;
602     QTest::newRow("<Hel(lo)>,|words")
603             << standard[2] << 3 << 5 << QDeclarative1TextInput::SelectWords << 0 << 5 << true;
604     QTest::newRow("Hello<()>,|words")
605             << standard[2] << 5 << 5 << QDeclarative1TextInput::SelectWords << 5 << 5 << true;
606     QTest::newRow("Hello,<()>|words")
607             << standard[2] << 6 << 6 << QDeclarative1TextInput::SelectWords << 6 << 6 << true;
608     QTest::newRow("Hello<,( )>world|words,ltr")
609             << standard[2] << 6 << 7 << QDeclarative1TextInput::SelectWords << 5 << 7 << false;
610     QTest::newRow("Hello,<( )world>|words,rtl")
611             << standard[2] << 7 << 6 << QDeclarative1TextInput::SelectWords << 6 << 12 << false;
612     QTest::newRow("Hello<,( world)>|words,ltr")
613             << standard[2] << 6 << 12 << QDeclarative1TextInput::SelectWords << 5 << 12 << false;
614     QTest::newRow("Hello,<( world)>|words,rtl")
615             << standard[2] << 12 << 6 << QDeclarative1TextInput::SelectWords << 6 << 12 << false;
616     QTest::newRow("Hello<,( world!)>|words,ltr")
617             << standard[2] << 6 << 13 << QDeclarative1TextInput::SelectWords << 5 << 13 << false;
618     QTest::newRow("Hello,<( world!)>|words,rtl")
619             << standard[2] << 13 << 6 << QDeclarative1TextInput::SelectWords << 6 << 13 << false;
620     QTest::newRow("Hello<(, world!)>|words")
621             << standard[2] << 5 << 13 << QDeclarative1TextInput::SelectWords << 5 << 13 << true;
622      QTest::newRow("world<(!)>|words")
623              << standard[2] << 12 << 13 << QDeclarative1TextInput::SelectWords << 12 << 13 << true;
624     QTest::newRow("world!<()>)|words")
625             << standard[2] << 13 << 13 << QDeclarative1TextInput::SelectWords << 13 << 13 << true;
626     QTest::newRow("world<()>!)|words")
627             << standard[2] << 12 << 12 << QDeclarative1TextInput::SelectWords << 12 << 12 << true;
628
629     QTest::newRow("<(,)>olleH |words")
630             << standard[3] << 7 << 8 << QDeclarative1TextInput::SelectWords << 7 << 8 << true;
631     QTest::newRow("<dlrow( ,)>olleH|words,ltr")
632             << standard[3] << 6 << 8 << QDeclarative1TextInput::SelectWords << 1 << 8 << false;
633     QTest::newRow("dlrow<( ,)>olleH|words,rtl")
634             << standard[3] << 8 << 6 << QDeclarative1TextInput::SelectWords << 6 << 8 << false;
635     QTest::newRow("<dlrow( ,ol)leH>|words,ltr")
636             << standard[3] << 6 << 10 << QDeclarative1TextInput::SelectWords << 1 << 13 << false;
637     QTest::newRow("dlrow<( ,ol)leH>|words,rtl")
638             << standard[3] << 10 << 6 << QDeclarative1TextInput::SelectWords << 6 << 13 << false;
639     QTest::newRow(",<(ol)leH>,|words")
640             << standard[3] << 8 << 10 << QDeclarative1TextInput::SelectWords << 8 << 13 << true;
641     QTest::newRow(",<()>olleH|words")
642             << standard[3] << 8 << 8 << QDeclarative1TextInput::SelectWords << 8 << 8 << true;
643     QTest::newRow("<()>,olleH|words")
644             << standard[3] << 7 << 7 << QDeclarative1TextInput::SelectWords << 7 << 7 << true;
645     QTest::newRow("<dlrow( )>,olleH|words,ltr")
646             << standard[3] << 6 << 7 << QDeclarative1TextInput::SelectWords << 1 << 7 << false;
647     QTest::newRow("dlrow<( ),>olleH|words,rtl")
648             << standard[3] << 7 << 6 << QDeclarative1TextInput::SelectWords << 6 << 8 << false;
649     QTest::newRow("<(dlrow )>,olleH|words,ltr")
650             << standard[3] << 1 << 7 << QDeclarative1TextInput::SelectWords << 1 << 7 << false;
651     QTest::newRow("<(dlrow ),>olleH|words,rtl")
652             << standard[3] << 7 << 1 << QDeclarative1TextInput::SelectWords << 1 << 8 << false;
653     QTest::newRow("<(!dlrow )>,olleH|words,ltr")
654             << standard[3] << 0 << 7 << QDeclarative1TextInput::SelectWords << 0 << 7 << false;
655     QTest::newRow("<(!dlrow ),>olleH|words,rtl")
656             << standard[3] << 7 << 0 << QDeclarative1TextInput::SelectWords << 0 << 8 << false;
657     QTest::newRow("(!dlrow ,)olleH|words")
658             << standard[3] << 0 << 8 << QDeclarative1TextInput::SelectWords << 0 << 8 << true;
659     QTest::newRow("<(!)>dlrow|words")
660             << standard[3] << 0 << 1 << QDeclarative1TextInput::SelectWords << 0 << 1 << true;
661     QTest::newRow("<()>!dlrow|words")
662             << standard[3] << 0 << 0 << QDeclarative1TextInput::SelectWords << 0 << 0 << true;
663     QTest::newRow("!<()>dlrow|words")
664             << standard[3] << 1 << 1 << QDeclarative1TextInput::SelectWords << 1 << 1 << true;
665
666     QTest::newRow(" <s(pac)ey>   text |words")
667             << standard[4] << 1 << 4 << QDeclarative1TextInput::SelectWords << 1 << 7 << true;
668     QTest::newRow(" spacey   <t(ex)t> |words")
669             << standard[4] << 11 << 13 << QDeclarative1TextInput::SelectWords << 10 << 14 << true;
670     QTest::newRow("<( )>spacey   text |words|ltr")
671             << standard[4] << 0 << 1 << QDeclarative1TextInput::SelectWords << 0 << 1 << false;
672     QTest::newRow("<( )spacey>   text |words|rtl")
673             << standard[4] << 1 << 0 << QDeclarative1TextInput::SelectWords << 0 << 7 << false;
674     QTest::newRow("spacey   <text( )>|words|ltr")
675             << standard[4] << 14 << 15 << QDeclarative1TextInput::SelectWords << 10 << 15 << false;
676     QTest::newRow("spacey   text<( )>|words|rtl")
677             << standard[4] << 15 << 14 << QDeclarative1TextInput::SelectWords << 14 << 15 << false;
678     QTest::newRow("<()> spacey   text |words")
679             << standard[4] << 0 << 0 << QDeclarative1TextInput::SelectWords << 0 << 0 << false;
680     QTest::newRow(" spacey   text <()>|words")
681             << standard[4] << 15 << 15 << QDeclarative1TextInput::SelectWords << 15 << 15 << false;
682 }
683
684 void tst_qdeclarativetextinput::moveCursorSelection()
685 {
686     QFETCH(QString, testStr);
687     QFETCH(int, cursorPosition);
688     QFETCH(int, movePosition);
689     QFETCH(QDeclarative1TextInput::SelectionMode, mode);
690     QFETCH(int, selectionStart);
691     QFETCH(int, selectionEnd);
692     QFETCH(bool, reversible);
693
694     QString componentStr = "import QtQuick 1.1\nTextInput {  text: \""+ testStr +"\"; }";
695     QDeclarativeComponent textinputComponent(&engine);
696     textinputComponent.setData(componentStr.toLatin1(), QUrl());
697     QDeclarative1TextInput *textinputObject = qobject_cast<QDeclarative1TextInput*>(textinputComponent.create());
698     QVERIFY(textinputObject != 0);
699
700     textinputObject->setCursorPosition(cursorPosition);
701     textinputObject->moveCursorSelection(movePosition, mode);
702
703     QCOMPARE(textinputObject->selectedText(), testStr.mid(selectionStart, selectionEnd - selectionStart));
704     QCOMPARE(textinputObject->selectionStart(), selectionStart);
705     QCOMPARE(textinputObject->selectionEnd(), selectionEnd);
706
707     if (reversible) {
708         textinputObject->setCursorPosition(movePosition);
709         textinputObject->moveCursorSelection(cursorPosition, mode);
710
711         QCOMPARE(textinputObject->selectedText(), testStr.mid(selectionStart, selectionEnd - selectionStart));
712         QCOMPARE(textinputObject->selectionStart(), selectionStart);
713         QCOMPARE(textinputObject->selectionEnd(), selectionEnd);
714     }
715
716     delete textinputObject;
717 }
718
719 void tst_qdeclarativetextinput::moveCursorSelectionSequence_data()
720 {
721     QTest::addColumn<QString>("testStr");
722     QTest::addColumn<int>("cursorPosition");
723     QTest::addColumn<int>("movePosition1");
724     QTest::addColumn<int>("movePosition2");
725     QTest::addColumn<int>("selection1Start");
726     QTest::addColumn<int>("selection1End");
727     QTest::addColumn<int>("selection2Start");
728     QTest::addColumn<int>("selection2End");
729
730     // () contains the text selected by the cursor.
731     // <> contains the actual selection.
732     // ^ is the revised cursor position.
733     // {} contains the revised selection.
734
735     QTest::newRow("the {<quick( bro)wn> f^ox} jumped|ltr")
736             << standard[0]
737             << 9 << 13 << 17
738             << 4 << 15
739             << 4 << 19;
740     QTest::newRow("the quick<( {bro)wn> f^ox} jumped|rtl")
741             << standard[0]
742             << 13 << 9 << 17
743             << 9 << 15
744             << 10 << 19;
745     QTest::newRow("the {<quick( bro)wn> ^}fox jumped|ltr")
746             << standard[0]
747             << 9 << 13 << 16
748             << 4 << 15
749             << 4 << 16;
750     QTest::newRow("the quick<( {bro)wn> ^}fox jumped|rtl")
751             << standard[0]
752             << 13 << 9 << 16
753             << 9 << 15
754             << 10 << 16;
755     QTest::newRow("the {<quick( bro)wn^>} fox jumped|ltr")
756             << standard[0]
757             << 9 << 13 << 15
758             << 4 << 15
759             << 4 << 15;
760     QTest::newRow("the quick<( {bro)wn^>} f^ox jumped|rtl")
761             << standard[0]
762             << 13 << 9 << 15
763             << 9 << 15
764             << 10 << 15;
765     QTest::newRow("the {<quick() ^}bro)wn> fox|ltr")
766             << standard[0]
767             << 9 << 13 << 10
768             << 4 << 15
769             << 4 << 10;
770     QTest::newRow("the quick<( {^bro)wn>} fox|rtl")
771             << standard[0]
772             << 13 << 9 << 10
773             << 9 << 15
774             << 10 << 15;
775     QTest::newRow("the {<quick^}( bro)wn> fox|ltr")
776             << standard[0]
777             << 9 << 13 << 9
778             << 4 << 15
779             << 4 << 9;
780     QTest::newRow("the quick{<(^ bro)wn>} fox|rtl")
781             << standard[0]
782             << 13 << 9 << 9
783             << 9 << 15
784             << 9 << 15;
785     QTest::newRow("the {<qui^ck}( bro)wn> fox|ltr")
786             << standard[0]
787             << 9 << 13 << 7
788             << 4 << 15
789             << 4 << 9;
790     QTest::newRow("the {<qui^ck}( bro)wn> fox|rtl")
791             << standard[0]
792             << 13 << 9 << 7
793             << 9 << 15
794             << 4 << 15;
795     QTest::newRow("the {<^quick}( bro)wn> fox|ltr")
796             << standard[0]
797             << 9 << 13 << 4
798             << 4 << 15
799             << 4 << 9;
800     QTest::newRow("the {<^quick}( bro)wn> fox|rtl")
801             << standard[0]
802             << 13 << 9 << 4
803             << 9 << 15
804             << 4 << 15;
805     QTest::newRow("the{^ <quick}( bro)wn> fox|ltr")
806             << standard[0]
807             << 9 << 13 << 3
808             << 4 << 15
809             << 3 << 9;
810     QTest::newRow("the{^ <quick}( bro)wn> fox|rtl")
811             << standard[0]
812             << 13 << 9 << 3
813             << 9 << 15
814             << 3 << 15;
815     QTest::newRow("{t^he <quick}( bro)wn> fox|ltr")
816             << standard[0]
817             << 9 << 13 << 1
818             << 4 << 15
819             << 0 << 9;
820     QTest::newRow("{t^he <quick}( bro)wn> fox|rtl")
821             << standard[0]
822             << 13 << 9 << 1
823             << 9 << 15
824             << 0 << 15;
825
826     QTest::newRow("{<He(ll)o>, w^orld}!|ltr")
827             << standard[2]
828             << 2 << 4 << 8
829             << 0 << 5
830             << 0 << 12;
831     QTest::newRow("{<He(ll)o>, w^orld}!|rtl")
832             << standard[2]
833             << 4 << 2 << 8
834             << 0 << 5
835             << 0 << 12;
836
837     QTest::newRow("!{dlro^w ,<o(ll)eH>}|ltr")
838             << standard[3]
839             << 9 << 11 << 5
840             << 8 << 13
841             << 1 << 13;
842     QTest::newRow("!{dlro^w ,<o(ll)eH>}|rtl")
843             << standard[3]
844             << 11 << 9 << 5
845             << 8 << 13
846             << 1 << 13;
847
848     QTest::newRow("{<(^} sp)acey>   text |ltr")
849             << standard[4]
850             << 0 << 3 << 0
851             << 0 << 7
852             << 0 << 0;
853     QTest::newRow("{<( ^}sp)acey>   text |ltr")
854             << standard[4]
855             << 0 << 3 << 1
856             << 0 << 7
857             << 0 << 1;
858     QTest::newRow("<( {s^p)acey>}   text |rtl")
859             << standard[4]
860             << 3 << 0 << 2
861             << 0 << 7
862             << 1 << 7;
863     QTest::newRow("<( {^sp)acey>}   text |rtl")
864             << standard[4]
865             << 3 << 0 << 1
866             << 0 << 7
867             << 1 << 7;
868
869     QTest::newRow(" spacey   <te(xt {^)>}|rtl")
870             << standard[4]
871             << 15 << 12 << 15
872             << 10 << 15
873             << 15 << 15;
874     QTest::newRow(" spacey   <te(xt{^ )>}|rtl")
875             << standard[4]
876             << 15 << 12 << 14
877             << 10 << 15
878             << 14 << 15;
879     QTest::newRow(" spacey   {<te(x^t} )>|ltr")
880             << standard[4]
881             << 12 << 15 << 13
882             << 10 << 15
883             << 10 << 14;
884     QTest::newRow(" spacey   {<te(xt^} )>|ltr")
885             << standard[4]
886             << 12 << 15 << 14
887             << 10 << 15
888             << 10 << 14;
889 }
890
891 void tst_qdeclarativetextinput::moveCursorSelectionSequence()
892 {
893     QFETCH(QString, testStr);
894     QFETCH(int, cursorPosition);
895     QFETCH(int, movePosition1);
896     QFETCH(int, movePosition2);
897     QFETCH(int, selection1Start);
898     QFETCH(int, selection1End);
899     QFETCH(int, selection2Start);
900     QFETCH(int, selection2End);
901
902     QString componentStr = "import QtQuick 1.1\nTextInput {  text: \""+ testStr +"\"; }";
903     QDeclarativeComponent textinputComponent(&engine);
904     textinputComponent.setData(componentStr.toLatin1(), QUrl());
905     QDeclarative1TextInput *textinputObject = qobject_cast<QDeclarative1TextInput*>(textinputComponent.create());
906     QVERIFY(textinputObject != 0);
907
908     textinputObject->setCursorPosition(cursorPosition);
909
910     textinputObject->moveCursorSelection(movePosition1, QDeclarative1TextInput::SelectWords);
911     QCOMPARE(textinputObject->selectedText(), testStr.mid(selection1Start, selection1End - selection1Start));
912     QCOMPARE(textinputObject->selectionStart(), selection1Start);
913     QCOMPARE(textinputObject->selectionEnd(), selection1End);
914
915     textinputObject->moveCursorSelection(movePosition2, QDeclarative1TextInput::SelectWords);
916     QCOMPARE(textinputObject->selectedText(), testStr.mid(selection2Start, selection2End - selection2Start));
917     QCOMPARE(textinputObject->selectionStart(), selection2Start);
918     QCOMPARE(textinputObject->selectionEnd(), selection2End);
919
920     delete textinputObject;
921 }
922
923 void tst_qdeclarativetextinput::mouseSelection_data()
924 {
925     QTest::addColumn<QString>("qmlfile");
926     QTest::addColumn<bool>("expectSelection");
927
928     // import installed
929     QTest::newRow("on") << SRCDIR "/data/mouseselection_true.qml" << true;
930     QTest::newRow("off") << SRCDIR "/data/mouseselection_false.qml" << false;
931     QTest::newRow("default") << SRCDIR "/data/mouseselection_default.qml" << false;
932     QTest::newRow("on word selection") << SRCDIR "/data/mouseselection_true_words.qml" << true;
933     QTest::newRow("off word selection") << SRCDIR "/data/mouseselection_false_words.qml" << false;
934     QTest::newRow("on read only") << SRCDIR "/data/mouseselection_true_readonly.qml" << true;
935     QTest::newRow("off read only") << SRCDIR "/data/mouseselection_false_readonly.qml" << false;
936 }
937
938 void tst_qdeclarativetextinput::mouseSelection()
939 {
940     QFETCH(QString, qmlfile);
941     QFETCH(bool, expectSelection);
942
943     QDeclarativeView *canvas = createView(qmlfile);
944
945     canvas->show();
946     QApplication::setActiveWindow(canvas);
947     QTest::qWaitForWindowShown(canvas);
948     QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(canvas));
949
950     QVERIFY(canvas->rootObject() != 0);
951     QDeclarative1TextInput *textInputObject = qobject_cast<QDeclarative1TextInput *>(canvas->rootObject());
952     QVERIFY(textInputObject != 0);
953
954     // press-and-drag-and-release from x1 to x2
955     int x1 = 10;
956     int x2 = 70;
957     int y = textInputObject->height()/2;
958     QTest::mousePress(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(x1,y)));
959     //QTest::mouseMove(canvas->viewport(), canvas->mapFromScene(QPoint(x2,y))); // doesn't work
960     QMouseEvent mv(QEvent::MouseMove, canvas->mapFromScene(QPoint(x2,y)), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
961     QApplication::sendEvent(canvas->viewport(), &mv);
962     QTest::mouseRelease(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(x2,y)));
963     QString str = textInputObject->selectedText();
964     if (expectSelection)
965         QVERIFY(str.length() > 3); // don't reallly care *what* was selected (and it's too sensitive to platform)
966     else
967         QVERIFY(str.isEmpty());
968
969     // Clicking and shift to clicking between the same points should select the same text.
970     textInputObject->setCursorPosition(0);
971     QTest::mouseClick(canvas->viewport(), Qt::LeftButton, Qt::NoModifier, canvas->mapFromScene(QPoint(x1,y)));
972     QTest::mouseClick(canvas->viewport(), Qt::LeftButton, Qt::ShiftModifier, canvas->mapFromScene(QPoint(x2,y)));
973     QCOMPARE(textInputObject->selectedText(), str);
974
975     delete canvas;
976 }
977
978 void tst_qdeclarativetextinput::deferEnableSelectByMouse_data()
979 {
980     QTest::addColumn<QString>("qmlfile");
981
982     QTest::newRow("writable") << SRCDIR "/data/mouseselection_false.qml";
983     QTest::newRow("read only") << SRCDIR "/data/mouseselection_false_readonly.qml";
984 }
985
986 void tst_qdeclarativetextinput::deferEnableSelectByMouse()
987 {
988     // Verify text isn't selected if selectByMouse is enabled after the mouse button has been pressed.
989     QFETCH(QString, qmlfile);
990
991     QDeclarativeView *canvas = createView(qmlfile);
992
993     canvas->show();
994     QApplication::setActiveWindow(canvas);
995     QTest::qWaitForWindowShown(canvas);
996     QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(canvas));
997
998     QVERIFY(canvas->rootObject() != 0);
999     QDeclarative1TextInput *textInputObject = qobject_cast<QDeclarative1TextInput *>(canvas->rootObject());
1000     QVERIFY(textInputObject != 0);
1001
1002     // press-and-drag-and-release from x1 to x2
1003     int x1 = 10;
1004     int x2 = 70;
1005     int y = textInputObject->height()/2;
1006
1007     QTest::mousePress(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(x1,y)));
1008     textInputObject->setSelectByMouse(true);
1009     //QTest::mouseMove(canvas->viewport(), canvas->mapFromScene(QPoint(x2,y))); // doesn't work
1010     QMouseEvent mv(QEvent::MouseMove, canvas->mapFromScene(QPoint(x2,y)), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
1011     QApplication::sendEvent(canvas->viewport(), &mv);
1012     QTest::mouseRelease(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(x2,y)));
1013     QVERIFY(textInputObject->selectedText().isEmpty());
1014
1015     delete canvas;
1016 }
1017
1018 void tst_qdeclarativetextinput::deferDisableSelectByMouse_data()
1019 {
1020     QTest::addColumn<QString>("qmlfile");
1021
1022     QTest::newRow("writable") << SRCDIR "/data/mouseselection_true.qml";
1023     QTest::newRow("read only") << SRCDIR "/data/mouseselection_true_readonly.qml";
1024 }
1025
1026 void tst_qdeclarativetextinput::deferDisableSelectByMouse()
1027 {
1028     // Verify text isn't selected if selectByMouse is enabled after the mouse button has been pressed.
1029     QFETCH(QString, qmlfile);
1030
1031     QDeclarativeView *canvas = createView(qmlfile);
1032
1033     canvas->show();
1034     QApplication::setActiveWindow(canvas);
1035     QTest::qWaitForWindowShown(canvas);
1036     QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(canvas));
1037
1038     QVERIFY(canvas->rootObject() != 0);
1039     QDeclarative1TextInput *textInputObject = qobject_cast<QDeclarative1TextInput *>(canvas->rootObject());
1040     QVERIFY(textInputObject != 0);
1041
1042     // press-and-drag-and-release from x1 to x2
1043     int x1 = 10;
1044     int x2 = 70;
1045     int y = textInputObject->height()/2;
1046
1047     QTest::mousePress(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(x1,y)));
1048     textInputObject->setSelectByMouse(false);
1049     //QTest::mouseMove(canvas->viewport(), canvas->mapFromScene(QPoint(x2,y))); // doesn't work
1050     QMouseEvent mv(QEvent::MouseMove, canvas->mapFromScene(QPoint(x2,y)), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
1051     QApplication::sendEvent(canvas->viewport(), &mv);
1052     QTest::mouseRelease(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(x2,y)));
1053     QVERIFY(textInputObject->selectedText().length() > 3);
1054
1055     delete canvas;
1056 }
1057
1058 void tst_qdeclarativetextinput::dragMouseSelection()
1059 {
1060     QString qmlfile = SRCDIR "/data/mouseselection_true.qml";
1061
1062     QDeclarativeView *canvas = createView(qmlfile);
1063
1064     canvas->show();
1065     QApplication::setActiveWindow(canvas);
1066     QTest::qWaitForWindowShown(canvas);
1067     QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(canvas));
1068
1069     QVERIFY(canvas->rootObject() != 0);
1070     QDeclarative1TextInput *textInputObject = qobject_cast<QDeclarative1TextInput *>(canvas->rootObject());
1071     QVERIFY(textInputObject != 0);
1072
1073     // press-and-drag-and-release from x1 to x2
1074     int x1 = 10;
1075     int x2 = 70;
1076     int y = textInputObject->height()/2;
1077     QTest::mousePress(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(x1,y)));
1078     {
1079         QMouseEvent mv(QEvent::MouseMove, canvas->mapFromScene(QPoint(x2,y)), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
1080         QApplication::sendEvent(canvas->viewport(), &mv);
1081     }
1082     QTest::mouseRelease(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(x2,y)));
1083
1084     QString str1 = textInputObject->selectedText();
1085     QVERIFY(str1.length() > 3);
1086
1087     // press and drag the current selection.
1088     x1 = 40;
1089     x2 = 100;
1090     QTest::mousePress(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(x1,y)));
1091     {
1092         QMouseEvent mv(QEvent::MouseMove, canvas->mapFromScene(QPoint(x2,y)), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
1093         QApplication::sendEvent(canvas->viewport(), &mv);
1094     }
1095         QTest::mouseRelease(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(x2,y)));
1096     QString str2 = textInputObject->selectedText();
1097     QVERIFY(str2.length() > 3);
1098
1099     QVERIFY(str1 != str2); // Verify the second press and drag is a new selection and doesn't not the first moved.
1100     delete canvas;
1101 }
1102
1103 void tst_qdeclarativetextinput::mouseSelectionMode_data()
1104 {
1105     QTest::addColumn<QString>("qmlfile");
1106     QTest::addColumn<bool>("selectWords");
1107
1108     // import installed
1109     QTest::newRow("SelectWords") << SRCDIR "/data/mouseselectionmode_words.qml" << true;
1110     QTest::newRow("SelectCharacters") << SRCDIR "/data/mouseselectionmode_characters.qml" << false;
1111     QTest::newRow("default") << SRCDIR "/data/mouseselectionmode_default.qml" << false;
1112 }
1113
1114 void tst_qdeclarativetextinput::mouseSelectionMode()
1115 {
1116     QFETCH(QString, qmlfile);
1117     QFETCH(bool, selectWords);
1118
1119     QString text = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1120
1121     QDeclarativeView *canvas = createView(qmlfile);
1122
1123     canvas->show();
1124     QApplication::setActiveWindow(canvas);
1125     QTest::qWaitForWindowShown(canvas);
1126     QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(canvas));
1127
1128     QVERIFY(canvas->rootObject() != 0);
1129     QDeclarative1TextInput *textInputObject = qobject_cast<QDeclarative1TextInput *>(canvas->rootObject());
1130     QVERIFY(textInputObject != 0);
1131
1132     // press-and-drag-and-release from x1 to x2
1133     int x1 = 10;
1134     int x2 = 70;
1135     int y = textInputObject->height()/2;
1136     QTest::mousePress(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(x1,y)));
1137     //QTest::mouseMove(canvas->viewport(), canvas->mapFromScene(QPoint(x2,y))); // doesn't work
1138     QMouseEvent mv(QEvent::MouseMove, canvas->mapFromScene(QPoint(x2,y)), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
1139     QApplication::sendEvent(canvas->viewport(), &mv);
1140     QTest::mouseRelease(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(x2,y)));
1141     QString str = textInputObject->selectedText();
1142     if (selectWords) {
1143         QCOMPARE(str, text);
1144     } else {
1145         QVERIFY(str.length() > 3);
1146         QVERIFY(str != text);
1147     }
1148
1149     delete canvas;
1150 }
1151
1152 void tst_qdeclarativetextinput::horizontalAlignment_data()
1153 {
1154     QTest::addColumn<int>("hAlign");
1155     QTest::addColumn<QString>("expectfile");
1156
1157     QTest::newRow("L") << int(Qt::AlignLeft) << "halign_left";
1158     QTest::newRow("R") << int(Qt::AlignRight) << "halign_right";
1159     QTest::newRow("C") << int(Qt::AlignHCenter) << "halign_center";
1160 }
1161
1162 void tst_qdeclarativetextinput::horizontalAlignment()
1163 {
1164     QFETCH(int, hAlign);
1165     QFETCH(QString, expectfile);
1166
1167     QDeclarativeView *canvas = createView(SRCDIR "/data/horizontalAlignment.qml");
1168
1169     canvas->show();
1170     QApplication::setActiveWindow(canvas);
1171     QTest::qWaitForWindowShown(canvas);
1172     QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(canvas));
1173     QObject *ob = canvas->rootObject();
1174     QVERIFY(ob != 0);
1175     ob->setProperty("horizontalAlignment",hAlign);
1176     QImage actual(canvas->width(), canvas->height(), QImage::Format_RGB32);
1177     actual.fill(qRgb(255,255,255));
1178     {
1179         QPainter p(&actual);
1180         canvas->render(&p);
1181     }
1182
1183     expectfile = createExpectedFileIfNotFound(expectfile, actual);
1184
1185     QImage expect(expectfile);
1186
1187     QCOMPARE(actual,expect);
1188
1189     delete canvas;
1190 }
1191
1192 void tst_qdeclarativetextinput::horizontalAlignment_RightToLeft()
1193 {
1194     QDeclarativeView *canvas = createView(SRCDIR "/data/horizontalAlignment_RightToLeft.qml");
1195     QDeclarative1TextInput *textInput = canvas->rootObject()->findChild<QDeclarative1TextInput*>("text");
1196     QVERIFY(textInput != 0);
1197     canvas->show();
1198
1199     const QString rtlText = textInput->text();
1200
1201     QDeclarative1TextInputPrivate *textInputPrivate = QDeclarative1TextInputPrivate::get(textInput);
1202     QVERIFY(textInputPrivate != 0);
1203     QVERIFY(-textInputPrivate->hscroll > canvas->width()/2);
1204
1205     // implicit alignment should follow the reading direction of RTL text
1206     QCOMPARE(textInput->hAlign(), QDeclarative1TextInput::AlignRight);
1207     QCOMPARE(textInput->effectiveHAlign(), textInput->hAlign());
1208     QVERIFY(-textInputPrivate->hscroll > canvas->width()/2);
1209
1210     // explicitly left aligned
1211     textInput->setHAlign(QDeclarative1TextInput::AlignLeft);
1212     QCOMPARE(textInput->hAlign(), QDeclarative1TextInput::AlignLeft);
1213     QCOMPARE(textInput->effectiveHAlign(), textInput->hAlign());
1214     QVERIFY(-textInputPrivate->hscroll < canvas->width()/2);
1215
1216     // explicitly right aligned
1217     textInput->setHAlign(QDeclarative1TextInput::AlignRight);
1218     QCOMPARE(textInput->effectiveHAlign(), textInput->hAlign());
1219     QCOMPARE(textInput->hAlign(), QDeclarative1TextInput::AlignRight);
1220     QVERIFY(-textInputPrivate->hscroll > canvas->width()/2);
1221
1222     // explicitly center aligned
1223     textInput->setHAlign(QDeclarative1TextInput::AlignHCenter);
1224     QCOMPARE(textInput->effectiveHAlign(), textInput->hAlign());
1225     QCOMPARE(textInput->hAlign(), QDeclarative1TextInput::AlignHCenter);
1226     QVERIFY(-textInputPrivate->hscroll < canvas->width()/2);
1227     QVERIFY(-textInputPrivate->hscroll + textInputPrivate->width() > canvas->width()/2);
1228
1229     // reseted alignment should go back to following the text reading direction
1230     textInput->resetHAlign();
1231     QCOMPARE(textInput->hAlign(), QDeclarative1TextInput::AlignRight);
1232     QCOMPARE(textInput->effectiveHAlign(), textInput->hAlign());
1233     QVERIFY(-textInputPrivate->hscroll > canvas->width()/2);
1234
1235     // mirror the text item
1236     QDeclarativeItemPrivate::get(textInput)->setLayoutMirror(true);
1237
1238     // mirrored implicit alignment should continue to follow the reading direction of the text
1239     QCOMPARE(textInput->hAlign(), QDeclarative1TextInput::AlignRight);
1240     QCOMPARE(textInput->effectiveHAlign(), textInput->hAlign());
1241     QVERIFY(-textInputPrivate->hscroll > canvas->width()/2);
1242
1243     // explicitly right aligned behaves as left aligned
1244     textInput->setHAlign(QDeclarative1TextInput::AlignRight);
1245     QCOMPARE(textInput->hAlign(), QDeclarative1TextInput::AlignRight);
1246     QCOMPARE(textInput->effectiveHAlign(), QDeclarative1TextInput::AlignLeft);
1247     QVERIFY(-textInputPrivate->hscroll < canvas->width()/2);
1248
1249     // mirrored explicitly left aligned behaves as right aligned
1250     textInput->setHAlign(QDeclarative1TextInput::AlignLeft);
1251     QCOMPARE(textInput->hAlign(), QDeclarative1TextInput::AlignLeft);
1252     QCOMPARE(textInput->effectiveHAlign(), QDeclarative1TextInput::AlignRight);
1253     QVERIFY(-textInputPrivate->hscroll > canvas->width()/2);
1254
1255     // disable mirroring
1256     QDeclarativeItemPrivate::get(textInput)->setLayoutMirror(false);
1257     QCOMPARE(textInput->effectiveHAlign(), textInput->hAlign());
1258     textInput->resetHAlign();
1259
1260     // English text should be implicitly left aligned
1261     textInput->setText("Hello world!");
1262     QCOMPARE(textInput->hAlign(), QDeclarative1TextInput::AlignLeft);
1263     QVERIFY(-textInputPrivate->hscroll < canvas->width()/2);
1264
1265     QApplication::setActiveWindow(canvas);
1266     QTest::qWaitForWindowShown(canvas);
1267     QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(canvas));
1268
1269     // If there is no commited text, the preedit text should determine the alignment.
1270     textInput->setText(QString());
1271     { QInputMethodEvent ev(rtlText, QList<QInputMethodEvent::Attribute>()); QApplication::sendEvent(canvas, &ev); }
1272     QCOMPARE(textInput->hAlign(), QDeclarative1TextInput::AlignRight);
1273     { QInputMethodEvent ev("Hello world!", QList<QInputMethodEvent::Attribute>()); QApplication::sendEvent(canvas, &ev); }
1274     QCOMPARE(textInput->hAlign(), QDeclarative1TextInput::AlignLeft);
1275
1276 #ifndef Q_OS_MAC    // QTBUG-18040
1277     // empty text with implicit alignment follows the system locale-based
1278     // keyboard input direction from QApplication::keyboardInputDirection
1279     textInput->setText("");
1280     QCOMPARE(textInput->hAlign(), QApplication::keyboardInputDirection() == Qt::LeftToRight ?
1281                                   QDeclarative1TextInput::AlignLeft : QDeclarative1TextInput::AlignRight);
1282     if (QApplication::keyboardInputDirection() == Qt::LeftToRight)
1283         QVERIFY(-textInputPrivate->hscroll < canvas->width()/2);
1284     else
1285         QVERIFY(-textInputPrivate->hscroll > canvas->width()/2);
1286     textInput->setHAlign(QDeclarative1TextInput::AlignRight);
1287     QCOMPARE(textInput->hAlign(), QDeclarative1TextInput::AlignRight);
1288     QVERIFY(-textInputPrivate->hscroll > canvas->width()/2);
1289 #endif
1290
1291     delete canvas;
1292
1293 #ifndef Q_OS_MAC    // QTBUG-18040
1294     // alignment of TextInput with no text set to it
1295     QString componentStr = "import QtQuick 1.0\nTextInput {}";
1296     QDeclarativeComponent textComponent(&engine);
1297     textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1298     QDeclarative1TextInput *textObject = qobject_cast<QDeclarative1TextInput*>(textComponent.create());
1299     QCOMPARE(textObject->hAlign(), QApplication::keyboardInputDirection() == Qt::LeftToRight ?
1300                                   QDeclarative1TextInput::AlignLeft : QDeclarative1TextInput::AlignRight);
1301     delete textObject;
1302 #endif
1303 }
1304
1305 void tst_qdeclarativetextinput::positionAt()
1306 {
1307     QDeclarativeView *canvas = createView(SRCDIR "/data/positionAt.qml");
1308     QVERIFY(canvas->rootObject() != 0);
1309     canvas->show();
1310     canvas->setFocus();
1311     QApplication::setActiveWindow(canvas);
1312     QTest::qWaitForWindowShown(canvas);
1313
1314     QDeclarative1TextInput *textinputObject = qobject_cast<QDeclarative1TextInput *>(canvas->rootObject());
1315     QVERIFY(textinputObject != 0);
1316
1317     // Check autoscrolled...
1318     QFontMetrics fm(textinputObject->font());
1319
1320     int pos = textinputObject->positionAt(textinputObject->width()/2);
1321     int diff = abs(int(fm.width(textinputObject->text()) - (fm.width(textinputObject->text().left(pos))+textinputObject->width()/2)));
1322
1323     // some tollerance for different fonts.
1324 #ifdef Q_OS_LINUX
1325     QVERIFY(diff < 2);
1326 #else
1327     QVERIFY(diff < 5);
1328 #endif
1329
1330     int x = textinputObject->positionToRectangle(pos + 1).x() - 1;
1331     QCOMPARE(textinputObject->positionAt(x, QDeclarative1TextInput::CursorBetweenCharacters), pos + 1);
1332     QCOMPARE(textinputObject->positionAt(x, QDeclarative1TextInput::CursorOnCharacter), pos);
1333
1334     // Check without autoscroll...
1335     textinputObject->setAutoScroll(false);
1336     pos = textinputObject->positionAt(textinputObject->width()/2);
1337     diff = abs(int(fm.width(textinputObject->text().left(pos))-textinputObject->width()/2));
1338
1339 #ifdef Q_WS_QPA
1340     QEXPECT_FAIL("", "QTBUG-21017 fails", Continue);
1341 #endif
1342     // some tollerance for different fonts.
1343 #ifdef Q_OS_LINUX
1344     QVERIFY(diff < 2);
1345 #else
1346     QVERIFY(diff < 5);
1347 #endif
1348
1349     x = textinputObject->positionToRectangle(pos + 1).x() - 1;
1350     QCOMPARE(textinputObject->positionAt(x, QDeclarative1TextInput::CursorBetweenCharacters), pos + 1);
1351     QCOMPARE(textinputObject->positionAt(x, QDeclarative1TextInput::CursorOnCharacter), pos);
1352
1353     const qreal x0 = textinputObject->positionToRectangle(pos).x();
1354     const qreal x1 = textinputObject->positionToRectangle(pos + 1).x();
1355
1356     QString preeditText = textinputObject->text().mid(0, pos);
1357     textinputObject->setText(textinputObject->text().mid(pos));
1358     textinputObject->setCursorPosition(0);
1359
1360     QInputMethodEvent inputEvent(preeditText, QList<QInputMethodEvent::Attribute>());
1361     QApplication::sendEvent(canvas, &inputEvent);
1362
1363     // Check all points within the preedit text return the same position.
1364     QCOMPARE(textinputObject->positionAt(0), 0);
1365     QCOMPARE(textinputObject->positionAt(x0 / 2), 0);
1366     QCOMPARE(textinputObject->positionAt(x0), 0);
1367
1368     // Verify positioning returns to normal after the preedit text.
1369     QCOMPARE(textinputObject->positionAt(x1), 1);
1370     QCOMPARE(textinputObject->positionToRectangle(1).x(), x1);
1371
1372     delete canvas;
1373 }
1374
1375 void tst_qdeclarativetextinput::maxLength()
1376 {
1377     QDeclarativeView *canvas = createView(SRCDIR "/data/maxLength.qml");
1378     QVERIFY(canvas->rootObject() != 0);
1379     canvas->show();
1380     canvas->setFocus();
1381     QApplication::setActiveWindow(canvas);
1382     QTest::qWaitForWindowShown(canvas);
1383
1384     QDeclarative1TextInput *textinputObject = qobject_cast<QDeclarative1TextInput *>(canvas->rootObject());
1385     QVERIFY(textinputObject != 0);
1386     QVERIFY(textinputObject->text().isEmpty());
1387     QVERIFY(textinputObject->maxLength() == 10);
1388     foreach(const QString &str, standard){
1389         QVERIFY(textinputObject->text().length() <= 10);
1390         textinputObject->setText(str);
1391         QVERIFY(textinputObject->text().length() <= 10);
1392     }
1393
1394     textinputObject->setText("");
1395     QTRY_VERIFY(textinputObject->hasActiveFocus() == true);
1396     for(int i=0; i<20; i++){
1397         QCOMPARE(textinputObject->text().length(), qMin(i,10));
1398         //simulateKey(canvas, Qt::Key_A);
1399         QTest::keyPress(canvas, Qt::Key_A);
1400         QTest::keyRelease(canvas, Qt::Key_A, Qt::NoModifier ,10);
1401     }
1402
1403     delete canvas;
1404 }
1405
1406 void tst_qdeclarativetextinput::masks()
1407 {
1408     //Not a comprehensive test of the possible masks, that's done elsewhere (QLineEdit)
1409     //QString componentStr = "import QtQuick 1.0\nTextInput {  inputMask: 'HHHHhhhh'; }";
1410     QDeclarativeView *canvas = createView(SRCDIR "/data/masks.qml");
1411     canvas->show();
1412     canvas->setFocus();
1413     QVERIFY(canvas->rootObject() != 0);
1414     QDeclarative1TextInput *textinputObject = qobject_cast<QDeclarative1TextInput *>(canvas->rootObject());
1415     QVERIFY(textinputObject != 0);
1416     QTRY_VERIFY(textinputObject->hasActiveFocus() == true);
1417     QVERIFY(textinputObject->text().length() == 0);
1418     QCOMPARE(textinputObject->inputMask(), QString("HHHHhhhh; "));
1419     for(int i=0; i<10; i++){
1420         QCOMPARE(qMin(i,8), textinputObject->text().length());
1421         QCOMPARE(i>=4, textinputObject->hasAcceptableInput());
1422         //simulateKey(canvas, Qt::Key_A);
1423         QTest::keyPress(canvas, Qt::Key_A);
1424         QTest::keyRelease(canvas, Qt::Key_A, Qt::NoModifier ,10);
1425     }
1426
1427     delete canvas;
1428 }
1429
1430 void tst_qdeclarativetextinput::validators()
1431 {
1432     // Note that this test assumes that the validators are working properly
1433     // so you may need to run their tests first. All validators are checked
1434     // here to ensure that their exposure to QML is working.
1435
1436     QDeclarativeView *canvas = createView(SRCDIR "/data/validators.qml");
1437     canvas->show();
1438     canvas->setFocus();
1439
1440     QVERIFY(canvas->rootObject() != 0);
1441
1442     QDeclarative1TextInput *intInput = qobject_cast<QDeclarative1TextInput *>(qvariant_cast<QObject *>(canvas->rootObject()->property("intInput")));
1443     QVERIFY(intInput);
1444     intInput->setFocus(true);
1445     QTRY_VERIFY(intInput->hasActiveFocus());
1446     QTest::keyPress(canvas, Qt::Key_1);
1447     QTest::keyRelease(canvas, Qt::Key_1, Qt::NoModifier ,10);
1448     QCOMPARE(intInput->text(), QLatin1String("1"));
1449     QCOMPARE(intInput->hasAcceptableInput(), false);
1450     QTest::keyPress(canvas, Qt::Key_2);
1451     QTest::keyRelease(canvas, Qt::Key_2, Qt::NoModifier ,10);
1452     QCOMPARE(intInput->text(), QLatin1String("1"));
1453     QCOMPARE(intInput->hasAcceptableInput(), false);
1454     QTest::keyPress(canvas, Qt::Key_1);
1455     QTest::keyRelease(canvas, Qt::Key_1, Qt::NoModifier ,10);
1456     QCOMPARE(intInput->text(), QLatin1String("11"));
1457     QCOMPARE(intInput->hasAcceptableInput(), true);
1458     QTest::keyPress(canvas, Qt::Key_0);
1459     QTest::keyRelease(canvas, Qt::Key_0, Qt::NoModifier ,10);
1460     QCOMPARE(intInput->text(), QLatin1String("11"));
1461     QCOMPARE(intInput->hasAcceptableInput(), true);
1462
1463     QDeclarative1TextInput *dblInput = qobject_cast<QDeclarative1TextInput *>(qvariant_cast<QObject *>(canvas->rootObject()->property("dblInput")));
1464     QTRY_VERIFY(dblInput);
1465     dblInput->setFocus(true);
1466     QVERIFY(dblInput->hasActiveFocus() == true);
1467     QTest::keyPress(canvas, Qt::Key_1);
1468     QTest::keyRelease(canvas, Qt::Key_1, Qt::NoModifier ,10);
1469     QCOMPARE(dblInput->text(), QLatin1String("1"));
1470     QCOMPARE(dblInput->hasAcceptableInput(), false);
1471     QTest::keyPress(canvas, Qt::Key_2);
1472     QTest::keyRelease(canvas, Qt::Key_2, Qt::NoModifier ,10);
1473     QCOMPARE(dblInput->text(), QLatin1String("12"));
1474     QCOMPARE(dblInput->hasAcceptableInput(), true);
1475     QTest::keyPress(canvas, Qt::Key_Period);
1476     QTest::keyRelease(canvas, Qt::Key_Period, Qt::NoModifier ,10);
1477     QCOMPARE(dblInput->text(), QLatin1String("12."));
1478     QCOMPARE(dblInput->hasAcceptableInput(), true);
1479     QTest::keyPress(canvas, Qt::Key_1);
1480     QTest::keyRelease(canvas, Qt::Key_1, Qt::NoModifier ,10);
1481     QCOMPARE(dblInput->text(), QLatin1String("12.1"));
1482     QCOMPARE(dblInput->hasAcceptableInput(), true);
1483     QTest::keyPress(canvas, Qt::Key_1);
1484     QTest::keyRelease(canvas, Qt::Key_1, Qt::NoModifier ,10);
1485     QCOMPARE(dblInput->text(), QLatin1String("12.11"));
1486     QCOMPARE(dblInput->hasAcceptableInput(), true);
1487     QTest::keyPress(canvas, Qt::Key_1);
1488     QTest::keyRelease(canvas, Qt::Key_1, Qt::NoModifier ,10);
1489     QCOMPARE(dblInput->text(), QLatin1String("12.11"));
1490     QCOMPARE(dblInput->hasAcceptableInput(), true);
1491
1492     QDeclarative1TextInput *strInput = qobject_cast<QDeclarative1TextInput *>(qvariant_cast<QObject *>(canvas->rootObject()->property("strInput")));
1493     QTRY_VERIFY(strInput);
1494     strInput->setFocus(true);
1495     QVERIFY(strInput->hasActiveFocus() == true);
1496     QTest::keyPress(canvas, Qt::Key_1);
1497     QTest::keyRelease(canvas, Qt::Key_1, Qt::NoModifier ,10);
1498     QCOMPARE(strInput->text(), QLatin1String(""));
1499     QCOMPARE(strInput->hasAcceptableInput(), false);
1500     QTest::keyPress(canvas, Qt::Key_A);
1501     QTest::keyRelease(canvas, Qt::Key_A, Qt::NoModifier ,10);
1502     QCOMPARE(strInput->text(), QLatin1String("a"));
1503     QCOMPARE(strInput->hasAcceptableInput(), false);
1504     QTest::keyPress(canvas, Qt::Key_A);
1505     QTest::keyRelease(canvas, Qt::Key_A, Qt::NoModifier ,10);
1506     QCOMPARE(strInput->text(), QLatin1String("aa"));
1507     QCOMPARE(strInput->hasAcceptableInput(), true);
1508     QTest::keyPress(canvas, Qt::Key_A);
1509     QTest::keyRelease(canvas, Qt::Key_A, Qt::NoModifier ,10);
1510     QCOMPARE(strInput->text(), QLatin1String("aaa"));
1511     QCOMPARE(strInput->hasAcceptableInput(), true);
1512     QTest::keyPress(canvas, Qt::Key_A);
1513     QTest::keyRelease(canvas, Qt::Key_A, Qt::NoModifier ,10);
1514     QCOMPARE(strInput->text(), QLatin1String("aaaa"));
1515     QCOMPARE(strInput->hasAcceptableInput(), true);
1516     QTest::keyPress(canvas, Qt::Key_A);
1517     QTest::keyRelease(canvas, Qt::Key_A, Qt::NoModifier ,10);
1518     QCOMPARE(strInput->text(), QLatin1String("aaaa"));
1519     QCOMPARE(strInput->hasAcceptableInput(), true);
1520
1521     delete canvas;
1522 }
1523
1524 void tst_qdeclarativetextinput::inputMethods()
1525 {
1526     QDeclarativeView *canvas = createView(SRCDIR "/data/inputmethods.qml");
1527     canvas->show();
1528     canvas->setFocus();
1529     QApplication::setActiveWindow(canvas);
1530     QTest::qWaitForWindowShown(canvas);
1531
1532     // test input method hints
1533     QVERIFY(canvas->rootObject() != 0);
1534     QDeclarative1TextInput *input = qobject_cast<QDeclarative1TextInput *>(canvas->rootObject());
1535     QVERIFY(input != 0);
1536     QVERIFY(input->imHints() & Qt::ImhNoPredictiveText);
1537     QVERIFY(input->inputMethodHints() & Qt::ImhNoPredictiveText);
1538     input->setIMHints(Qt::ImhUppercaseOnly);
1539     QVERIFY(input->imHints() & Qt::ImhUppercaseOnly);
1540     QVERIFY(input->inputMethodHints() & Qt::ImhUppercaseOnly);
1541
1542     QVERIFY(canvas->rootObject() != 0);
1543
1544     input->setFocus(true);
1545     QVERIFY(input->hasActiveFocus() == true);
1546     // test that input method event is committed
1547     QInputMethodEvent event;
1548     event.setCommitString( "My ", -12, 0);
1549     QApplication::sendEvent(canvas, &event);
1550     QCOMPARE(input->text(), QString("My Hello world!"));
1551
1552     input->setCursorPosition(2);
1553     event.setCommitString("Your", -2, 2);
1554     QApplication::sendEvent(canvas, &event);
1555     QCOMPARE(input->text(), QString("Your Hello world!"));
1556     QCOMPARE(input->cursorPosition(), 4);
1557
1558     input->setCursorPosition(7);
1559     event.setCommitString("Goodbye", -2, 5);
1560     QApplication::sendEvent(canvas, &event);
1561     QCOMPARE(input->text(), QString("Your Goodbye world!"));
1562     QCOMPARE(input->cursorPosition(), 12);
1563
1564     input->setCursorPosition(8);
1565     event.setCommitString("Our", -8, 4);
1566     QApplication::sendEvent(canvas, &event);
1567     QCOMPARE(input->text(), QString("Our Goodbye world!"));
1568     QCOMPARE(input->cursorPosition(), 7);
1569
1570     delete canvas;
1571 }
1572
1573 /*
1574 TextInput element should only handle left/right keys until the cursor reaches
1575 the extent of the text, then they should ignore the keys.
1576
1577 */
1578 void tst_qdeclarativetextinput::navigation()
1579 {
1580     QDeclarativeView *canvas = createView(SRCDIR "/data/navigation.qml");
1581     canvas->show();
1582     canvas->setFocus();
1583
1584     QVERIFY(canvas->rootObject() != 0);
1585
1586     QDeclarative1TextInput *input = qobject_cast<QDeclarative1TextInput *>(qvariant_cast<QObject *>(canvas->rootObject()->property("myInput")));
1587
1588     QVERIFY(input != 0);
1589     input->setCursorPosition(0);
1590     QTRY_VERIFY(input->hasActiveFocus() == true);
1591     simulateKey(canvas, Qt::Key_Left);
1592     QVERIFY(input->hasActiveFocus() == false);
1593     simulateKey(canvas, Qt::Key_Right);
1594     QVERIFY(input->hasActiveFocus() == true);
1595     //QT-2944: If text is selected, ensure we deselect upon cursor motion
1596     input->setCursorPosition(input->text().length());
1597     input->select(0,input->text().length());
1598     QVERIFY(input->selectionStart() != input->selectionEnd());
1599     simulateKey(canvas, Qt::Key_Right);
1600     QVERIFY(input->selectionStart() == input->selectionEnd());
1601     QVERIFY(input->selectionStart() == input->text().length());
1602     QVERIFY(input->hasActiveFocus() == true);
1603     simulateKey(canvas, Qt::Key_Right);
1604     QVERIFY(input->hasActiveFocus() == false);
1605     simulateKey(canvas, Qt::Key_Left);
1606     QVERIFY(input->hasActiveFocus() == true);
1607
1608     // Up and Down should NOT do Home/End, even on Mac OS X (QTBUG-10438).
1609     input->setCursorPosition(2);
1610     QCOMPARE(input->cursorPosition(),2);
1611     simulateKey(canvas, Qt::Key_Up);
1612     QCOMPARE(input->cursorPosition(),2);
1613     simulateKey(canvas, Qt::Key_Down);
1614     QCOMPARE(input->cursorPosition(),2);
1615
1616     delete canvas;
1617 }
1618
1619 void tst_qdeclarativetextinput::navigation_RTL()
1620 {
1621     QDeclarativeView *canvas = createView(SRCDIR "/data/navigation.qml");
1622     canvas->show();
1623     canvas->setFocus();
1624
1625     QVERIFY(canvas->rootObject() != 0);
1626
1627     QDeclarative1TextInput *input = qobject_cast<QDeclarative1TextInput *>(qvariant_cast<QObject *>(canvas->rootObject()->property("myInput")));
1628
1629     QVERIFY(input != 0);
1630     const quint16 arabic_str[] = { 0x0638, 0x0643, 0x00646, 0x0647, 0x0633, 0x0638, 0x0643, 0x00646, 0x0647, 0x0633, 0x0647};
1631     input->setText(QString::fromUtf16(arabic_str, 11));
1632
1633     input->setCursorPosition(0);
1634     QTRY_VERIFY(input->hasActiveFocus() == true);
1635
1636     // move off
1637     simulateKey(canvas, Qt::Key_Right);
1638     QVERIFY(input->hasActiveFocus() == false);
1639
1640     // move back
1641     simulateKey(canvas, Qt::Key_Left);
1642     QVERIFY(input->hasActiveFocus() == true);
1643
1644     input->setCursorPosition(input->text().length());
1645     QVERIFY(input->hasActiveFocus() == true);
1646
1647     // move off
1648     simulateKey(canvas, Qt::Key_Left);
1649     QVERIFY(input->hasActiveFocus() == false);
1650
1651     // move back
1652     simulateKey(canvas, Qt::Key_Right);
1653     QVERIFY(input->hasActiveFocus() == true);
1654
1655     delete canvas;
1656 }
1657
1658 void tst_qdeclarativetextinput::copyAndPaste() {
1659 #ifndef QT_NO_CLIPBOARD
1660
1661 #ifdef Q_WS_MAC
1662     {
1663         PasteboardRef pasteboard;
1664         OSStatus status = PasteboardCreate(0, &pasteboard);
1665         if (status == noErr)
1666             CFRelease(pasteboard);
1667         else
1668             QSKIP("This machine doesn't support the clipboard", SkipAll);
1669     }
1670 #endif
1671
1672     QString componentStr = "import QtQuick 1.0\nTextInput { text: \"Hello world!\" }";
1673     QDeclarativeComponent textInputComponent(&engine);
1674     textInputComponent.setData(componentStr.toLatin1(), QUrl());
1675     QDeclarative1TextInput *textInput = qobject_cast<QDeclarative1TextInput*>(textInputComponent.create());
1676     QVERIFY(textInput != 0);
1677
1678     // copy and paste
1679     QCOMPARE(textInput->text().length(), 12);
1680     textInput->select(0, textInput->text().length());;
1681     textInput->copy();
1682     QCOMPARE(textInput->selectedText(), QString("Hello world!"));
1683     QCOMPARE(textInput->selectedText().length(), 12);
1684     textInput->setCursorPosition(0);
1685     QVERIFY(textInput->canPaste());
1686     textInput->paste();
1687     QCOMPARE(textInput->text(), QString("Hello world!Hello world!"));
1688     QCOMPARE(textInput->text().length(), 24);
1689
1690     // can paste
1691     QVERIFY(textInput->canPaste());
1692     textInput->setReadOnly(true);
1693     QVERIFY(!textInput->canPaste());
1694     textInput->setReadOnly(false);
1695     QVERIFY(textInput->canPaste());
1696
1697     // select word
1698     textInput->setCursorPosition(0);
1699     textInput->selectWord();
1700     QCOMPARE(textInput->selectedText(), QString("Hello"));
1701
1702     // select all and cut
1703     textInput->selectAll();
1704     textInput->cut();
1705     QCOMPARE(textInput->text().length(), 0);
1706     textInput->paste();
1707     QCOMPARE(textInput->text(), QString("Hello world!Hello world!"));
1708     QCOMPARE(textInput->text().length(), 24);
1709
1710     // clear copy buffer
1711     QClipboard *clipboard = QApplication::clipboard();
1712     QVERIFY(clipboard);
1713     clipboard->clear();
1714     QVERIFY(!textInput->canPaste());
1715
1716     // test that copy functionality is disabled
1717     // when echo mode is set to hide text/password mode
1718     int index = 0;
1719     while (index < 4) {
1720         QDeclarative1TextInput::EchoMode echoMode = QDeclarative1TextInput::EchoMode(index);
1721         textInput->setEchoMode(echoMode);
1722         textInput->setText("My password");
1723         textInput->select(0, textInput->text().length());;
1724         textInput->copy();
1725         if (echoMode == QDeclarative1TextInput::Normal) {
1726             QVERIFY(!clipboard->text().isEmpty());
1727             QCOMPARE(clipboard->text(), QString("My password"));
1728             clipboard->clear();
1729         } else {
1730             QVERIFY(clipboard->text().isEmpty());
1731         }
1732         index++;
1733     }
1734
1735     delete textInput;
1736 #endif
1737 }
1738
1739 void tst_qdeclarativetextinput::canPasteEmpty() {
1740 #ifndef QT_NO_CLIPBOARD
1741
1742     QApplication::clipboard()->clear();
1743
1744     QString componentStr = "import QtQuick 1.0\nTextInput { text: \"Hello world!\" }";
1745     QDeclarativeComponent textInputComponent(&engine);
1746     textInputComponent.setData(componentStr.toLatin1(), QUrl());
1747     QDeclarative1TextInput *textInput = qobject_cast<QDeclarative1TextInput*>(textInputComponent.create());
1748     QVERIFY(textInput != 0);
1749
1750     QLineControl lc;
1751     bool cp = !lc.isReadOnly() && QApplication::clipboard()->text().length() != 0;
1752     QCOMPARE(textInput->canPaste(), cp);
1753
1754 #endif
1755 }
1756
1757 void tst_qdeclarativetextinput::canPaste() {
1758 #ifndef QT_NO_CLIPBOARD
1759
1760     QApplication::clipboard()->setText("Some text");
1761
1762     QString componentStr = "import QtQuick 1.0\nTextInput { text: \"Hello world!\" }";
1763     QDeclarativeComponent textInputComponent(&engine);
1764     textInputComponent.setData(componentStr.toLatin1(), QUrl());
1765     QDeclarative1TextInput *textInput = qobject_cast<QDeclarative1TextInput*>(textInputComponent.create());
1766     QVERIFY(textInput != 0);
1767
1768     QLineControl lc;
1769     bool cp = !lc.isReadOnly() && QApplication::clipboard()->text().length() != 0;
1770     QCOMPARE(textInput->canPaste(), cp);
1771
1772 #endif
1773 }
1774
1775 void tst_qdeclarativetextinput::passwordCharacter()
1776 {
1777     QString componentStr = "import QtQuick 1.0\nTextInput { text: \"Hello world!\"; font.family: \"Helvetica\"; echoMode: TextInput.Password }";
1778     QDeclarativeComponent textInputComponent(&engine);
1779     textInputComponent.setData(componentStr.toLatin1(), QUrl());
1780     QDeclarative1TextInput *textInput = qobject_cast<QDeclarative1TextInput*>(textInputComponent.create());
1781     QVERIFY(textInput != 0);
1782
1783     textInput->setPasswordCharacter("X");
1784     QSize contentsSize = textInput->contentsSize();
1785     textInput->setPasswordCharacter(".");
1786     // QTBUG-12383 content is updated and redrawn
1787     QVERIFY(contentsSize != textInput->contentsSize());
1788
1789     delete textInput;
1790 }
1791
1792 void tst_qdeclarativetextinput::cursorDelegate()
1793 {
1794     QDeclarativeView* view = createView(SRCDIR "/data/cursorTest.qml");
1795     view->show();
1796     view->setFocus();
1797     QDeclarative1TextInput *textInputObject = view->rootObject()->findChild<QDeclarative1TextInput*>("textInputObject");
1798     QVERIFY(textInputObject != 0);
1799     QVERIFY(textInputObject->findChild<QDeclarativeItem*>("cursorInstance"));
1800     //Test Delegate gets created
1801     textInputObject->setFocus(true);
1802     QDeclarativeItem* delegateObject = textInputObject->findChild<QDeclarativeItem*>("cursorInstance");
1803     QVERIFY(delegateObject);
1804     //Test Delegate gets moved
1805     for(int i=0; i<= textInputObject->text().length(); i++){
1806         textInputObject->setCursorPosition(i);
1807         QCOMPARE(textInputObject->cursorRectangle().x(), qRound(delegateObject->x()));
1808         QCOMPARE(textInputObject->cursorRectangle().y(), qRound(delegateObject->y()));
1809     }
1810     const QString preedit = "preedit";
1811     for (int i = 0; i <= preedit.length(); i++) {
1812         QInputMethodEvent event(preedit, QList<QInputMethodEvent::Attribute>()
1813                 << QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, i, 1, QVariant()));
1814         QApplication::sendEvent(view, &event);
1815
1816         QCOMPARE(textInputObject->cursorRectangle().x(), qRound(delegateObject->x()));
1817         QCOMPARE(textInputObject->cursorRectangle().y(), qRound(delegateObject->y()));
1818     }
1819     textInputObject->setCursorPosition(0);
1820     QCOMPARE(textInputObject->cursorRectangle().x(), qRound(delegateObject->x()));
1821     QCOMPARE(textInputObject->cursorRectangle().y(), qRound(delegateObject->y()));
1822     //Test Delegate gets deleted
1823     textInputObject->setCursorDelegate(0);
1824     QVERIFY(!textInputObject->findChild<QDeclarativeItem*>("cursorInstance"));
1825
1826     delete view;
1827 }
1828
1829 void tst_qdeclarativetextinput::cursorVisible()
1830 {
1831     QGraphicsScene scene;
1832     QGraphicsView view(&scene);
1833     view.show();
1834     QApplication::setActiveWindow(&view);
1835     QTest::qWaitForWindowShown(&view);
1836     QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
1837
1838     QDeclarative1TextInput input;
1839     QSignalSpy spy(&input, SIGNAL(cursorVisibleChanged(bool)));
1840
1841     QCOMPARE(input.isCursorVisible(), false);
1842
1843     input.setCursorVisible(true);
1844     QCOMPARE(input.isCursorVisible(), true);
1845     QCOMPARE(spy.count(), 1);
1846
1847     input.setCursorVisible(false);
1848     QCOMPARE(input.isCursorVisible(), false);
1849     QCOMPARE(spy.count(), 2);
1850
1851     input.setFocus(true);
1852     QCOMPARE(input.isCursorVisible(), false);
1853     QCOMPARE(spy.count(), 2);
1854
1855     scene.addItem(&input);
1856     QCOMPARE(input.isCursorVisible(), true);
1857     QCOMPARE(spy.count(), 3);
1858
1859     input.setFocus(false);
1860     QCOMPARE(input.isCursorVisible(), false);
1861     QCOMPARE(spy.count(), 4);
1862
1863     input.setFocus(true);
1864     QCOMPARE(input.isCursorVisible(), true);
1865     QCOMPARE(spy.count(), 5);
1866
1867     scene.clearFocus();
1868     QCOMPARE(input.isCursorVisible(), false);
1869     QCOMPARE(spy.count(), 6);
1870
1871     scene.setFocus();
1872     QCOMPARE(input.isCursorVisible(), true);
1873     QCOMPARE(spy.count(), 7);
1874
1875     view.clearFocus();
1876     QCOMPARE(input.isCursorVisible(), false);
1877     QCOMPARE(spy.count(), 8);
1878
1879     view.setFocus();
1880     QCOMPARE(input.isCursorVisible(), true);
1881     QCOMPARE(spy.count(), 9);
1882
1883     // on mac, setActiveWindow(0) on mac does not deactivate the current application
1884     // (you have to switch to a different app or hide the current app to trigger this)
1885 #if !defined(Q_WS_MAC)
1886     QApplication::setActiveWindow(0);
1887     QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(0));
1888     QCOMPARE(input.isCursorVisible(), false);
1889     QCOMPARE(spy.count(), 10);
1890
1891     QApplication::setActiveWindow(&view);
1892     QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
1893     QCOMPARE(input.isCursorVisible(), true);
1894     QCOMPARE(spy.count(), 11);
1895 #endif
1896 }
1897
1898 void tst_qdeclarativetextinput::cursorRectangle()
1899 {
1900     QString text = "Hello World!";
1901
1902     QDeclarative1TextInput input;
1903     input.setText(text);
1904     QFontMetricsF fm(input.font());
1905     input.setWidth(fm.width(text.mid(0, 5)));
1906
1907     QRect r;
1908
1909     // some tolerance for different fonts.
1910 #ifdef Q_OS_LINUX
1911     const int error = 2;
1912 #else
1913     const int error = 5;
1914 #endif
1915
1916     for (int i = 0; i <= 5; ++i) {
1917         input.setCursorPosition(i);
1918         r = input.cursorRectangle();
1919         int textWidth = fm.width(text.mid(0, i));
1920
1921         QVERIFY(r.left() < textWidth + error);
1922         QVERIFY(r.right() > textWidth - error);
1923         QCOMPARE(input.inputMethodQuery(Qt::ImMicroFocus).toRect(), r);
1924     }
1925
1926     // Check the cursor rectangle remains within the input bounding rect when auto scrolling.
1927     QVERIFY(r.left() < input.boundingRect().width());
1928     QVERIFY(r.right() >= input.width() - error);
1929
1930     for (int i = 6; i < text.length(); ++i) {
1931         input.setCursorPosition(i);
1932         QCOMPARE(r, input.cursorRectangle());
1933         QCOMPARE(input.inputMethodQuery(Qt::ImMicroFocus).toRect(), r);
1934     }
1935
1936     for (int i = text.length() - 2; i >= 0; --i) {
1937         input.setCursorPosition(i);
1938         r = input.cursorRectangle();
1939         QVERIFY(r.right() >= 0);
1940         QCOMPARE(input.inputMethodQuery(Qt::ImMicroFocus).toRect(), r);
1941     }
1942 }
1943
1944 void tst_qdeclarativetextinput::readOnly()
1945 {
1946     QDeclarativeView *canvas = createView(SRCDIR "/data/readOnly.qml");
1947     canvas->show();
1948     canvas->setFocus();
1949
1950     QVERIFY(canvas->rootObject() != 0);
1951
1952     QDeclarative1TextInput *input = qobject_cast<QDeclarative1TextInput *>(qvariant_cast<QObject *>(canvas->rootObject()->property("myInput")));
1953
1954     QVERIFY(input != 0);
1955     QTRY_VERIFY(input->hasActiveFocus() == true);
1956     QVERIFY(input->isReadOnly() == true);
1957     QString initial = input->text();
1958     for(int k=Qt::Key_0; k<=Qt::Key_Z; k++)
1959         simulateKey(canvas, k);
1960     simulateKey(canvas, Qt::Key_Return);
1961     simulateKey(canvas, Qt::Key_Space);
1962     simulateKey(canvas, Qt::Key_Escape);
1963     QCOMPARE(input->text(), initial);
1964
1965     delete canvas;
1966 }
1967
1968 void tst_qdeclarativetextinput::echoMode()
1969 {
1970     QDeclarativeView *canvas = createView(SRCDIR "/data/echoMode.qml");
1971     canvas->show();
1972     canvas->setFocus();
1973     QApplication::setActiveWindow(canvas);
1974     QTest::qWaitForWindowShown(canvas);
1975     QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(canvas));
1976
1977     QVERIFY(canvas->rootObject() != 0);
1978
1979     QDeclarative1TextInput *input = qobject_cast<QDeclarative1TextInput *>(qvariant_cast<QObject *>(canvas->rootObject()->property("myInput")));
1980
1981     QVERIFY(input != 0);
1982     QTRY_VERIFY(input->hasActiveFocus() == true);
1983     QString initial = input->text();
1984     Qt::InputMethodHints ref;
1985     QCOMPARE(initial, QLatin1String("ABCDefgh"));
1986     QCOMPARE(input->echoMode(), QDeclarative1TextInput::Normal);
1987     QCOMPARE(input->displayText(), input->text());
1988     //Normal
1989     ref &= ~Qt::ImhHiddenText;
1990     ref &= ~(Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText);
1991     QCOMPARE(input->inputMethodHints(), ref);
1992     QCOMPARE(input->imHints(), Qt::ImhNone);
1993     input->setEchoMode(QDeclarative1TextInput::NoEcho);
1994     QCOMPARE(input->text(), initial);
1995     QCOMPARE(input->displayText(), QLatin1String(""));
1996     QCOMPARE(input->passwordCharacter(), QLatin1String("*"));
1997     //NoEcho
1998     ref |= Qt::ImhHiddenText;
1999     ref |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText);
2000     QCOMPARE(input->inputMethodHints(), ref);
2001     QCOMPARE(input->imHints(), Qt::ImhNone);
2002     input->setEchoMode(QDeclarative1TextInput::Password);
2003     //Password
2004     ref |= Qt::ImhHiddenText;
2005     ref |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText);
2006     QCOMPARE(input->text(), initial);
2007     QCOMPARE(input->displayText(), QLatin1String("********"));
2008     QCOMPARE(input->inputMethodHints(), ref);
2009     QCOMPARE(input->imHints(), Qt::ImhNone);
2010     input->setPasswordCharacter(QChar('Q'));
2011     QCOMPARE(input->passwordCharacter(), QLatin1String("Q"));
2012     QCOMPARE(input->text(), initial);
2013     QCOMPARE(input->displayText(), QLatin1String("QQQQQQQQ"));
2014     input->setEchoMode(QDeclarative1TextInput::PasswordEchoOnEdit);
2015     //PasswordEchoOnEdit
2016     ref &= ~Qt::ImhHiddenText;
2017     ref |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText);
2018     QCOMPARE(input->inputMethodHints(), ref);
2019     QCOMPARE(input->imHints(), Qt::ImhNone);
2020     QCOMPARE(input->text(), initial);
2021     QCOMPARE(input->displayText(), QLatin1String("QQQQQQQQ"));
2022     QCOMPARE(input->inputMethodQuery(Qt::ImSurroundingText).toString(), QLatin1String("QQQQQQQQ"));
2023     QTest::keyPress(canvas, Qt::Key_A);//Clearing previous entry is part of PasswordEchoOnEdit
2024     QTest::keyRelease(canvas, Qt::Key_A, Qt::NoModifier ,10);
2025     QCOMPARE(input->text(), QLatin1String("a"));
2026     QCOMPARE(input->displayText(), QLatin1String("a"));
2027     QCOMPARE(input->inputMethodQuery(Qt::ImSurroundingText).toString(), QLatin1String("a"));
2028     input->setFocus(false);
2029     QVERIFY(input->hasActiveFocus() == false);
2030     QCOMPARE(input->displayText(), QLatin1String("Q"));
2031     QCOMPARE(input->inputMethodQuery(Qt::ImSurroundingText).toString(), QLatin1String("Q"));
2032     input->setFocus(true);
2033     QInputMethodEvent inputEvent;
2034     inputEvent.setCommitString(initial);
2035     QApplication::sendEvent(canvas, &inputEvent);
2036     QCOMPARE(input->text(), initial);
2037     QCOMPARE(input->displayText(), initial);
2038     QCOMPARE(input->inputMethodQuery(Qt::ImSurroundingText).toString(), initial);
2039
2040     // Test echo mode doesn't override imHints.
2041     input->setIMHints(Qt::ImhHiddenText | Qt::ImhDialableCharactersOnly);
2042     ref |=  Qt::ImhDialableCharactersOnly;
2043     //Normal
2044     input->setEchoMode(QDeclarative1TextInput::Normal);
2045     ref |= Qt::ImhHiddenText;
2046     ref &= ~(Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText);
2047     QCOMPARE(input->inputMethodHints(), ref);
2048     QCOMPARE(input->imHints(), Qt::ImhHiddenText | Qt::ImhDialableCharactersOnly);
2049     //NoEcho
2050     input->setEchoMode(QDeclarative1TextInput::NoEcho);
2051     ref |= Qt::ImhHiddenText;
2052     ref |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText);
2053     QCOMPARE(input->inputMethodHints(), ref);
2054     QCOMPARE(input->imHints(), Qt::ImhHiddenText | Qt::ImhDialableCharactersOnly);
2055     //Password
2056     input->setEchoMode(QDeclarative1TextInput::Password);
2057     ref |= Qt::ImhHiddenText;
2058     ref |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText);
2059     QCOMPARE(input->inputMethodHints(), ref);
2060     QCOMPARE(input->imHints(), Qt::ImhHiddenText | Qt::ImhDialableCharactersOnly);
2061     //PasswordEchoOnEdit
2062     input->setEchoMode(QDeclarative1TextInput::PasswordEchoOnEdit);
2063     ref &= ~Qt::ImhHiddenText;
2064     ref |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText);
2065     QCOMPARE(input->inputMethodHints(), ref);
2066     QCOMPARE(input->imHints(), Qt::ImhHiddenText | Qt::ImhDialableCharactersOnly);
2067     //Normal
2068     input->setEchoMode(QDeclarative1TextInput::Normal);
2069     ref |= Qt::ImhHiddenText;
2070     ref &= ~(Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText);
2071     QCOMPARE(input->inputMethodHints(), ref);
2072     QCOMPARE(input->imHints(), Qt::ImhHiddenText | Qt::ImhDialableCharactersOnly);
2073
2074     delete canvas;
2075 }
2076
2077
2078 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2079 void tst_qdeclarativetextinput::passwordEchoDelay()
2080 {
2081     QDeclarativeView *canvas = createView(SRCDIR "/data/echoMode.qml");
2082     canvas->show();
2083     canvas->setFocus();
2084     QApplication::setActiveWindow(canvas);
2085     QTest::qWaitForWindowShown(canvas);
2086     QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(canvas));
2087
2088     QVERIFY(canvas->rootObject() != 0);
2089
2090     QDeclarative1TextInput *input = qobject_cast<QDeclarative1TextInput *>(qvariant_cast<QObject *>(canvas->rootObject()->property("myInput")));
2091
2092     QChar fillChar = QLatin1Char('*');
2093
2094     input->setEchoMode(QDeclarativeTextInput::Password);
2095     QCOMPARE(input->displayText(), QString(8, fillChar));
2096     input->setText(QString());
2097     QCOMPARE(input->displayText(), QString());
2098
2099     QTest::keyPress(canvas, '0');
2100     QTest::keyPress(canvas, '1');
2101     QTest::keyPress(canvas, '2');
2102     QCOMPARE(input->displayText(), QString(2, fillChar) + QLatin1Char('2'));
2103     QTest::keyPress(canvas, '3');
2104     QTest::keyPress(canvas, '4');
2105     QCOMPARE(input->displayText(), QString(4, fillChar) + QLatin1Char('4'));
2106     QTest::keyPress(canvas, Qt::Key_Backspace);
2107     QCOMPARE(input->displayText(), QString(4, fillChar));
2108     QTest::keyPress(canvas, '4');
2109     QCOMPARE(input->displayText(), QString(4, fillChar) + QLatin1Char('4'));
2110     QTest::qWait(QT_GUI_PASSWORD_ECHO_DELAY);
2111     QTRY_COMPARE(input->displayText(), QString(5, fillChar));
2112     QTest::keyPress(canvas, '5');
2113     QCOMPARE(input->displayText(), QString(5, fillChar) + QLatin1Char('5'));
2114     input->setFocus(false);
2115     QVERIFY(!input->hasFocus());
2116     QCOMPARE(input->displayText(), QString(6, fillChar));
2117     input->setFocus(true);
2118     QTRY_VERIFY(input->hasFocus());
2119     QCOMPARE(input->displayText(), QString(6, fillChar));
2120     QTest::keyPress(canvas, '6');
2121     QCOMPARE(input->displayText(), QString(6, fillChar) + QLatin1Char('6'));
2122
2123     QInputMethodEvent ev;
2124     ev.setCommitString(QLatin1String("7"));
2125     QApplication::sendEvent(canvas, &ev);
2126     QCOMPARE(input->displayText(), QString(7, fillChar) + QLatin1Char('7'));
2127
2128     delete canvas;
2129 }
2130 #endif
2131
2132
2133 void tst_qdeclarativetextinput::simulateKey(QDeclarativeView *view, int key)
2134 {
2135     QKeyEvent press(QKeyEvent::KeyPress, key, 0);
2136     QKeyEvent release(QKeyEvent::KeyRelease, key, 0);
2137
2138     QApplication::sendEvent(view, &press);
2139     QApplication::sendEvent(view, &release);
2140 }
2141
2142 QDeclarativeView *tst_qdeclarativetextinput::createView(const QString &filename)
2143 {
2144     QDeclarativeView *canvas = new QDeclarativeView(0);
2145
2146     canvas->setSource(QUrl::fromLocalFile(filename));
2147
2148     return canvas;
2149 }
2150 class MyInputContext : public QInputContext
2151 {
2152 public:
2153     MyInputContext() : openInputPanelReceived(false), closeInputPanelReceived(false), updateReceived(false), eventType(QEvent::None) {}
2154     ~MyInputContext() {}
2155
2156     QString identifierName() { return QString(); }
2157     QString language() { return QString(); }
2158
2159     void reset() {}
2160
2161     bool isComposing() const { return false; }
2162
2163     bool filterEvent( const QEvent *event )
2164     {
2165         if (event->type() == QEvent::RequestSoftwareInputPanel)
2166             openInputPanelReceived = true;
2167         if (event->type() == QEvent::CloseSoftwareInputPanel)
2168             closeInputPanelReceived = true;
2169         return false; //QInputContext::filterEvent(event);
2170     }
2171
2172     void update() { updateReceived = true; }
2173
2174     void mouseHandler(int x, QMouseEvent *event)
2175     {
2176         cursor = x;
2177         eventType = event->type();
2178         eventPosition = event->pos();
2179         eventGlobalPosition = event->globalPos();
2180         eventButton = event->button();
2181         eventButtons = event->buttons();
2182         eventModifiers = event->modifiers();
2183     }
2184
2185     void sendPreeditText(const QString &text, int cursor)
2186     {
2187         QList<QInputMethodEvent::Attribute> attributes;
2188         attributes.append(QInputMethodEvent::Attribute(
2189                 QInputMethodEvent::Cursor, cursor, text.length(), QVariant()));
2190
2191         QInputMethodEvent event(text, attributes);
2192         sendEvent(event);
2193     }
2194
2195     bool openInputPanelReceived;
2196     bool closeInputPanelReceived;
2197     bool updateReceived;
2198     int cursor;
2199     QEvent::Type eventType;
2200     QPoint eventPosition;
2201     QPoint eventGlobalPosition;
2202     Qt::MouseButton eventButton;
2203     Qt::MouseButtons eventButtons;
2204     Qt::KeyboardModifiers eventModifiers;
2205 };
2206
2207 void tst_qdeclarativetextinput::openInputPanelOnClick()
2208 {
2209     QGraphicsScene scene;
2210     QGraphicsView view(&scene);
2211     MyInputContext ic;
2212     view.setInputContext(&ic);
2213     QDeclarative1TextInput input;
2214     QSignalSpy focusOnPressSpy(&input, SIGNAL(activeFocusOnPressChanged(bool)));
2215     input.setText("Hello world");
2216     input.setPos(0, 0);
2217     scene.addItem(&input);
2218     view.show();
2219     qApp->setAutoSipEnabled(true);
2220     QApplication::setActiveWindow(&view);
2221     QTest::qWaitForWindowShown(&view);
2222     QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
2223
2224     QDeclarativeItemPrivate* pri = QDeclarativeItemPrivate::get(&input);
2225     QDeclarative1TextInputPrivate *inputPrivate = static_cast<QDeclarative1TextInputPrivate*>(pri);
2226
2227     // input panel on click
2228     inputPrivate->showInputPanelOnFocus = false;
2229
2230     QStyle::RequestSoftwareInputPanel behavior = QStyle::RequestSoftwareInputPanel(
2231             view.style()->styleHint(QStyle::SH_RequestSoftwareInputPanel));
2232     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(input.scenePos()));
2233     QApplication::processEvents();
2234     if (behavior == QStyle::RSIP_OnMouseClickAndAlreadyFocused) {
2235         QCOMPARE(ic.openInputPanelReceived, false);
2236         QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(input.scenePos()));
2237         QApplication::processEvents();
2238         QCOMPARE(ic.openInputPanelReceived, true);
2239     } else if (behavior == QStyle::RSIP_OnMouseClick) {
2240         QCOMPARE(ic.openInputPanelReceived, true);
2241     }
2242     ic.openInputPanelReceived = false;
2243
2244     // focus should not cause input panels to open or close
2245     input.setFocus(false);
2246     input.setFocus(true);
2247     input.setFocus(false);
2248     input.setFocus(true);
2249     input.setFocus(false);
2250     QCOMPARE(ic.openInputPanelReceived, false);
2251     QCOMPARE(ic.closeInputPanelReceived, false);
2252 }
2253
2254 void tst_qdeclarativetextinput::openInputPanelOnFocus()
2255 {
2256     QGraphicsScene scene;
2257     QGraphicsView view(&scene);
2258     MyInputContext ic;
2259     view.setInputContext(&ic);
2260     QDeclarative1TextInput input;
2261     QSignalSpy focusOnPressSpy(&input, SIGNAL(activeFocusOnPressChanged(bool)));
2262     input.setText("Hello world");
2263     input.setPos(0, 0);
2264     scene.addItem(&input);
2265     view.show();
2266     qApp->setAutoSipEnabled(true);
2267     QApplication::setActiveWindow(&view);
2268     QTest::qWaitForWindowShown(&view);
2269     QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
2270
2271     QDeclarativeItemPrivate* pri = QDeclarativeItemPrivate::get(&input);
2272     QDeclarative1TextInputPrivate *inputPrivate = static_cast<QDeclarative1TextInputPrivate*>(pri);
2273     inputPrivate->showInputPanelOnFocus = true;
2274
2275     // test default values
2276     QVERIFY(input.focusOnPress());
2277     QCOMPARE(ic.openInputPanelReceived, false);
2278     QCOMPARE(ic.closeInputPanelReceived, false);
2279
2280     // focus on press, input panel on focus
2281     QTest::mousePress(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(input.scenePos()));
2282     QApplication::processEvents();
2283     QVERIFY(input.hasActiveFocus());
2284     QCOMPARE(ic.openInputPanelReceived, true);
2285     ic.openInputPanelReceived = false;
2286
2287     // no events on release
2288     QTest::mouseRelease(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(input.scenePos()));
2289     QCOMPARE(ic.openInputPanelReceived, false);
2290     ic.openInputPanelReceived = false;
2291
2292     // if already focused, input panel can be opened on press
2293     QVERIFY(input.hasActiveFocus());
2294     QTest::mousePress(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(input.scenePos()));
2295     QApplication::processEvents();
2296     QCOMPARE(ic.openInputPanelReceived, true);
2297     ic.openInputPanelReceived = false;
2298
2299     // input method should stay enabled if focus
2300     // is lost to an item that also accepts inputs
2301     QDeclarative1TextInput anotherInput;
2302     scene.addItem(&anotherInput);
2303     anotherInput.setFocus(true);
2304     QApplication::processEvents();
2305     QCOMPARE(ic.openInputPanelReceived, true);
2306     ic.openInputPanelReceived = false;
2307     QCOMPARE(view.inputContext(), (QInputContext*)&ic);
2308     QVERIFY(view.testAttribute(Qt::WA_InputMethodEnabled));
2309
2310     // input method should be disabled if focus
2311     // is lost to an item that doesn't accept inputs
2312     QDeclarativeItem item;
2313     scene.addItem(&item);
2314     item.setFocus(true);
2315     QApplication::processEvents();
2316     QCOMPARE(ic.openInputPanelReceived, false);
2317     QVERIFY(view.inputContext() == 0);
2318     QVERIFY(!view.testAttribute(Qt::WA_InputMethodEnabled));
2319
2320     // no automatic input panel events should
2321     // be sent if activeFocusOnPress is false
2322     input.setFocusOnPress(false);
2323     QCOMPARE(focusOnPressSpy.count(),1);
2324     input.setFocusOnPress(false);
2325     QCOMPARE(focusOnPressSpy.count(),1);
2326     input.setFocus(false);
2327     input.setFocus(true);
2328     QTest::mousePress(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(input.scenePos()));
2329     QTest::mouseRelease(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(input.scenePos()));
2330     QApplication::processEvents();
2331     QCOMPARE(ic.openInputPanelReceived, false);
2332     QCOMPARE(ic.closeInputPanelReceived, false);
2333
2334     // one show input panel event should
2335     // be set when openSoftwareInputPanel is called
2336     input.openSoftwareInputPanel();
2337     QCOMPARE(ic.openInputPanelReceived, true);
2338     QCOMPARE(ic.closeInputPanelReceived, false);
2339     ic.openInputPanelReceived = false;
2340
2341     // one close input panel event should
2342     // be sent when closeSoftwareInputPanel is called
2343     input.closeSoftwareInputPanel();
2344     QCOMPARE(ic.openInputPanelReceived, false);
2345     QCOMPARE(ic.closeInputPanelReceived, true);
2346     ic.closeInputPanelReceived = false;
2347
2348     // set activeFocusOnPress back to true
2349     input.setFocusOnPress(true);
2350     QCOMPARE(focusOnPressSpy.count(),2);
2351     input.setFocusOnPress(true);
2352     QCOMPARE(focusOnPressSpy.count(),2);
2353     input.setFocus(false);
2354     QApplication::processEvents();
2355     QCOMPARE(ic.openInputPanelReceived, false);
2356     QCOMPARE(ic.closeInputPanelReceived, false);
2357     ic.closeInputPanelReceived = false;
2358
2359     // input panel should not re-open
2360     // if focus has already been set
2361     input.setFocus(true);
2362     QCOMPARE(ic.openInputPanelReceived, true);
2363     ic.openInputPanelReceived = false;
2364     input.setFocus(true);
2365     QCOMPARE(ic.openInputPanelReceived, false);
2366
2367     // input method should be disabled
2368     // if TextInput loses focus
2369     input.setFocus(false);
2370     QApplication::processEvents();
2371     QVERIFY(view.inputContext() == 0);
2372     QVERIFY(!view.testAttribute(Qt::WA_InputMethodEnabled));
2373
2374     // input method should not be enabled
2375     // if TextEdit is read only.
2376     input.setReadOnly(true);
2377     ic.openInputPanelReceived = false;
2378     input.setFocus(true);
2379     QApplication::processEvents();
2380     QCOMPARE(ic.openInputPanelReceived, false);
2381     QVERIFY(view.inputContext() == 0);
2382     QVERIFY(!view.testAttribute(Qt::WA_InputMethodEnabled));
2383 }
2384
2385 class MyTextInput : public QDeclarative1TextInput
2386 {
2387 public:
2388     MyTextInput(QDeclarativeItem *parent = 0) : QDeclarative1TextInput(parent)
2389     {
2390         nbPaint = 0;
2391     }
2392     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
2393     {
2394        nbPaint++;
2395        QDeclarative1TextInput::paint(painter, option, widget);
2396     }
2397     int nbPaint;
2398 };
2399
2400 void tst_qdeclarativetextinput::setHAlignClearCache()
2401 {
2402     QGraphicsScene scene;
2403     QGraphicsView view(&scene);
2404     MyTextInput input;
2405     input.setText("Hello world");
2406     scene.addItem(&input);
2407     view.show();
2408     QApplication::setActiveWindow(&view);
2409     QTest::qWaitForWindowShown(&view);
2410 #ifdef Q_WS_QPA
2411     QEXPECT_FAIL("", "QTBUG-21017 fails", Abort);
2412 #endif
2413     QTRY_COMPARE(input.nbPaint, 1);
2414     input.setHAlign(QDeclarative1TextInput::AlignRight);
2415     QApplication::processEvents();
2416     //Changing the alignment should trigger a repaint
2417     QCOMPARE(input.nbPaint, 2);
2418 }
2419
2420 void tst_qdeclarativetextinput::focusOutClearSelection()
2421 {
2422     QGraphicsScene scene;
2423     QGraphicsView view(&scene);
2424     QDeclarative1TextInput input;
2425     QDeclarative1TextInput input2;
2426     input.setText(QLatin1String("Hello world"));
2427     input.setFocus(true);
2428     scene.addItem(&input2);
2429     scene.addItem(&input);
2430     view.show();
2431     QApplication::setActiveWindow(&view);
2432     QTest::qWaitForWindowShown(&view);
2433     input.select(2,5);
2434     //The selection should work
2435     QTRY_COMPARE(input.selectedText(), QLatin1String("llo"));
2436     input2.setFocus(true);
2437     QApplication::processEvents();
2438     //The input lost the focus selection should be cleared
2439     QTRY_COMPARE(input.selectedText(), QLatin1String(""));
2440 }
2441
2442 void tst_qdeclarativetextinput::geometrySignals()
2443 {
2444     QDeclarativeComponent component(&engine, SRCDIR "/data/geometrySignals.qml");
2445     QObject *o = component.create();
2446     QVERIFY(o);
2447     QCOMPARE(o->property("bindingWidth").toInt(), 400);
2448     QCOMPARE(o->property("bindingHeight").toInt(), 500);
2449     delete o;
2450 }
2451
2452 void tst_qdeclarativetextinput::testQtQuick11Attributes()
2453 {
2454     QFETCH(QString, code);
2455     QFETCH(QString, warning);
2456     QFETCH(QString, error);
2457
2458     QDeclarativeEngine engine;
2459     QObject *obj;
2460
2461     QDeclarativeComponent valid(&engine);
2462     valid.setData("import QtQuick 1.1; TextInput { " + code.toUtf8() + " }", QUrl(""));
2463     obj = valid.create();
2464     QVERIFY(obj);
2465     QVERIFY(valid.errorString().isEmpty());
2466     delete obj;
2467
2468     QDeclarativeComponent invalid(&engine);
2469     invalid.setData("import QtQuick 1.0; TextInput { " + code.toUtf8() + " }", QUrl(""));
2470     QTest::ignoreMessage(QtWarningMsg, warning.toUtf8());
2471     obj = invalid.create();
2472     QCOMPARE(invalid.errorString(), error);
2473     delete obj;
2474 }
2475
2476 void tst_qdeclarativetextinput::testQtQuick11Attributes_data()
2477 {
2478     QTest::addColumn<QString>("code");
2479     QTest::addColumn<QString>("warning");
2480     QTest::addColumn<QString>("error");
2481
2482     QTest::newRow("canPaste") << "property bool foo: canPaste"
2483         << "<Unknown File>:1: ReferenceError: Can't find variable: canPaste"
2484         << "";
2485
2486     QTest::newRow("moveCursorSelection") << "Component.onCompleted: moveCursorSelection(0, TextEdit.SelectCharacters)"
2487         << "<Unknown File>:1: ReferenceError: Can't find variable: moveCursorSelection"
2488         << "";
2489
2490     QTest::newRow("deselect") << "Component.onCompleted: deselect()"
2491         << "<Unknown File>:1: ReferenceError: Can't find variable: deselect"
2492         << "";
2493 }
2494
2495 void tst_qdeclarativetextinput::preeditAutoScroll()
2496 {
2497     QString committedText = "super";
2498     QString preeditText = "califragisiticexpialidocious!";
2499
2500     QGraphicsScene scene;
2501     QGraphicsView view(&scene);
2502     MyInputContext ic;
2503     view.setInputContext(&ic);
2504     QDeclarative1TextInput input;
2505     QFontMetricsF fm(input.font());
2506     input.setWidth(fm.width(committedText));
2507     input.setText(committedText);
2508     input.setPos(0, 0);
2509     input.setFocus(true);
2510     scene.addItem(&input);
2511     view.show();
2512     QApplication::setActiveWindow(&view);
2513     QTest::qWaitForWindowShown(&view);
2514     QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
2515
2516     QSignalSpy cursorRectangleSpy(&input, SIGNAL(cursorRectangleChanged()));
2517     int cursorRectangleChanges = 0;
2518
2519     // test the text is scrolled so the preedit is visible.
2520     ic.sendPreeditText(preeditText.mid(0, 3), 1);
2521 #ifdef Q_WS_QPA
2522     QEXPECT_FAIL("", "QTBUG-21017 fails", Abort);
2523 #endif
2524     QVERIFY(input.positionAt(0) != 0);
2525     QVERIFY(input.cursorRectangle().left() < input.boundingRect().width());
2526     QCOMPARE(cursorRectangleSpy.count(), ++cursorRectangleChanges);
2527
2528     // test the text is scrolled back when the preedit is removed.
2529     ic.sendEvent(QInputMethodEvent());
2530     QCOMPARE(input.positionAt(0), 0);
2531     QCOMPARE(input.positionAt(input.width()), 5);
2532     QCOMPARE(cursorRectangleSpy.count(), ++cursorRectangleChanges);
2533
2534     // some tolerance for different fonts.
2535 #ifdef Q_OS_LINUX
2536     const int error = 2;
2537 #else
2538     const int error = 5;
2539 #endif
2540
2541     // test if the preedit is larger than the text input that the
2542     // character preceding the cursor is still visible.
2543     qreal x = input.positionToRectangle(0).x();
2544     for (int i = 0; i < 3; ++i) {
2545         ic.sendPreeditText(preeditText, i + 1);
2546         QVERIFY(input.cursorRectangle().right() >= fm.width(preeditText.at(i)) - error);
2547         QVERIFY(input.positionToRectangle(0).x() < x);
2548         QCOMPARE(cursorRectangleSpy.count(), ++cursorRectangleChanges);
2549         x = input.positionToRectangle(0).x();
2550     }
2551     for (int i = 1; i >= 0; --i) {
2552         ic.sendPreeditText(preeditText, i + 1);
2553         QVERIFY(input.cursorRectangle().right() >= fm.width(preeditText.at(i)) - error);
2554         QVERIFY(input.positionToRectangle(0).x() > x);
2555         QCOMPARE(cursorRectangleSpy.count(), ++cursorRectangleChanges);
2556         x = input.positionToRectangle(0).x();
2557     }
2558
2559     // Test incrementing the preedit cursor doesn't cause further
2560     // scrolling when right most text is visible.
2561     ic.sendPreeditText(preeditText, preeditText.length() - 3);
2562     QCOMPARE(cursorRectangleSpy.count(), ++cursorRectangleChanges);
2563     x = input.positionToRectangle(0).x();
2564     for (int i = 2; i >= 0; --i) {
2565         ic.sendPreeditText(preeditText, preeditText.length() - i);
2566         QCOMPARE(input.positionToRectangle(0).x(), x);
2567         QCOMPARE(cursorRectangleSpy.count(), ++cursorRectangleChanges);
2568     }
2569     for (int i = 1; i <  3; ++i) {
2570         ic.sendPreeditText(preeditText, preeditText.length() - i);
2571         QCOMPARE(input.positionToRectangle(0).x(), x);
2572         QCOMPARE(cursorRectangleSpy.count(), ++cursorRectangleChanges);
2573     }
2574
2575     // Test disabling auto scroll.
2576     ic.sendEvent(QInputMethodEvent());
2577
2578     input.setAutoScroll(false);
2579     ic.sendPreeditText(preeditText.mid(0, 3), 1);
2580     QCOMPARE(input.positionAt(0), 0);
2581     QCOMPARE(input.positionAt(input.width()), 5);
2582
2583     ic.sendEvent(QInputMethodEvent());
2584     input.setAutoScroll(true);
2585     // Test committing pre-edit text at the start of the string. QTBUG-18789
2586     input.setCursorPosition(0);
2587     ic.sendPreeditText(input.text(), 5);
2588     QCOMPARE(input.positionAt(0), 0);
2589
2590     QInputMethodEvent event;
2591     event.setCommitString(input.text());
2592     ic.sendEvent(event);
2593
2594     QCOMPARE(input.positionAt(0), 0);
2595     QCOMPARE(input.positionAt(input.width()), 5);
2596 }
2597
2598 void tst_qdeclarativetextinput::preeditMicroFocus()
2599 {
2600     QString preeditText = "super";
2601
2602     QGraphicsScene scene;
2603     QGraphicsView view(&scene);
2604     MyInputContext ic;
2605     view.setInputContext(&ic);
2606     QDeclarative1TextInput input;
2607     input.setPos(0, 0);
2608     input.setAutoScroll(false);
2609     input.setFocus(true);
2610     scene.addItem(&input);
2611     view.show();
2612     QApplication::setActiveWindow(&view);
2613     QTest::qWaitForWindowShown(&view);
2614     QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
2615
2616     QRect currentRect;
2617     QRect previousRect = input.inputMethodQuery(Qt::ImMicroFocus).toRect();
2618
2619     // Verify that the micro focus rect is positioned the same for position 0 as
2620     // it would be if there was no preedit text.
2621     ic.updateReceived = false;
2622     ic.sendPreeditText(preeditText, 0);
2623     currentRect = input.inputMethodQuery(Qt::ImMicroFocus).toRect();
2624     QCOMPARE(currentRect, previousRect);
2625 #if defined(Q_WS_X11) || defined(Q_WS_QWS)
2626     QCOMPARE(ic.updateReceived, true);
2627 #endif
2628
2629     // Verify that the micro focus rect moves to the left as the cursor position
2630     // is incremented.
2631     for (int i = 1; i <= 5; ++i) {
2632         ic.updateReceived = false;
2633         ic.sendPreeditText(preeditText, i);
2634         currentRect = input.inputMethodQuery(Qt::ImMicroFocus).toRect();
2635         QVERIFY(previousRect.left() < currentRect.left());
2636 #if defined(Q_WS_X11) || defined(Q_WS_QWS)
2637         QCOMPARE(ic.updateReceived, true);
2638 #endif
2639         previousRect = currentRect;
2640     }
2641
2642     // Verify that if there is no preedit cursor then the micro focus rect is the
2643     // same as it would be if it were positioned at the end of the preedit text.
2644     ic.sendPreeditText(preeditText, 0);
2645     ic.updateReceived = false;
2646     ic.sendEvent(QInputMethodEvent(preeditText, QList<QInputMethodEvent::Attribute>()));
2647     currentRect = input.inputMethodQuery(Qt::ImMicroFocus).toRect();
2648     QCOMPARE(currentRect, previousRect);
2649 #if defined(Q_WS_X11) || defined(Q_WS_QWS)
2650     QCOMPARE(ic.updateReceived, true);
2651 #endif
2652 }
2653
2654 void tst_qdeclarativetextinput::inputContextMouseHandler()
2655 {
2656     QString text = "supercalifragisiticexpialidocious!";
2657
2658     QGraphicsScene scene;
2659     QGraphicsView view(&scene);
2660     MyInputContext ic;
2661     view.setInputContext(&ic);
2662     QDeclarative1TextInput input;
2663     input.setWidth(200);
2664     input.setText(text.mid(0, 12));
2665     input.setCursorPosition(12);
2666     input.setPos(0, 0);
2667     input.setFocus(true);
2668     scene.addItem(&input);
2669     view.show();
2670     QApplication::setActiveWindow(&view);
2671     QTest::qWaitForWindowShown(&view);
2672     QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
2673
2674     QFontMetricsF fm(input.font());
2675     const qreal y = fm.height() / 2;
2676
2677     QPoint position2 = view.mapFromScene(input.mapToScene(QPointF(fm.width(text.mid(0, 2)), y)));
2678     QPoint position8 = view.mapFromScene(input.mapToScene(QPointF(fm.width(text.mid(0, 8)), y)));
2679     QPoint position20 = view.mapFromScene(input.mapToScene(QPointF(fm.width(text.mid(0, 20)), y)));
2680     QPoint position27 = view.mapFromScene(input.mapToScene(QPointF(fm.width(text.mid(0, 27)), y)));
2681     QPoint globalPosition2 = view.viewport()->mapToGlobal(position2);
2682     QPoint globalposition8 = view.viewport()->mapToGlobal(position8);
2683     QPoint globalposition20 = view.viewport()->mapToGlobal(position20);
2684     QPoint globalposition27 = view.viewport()->mapToGlobal(position27);
2685
2686     ic.sendEvent(QInputMethodEvent(text.mid(12), QList<QInputMethodEvent::Attribute>()));
2687
2688     QTest::mouseDClick(view.viewport(), Qt::LeftButton, Qt::NoModifier, position2);
2689     QCOMPARE(ic.eventType, QEvent::MouseButtonDblClick);
2690     QCOMPARE(ic.eventPosition, position2);
2691     QCOMPARE(ic.eventGlobalPosition, globalPosition2);
2692     QCOMPARE(ic.eventButton, Qt::LeftButton);
2693     QCOMPARE(ic.eventModifiers, Qt::NoModifier);
2694     QVERIFY(ic.cursor < 0);
2695     ic.eventType = QEvent::None;
2696
2697     QTest::mousePress(view.viewport(), Qt::LeftButton, Qt::NoModifier, position2);
2698     QCOMPARE(ic.eventType, QEvent::MouseButtonPress);
2699     QCOMPARE(ic.eventPosition, position2);
2700     QCOMPARE(ic.eventGlobalPosition, globalPosition2);
2701     QCOMPARE(ic.eventButton, Qt::LeftButton);
2702     QCOMPARE(ic.eventModifiers, Qt::NoModifier);
2703     QVERIFY(ic.cursor < 0);
2704     ic.eventType = QEvent::None;
2705
2706     {   QMouseEvent mv(QEvent::MouseMove, position8, globalposition8, Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
2707         QApplication::sendEvent(view.viewport(), &mv); }
2708     QCOMPARE(ic.eventType, QEvent::None);
2709
2710     {   QMouseEvent mv(QEvent::MouseMove, position27, globalposition27, Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
2711         QApplication::sendEvent(view.viewport(), &mv); }
2712     QCOMPARE(ic.eventType, QEvent::MouseMove);
2713     QCOMPARE(ic.eventPosition, position27);
2714     QCOMPARE(ic.eventGlobalPosition, globalposition27);
2715     QCOMPARE(ic.eventButton, Qt::LeftButton);
2716     QCOMPARE(ic.eventModifiers, Qt::NoModifier);
2717     QVERIFY(ic.cursor >= 14 && ic.cursor <= 16);    // 15 is expected but some platforms may be off by one.
2718     ic.eventType = QEvent::None;
2719
2720     QTest::mouseRelease(view.viewport(), Qt::LeftButton, Qt::NoModifier, position27);
2721     QCOMPARE(ic.eventType, QEvent::MouseButtonRelease);
2722     QCOMPARE(ic.eventPosition, position27);
2723     QCOMPARE(ic.eventGlobalPosition, globalposition27);
2724     QCOMPARE(ic.eventButton, Qt::LeftButton);
2725     QCOMPARE(ic.eventModifiers, Qt::NoModifier);
2726     QVERIFY(ic.cursor >= 14 && ic.cursor <= 16);
2727     ic.eventType = QEvent::None;
2728
2729     // And in the other direction.
2730     QTest::mouseDClick(view.viewport(), Qt::LeftButton, Qt::ControlModifier, position27);
2731     QCOMPARE(ic.eventType, QEvent::MouseButtonDblClick);
2732     QCOMPARE(ic.eventPosition, position27);
2733     QCOMPARE(ic.eventGlobalPosition, globalposition27);
2734     QCOMPARE(ic.eventButton, Qt::LeftButton);
2735     QCOMPARE(ic.eventModifiers, Qt::ControlModifier);
2736     QVERIFY(ic.cursor >= 14 && ic.cursor <= 16);
2737     ic.eventType = QEvent::None;
2738
2739     QTest::mousePress(view.viewport(), Qt::RightButton, Qt::ControlModifier, position27);
2740     QCOMPARE(ic.eventType, QEvent::MouseButtonPress);
2741     QCOMPARE(ic.eventPosition, position27);
2742     QCOMPARE(ic.eventGlobalPosition, globalposition27);
2743     QCOMPARE(ic.eventButton, Qt::RightButton);
2744     QCOMPARE(ic.eventModifiers, Qt::ControlModifier);
2745     QVERIFY(ic.cursor >= 14 && ic.cursor <= 16);
2746     ic.eventType = QEvent::None;
2747
2748     {   QMouseEvent mv(QEvent::MouseMove, position20, globalposition20, Qt::RightButton, Qt::RightButton,Qt::ControlModifier);
2749         QApplication::sendEvent(view.viewport(), &mv); }
2750     QCOMPARE(ic.eventType, QEvent::MouseMove);
2751     QCOMPARE(ic.eventPosition, position20);
2752     QCOMPARE(ic.eventGlobalPosition, globalposition20);
2753     QCOMPARE(ic.eventButton, Qt::RightButton);
2754     QCOMPARE(ic.eventModifiers, Qt::ControlModifier);
2755     QVERIFY(ic.cursor >= 7 && ic.cursor <= 9);
2756     ic.eventType = QEvent::None;
2757
2758     {   QMouseEvent mv(QEvent::MouseMove, position2, globalPosition2, Qt::RightButton, Qt::RightButton,Qt::ControlModifier);
2759         QApplication::sendEvent(view.viewport(), &mv); }
2760     QCOMPARE(ic.eventType, QEvent::None);
2761
2762     QTest::mouseRelease(view.viewport(), Qt::RightButton, Qt::ControlModifier, position2);
2763     QCOMPARE(ic.eventType, QEvent::MouseButtonRelease);
2764     QCOMPARE(ic.eventPosition, position2);
2765     QCOMPARE(ic.eventGlobalPosition, globalPosition2);
2766     QCOMPARE(ic.eventButton, Qt::RightButton);
2767     QCOMPARE(ic.eventModifiers, Qt::ControlModifier);
2768     QVERIFY(ic.cursor < 0);
2769     ic.eventType = QEvent::None;
2770 }
2771
2772 void tst_qdeclarativetextinput::inputMethodComposing()
2773 {
2774     QString text = "supercalifragisiticexpialidocious!";
2775
2776     QGraphicsScene scene;
2777     QGraphicsView view(&scene);
2778     MyInputContext ic;
2779     view.setInputContext(&ic);
2780     QDeclarative1TextInput input;
2781     input.setWidth(200);
2782     input.setText(text.mid(0, 12));
2783     input.setCursorPosition(12);
2784     input.setPos(0, 0);
2785     input.setFocus(true);
2786     scene.addItem(&input);
2787     view.show();
2788     QApplication::setActiveWindow(&view);
2789     QTest::qWaitForWindowShown(&view);
2790     QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
2791
2792     QSignalSpy spy(&input, SIGNAL(inputMethodComposingChanged()));
2793
2794     QCOMPARE(input.isInputMethodComposing(), false);
2795
2796     ic.sendEvent(QInputMethodEvent(text.mid(3), QList<QInputMethodEvent::Attribute>()));
2797     QCOMPARE(input.isInputMethodComposing(), true);
2798     QCOMPARE(spy.count(), 1);
2799
2800     ic.sendEvent(QInputMethodEvent(text.mid(12), QList<QInputMethodEvent::Attribute>()));
2801     QCOMPARE(input.isInputMethodComposing(), true);
2802     QCOMPARE(spy.count(), 1);
2803
2804     ic.sendEvent(QInputMethodEvent());
2805     QCOMPARE(input.isInputMethodComposing(), false);
2806     QCOMPARE(spy.count(), 2);
2807 }
2808
2809 void tst_qdeclarativetextinput::cursorRectangleSize()
2810 {
2811     QDeclarativeView *canvas = createView(SRCDIR "/data/positionAt.qml");
2812     QVERIFY(canvas->rootObject() != 0);
2813     canvas->show();
2814     canvas->setFocus();
2815     QApplication::setActiveWindow(canvas);
2816     QTest::qWaitForWindowShown(canvas);
2817
2818     QDeclarative1TextInput *textInput = qobject_cast<QDeclarative1TextInput *>(canvas->rootObject());
2819     QVERIFY(textInput != 0);
2820     textInput->setFocus(Qt::OtherFocusReason);
2821     QRectF cursorRect = textInput->positionToRectangle(textInput->cursorPosition());
2822     QRectF microFocusFromScene = canvas->scene()->inputMethodQuery(Qt::ImMicroFocus).toRectF();
2823     QRectF microFocusFromApp= QApplication::focusWidget()->inputMethodQuery(Qt::ImMicroFocus).toRectF();
2824
2825     QCOMPARE(microFocusFromScene.size(), cursorRect.size());
2826     QCOMPARE(microFocusFromApp.size(), cursorRect.size());
2827 }
2828
2829 QTEST_MAIN(tst_qdeclarativetextinput)
2830
2831 #include "tst_qdeclarativetextinput.moc"