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