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