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