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