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