1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the test suite of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include <QtTest/QSignalSpy>
43 #include "../shared/testhttpserver.h"
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 <QtGui/qguiapplication.h>
52 #include <private/qquicktextedit_p.h>
53 #include <private/qquicktextedit_p_p.h>
54 #include <private/qsgdistancefieldglyphcache_p.h>
55 #include <QFontMetrics>
59 #include <QInputContext>
60 #include <QInputPanel>
63 #include <private/qtextcontrol_p.h>
64 #include "../shared/util.h"
67 #include <Carbon/Carbon.h>
71 #define QTBUG_21691_MESSAGE "QTBUG-21691: The test needs to be rewritten to not use QInputContext"
73 Q_DECLARE_METATYPE(QQuickTextEdit::SelectionMode)
74 DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
76 QString createExpectedFileIfNotFound(const QString& filebasename, const QImage& actual)
78 // XXX This will be replaced by some clever persistent platform image store.
79 QString persistent_dir = TESTDATA("");
80 QString arch = "unknown-architecture"; // QTest needs to help with this.
82 QString expectfile = persistent_dir + QDir::separator() + filebasename + "-" + arch + ".png";
84 if (!QFile::exists(expectfile)) {
85 actual.save(expectfile);
86 qWarning() << "created" << expectfile;
93 class tst_qquicktextedit : public QObject
102 void cleanupTestCase();
108 void alignments_data();
110 // ### these tests may be trivial
112 void hAlign_RightToLeft();
117 void persistentSelection();
120 void isRightToLeft_data();
121 void isRightToLeft();
123 void moveCursorSelection_data();
124 void moveCursorSelection();
125 void moveCursorSelectionSequence_data();
126 void moveCursorSelectionSequence();
127 void mouseSelection_data();
128 void mouseSelection();
129 void mouseSelectionMode_data();
130 void mouseSelectionMode();
131 void dragMouseSelection();
132 void inputMethodHints();
136 void cursorDelegate();
137 void cursorVisible();
138 void delegateLoading_data();
139 void delegateLoading();
144 void canPasteEmpty();
146 void openInputPanel();
147 void geometrySignals();
148 void pastingRichText_QTBUG_14003();
149 void implicitSize_data();
151 void testQtQuick11Attributes();
152 void testQtQuick11Attributes_data();
154 void preeditMicroFocus();
155 void inputContextMouseHandler();
156 void inputMethodComposing();
157 void cursorRectangleSize();
159 void emptytags_QTBUG_22058();
162 void simulateKey(QQuickView *, int key, Qt::KeyboardModifiers modifiers = 0);
164 QStringList standard;
165 QStringList richText;
167 QStringList hAlignmentStrings;
168 QStringList vAlignmentStrings;
170 QList<Qt::Alignment> vAlignments;
171 QList<Qt::Alignment> hAlignments;
173 QStringList colorStrings;
175 QDeclarativeEngine engine;
177 void tst_qquicktextedit::initTestCase()
181 void tst_qquicktextedit::cleanupTestCase()
185 tst_qquicktextedit::tst_qquicktextedit()
187 standard << "the quick brown fox jumped over the lazy dog"
188 << "the quick brown fox\n jumped over the lazy dog"
192 richText << "<i>the <b>quick</b> brown <a href=\\\"http://www.google.com\\\">fox</a> jumped over the <b>lazy</b> dog</i>"
193 << "<i>the <b>quick</b> brown <a href=\\\"http://www.google.com\\\">fox</a><br>jumped over the <b>lazy</b> dog</i>";
195 hAlignmentStrings << "AlignLeft"
199 vAlignmentStrings << "AlignTop"
203 hAlignments << Qt::AlignLeft
207 vAlignments << Qt::AlignTop
211 colorStrings << "aliceblue"
224 // need a different test to do alpha channel test
230 void tst_qquicktextedit::text()
233 QDeclarativeComponent texteditComponent(&engine);
234 texteditComponent.setData("import QtQuick 2.0\nTextEdit { text: \"\" }", QUrl());
235 QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
237 QVERIFY(textEditObject != 0);
238 QCOMPARE(textEditObject->text(), QString(""));
241 for (int i = 0; i < standard.size(); i++)
243 QString componentStr = "import QtQuick 2.0\nTextEdit { text: \"" + standard.at(i) + "\" }";
244 QDeclarativeComponent texteditComponent(&engine);
245 texteditComponent.setData(componentStr.toLatin1(), QUrl());
246 QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
248 QVERIFY(textEditObject != 0);
249 QCOMPARE(textEditObject->text(), standard.at(i));
252 for (int i = 0; i < richText.size(); i++)
254 QString componentStr = "import QtQuick 2.0\nTextEdit { text: \"" + richText.at(i) + "\" }";
255 QDeclarativeComponent texteditComponent(&engine);
256 texteditComponent.setData(componentStr.toLatin1(), QUrl());
257 QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
259 QVERIFY(textEditObject != 0);
260 QString actual = textEditObject->text();
261 QString expected = richText.at(i);
262 actual.replace(QRegExp(".*<body[^>]*>"),"");
263 actual.replace(QRegExp("(<[^>]*>)+"),"<>");
264 expected.replace(QRegExp("(<[^>]*>)+"),"<>");
265 QCOMPARE(actual.simplified(),expected.simplified());
269 void tst_qquicktextedit::width()
271 // uses Font metrics to find the width for standard and document to find the width for rich
273 QDeclarativeComponent texteditComponent(&engine);
274 texteditComponent.setData("import QtQuick 2.0\nTextEdit { text: \"\" }", QUrl());
275 QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
277 QVERIFY(textEditObject != 0);
278 QCOMPARE(textEditObject->width(), 0.0);
281 bool requiresUnhintedMetrics = !qmlDisableDistanceField();
283 for (int i = 0; i < standard.size(); i++)
286 qreal metricWidth = 0.0;
288 if (requiresUnhintedMetrics) {
289 QString s = standard.at(i);
290 s.replace(QLatin1Char('\n'), QChar::LineSeparator);
292 QTextLayout layout(s);
293 layout.setFlags(Qt::TextExpandTabs | Qt::TextShowMnemonic);
296 option.setUseDesignMetrics(true);
297 layout.setTextOption(option);
300 layout.beginLayout();
302 QTextLine line = layout.createLine();
309 metricWidth = ceil(layout.boundingRect().width());
312 metricWidth = fm.size(Qt::TextExpandTabs | Qt::TextShowMnemonic, standard.at(i)).width();
313 metricWidth = ceil(metricWidth);
316 QString componentStr = "import QtQuick 2.0\nTextEdit { text: \"" + standard.at(i) + "\" }";
317 QDeclarativeComponent texteditComponent(&engine);
318 texteditComponent.setData(componentStr.toLatin1(), QUrl());
319 QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
321 QVERIFY(textEditObject != 0);
322 QCOMPARE(textEditObject->width(), qreal(metricWidth));
325 for (int i = 0; i < richText.size(); i++)
327 QTextDocument document;
328 document.setHtml(richText.at(i));
329 document.setDocumentMargin(0);
330 if (requiresUnhintedMetrics)
331 document.setUseDesignMetrics(true);
333 int documentWidth = ceil(document.idealWidth());
335 QString componentStr = "import QtQuick 2.0\nTextEdit { text: \"" + richText.at(i) + "\" }";
336 QDeclarativeComponent texteditComponent(&engine);
337 texteditComponent.setData(componentStr.toLatin1(), QUrl());
338 QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
340 QVERIFY(textEditObject != 0);
341 QCOMPARE(textEditObject->width(), qreal(documentWidth));
345 void tst_qquicktextedit::wrap()
347 // for specified width and wrap set true
349 QDeclarativeComponent texteditComponent(&engine);
350 texteditComponent.setData("import QtQuick 2.0\nTextEdit { text: \"\"; wrapMode: TextEdit.WordWrap; width: 300 }", QUrl());
351 QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
353 QVERIFY(textEditObject != 0);
354 QCOMPARE(textEditObject->width(), 300.);
357 for (int i = 0; i < standard.size(); i++)
359 QString componentStr = "import QtQuick 2.0\nTextEdit { wrapMode: TextEdit.WordWrap; width: 300; text: \"" + standard.at(i) + "\" }";
360 QDeclarativeComponent texteditComponent(&engine);
361 texteditComponent.setData(componentStr.toLatin1(), QUrl());
362 QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
364 QVERIFY(textEditObject != 0);
365 QCOMPARE(textEditObject->width(), 300.);
368 for (int i = 0; i < richText.size(); i++)
370 QString componentStr = "import QtQuick 2.0\nTextEdit { wrapMode: TextEdit.WordWrap; width: 300; text: \"" + richText.at(i) + "\" }";
371 QDeclarativeComponent texteditComponent(&engine);
372 texteditComponent.setData(componentStr.toLatin1(), QUrl());
373 QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
375 QVERIFY(textEditObject != 0);
376 QCOMPARE(textEditObject->width(), 300.);
381 void tst_qquicktextedit::textFormat()
384 QDeclarativeComponent textComponent(&engine);
385 textComponent.setData("import QtQuick 2.0\nTextEdit { text: \"Hello\"; textFormat: Text.RichText }", QUrl::fromLocalFile(""));
386 QQuickTextEdit *textObject = qobject_cast<QQuickTextEdit*>(textComponent.create());
388 QVERIFY(textObject != 0);
389 QVERIFY(textObject->textFormat() == QQuickTextEdit::RichText);
392 QDeclarativeComponent textComponent(&engine);
393 textComponent.setData("import QtQuick 2.0\nTextEdit { text: \"<b>Hello</b>\"; textFormat: Text.PlainText }", QUrl::fromLocalFile(""));
394 QQuickTextEdit *textObject = qobject_cast<QQuickTextEdit*>(textComponent.create());
396 QVERIFY(textObject != 0);
397 QVERIFY(textObject->textFormat() == QQuickTextEdit::PlainText);
401 void tst_qquicktextedit::alignments_data()
403 QTest::addColumn<int>("hAlign");
404 QTest::addColumn<int>("vAlign");
405 QTest::addColumn<QString>("expectfile");
407 QTest::newRow("LT") << int(Qt::AlignLeft) << int(Qt::AlignTop) << "alignments_lt";
408 QTest::newRow("RT") << int(Qt::AlignRight) << int(Qt::AlignTop) << "alignments_rt";
409 QTest::newRow("CT") << int(Qt::AlignHCenter) << int(Qt::AlignTop) << "alignments_ct";
411 QTest::newRow("LB") << int(Qt::AlignLeft) << int(Qt::AlignBottom) << "alignments_lb";
412 QTest::newRow("RB") << int(Qt::AlignRight) << int(Qt::AlignBottom) << "alignments_rb";
413 QTest::newRow("CB") << int(Qt::AlignHCenter) << int(Qt::AlignBottom) << "alignments_cb";
415 QTest::newRow("LC") << int(Qt::AlignLeft) << int(Qt::AlignVCenter) << "alignments_lc";
416 QTest::newRow("RC") << int(Qt::AlignRight) << int(Qt::AlignVCenter) << "alignments_rc";
417 QTest::newRow("CC") << int(Qt::AlignHCenter) << int(Qt::AlignVCenter) << "alignments_cc";
421 void tst_qquicktextedit::alignments()
423 QSKIP("Image comparison of text is almost guaranteed to fail during development");
427 QFETCH(QString, expectfile);
429 QQuickView canvas(QUrl::fromLocalFile(TESTDATA("alignments.qml")));
432 canvas.requestActivateWindow();
433 QTest::qWaitForWindowShown(&canvas);
434 QTRY_COMPARE(&canvas, qGuiApp->focusWindow());
436 QObject *ob = canvas.rootObject();
438 ob->setProperty("horizontalAlignment",hAlign);
439 ob->setProperty("verticalAlignment",vAlign);
440 QTRY_COMPARE(ob->property("running").toBool(),false);
441 QImage actual = canvas.grabFrameBuffer();
443 expectfile = createExpectedFileIfNotFound(expectfile, actual);
445 QImage expect(expectfile);
447 QCOMPARE(actual,expect);
451 //the alignment tests may be trivial o.oa
452 void tst_qquicktextedit::hAlign()
454 //test one align each, and then test if two align fails.
456 for (int i = 0; i < standard.size(); i++)
458 for (int j=0; j < hAlignmentStrings.size(); j++)
460 QString componentStr = "import QtQuick 2.0\nTextEdit { horizontalAlignment: \"" + hAlignmentStrings.at(j) + "\"; text: \"" + standard.at(i) + "\" }";
461 QDeclarativeComponent texteditComponent(&engine);
462 texteditComponent.setData(componentStr.toLatin1(), QUrl());
463 QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
465 QVERIFY(textEditObject != 0);
466 QCOMPARE((int)textEditObject->hAlign(), (int)hAlignments.at(j));
470 for (int i = 0; i < richText.size(); i++)
472 for (int j=0; j < hAlignmentStrings.size(); j++)
474 QString componentStr = "import QtQuick 2.0\nTextEdit { horizontalAlignment: \"" + hAlignmentStrings.at(j) + "\"; text: \"" + richText.at(i) + "\" }";
475 QDeclarativeComponent texteditComponent(&engine);
476 texteditComponent.setData(componentStr.toLatin1(), QUrl());
477 QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
479 QVERIFY(textEditObject != 0);
480 QCOMPARE((int)textEditObject->hAlign(), (int)hAlignments.at(j));
486 void tst_qquicktextedit::hAlign_RightToLeft()
488 QQuickView canvas(QUrl::fromLocalFile(TESTDATA("horizontalAlignment_RightToLeft.qml")));
489 QQuickTextEdit *textEdit = canvas.rootObject()->findChild<QQuickTextEdit*>("text");
490 QVERIFY(textEdit != 0);
493 const QString rtlText = textEdit->text();
495 // implicit alignment should follow the reading direction of text
496 QCOMPARE(textEdit->hAlign(), QQuickTextEdit::AlignRight);
497 QVERIFY(textEdit->positionToRectangle(0).x() > canvas.width()/2);
499 // explicitly left aligned
500 textEdit->setHAlign(QQuickTextEdit::AlignLeft);
501 QCOMPARE(textEdit->hAlign(), QQuickTextEdit::AlignLeft);
502 QVERIFY(textEdit->positionToRectangle(0).x() < canvas.width()/2);
504 // explicitly right aligned
505 textEdit->setHAlign(QQuickTextEdit::AlignRight);
506 QCOMPARE(textEdit->hAlign(), QQuickTextEdit::AlignRight);
507 QVERIFY(textEdit->positionToRectangle(0).x() > canvas.width()/2);
509 QString textString = textEdit->text();
510 textEdit->setText(QString("<i>") + textString + QString("</i>"));
511 textEdit->resetHAlign();
513 // implicitly aligned rich text should follow the reading direction of RTL text
514 QCOMPARE(textEdit->hAlign(), QQuickTextEdit::AlignRight);
515 QCOMPARE(textEdit->effectiveHAlign(), textEdit->hAlign());
516 QVERIFY(textEdit->positionToRectangle(0).x() > canvas.width()/2);
518 // explicitly left aligned rich text
519 textEdit->setHAlign(QQuickTextEdit::AlignLeft);
520 QCOMPARE(textEdit->hAlign(), QQuickTextEdit::AlignLeft);
521 QCOMPARE(textEdit->effectiveHAlign(), textEdit->hAlign());
522 QVERIFY(textEdit->positionToRectangle(0).x() < canvas.width()/2);
524 // explicitly right aligned rich text
525 textEdit->setHAlign(QQuickTextEdit::AlignRight);
526 QCOMPARE(textEdit->hAlign(), QQuickTextEdit::AlignRight);
527 QCOMPARE(textEdit->effectiveHAlign(), textEdit->hAlign());
528 QVERIFY(textEdit->positionToRectangle(0).x() > canvas.width()/2);
530 textEdit->setText(textString);
532 // explicitly center aligned
533 textEdit->setHAlign(QQuickTextEdit::AlignHCenter);
534 QCOMPARE(textEdit->hAlign(), QQuickTextEdit::AlignHCenter);
535 QVERIFY(textEdit->positionToRectangle(0).x() > canvas.width()/2);
537 // reseted alignment should go back to following the text reading direction
538 textEdit->resetHAlign();
539 QCOMPARE(textEdit->hAlign(), QQuickTextEdit::AlignRight);
540 QVERIFY(textEdit->positionToRectangle(0).x() > canvas.width()/2);
542 // mirror the text item
543 QQuickItemPrivate::get(textEdit)->setLayoutMirror(true);
545 // mirrored implicit alignment should continue to follow the reading direction of the text
546 QCOMPARE(textEdit->hAlign(), QQuickTextEdit::AlignRight);
547 QCOMPARE(textEdit->effectiveHAlign(), QQuickTextEdit::AlignRight);
548 QVERIFY(textEdit->positionToRectangle(0).x() > canvas.width()/2);
550 // mirrored explicitly right aligned behaves as left aligned
551 textEdit->setHAlign(QQuickTextEdit::AlignRight);
552 QCOMPARE(textEdit->hAlign(), QQuickTextEdit::AlignRight);
553 QCOMPARE(textEdit->effectiveHAlign(), QQuickTextEdit::AlignLeft);
554 QVERIFY(textEdit->positionToRectangle(0).x() < canvas.width()/2);
556 // mirrored explicitly left aligned behaves as right aligned
557 textEdit->setHAlign(QQuickTextEdit::AlignLeft);
558 QCOMPARE(textEdit->hAlign(), QQuickTextEdit::AlignLeft);
559 QCOMPARE(textEdit->effectiveHAlign(), QQuickTextEdit::AlignRight);
560 QVERIFY(textEdit->positionToRectangle(0).x() > canvas.width()/2);
563 QQuickItemPrivate::get(textEdit)->setLayoutMirror(false);
564 textEdit->resetHAlign();
566 // English text should be implicitly left aligned
567 textEdit->setText("Hello world!");
568 QCOMPARE(textEdit->hAlign(), QQuickTextEdit::AlignLeft);
569 QVERIFY(textEdit->positionToRectangle(0).x() < canvas.width()/2);
571 canvas.requestActivateWindow();
572 QTest::qWaitForWindowShown(&canvas);
573 QTRY_COMPARE(&canvas, qGuiApp->focusWindow());
575 textEdit->setText(QString());
576 { QInputMethodEvent ev(rtlText, QList<QInputMethodEvent::Attribute>()); QGuiApplication::sendEvent(&canvas, &ev); }
577 QEXPECT_FAIL("", "QTBUG-21691", Abort);
578 QCOMPARE(textEdit->hAlign(), QQuickTextEdit::AlignRight);
579 { QInputMethodEvent ev("Hello world!", QList<QInputMethodEvent::Attribute>()); QGuiApplication::sendEvent(&canvas, &ev); }
580 QCOMPARE(textEdit->hAlign(), QQuickTextEdit::AlignLeft);
582 #ifndef Q_OS_MAC // QTBUG-18040
583 // empty text with implicit alignment follows the system locale-based
584 // keyboard input direction from QGuiApplication::keyboardInputDirection
585 textEdit->setText("");
586 QCOMPARE(textEdit->hAlign(), QGuiApplication::keyboardInputDirection() == Qt::LeftToRight ?
587 QQuickTextEdit::AlignLeft : QQuickTextEdit::AlignRight);
588 if (QGuiApplication::keyboardInputDirection() == Qt::LeftToRight)
589 QVERIFY(textEdit->positionToRectangle(0).x() < canvas.width()/2);
591 QVERIFY(textEdit->positionToRectangle(0).x() > canvas.width()/2);
592 textEdit->setHAlign(QQuickTextEdit::AlignRight);
593 QCOMPARE(textEdit->hAlign(), QQuickTextEdit::AlignRight);
594 QVERIFY(textEdit->positionToRectangle(0).x() > canvas.width()/2);
597 #ifndef Q_OS_MAC // QTBUG-18040
598 // alignment of TextEdit with no text set to it
599 QString componentStr = "import QtQuick 2.0\nTextEdit {}";
600 QDeclarativeComponent textComponent(&engine);
601 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
602 QQuickTextEdit *textObject = qobject_cast<QQuickTextEdit*>(textComponent.create());
603 QCOMPARE(textObject->hAlign(), QGuiApplication::keyboardInputDirection() == Qt::LeftToRight ?
604 QQuickTextEdit::AlignLeft : QQuickTextEdit::AlignRight);
609 void tst_qquicktextedit::vAlign()
611 //test one align each, and then test if two align fails.
613 for (int i = 0; i < standard.size(); i++)
615 for (int j=0; j < vAlignmentStrings.size(); j++)
617 QString componentStr = "import QtQuick 2.0\nTextEdit { verticalAlignment: \"" + vAlignmentStrings.at(j) + "\"; text: \"" + standard.at(i) + "\" }";
618 QDeclarativeComponent texteditComponent(&engine);
619 texteditComponent.setData(componentStr.toLatin1(), QUrl());
620 QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
622 QVERIFY(textEditObject != 0);
623 QCOMPARE((int)textEditObject->vAlign(), (int)vAlignments.at(j));
627 for (int i = 0; i < richText.size(); i++)
629 for (int j=0; j < vAlignmentStrings.size(); j++)
631 QString componentStr = "import QtQuick 2.0\nTextEdit { verticalAlignment: \"" + vAlignmentStrings.at(j) + "\"; text: \"" + richText.at(i) + "\" }";
632 QDeclarativeComponent texteditComponent(&engine);
633 texteditComponent.setData(componentStr.toLatin1(), QUrl());
634 QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
636 QVERIFY(textEditObject != 0);
637 QCOMPARE((int)textEditObject->vAlign(), (int)vAlignments.at(j));
643 void tst_qquicktextedit::font()
645 //test size, then bold, then italic, then family
647 QString componentStr = "import QtQuick 2.0\nTextEdit { font.pointSize: 40; text: \"Hello World\" }";
648 QDeclarativeComponent texteditComponent(&engine);
649 texteditComponent.setData(componentStr.toLatin1(), QUrl());
650 QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
652 QVERIFY(textEditObject != 0);
653 QCOMPARE(textEditObject->font().pointSize(), 40);
654 QCOMPARE(textEditObject->font().bold(), false);
655 QCOMPARE(textEditObject->font().italic(), false);
659 QString componentStr = "import QtQuick 2.0\nTextEdit { font.bold: true; text: \"Hello World\" }";
660 QDeclarativeComponent texteditComponent(&engine);
661 texteditComponent.setData(componentStr.toLatin1(), QUrl());
662 QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
664 QVERIFY(textEditObject != 0);
665 QCOMPARE(textEditObject->font().bold(), true);
666 QCOMPARE(textEditObject->font().italic(), false);
670 QString componentStr = "import QtQuick 2.0\nTextEdit { font.italic: true; text: \"Hello World\" }";
671 QDeclarativeComponent texteditComponent(&engine);
672 texteditComponent.setData(componentStr.toLatin1(), QUrl());
673 QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
675 QVERIFY(textEditObject != 0);
676 QCOMPARE(textEditObject->font().italic(), true);
677 QCOMPARE(textEditObject->font().bold(), false);
681 QString componentStr = "import QtQuick 2.0\nTextEdit { font.family: \"Helvetica\"; text: \"Hello World\" }";
682 QDeclarativeComponent texteditComponent(&engine);
683 texteditComponent.setData(componentStr.toLatin1(), QUrl());
684 QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
686 QVERIFY(textEditObject != 0);
687 QCOMPARE(textEditObject->font().family(), QString("Helvetica"));
688 QCOMPARE(textEditObject->font().bold(), false);
689 QCOMPARE(textEditObject->font().italic(), false);
693 QString componentStr = "import QtQuick 2.0\nTextEdit { font.family: \"\"; text: \"Hello World\" }";
694 QDeclarativeComponent texteditComponent(&engine);
695 texteditComponent.setData(componentStr.toLatin1(), QUrl());
696 QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
698 QVERIFY(textEditObject != 0);
699 QCOMPARE(textEditObject->font().family(), QString(""));
703 void tst_qquicktextedit::color()
707 QString componentStr = "import QtQuick 2.0\nTextEdit { text: \"Hello World\" }";
708 QDeclarativeComponent texteditComponent(&engine);
709 texteditComponent.setData(componentStr.toLatin1(), QUrl());
710 QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
712 QQuickTextEditPrivate *textEditPrivate = static_cast<QQuickTextEditPrivate*>(QQuickItemPrivate::get(textEditObject));
714 QVERIFY(textEditObject);
715 QVERIFY(textEditPrivate);
716 QVERIFY(textEditPrivate->control);
718 QPalette pal = textEditPrivate->control->palette();
719 QCOMPARE(textEditPrivate->color, QColor("black"));
720 QCOMPARE(textEditPrivate->color, pal.color(QPalette::Text));
723 for (int i = 0; i < colorStrings.size(); i++)
725 QString componentStr = "import QtQuick 2.0\nTextEdit { color: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
726 QDeclarativeComponent texteditComponent(&engine);
727 texteditComponent.setData(componentStr.toLatin1(), QUrl());
728 QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
729 //qDebug() << "textEditObject: " << textEditObject->color() << "vs. " << QColor(colorStrings.at(i));
730 QVERIFY(textEditObject != 0);
731 QCOMPARE(textEditObject->color(), QColor(colorStrings.at(i)));
735 for (int i = 0; i < colorStrings.size(); i++)
737 QString componentStr = "import QtQuick 2.0\nTextEdit { selectionColor: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
738 QDeclarativeComponent texteditComponent(&engine);
739 texteditComponent.setData(componentStr.toLatin1(), QUrl());
740 QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
741 QVERIFY(textEditObject != 0);
742 QCOMPARE(textEditObject->selectionColor(), QColor(colorStrings.at(i)));
746 for (int i = 0; i < colorStrings.size(); i++)
748 QString componentStr = "import QtQuick 2.0\nTextEdit { selectedTextColor: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
749 QDeclarativeComponent texteditComponent(&engine);
750 texteditComponent.setData(componentStr.toLatin1(), QUrl());
751 QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
752 QVERIFY(textEditObject != 0);
753 QCOMPARE(textEditObject->selectedTextColor(), QColor(colorStrings.at(i)));
757 QString colorStr = "#AA001234";
758 QColor testColor("#001234");
759 testColor.setAlpha(170);
761 QString componentStr = "import QtQuick 2.0\nTextEdit { color: \"" + colorStr + "\"; text: \"Hello World\" }";
762 QDeclarativeComponent texteditComponent(&engine);
763 texteditComponent.setData(componentStr.toLatin1(), QUrl());
764 QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
766 QVERIFY(textEditObject != 0);
767 QCOMPARE(textEditObject->color(), testColor);
771 void tst_qquicktextedit::textMargin()
773 for (qreal i=0; i<=10; i+=0.3) {
774 QString componentStr = "import QtQuick 2.0\nTextEdit { textMargin: " + QString::number(i) + "; text: \"Hello World\" }";
775 QDeclarativeComponent texteditComponent(&engine);
776 texteditComponent.setData(componentStr.toLatin1(), QUrl());
777 QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
778 QVERIFY(textEditObject != 0);
779 QCOMPARE(textEditObject->textMargin(), i);
783 void tst_qquicktextedit::persistentSelection()
786 QString componentStr = "import QtQuick 2.0\nTextEdit { persistentSelection: true; text: \"Hello World\" }";
787 QDeclarativeComponent texteditComponent(&engine);
788 texteditComponent.setData(componentStr.toLatin1(), QUrl());
789 QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
790 QVERIFY(textEditObject != 0);
791 QCOMPARE(textEditObject->persistentSelection(), true);
795 QString componentStr = "import QtQuick 2.0\nTextEdit { persistentSelection: false; text: \"Hello World\" }";
796 QDeclarativeComponent texteditComponent(&engine);
797 texteditComponent.setData(componentStr.toLatin1(), QUrl());
798 QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
799 QVERIFY(textEditObject != 0);
800 QCOMPARE(textEditObject->persistentSelection(), false);
804 void tst_qquicktextedit::focusOnPress()
807 QString componentStr = "import QtQuick 2.0\nTextEdit { activeFocusOnPress: true; text: \"Hello World\" }";
808 QDeclarativeComponent texteditComponent(&engine);
809 texteditComponent.setData(componentStr.toLatin1(), QUrl());
810 QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
811 QVERIFY(textEditObject != 0);
812 QCOMPARE(textEditObject->focusOnPress(), true);
816 QString componentStr = "import QtQuick 2.0\nTextEdit { activeFocusOnPress: false; text: \"Hello World\" }";
817 QDeclarativeComponent texteditComponent(&engine);
818 texteditComponent.setData(componentStr.toLatin1(), QUrl());
819 QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
820 QVERIFY(textEditObject != 0);
821 QCOMPARE(textEditObject->focusOnPress(), false);
825 void tst_qquicktextedit::selection()
827 QString testStr = standard[0];//TODO: What should happen for multiline/rich text?
828 QString componentStr = "import QtQuick 2.0\nTextEdit { text: \""+ testStr +"\"; }";
829 QDeclarativeComponent texteditComponent(&engine);
830 texteditComponent.setData(componentStr.toLatin1(), QUrl());
831 QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
832 QVERIFY(textEditObject != 0);
835 //Test selection follows cursor
836 for (int i=0; i<= testStr.size(); i++) {
837 textEditObject->setCursorPosition(i);
838 QCOMPARE(textEditObject->cursorPosition(), i);
839 QCOMPARE(textEditObject->selectionStart(), i);
840 QCOMPARE(textEditObject->selectionEnd(), i);
841 QVERIFY(textEditObject->selectedText().isNull());
844 textEditObject->setCursorPosition(0);
845 QVERIFY(textEditObject->cursorPosition() == 0);
846 QVERIFY(textEditObject->selectionStart() == 0);
847 QVERIFY(textEditObject->selectionEnd() == 0);
848 QVERIFY(textEditObject->selectedText().isNull());
850 // Verify invalid positions are ignored.
851 textEditObject->setCursorPosition(-1);
852 QVERIFY(textEditObject->cursorPosition() == 0);
853 QVERIFY(textEditObject->selectionStart() == 0);
854 QVERIFY(textEditObject->selectionEnd() == 0);
855 QVERIFY(textEditObject->selectedText().isNull());
857 textEditObject->setCursorPosition(textEditObject->text().count()+1);
858 QVERIFY(textEditObject->cursorPosition() == 0);
859 QVERIFY(textEditObject->selectionStart() == 0);
860 QVERIFY(textEditObject->selectionEnd() == 0);
861 QVERIFY(textEditObject->selectedText().isNull());
864 for (int i=0; i<= testStr.size(); i++) {
865 textEditObject->select(0,i);
866 QCOMPARE(testStr.mid(0,i), textEditObject->selectedText());
868 for (int i=0; i<= testStr.size(); i++) {
869 textEditObject->select(i,testStr.size());
870 QCOMPARE(testStr.mid(i,testStr.size()-i), textEditObject->selectedText());
873 textEditObject->setCursorPosition(0);
874 QVERIFY(textEditObject->cursorPosition() == 0);
875 QVERIFY(textEditObject->selectionStart() == 0);
876 QVERIFY(textEditObject->selectionEnd() == 0);
877 QVERIFY(textEditObject->selectedText().isNull());
879 //Test Error Ignoring behaviour
880 textEditObject->setCursorPosition(0);
881 QVERIFY(textEditObject->selectedText().isNull());
882 textEditObject->select(-10,0);
883 QVERIFY(textEditObject->selectedText().isNull());
884 textEditObject->select(100,101);
885 QVERIFY(textEditObject->selectedText().isNull());
886 textEditObject->select(0,-10);
887 QVERIFY(textEditObject->selectedText().isNull());
888 textEditObject->select(0,100);
889 QVERIFY(textEditObject->selectedText().isNull());
890 textEditObject->select(0,10);
891 QVERIFY(textEditObject->selectedText().size() == 10);
892 textEditObject->select(-10,0);
893 QVERIFY(textEditObject->selectedText().size() == 10);
894 textEditObject->select(100,101);
895 QVERIFY(textEditObject->selectedText().size() == 10);
896 textEditObject->select(0,-10);
897 QVERIFY(textEditObject->selectedText().size() == 10);
898 textEditObject->select(0,100);
899 QVERIFY(textEditObject->selectedText().size() == 10);
901 textEditObject->deselect();
902 QVERIFY(textEditObject->selectedText().isNull());
903 textEditObject->select(0,10);
904 QVERIFY(textEditObject->selectedText().size() == 10);
905 textEditObject->deselect();
906 QVERIFY(textEditObject->selectedText().isNull());
909 void tst_qquicktextedit::isRightToLeft_data()
911 QTest::addColumn<QString>("text");
912 QTest::addColumn<bool>("emptyString");
913 QTest::addColumn<bool>("firstCharacter");
914 QTest::addColumn<bool>("lastCharacter");
915 QTest::addColumn<bool>("middleCharacter");
916 QTest::addColumn<bool>("startString");
917 QTest::addColumn<bool>("midString");
918 QTest::addColumn<bool>("endString");
920 const quint16 arabic_str[] = { 0x0638, 0x0643, 0x00646, 0x0647, 0x0633, 0x0638, 0x0643, 0x00646, 0x0647, 0x0633, 0x0647};
921 QTest::newRow("Empty") << "" << false << false << false << false << false << false << false;
922 QTest::newRow("Neutral") << "23244242" << false << false << false << false << false << false << false;
923 QTest::newRow("LTR") << "Hello world" << false << false << false << false << false << false << false;
924 QTest::newRow("RTL") << QString::fromUtf16(arabic_str, 11) << false << true << true << true << true << true << true;
925 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;
926 QTest::newRow("Bidi LTR + RTL + LTR") << QString("Hello world") + QString::fromUtf16(arabic_str, 11) + QString("Hello world") << false << false << false << true << false << false << false;
929 void tst_qquicktextedit::isRightToLeft()
931 QFETCH(QString, text);
932 QFETCH(bool, emptyString);
933 QFETCH(bool, firstCharacter);
934 QFETCH(bool, lastCharacter);
935 QFETCH(bool, middleCharacter);
936 QFETCH(bool, startString);
937 QFETCH(bool, midString);
938 QFETCH(bool, endString);
940 QQuickTextEdit textEdit;
941 textEdit.setText(text);
943 // first test that the right string is delivered to the QString::isRightToLeft()
944 QCOMPARE(textEdit.isRightToLeft(0,0), text.mid(0,0).isRightToLeft());
945 QCOMPARE(textEdit.isRightToLeft(0,1), text.mid(0,1).isRightToLeft());
946 QCOMPARE(textEdit.isRightToLeft(text.count()-2, text.count()-1), text.mid(text.count()-2, text.count()-1).isRightToLeft());
947 QCOMPARE(textEdit.isRightToLeft(text.count()/2, text.count()/2 + 1), text.mid(text.count()/2, text.count()/2 + 1).isRightToLeft());
948 QCOMPARE(textEdit.isRightToLeft(0,text.count()/4), text.mid(0,text.count()/4).isRightToLeft());
949 QCOMPARE(textEdit.isRightToLeft(text.count()/4,3*text.count()/4), text.mid(text.count()/4,3*text.count()/4).isRightToLeft());
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), text.mid(3*text.count()/4,text.count()-1).isRightToLeft());
954 // then test that the feature actually works
955 QCOMPARE(textEdit.isRightToLeft(0,0), emptyString);
956 QCOMPARE(textEdit.isRightToLeft(0,1), firstCharacter);
957 QCOMPARE(textEdit.isRightToLeft(text.count()-2, text.count()-1), lastCharacter);
958 QCOMPARE(textEdit.isRightToLeft(text.count()/2, text.count()/2 + 1), middleCharacter);
959 QCOMPARE(textEdit.isRightToLeft(0,text.count()/4), startString);
960 QCOMPARE(textEdit.isRightToLeft(text.count()/4,3*text.count()/4), midString);
962 QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML TextEdit: isRightToLeft(start, end) called with the end property being smaller than the start.");
963 QCOMPARE(textEdit.isRightToLeft(3*text.count()/4,text.count()-1), endString);
966 void tst_qquicktextedit::keySelection()
968 QQuickView canvas(QUrl::fromLocalFile(TESTDATA("navigation.qml")));
970 canvas.requestActivateWindow();
971 QTest::qWaitForWindowShown(&canvas);
972 QTRY_COMPARE(&canvas, qGuiApp->focusWindow());
973 canvas.requestActivateWindow();
975 QVERIFY(canvas.rootObject() != 0);
977 QQuickTextEdit *input = qobject_cast<QQuickTextEdit *>(qvariant_cast<QObject *>(canvas.rootObject()->property("myInput")));
980 QTRY_VERIFY(input->hasActiveFocus() == true);
982 QSignalSpy spy(input, SIGNAL(selectionChanged()));
984 simulateKey(&canvas, Qt::Key_Right, Qt::ShiftModifier);
985 QVERIFY(input->hasActiveFocus() == true);
986 QCOMPARE(input->selectedText(), QString("a"));
987 QCOMPARE(spy.count(), 1);
988 simulateKey(&canvas, Qt::Key_Right);
989 QVERIFY(input->hasActiveFocus() == true);
990 QCOMPARE(input->selectedText(), QString());
991 QCOMPARE(spy.count(), 2);
992 simulateKey(&canvas, Qt::Key_Right);
993 QVERIFY(input->hasActiveFocus() == false);
994 QCOMPARE(input->selectedText(), QString());
995 QCOMPARE(spy.count(), 2);
997 simulateKey(&canvas, Qt::Key_Left);
998 QVERIFY(input->hasActiveFocus() == true);
999 QCOMPARE(spy.count(), 2);
1000 simulateKey(&canvas, Qt::Key_Left, Qt::ShiftModifier);
1001 QVERIFY(input->hasActiveFocus() == true);
1002 QCOMPARE(input->selectedText(), QString("a"));
1003 QCOMPARE(spy.count(), 3);
1004 simulateKey(&canvas, Qt::Key_Left);
1005 QVERIFY(input->hasActiveFocus() == true);
1006 QCOMPARE(input->selectedText(), QString());
1007 QCOMPARE(spy.count(), 4);
1008 simulateKey(&canvas, Qt::Key_Left);
1009 QVERIFY(input->hasActiveFocus() == false);
1010 QCOMPARE(input->selectedText(), QString());
1011 QCOMPARE(spy.count(), 4);
1014 void tst_qquicktextedit::moveCursorSelection_data()
1016 QTest::addColumn<QString>("testStr");
1017 QTest::addColumn<int>("cursorPosition");
1018 QTest::addColumn<int>("movePosition");
1019 QTest::addColumn<QQuickTextEdit::SelectionMode>("mode");
1020 QTest::addColumn<int>("selectionStart");
1021 QTest::addColumn<int>("selectionEnd");
1022 QTest::addColumn<bool>("reversible");
1024 QTest::newRow("(t)he|characters")
1025 << standard[0] << 0 << 1 << QQuickTextEdit::SelectCharacters << 0 << 1 << true;
1026 QTest::newRow("do(g)|characters")
1027 << standard[0] << 43 << 44 << QQuickTextEdit::SelectCharacters << 43 << 44 << true;
1028 QTest::newRow("jum(p)ed|characters")
1029 << standard[0] << 23 << 24 << QQuickTextEdit::SelectCharacters << 23 << 24 << true;
1030 QTest::newRow("jumped( )over|characters")
1031 << standard[0] << 26 << 27 << QQuickTextEdit::SelectCharacters << 26 << 27 << true;
1032 QTest::newRow("(the )|characters")
1033 << standard[0] << 0 << 4 << QQuickTextEdit::SelectCharacters << 0 << 4 << true;
1034 QTest::newRow("( dog)|characters")
1035 << standard[0] << 40 << 44 << QQuickTextEdit::SelectCharacters << 40 << 44 << true;
1036 QTest::newRow("( jumped )|characters")
1037 << standard[0] << 19 << 27 << QQuickTextEdit::SelectCharacters << 19 << 27 << true;
1038 QTest::newRow("th(e qu)ick|characters")
1039 << standard[0] << 2 << 6 << QQuickTextEdit::SelectCharacters << 2 << 6 << true;
1040 QTest::newRow("la(zy d)og|characters")
1041 << standard[0] << 38 << 42 << QQuickTextEdit::SelectCharacters << 38 << 42 << true;
1042 QTest::newRow("jum(ped ov)er|characters")
1043 << standard[0] << 23 << 29 << QQuickTextEdit::SelectCharacters << 23 << 29 << true;
1044 QTest::newRow("()the|characters")
1045 << standard[0] << 0 << 0 << QQuickTextEdit::SelectCharacters << 0 << 0 << true;
1046 QTest::newRow("dog()|characters")
1047 << standard[0] << 44 << 44 << QQuickTextEdit::SelectCharacters << 44 << 44 << true;
1048 QTest::newRow("jum()ped|characters")
1049 << standard[0] << 23 << 23 << QQuickTextEdit::SelectCharacters << 23 << 23 << true;
1051 QTest::newRow("<(t)he>|words")
1052 << standard[0] << 0 << 1 << QQuickTextEdit::SelectWords << 0 << 3 << true;
1053 QTest::newRow("<do(g)>|words")
1054 << standard[0] << 43 << 44 << QQuickTextEdit::SelectWords << 41 << 44 << true;
1055 QTest::newRow("<jum(p)ed>|words")
1056 << standard[0] << 23 << 24 << QQuickTextEdit::SelectWords << 20 << 26 << true;
1057 QTest::newRow("<jumped( )>over|words")
1058 << standard[0] << 26 << 27 << QQuickTextEdit::SelectWords << 20 << 27 << false;
1059 QTest::newRow("jumped<( )over>|words,reversed")
1060 << standard[0] << 27 << 26 << QQuickTextEdit::SelectWords << 26 << 31 << false;
1061 QTest::newRow("<(the )>quick|words")
1062 << standard[0] << 0 << 4 << QQuickTextEdit::SelectWords << 0 << 4 << false;
1063 QTest::newRow("<(the )quick>|words,reversed")
1064 << standard[0] << 4 << 0 << QQuickTextEdit::SelectWords << 0 << 9 << false;
1065 QTest::newRow("<lazy( dog)>|words")
1066 << standard[0] << 40 << 44 << QQuickTextEdit::SelectWords << 36 << 44 << false;
1067 QTest::newRow("lazy<( dog)>|words,reversed")
1068 << standard[0] << 44 << 40 << QQuickTextEdit::SelectWords << 40 << 44 << false;
1069 QTest::newRow("<fox( jumped )>over|words")
1070 << standard[0] << 19 << 27 << QQuickTextEdit::SelectWords << 16 << 27 << false;
1071 QTest::newRow("fox<( jumped )over>|words,reversed")
1072 << standard[0] << 27 << 19 << QQuickTextEdit::SelectWords << 19 << 31 << false;
1073 QTest::newRow("<th(e qu)ick>|words")
1074 << standard[0] << 2 << 6 << QQuickTextEdit::SelectWords << 0 << 9 << true;
1075 QTest::newRow("<la(zy d)og|words>")
1076 << standard[0] << 38 << 42 << QQuickTextEdit::SelectWords << 36 << 44 << true;
1077 QTest::newRow("<jum(ped ov)er>|words")
1078 << standard[0] << 23 << 29 << QQuickTextEdit::SelectWords << 20 << 31 << true;
1079 QTest::newRow("<()>the|words")
1080 << standard[0] << 0 << 0 << QQuickTextEdit::SelectWords << 0 << 0 << true;
1081 QTest::newRow("dog<()>|words")
1082 << standard[0] << 44 << 44 << QQuickTextEdit::SelectWords << 44 << 44 << true;
1083 QTest::newRow("jum<()>ped|words")
1084 << standard[0] << 23 << 23 << QQuickTextEdit::SelectWords << 23 << 23 << true;
1086 QTest::newRow("Hello<(,)> |words")
1087 << standard[2] << 5 << 6 << QQuickTextEdit::SelectWords << 5 << 6 << true;
1088 QTest::newRow("Hello<(, )>world|words")
1089 << standard[2] << 5 << 7 << QQuickTextEdit::SelectWords << 5 << 7 << false;
1090 QTest::newRow("Hello<(, )world>|words,reversed")
1091 << standard[2] << 7 << 5 << QQuickTextEdit::SelectWords << 5 << 12 << false;
1092 QTest::newRow("<Hel(lo, )>world|words")
1093 << standard[2] << 3 << 7 << QQuickTextEdit::SelectWords << 0 << 7 << false;
1094 QTest::newRow("<Hel(lo, )world>|words,reversed")
1095 << standard[2] << 7 << 3 << QQuickTextEdit::SelectWords << 0 << 12 << false;
1096 QTest::newRow("<Hel(lo)>,|words")
1097 << standard[2] << 3 << 5 << QQuickTextEdit::SelectWords << 0 << 5 << true;
1098 QTest::newRow("Hello<()>,|words")
1099 << standard[2] << 5 << 5 << QQuickTextEdit::SelectWords << 5 << 5 << true;
1100 QTest::newRow("Hello,<()>|words")
1101 << standard[2] << 6 << 6 << QQuickTextEdit::SelectWords << 6 << 6 << true;
1102 QTest::newRow("Hello<,( )>world|words")
1103 << standard[2] << 6 << 7 << QQuickTextEdit::SelectWords << 5 << 7 << false;
1104 QTest::newRow("Hello,<( )world>|words,reversed")
1105 << standard[2] << 7 << 6 << QQuickTextEdit::SelectWords << 6 << 12 << false;
1106 QTest::newRow("Hello<,( world)>|words")
1107 << standard[2] << 6 << 12 << QQuickTextEdit::SelectWords << 5 << 12 << false;
1108 QTest::newRow("Hello,<( world)>|words,reversed")
1109 << standard[2] << 12 << 6 << QQuickTextEdit::SelectWords << 6 << 12 << false;
1110 QTest::newRow("Hello<,( world!)>|words")
1111 << standard[2] << 6 << 13 << QQuickTextEdit::SelectWords << 5 << 13 << false;
1112 QTest::newRow("Hello,<( world!)>|words,reversed")
1113 << standard[2] << 13 << 6 << QQuickTextEdit::SelectWords << 6 << 13 << false;
1114 QTest::newRow("Hello<(, world!)>|words")
1115 << standard[2] << 5 << 13 << QQuickTextEdit::SelectWords << 5 << 13 << true;
1116 QTest::newRow("world<(!)>|words")
1117 << standard[2] << 12 << 13 << QQuickTextEdit::SelectWords << 12 << 13 << true;
1118 QTest::newRow("world!<()>)|words")
1119 << standard[2] << 13 << 13 << QQuickTextEdit::SelectWords << 13 << 13 << true;
1120 QTest::newRow("world<()>!)|words")
1121 << standard[2] << 12 << 12 << QQuickTextEdit::SelectWords << 12 << 12 << true;
1123 QTest::newRow("<(,)>olleH |words")
1124 << standard[3] << 7 << 8 << QQuickTextEdit::SelectWords << 7 << 8 << true;
1125 QTest::newRow("<dlrow( ,)>olleH|words")
1126 << standard[3] << 6 << 8 << QQuickTextEdit::SelectWords << 1 << 8 << false;
1127 QTest::newRow("dlrow<( ,)>olleH|words,reversed")
1128 << standard[3] << 8 << 6 << QQuickTextEdit::SelectWords << 6 << 8 << false;
1129 QTest::newRow("<dlrow( ,ol)leH>|words")
1130 << standard[3] << 6 << 10 << QQuickTextEdit::SelectWords << 1 << 13 << false;
1131 QTest::newRow("dlrow<( ,ol)leH>|words,reversed")
1132 << standard[3] << 10 << 6 << QQuickTextEdit::SelectWords << 6 << 13 << false;
1133 QTest::newRow(",<(ol)leH>,|words")
1134 << standard[3] << 8 << 10 << QQuickTextEdit::SelectWords << 8 << 13 << true;
1135 QTest::newRow(",<()>olleH|words")
1136 << standard[3] << 8 << 8 << QQuickTextEdit::SelectWords << 8 << 8 << true;
1137 QTest::newRow("<()>,olleH|words")
1138 << standard[3] << 7 << 7 << QQuickTextEdit::SelectWords << 7 << 7 << true;
1139 QTest::newRow("<dlrow( )>,olleH|words")
1140 << standard[3] << 6 << 7 << QQuickTextEdit::SelectWords << 1 << 7 << false;
1141 QTest::newRow("dlrow<( ),>olleH|words,reversed")
1142 << standard[3] << 7 << 6 << QQuickTextEdit::SelectWords << 6 << 8 << false;
1143 QTest::newRow("<(dlrow )>,olleH|words")
1144 << standard[3] << 1 << 7 << QQuickTextEdit::SelectWords << 1 << 7 << false;
1145 QTest::newRow("<(dlrow ),>olleH|words,reversed")
1146 << standard[3] << 7 << 1 << QQuickTextEdit::SelectWords << 1 << 8 << false;
1147 QTest::newRow("<(!dlrow )>,olleH|words")
1148 << standard[3] << 0 << 7 << QQuickTextEdit::SelectWords << 0 << 7 << false;
1149 QTest::newRow("<(!dlrow ),>olleH|words,reversed")
1150 << standard[3] << 7 << 0 << QQuickTextEdit::SelectWords << 0 << 8 << false;
1151 QTest::newRow("(!dlrow ,)olleH|words")
1152 << standard[3] << 0 << 8 << QQuickTextEdit::SelectWords << 0 << 8 << true;
1153 QTest::newRow("<(!)>dlrow|words")
1154 << standard[3] << 0 << 1 << QQuickTextEdit::SelectWords << 0 << 1 << true;
1155 QTest::newRow("<()>!dlrow|words")
1156 << standard[3] << 0 << 0 << QQuickTextEdit::SelectWords << 0 << 0 << true;
1157 QTest::newRow("!<()>dlrow|words")
1158 << standard[3] << 1 << 1 << QQuickTextEdit::SelectWords << 1 << 1 << true;
1161 void tst_qquicktextedit::moveCursorSelection()
1163 QFETCH(QString, testStr);
1164 QFETCH(int, cursorPosition);
1165 QFETCH(int, movePosition);
1166 QFETCH(QQuickTextEdit::SelectionMode, mode);
1167 QFETCH(int, selectionStart);
1168 QFETCH(int, selectionEnd);
1169 QFETCH(bool, reversible);
1171 QString componentStr = "import QtQuick 2.0\nTextEdit { text: \""+ testStr +"\"; }";
1172 QDeclarativeComponent textinputComponent(&engine);
1173 textinputComponent.setData(componentStr.toLatin1(), QUrl());
1174 QQuickTextEdit *texteditObject = qobject_cast<QQuickTextEdit*>(textinputComponent.create());
1175 QVERIFY(texteditObject != 0);
1177 texteditObject->setCursorPosition(cursorPosition);
1178 texteditObject->moveCursorSelection(movePosition, mode);
1180 QCOMPARE(texteditObject->selectedText(), testStr.mid(selectionStart, selectionEnd - selectionStart));
1181 QCOMPARE(texteditObject->selectionStart(), selectionStart);
1182 QCOMPARE(texteditObject->selectionEnd(), selectionEnd);
1185 texteditObject->setCursorPosition(movePosition);
1186 texteditObject->moveCursorSelection(cursorPosition, mode);
1188 QCOMPARE(texteditObject->selectedText(), testStr.mid(selectionStart, selectionEnd - selectionStart));
1189 QCOMPARE(texteditObject->selectionStart(), selectionStart);
1190 QCOMPARE(texteditObject->selectionEnd(), selectionEnd);
1194 void tst_qquicktextedit::moveCursorSelectionSequence_data()
1196 QTest::addColumn<QString>("testStr");
1197 QTest::addColumn<int>("cursorPosition");
1198 QTest::addColumn<int>("movePosition1");
1199 QTest::addColumn<int>("movePosition2");
1200 QTest::addColumn<int>("selection1Start");
1201 QTest::addColumn<int>("selection1End");
1202 QTest::addColumn<int>("selection2Start");
1203 QTest::addColumn<int>("selection2End");
1205 QTest::newRow("the {<quick( bro)wn> f^ox} jumped|ltr")
1210 QTest::newRow("the quick<( {bro)wn> f^ox} jumped|rtl")
1215 QTest::newRow("the {<quick( bro)wn> ^}fox jumped|ltr")
1220 QTest::newRow("the quick<( {bro)wn> ^}fox jumped|rtl")
1225 QTest::newRow("the {<quick( bro)wn^>} fox jumped|ltr")
1230 QTest::newRow("the quick<( {bro)wn^>} f^ox jumped|rtl")
1235 QTest::newRow("the {<quick() ^}bro)wn> fox|ltr")
1240 QTest::newRow("the quick<(^ {^bro)wn>} fox|rtl")
1245 QTest::newRow("the {<quick^}( bro)wn> fox|ltr")
1250 QTest::newRow("the quick{<(^ bro)wn>} fox|rtl")
1255 QTest::newRow("the {<qui^ck}( bro)wn> fox|ltr")
1260 QTest::newRow("the {<qui^ck}( bro)wn> fox|rtl")
1265 QTest::newRow("the {<^quick}( bro)wn> fox|ltr")
1270 QTest::newRow("the {<^quick}( bro)wn> fox|rtl")
1275 QTest::newRow("the{^ <quick}( bro)wn> fox|ltr")
1280 QTest::newRow("the{^ <quick}( bro)wn> fox|rtl")
1285 QTest::newRow("{t^he <quick}( bro)wn> fox|ltr")
1290 QTest::newRow("{t^he <quick}( bro)wn> fox|rtl")
1296 QTest::newRow("{<He(ll)o>, w^orld}!|ltr")
1301 QTest::newRow("{<He(ll)o>, w^orld}!|rtl")
1307 QTest::newRow("!{dlro^w ,<o(ll)eH>}|ltr")
1312 QTest::newRow("!{dlro^w ,<o(ll)eH>}|rtl")
1319 void tst_qquicktextedit::moveCursorSelectionSequence()
1321 QFETCH(QString, testStr);
1322 QFETCH(int, cursorPosition);
1323 QFETCH(int, movePosition1);
1324 QFETCH(int, movePosition2);
1325 QFETCH(int, selection1Start);
1326 QFETCH(int, selection1End);
1327 QFETCH(int, selection2Start);
1328 QFETCH(int, selection2End);
1330 QString componentStr = "import QtQuick 2.0\nTextEdit { text: \""+ testStr +"\"; }";
1331 QDeclarativeComponent texteditComponent(&engine);
1332 texteditComponent.setData(componentStr.toLatin1(), QUrl());
1333 QQuickTextEdit *texteditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create());
1334 QVERIFY(texteditObject != 0);
1336 texteditObject->setCursorPosition(cursorPosition);
1338 texteditObject->moveCursorSelection(movePosition1, QQuickTextEdit::SelectWords);
1339 QCOMPARE(texteditObject->selectedText(), testStr.mid(selection1Start, selection1End - selection1Start));
1340 QCOMPARE(texteditObject->selectionStart(), selection1Start);
1341 QCOMPARE(texteditObject->selectionEnd(), selection1End);
1343 texteditObject->moveCursorSelection(movePosition2, QQuickTextEdit::SelectWords);
1344 QCOMPARE(texteditObject->selectedText(), testStr.mid(selection2Start, selection2End - selection2Start));
1345 QCOMPARE(texteditObject->selectionStart(), selection2Start);
1346 QCOMPARE(texteditObject->selectionEnd(), selection2End);
1350 void tst_qquicktextedit::mouseSelection_data()
1352 QTest::addColumn<QString>("qmlfile");
1353 QTest::addColumn<int>("from");
1354 QTest::addColumn<int>("to");
1355 QTest::addColumn<QString>("selectedText");
1358 QTest::newRow("on") << TESTDATA("mouseselection_true.qml") << 4 << 9 << "45678";
1359 QTest::newRow("off") << TESTDATA("mouseselection_false.qml") << 4 << 9 << QString();
1360 QTest::newRow("default") << TESTDATA("mouseselection_default.qml") << 4 << 9 << QString();
1361 QTest::newRow("off word selection") << TESTDATA("mouseselection_false_words.qml") << 4 << 9 << QString();
1362 QTest::newRow("on word selection (4,9)") << TESTDATA("mouseselection_true_words.qml") << 4 << 9 << "0123456789";
1363 QTest::newRow("on word selection (2,13)") << TESTDATA("mouseselection_true_words.qml") << 2 << 13 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1364 QTest::newRow("on word selection (2,30)") << TESTDATA("mouseselection_true_words.qml") << 2 << 30 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1365 QTest::newRow("on word selection (9,13)") << TESTDATA("mouseselection_true_words.qml") << 9 << 13 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1366 QTest::newRow("on word selection (9,30)") << TESTDATA("mouseselection_true_words.qml") << 9 << 30 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1367 QTest::newRow("on word selection (13,2)") << TESTDATA("mouseselection_true_words.qml") << 13 << 2 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1368 QTest::newRow("on word selection (20,2)") << TESTDATA("mouseselection_true_words.qml") << 20 << 2 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1369 QTest::newRow("on word selection (12,9)") << TESTDATA("mouseselection_true_words.qml") << 12 << 9 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1370 QTest::newRow("on word selection (30,9)") << TESTDATA("mouseselection_true_words.qml") << 30 << 9 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1373 void tst_qquicktextedit::mouseSelection()
1375 QFETCH(QString, qmlfile);
1378 QFETCH(QString, selectedText);
1380 QQuickView canvas(QUrl::fromLocalFile(qmlfile));
1383 canvas.requestActivateWindow();
1384 QTest::qWaitForWindowShown(&canvas);
1385 QTRY_COMPARE(&canvas, qGuiApp->focusWindow());
1387 QVERIFY(canvas.rootObject() != 0);
1388 QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit *>(canvas.rootObject());
1389 QVERIFY(textEditObject != 0);
1391 // press-and-drag-and-release from x1 to x2
1392 QPoint p1 = textEditObject->positionToRectangle(from).center().toPoint();
1393 QPoint p2 = textEditObject->positionToRectangle(to).center().toPoint();
1394 QTest::mousePress(&canvas, Qt::LeftButton, 0, p1);
1395 QTest::mouseMove(&canvas, p2);
1396 QTest::mouseRelease(&canvas, Qt::LeftButton, 0, p2);
1398 QTRY_COMPARE(textEditObject->selectedText(), selectedText);
1400 // Clicking and shift to clicking between the same points should select the same text.
1401 textEditObject->setCursorPosition(0);
1402 QTest::mouseClick(&canvas, Qt::LeftButton, Qt::NoModifier, p1);
1403 QTest::mouseClick(&canvas, Qt::LeftButton, Qt::ShiftModifier, p2);
1405 if (!selectedText.isEmpty())
1406 QEXPECT_FAIL("", "QTBUG-21743", Continue);
1407 QTRY_COMPARE(textEditObject->selectedText(), selectedText);
1410 void tst_qquicktextedit::dragMouseSelection()
1412 QString qmlfile = TESTDATA("mouseselection_true.qml");
1414 QQuickView canvas(QUrl::fromLocalFile(qmlfile));
1417 canvas.requestActivateWindow();
1418 QTest::qWaitForWindowShown(&canvas);
1419 QTRY_COMPARE(&canvas, qGuiApp->focusWindow());
1421 QVERIFY(canvas.rootObject() != 0);
1422 QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit *>(canvas.rootObject());
1423 QVERIFY(textEditObject != 0);
1425 // press-and-drag-and-release from x1 to x2
1428 int y = textEditObject->height()/2;
1429 QTest::mousePress(&canvas, Qt::LeftButton, 0, QPoint(x1,y));
1430 QTest::mouseMove(&canvas, QPoint(x2, y));
1431 QTest::mouseRelease(&canvas, Qt::LeftButton, 0, QPoint(x2,y));
1434 QTRY_VERIFY((str1 = textEditObject->selectedText()).length() > 3);
1436 // press and drag the current selection.
1439 QTest::mousePress(&canvas, Qt::LeftButton, 0, QPoint(x1,y));
1440 QTest::mouseMove(&canvas, QPoint(x2, y));
1441 QTest::mouseRelease(&canvas, Qt::LeftButton, 0, QPoint(x2,y));
1444 QTRY_VERIFY((str2 = textEditObject->selectedText()).length() > 3);
1446 QVERIFY(str1 != str2); // Verify the second press and drag is a new selection and not the first moved.
1449 void tst_qquicktextedit::mouseSelectionMode_data()
1451 QTest::addColumn<QString>("qmlfile");
1452 QTest::addColumn<bool>("selectWords");
1455 QTest::newRow("SelectWords") << TESTDATA("mouseselectionmode_words.qml") << true;
1456 QTest::newRow("SelectCharacters") << TESTDATA("mouseselectionmode_characters.qml") << false;
1457 QTest::newRow("default") << TESTDATA("mouseselectionmode_default.qml") << false;
1460 void tst_qquicktextedit::mouseSelectionMode()
1462 QFETCH(QString, qmlfile);
1463 QFETCH(bool, selectWords);
1465 QString text = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1467 QQuickView canvas(QUrl::fromLocalFile(qmlfile));
1470 canvas.requestActivateWindow();
1471 QTest::qWaitForWindowShown(&canvas);
1472 QTRY_COMPARE(&canvas, qGuiApp->focusWindow());
1474 QVERIFY(canvas.rootObject() != 0);
1475 QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit *>(canvas.rootObject());
1476 QVERIFY(textEditObject != 0);
1478 // press-and-drag-and-release from x1 to x2
1481 int y = textEditObject->height()/2;
1482 QTest::mousePress(&canvas, Qt::LeftButton, 0, QPoint(x1,y));
1483 QTest::mouseMove(&canvas, QPoint(x2, y));
1484 //QTest::mouseMove(canvas, QPoint(x2,y)); // doesn't work
1485 // QMouseEvent mv(QEvent::MouseMove, QPoint(x2,y), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
1486 // QGuiApplication::sendEvent(&canvas, &mv);
1487 QTest::mouseRelease(&canvas, Qt::LeftButton, 0, QPoint(x2,y));
1488 QString str = textEditObject->selectedText();
1490 QTRY_COMPARE(textEditObject->selectedText(), text);
1492 QTRY_VERIFY(textEditObject->selectedText().length() > 3);
1493 QVERIFY(str != text);
1497 void tst_qquicktextedit::inputMethodHints()
1499 QQuickView canvas(QUrl::fromLocalFile(TESTDATA("inputmethodhints.qml")));
1501 canvas.requestActivateWindow();
1503 QVERIFY(canvas.rootObject() != 0);
1504 QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit *>(canvas.rootObject());
1505 QVERIFY(textEditObject != 0);
1506 QVERIFY(textEditObject->inputMethodHints() & Qt::ImhNoPredictiveText);
1507 textEditObject->setInputMethodHints(Qt::ImhUppercaseOnly);
1508 QVERIFY(textEditObject->inputMethodHints() & Qt::ImhUppercaseOnly);
1511 void tst_qquicktextedit::positionAt()
1513 QQuickView canvas(QUrl::fromLocalFile(TESTDATA("positionAt.qml")));
1514 QVERIFY(canvas.rootObject() != 0);
1516 canvas.requestActivateWindow();
1517 canvas.requestActivateWindow();
1518 QTest::qWaitForWindowShown(&canvas);
1520 QQuickTextEdit *texteditObject = qobject_cast<QQuickTextEdit *>(canvas.rootObject());
1521 QVERIFY(texteditObject != 0);
1523 QFontMetrics fm(texteditObject->font());
1524 const int y0 = fm.height() / 2;
1525 const int y1 = fm.height() * 3 / 2;
1527 int pos = texteditObject->positionAt(texteditObject->width()/2, y0);
1529 if (!qmlDisableDistanceField()) {
1530 QTextLayout layout(texteditObject->text().left(pos));
1534 option.setUseDesignMetrics(true);
1535 layout.setTextOption(option);
1538 layout.beginLayout();
1539 QTextLine line = layout.createLine();
1542 width = ceil(line.horizontalAdvance());
1545 width = fm.width(texteditObject->text().left(pos));
1549 int diff = abs(int(width-texteditObject->width()/2));
1551 QEXPECT_FAIL("", "QTBUG-21689", Abort);
1552 // some tollerance for different fonts.
1559 const qreal x0 = texteditObject->positionToRectangle(pos).x();
1560 const qreal x1 = texteditObject->positionToRectangle(pos + 1).x();
1562 QString preeditText = texteditObject->text().mid(0, pos);
1563 texteditObject->setText(texteditObject->text().mid(pos));
1564 texteditObject->setCursorPosition(0);
1566 QInputMethodEvent inputEvent(preeditText, QList<QInputMethodEvent::Attribute>());
1567 QGuiApplication::sendEvent(&canvas, &inputEvent);
1569 // Check all points within the preedit text return the same position.
1570 QCOMPARE(texteditObject->positionAt(0, y0), 0);
1571 QCOMPARE(texteditObject->positionAt(x0 / 2, y0), 0);
1572 QCOMPARE(texteditObject->positionAt(x0, y0), 0);
1574 // Verify positioning returns to normal after the preedit text.
1575 QCOMPARE(texteditObject->positionAt(x1, y0), 1);
1576 QCOMPARE(texteditObject->positionToRectangle(1).x(), x1);
1578 QVERIFY(texteditObject->positionAt(x0 / 2, y1) > 0);
1581 void tst_qquicktextedit::cursorDelegate()
1583 QQuickView view(QUrl::fromLocalFile(TESTDATA("cursorTest.qml")));
1585 view.requestActivateWindow();
1586 QQuickTextEdit *textEditObject = view.rootObject()->findChild<QQuickTextEdit*>("textEditObject");
1587 QVERIFY(textEditObject != 0);
1588 QVERIFY(textEditObject->findChild<QQuickItem*>("cursorInstance"));
1589 //Test Delegate gets created
1590 textEditObject->setFocus(true);
1591 QQuickItem* delegateObject = textEditObject->findChild<QQuickItem*>("cursorInstance");
1592 QVERIFY(delegateObject);
1593 QCOMPARE(delegateObject->property("localProperty").toString(), QString("Hello"));
1594 //Test Delegate gets moved
1595 for (int i=0; i<= textEditObject->text().length(); i++) {
1596 textEditObject->setCursorPosition(i);
1597 QCOMPARE(textEditObject->cursorRectangle().x(), qRound(delegateObject->x()));
1598 QCOMPARE(textEditObject->cursorRectangle().y(), qRound(delegateObject->y()));
1600 // Clear preedit text;
1601 QInputMethodEvent event;
1602 QGuiApplication::sendEvent(&view, &event);
1605 // Test delegate gets moved on mouse press.
1606 textEditObject->setSelectByMouse(true);
1607 textEditObject->setCursorPosition(0);
1608 const QPoint point1 = textEditObject->positionToRectangle(5).center().toPoint();
1609 QTest::mouseClick(&view, Qt::LeftButton, 0, point1);
1611 QTRY_VERIFY(textEditObject->cursorPosition() != 0);
1612 QCOMPARE(textEditObject->cursorRectangle().x(), qRound(delegateObject->x()));
1613 QCOMPARE(textEditObject->cursorRectangle().y(), qRound(delegateObject->y()));
1615 // Test delegate gets moved on mouse drag
1616 textEditObject->setCursorPosition(0);
1617 const QPoint point2 = textEditObject->positionToRectangle(10).center().toPoint();
1618 QTest::mousePress(&view, Qt::LeftButton, 0, point1);
1619 QMouseEvent mv(QEvent::MouseMove, point2, Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
1620 QGuiApplication::sendEvent(&view, &mv);
1621 QTest::mouseRelease(&view, Qt::LeftButton, 0, point2);
1623 QTRY_COMPARE(textEditObject->cursorRectangle().x(), qRound(delegateObject->x()));
1624 QCOMPARE(textEditObject->cursorRectangle().y(), qRound(delegateObject->y()));
1626 textEditObject->setReadOnly(true);
1627 textEditObject->setCursorPosition(0);
1628 QTest::mouseClick(&view, Qt::LeftButton, 0, textEditObject->positionToRectangle(5).center().toPoint());
1630 QTRY_VERIFY(textEditObject->cursorPosition() != 0);
1631 QCOMPARE(textEditObject->cursorRectangle().x(), qRound(delegateObject->x()));
1632 QCOMPARE(textEditObject->cursorRectangle().y(), qRound(delegateObject->y()));
1634 textEditObject->setCursorPosition(0);
1635 QTest::mouseClick(&view, Qt::LeftButton, 0, textEditObject->positionToRectangle(5).center().toPoint());
1637 QTRY_VERIFY(textEditObject->cursorPosition() != 0);
1638 QCOMPARE(textEditObject->cursorRectangle().x(), qRound(delegateObject->x()));
1639 QCOMPARE(textEditObject->cursorRectangle().y(), qRound(delegateObject->y()));
1641 textEditObject->setCursorPosition(0);
1642 QCOMPARE(textEditObject->cursorRectangle().x(), qRound(delegateObject->x()));
1643 QCOMPARE(textEditObject->cursorRectangle().y(), qRound(delegateObject->y()));
1644 //Test Delegate gets deleted
1645 textEditObject->setCursorDelegate(0);
1646 QVERIFY(!textEditObject->findChild<QQuickItem*>("cursorInstance"));
1649 void tst_qquicktextedit::cursorVisible()
1651 QQuickView view(QUrl::fromLocalFile(TESTDATA("cursorVisible.qml")));
1653 view.requestActivateWindow();
1654 QTest::qWaitForWindowShown(&view);
1655 QTRY_COMPARE(&view, qGuiApp->focusWindow());
1657 QQuickTextEdit edit;
1658 QSignalSpy spy(&edit, SIGNAL(cursorVisibleChanged(bool)));
1660 QCOMPARE(edit.isCursorVisible(), false);
1662 edit.setCursorVisible(true);
1663 QCOMPARE(edit.isCursorVisible(), true);
1664 QCOMPARE(spy.count(), 1);
1666 edit.setCursorVisible(false);
1667 QCOMPARE(edit.isCursorVisible(), false);
1668 QCOMPARE(spy.count(), 2);
1670 edit.setFocus(true);
1671 QCOMPARE(edit.isCursorVisible(), false);
1672 QCOMPARE(spy.count(), 2);
1674 edit.setParentItem(view.rootObject());
1675 QCOMPARE(edit.isCursorVisible(), true);
1676 QCOMPARE(spy.count(), 3);
1678 edit.setFocus(false);
1679 QCOMPARE(edit.isCursorVisible(), false);
1680 QCOMPARE(spy.count(), 4);
1682 edit.setFocus(true);
1683 QCOMPARE(edit.isCursorVisible(), true);
1684 QCOMPARE(spy.count(), 5);
1686 QQuickView alternateView;
1687 alternateView.show();
1688 alternateView.requestActivateWindow();
1689 QTest::qWaitForWindowShown(&alternateView);
1691 QCOMPARE(edit.isCursorVisible(), false);
1692 QCOMPARE(spy.count(), 6);
1694 view.requestActivateWindow();
1695 QTest::qWaitForWindowShown(&view);
1696 QCOMPARE(edit.isCursorVisible(), true);
1697 QCOMPARE(spy.count(), 7);
1700 void tst_qquicktextedit::delegateLoading_data()
1702 QTest::addColumn<QString>("qmlfile");
1703 QTest::addColumn<QString>("error");
1706 QTest::newRow("pass") << "cursorHttpTestPass.qml" << "";
1707 QTest::newRow("fail1") << "cursorHttpTestFail1.qml" << "http://localhost:42332/FailItem.qml: Remote host closed the connection ";
1708 QTest::newRow("fail2") << "cursorHttpTestFail2.qml" << "http://localhost:42332/ErrItem.qml:4:5: Fungus is not a type ";
1711 void tst_qquicktextedit::delegateLoading()
1713 QFETCH(QString, qmlfile);
1714 QFETCH(QString, error);
1716 TestHTTPServer server(42332);
1717 server.serveDirectory(TESTDATA("httpfail"), TestHTTPServer::Disconnect);
1718 server.serveDirectory(TESTDATA("httpslow"), TestHTTPServer::Delay);
1719 server.serveDirectory(TESTDATA("http"));
1721 QQuickView view(QUrl(QLatin1String("http://localhost:42332/") + qmlfile));
1723 view.requestActivateWindow();
1725 if (!error.isEmpty()) {
1726 QTest::ignoreMessage(QtWarningMsg, error.toUtf8());
1727 QTRY_VERIFY(view.status()==QQuickView::Error);
1728 QTRY_VERIFY(!view.rootObject()); // there is fail item inside this test
1730 QTRY_VERIFY(view.rootObject());//Wait for loading to finish.
1731 QQuickTextEdit *textEditObject = view.rootObject()->findChild<QQuickTextEdit*>("textEditObject");
1732 // view.rootObject()->dumpObjectTree();
1733 QVERIFY(textEditObject != 0);
1734 textEditObject->setFocus(true);
1735 QQuickItem *delegate;
1736 delegate = view.rootObject()->findChild<QQuickItem*>("delegateOkay");
1738 delegate = view.rootObject()->findChild<QQuickItem*>("delegateSlow");
1745 //A test should be added here with a component which is ready but component.create() returns null
1746 //Not sure how to accomplish this with QQuickTextEdits cursor delegate
1747 //###This was only needed for code coverage, and could be a case of overzealous defensive programming
1748 //delegate = view.rootObject()->findChild<QQuickItem*>("delegateErrorB");
1749 //QVERIFY(!delegate);
1753 TextEdit element should only handle left/right keys until the cursor reaches
1754 the extent of the text, then they should ignore the keys.
1756 void tst_qquicktextedit::navigation()
1758 QQuickView canvas(QUrl::fromLocalFile(TESTDATA("navigation.qml")));
1760 canvas.requestActivateWindow();
1762 QVERIFY(canvas.rootObject() != 0);
1764 QQuickItem *input = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(canvas.rootObject()->property("myInput")));
1766 QVERIFY(input != 0);
1767 QTRY_VERIFY(input->hasActiveFocus() == true);
1768 simulateKey(&canvas, Qt::Key_Left);
1769 QVERIFY(input->hasActiveFocus() == false);
1770 simulateKey(&canvas, Qt::Key_Right);
1771 QVERIFY(input->hasActiveFocus() == true);
1772 simulateKey(&canvas, Qt::Key_Right);
1773 QVERIFY(input->hasActiveFocus() == true);
1774 simulateKey(&canvas, Qt::Key_Right);
1775 QVERIFY(input->hasActiveFocus() == false);
1776 simulateKey(&canvas, Qt::Key_Left);
1777 QVERIFY(input->hasActiveFocus() == true);
1780 void tst_qquicktextedit::copyAndPaste() {
1781 #ifndef QT_NO_CLIPBOARD
1785 PasteboardRef pasteboard;
1786 OSStatus status = PasteboardCreate(0, &pasteboard);
1787 if (status == noErr)
1788 CFRelease(pasteboard);
1790 QSKIP("This machine doesn't support the clipboard");
1794 QString componentStr = "import QtQuick 2.0\nTextEdit { text: \"Hello world!\" }";
1795 QDeclarativeComponent textEditComponent(&engine);
1796 textEditComponent.setData(componentStr.toLatin1(), QUrl());
1797 QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit*>(textEditComponent.create());
1798 QVERIFY(textEdit != 0);
1801 QCOMPARE(textEdit->text().length(), 12);
1802 textEdit->select(0, textEdit->text().length());;
1804 QCOMPARE(textEdit->selectedText(), QString("Hello world!"));
1805 QCOMPARE(textEdit->selectedText().length(), 12);
1806 textEdit->setCursorPosition(0);
1807 QVERIFY(textEdit->canPaste());
1809 QCOMPARE(textEdit->text(), QString("Hello world!Hello world!"));
1810 QCOMPARE(textEdit->text().length(), 24);
1813 QVERIFY(textEdit->canPaste());
1814 textEdit->setReadOnly(true);
1815 QVERIFY(!textEdit->canPaste());
1816 textEdit->setReadOnly(false);
1817 QVERIFY(textEdit->canPaste());
1820 // test that document and internal text attribute are in sync
1821 QQuickItemPrivate* pri = QQuickItemPrivate::get(textEdit);
1822 QQuickTextEditPrivate *editPrivate = static_cast<QQuickTextEditPrivate*>(pri);
1823 QCOMPARE(textEdit->text(), editPrivate->text);
1826 textEdit->setCursorPosition(0);
1827 textEdit->selectWord();
1828 QCOMPARE(textEdit->selectedText(), QString("Hello"));
1830 // select all and cut
1831 textEdit->selectAll();
1833 QCOMPARE(textEdit->text().length(), 0);
1835 QCOMPARE(textEdit->text(), QString("Hello world!Hello world!"));
1836 QCOMPARE(textEdit->text().length(), 24);
1840 void tst_qquicktextedit::canPaste() {
1841 #ifndef QT_NO_CLIPBOARD
1843 QGuiApplication::clipboard()->setText("Some text");
1845 QString componentStr = "import QtQuick 2.0\nTextEdit { text: \"Hello world!\" }";
1846 QDeclarativeComponent textEditComponent(&engine);
1847 textEditComponent.setData(componentStr.toLatin1(), QUrl());
1848 QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit*>(textEditComponent.create());
1849 QVERIFY(textEdit != 0);
1851 // check initial value - QTBUG-17765
1853 QCOMPARE(textEdit->canPaste(), tc.canPaste());
1858 void tst_qquicktextedit::canPasteEmpty() {
1859 #ifndef QT_NO_CLIPBOARD
1861 QGuiApplication::clipboard()->clear();
1863 QString componentStr = "import QtQuick 2.0\nTextEdit { text: \"Hello world!\" }";
1864 QDeclarativeComponent textEditComponent(&engine);
1865 textEditComponent.setData(componentStr.toLatin1(), QUrl());
1866 QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit*>(textEditComponent.create());
1867 QVERIFY(textEdit != 0);
1869 // check initial value - QTBUG-17765
1871 QCOMPARE(textEdit->canPaste(), tc.canPaste());
1876 void tst_qquicktextedit::readOnly()
1878 QQuickView canvas(QUrl::fromLocalFile(TESTDATA("readOnly.qml")));
1880 canvas.requestActivateWindow();
1882 QVERIFY(canvas.rootObject() != 0);
1884 QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(qvariant_cast<QObject *>(canvas.rootObject()->property("myInput")));
1887 QTRY_VERIFY(edit->hasActiveFocus() == true);
1888 QVERIFY(edit->isReadOnly() == true);
1889 QString initial = edit->text();
1890 for (int k=Qt::Key_0; k<=Qt::Key_Z; k++)
1891 simulateKey(&canvas, k);
1892 simulateKey(&canvas, Qt::Key_Return);
1893 simulateKey(&canvas, Qt::Key_Space);
1894 simulateKey(&canvas, Qt::Key_Escape);
1895 QCOMPARE(edit->text(), initial);
1897 edit->setCursorPosition(3);
1898 edit->setReadOnly(false);
1899 QCOMPARE(edit->isReadOnly(), false);
1900 QCOMPARE(edit->cursorPosition(), edit->text().length());
1903 void tst_qquicktextedit::simulateKey(QQuickView *view, int key, Qt::KeyboardModifiers modifiers)
1905 QKeyEvent press(QKeyEvent::KeyPress, key, modifiers);
1906 QKeyEvent release(QKeyEvent::KeyRelease, key, modifiers);
1908 QGuiApplication::sendEvent(view, &press);
1909 QGuiApplication::sendEvent(view, &release);
1914 class MyInputContext : public QInputContext
1917 MyInputContext() : updateReceived(false), eventType(QEvent::None) {}
1918 ~MyInputContext() {}
1920 QString identifierName() { return QString(); }
1921 QString language() { return QString(); }
1925 bool isComposing() const { return false; }
1927 void update() { updateReceived = true; }
1929 void sendPreeditText(const QString &text, int cursor)
1931 QList<QInputMethodEvent::Attribute> attributes;
1932 attributes.append(QInputMethodEvent::Attribute(
1933 QInputMethodEvent::Cursor, cursor, text.length(), QVariant()));
1935 QInputMethodEvent event(text, attributes);
1939 void mouseHandler(int x, QMouseEvent *event)
1942 eventType = event->type();
1943 eventPosition = event->pos();
1944 eventGlobalPosition = event->globalPos();
1945 eventButton = event->button();
1946 eventButtons = event->buttons();
1947 eventModifiers = event->modifiers();
1950 bool updateReceived;
1952 QEvent::Type eventType;
1953 QPoint eventPosition;
1954 QPoint eventGlobalPosition;
1955 Qt::MouseButton eventButton;
1956 Qt::MouseButtons eventButtons;
1957 Qt::KeyboardModifiers eventModifiers;
1961 void tst_qquicktextedit::textInput()
1963 QQuickView view(QUrl::fromLocalFile(TESTDATA("inputMethodEvent.qml")));
1965 view.requestActivateWindow();
1966 QTest::qWaitForWindowShown(&view);
1967 QTRY_COMPARE(&view, qGuiApp->focusWindow());
1968 QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(view.rootObject());
1970 QVERIFY(edit->hasActiveFocus() == true);
1972 // test that input method event is committed
1973 QInputMethodEvent event;
1974 event.setCommitString( "Hello world!", 0, 0);
1975 QGuiApplication::sendEvent(&view, &event);
1976 QEXPECT_FAIL("", "QTBUG-21689", Abort);
1977 QCOMPARE(edit->text(), QString("Hello world!"));
1980 // test that document and internal text attribute are in sync
1981 QQuickTextEditPrivate *editPrivate = static_cast<QQuickTextEditPrivate*>(QQuickItemPrivate::get(edit));
1982 QCOMPARE(editPrivate->text, QString("Hello world!"));
1985 void tst_qquicktextedit::openInputPanel()
1987 QQuickView view(QUrl::fromLocalFile(TESTDATA("openInputPanel.qml")));
1989 view.requestActivateWindow();
1990 QTest::qWaitForWindowShown(&view);
1991 QTRY_COMPARE(&view, qGuiApp->focusWindow());
1993 QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(view.rootObject());
1996 // check default values
1997 QVERIFY(edit->focusOnPress());
1998 QVERIFY(!edit->hasActiveFocus());
1999 qDebug() << &edit << qApp->inputPanel()->inputItem();
2000 QCOMPARE(qApp->inputPanel()->inputItem(), static_cast<QObject*>(0));
2001 QEXPECT_FAIL("", "QTBUG-21946", Abort);
2002 QCOMPARE(qApp->inputPanel()->visible(), false);
2004 // input panel should open on focus
2005 QPoint centerPoint(view.width()/2, view.height()/2);
2006 Qt::KeyboardModifiers noModifiers = 0;
2007 QTest::mousePress(&view, Qt::LeftButton, noModifiers, centerPoint);
2008 QGuiApplication::processEvents();
2009 QVERIFY(edit->hasActiveFocus());
2010 QCOMPARE(qApp->inputPanel()->inputItem(), edit);
2011 QCOMPARE(qApp->inputPanel()->visible(), true);
2012 QTest::mouseRelease(&view, Qt::LeftButton, noModifiers, centerPoint);
2014 // input panel should be re-opened when pressing already focused TextEdit
2015 qApp->inputPanel()->hide();
2016 QCOMPARE(qApp->inputPanel()->visible(), false);
2017 QVERIFY(edit->hasActiveFocus());
2018 QTest::mousePress(&view, Qt::LeftButton, noModifiers, centerPoint);
2019 QGuiApplication::processEvents();
2020 QCOMPARE(qApp->inputPanel()->visible(), true);
2021 QTest::mouseRelease(&view, Qt::LeftButton, noModifiers, centerPoint);
2023 // input panel should stay visible if focus is lost to another text editor
2024 QSignalSpy inputPanelVisibilitySpy(qApp->inputPanel(), SIGNAL(visibleChanged()));
2025 QQuickTextEdit anotherEdit;
2026 anotherEdit.setParentItem(view.rootObject());
2027 anotherEdit.setFocus(true);
2028 QCOMPARE(qApp->inputPanel()->visible(), true);
2029 QCOMPARE(qApp->inputPanel()->inputItem(), qobject_cast<QObject*>(&anotherEdit));
2030 QCOMPARE(inputPanelVisibilitySpy.count(), 0);
2032 anotherEdit.setFocus(false);
2033 QCOMPARE(qApp->inputPanel()->inputItem(), static_cast<QObject*>(0));
2034 QCOMPARE(view.activeFocusItem(), view.rootItem());
2035 anotherEdit.setFocus(true);
2037 // input item should be null if focus is lost to an item that doesn't accept inputs
2039 item.setParentItem(view.rootObject());
2040 item.setFocus(true);
2041 QCOMPARE(qApp->inputPanel()->inputItem(), static_cast<QObject*>(0));
2042 QCOMPARE(view.activeFocusItem(), &item);
2044 qApp->inputPanel()->hide();
2046 // input panel should not be opened if TextEdit is read only
2047 edit->setReadOnly(true);
2048 edit->setFocus(true);
2049 QCOMPARE(qApp->inputPanel()->visible(), false);
2050 QTest::mousePress(&view, Qt::LeftButton, noModifiers, centerPoint);
2051 QTest::mouseRelease(&view, Qt::LeftButton, noModifiers, centerPoint);
2052 QGuiApplication::processEvents();
2053 QCOMPARE(qApp->inputPanel()->visible(), false);
2055 // input panel should not be opened if focusOnPress is set to false
2056 edit->setFocusOnPress(false);
2057 edit->setFocus(false);
2058 edit->setFocus(true);
2059 QCOMPARE(qApp->inputPanel()->visible(), false);
2060 QTest::mousePress(&view, Qt::LeftButton, noModifiers, centerPoint);
2061 QTest::mouseRelease(&view, Qt::LeftButton, noModifiers, centerPoint);
2062 QCOMPARE(qApp->inputPanel()->visible(), false);
2064 // input panel should open when openSoftwareInputPanel is called
2065 edit->openSoftwareInputPanel();
2066 QCOMPARE(qApp->inputPanel()->visible(), true);
2068 // input panel should close when closeSoftwareInputPanel is called
2069 edit->closeSoftwareInputPanel();
2070 QCOMPARE(qApp->inputPanel()->visible(), false);
2073 void tst_qquicktextedit::geometrySignals()
2075 QDeclarativeComponent component(&engine, TESTDATA("geometrySignals.qml"));
2076 QObject *o = component.create();
2078 QCOMPARE(o->property("bindingWidth").toInt(), 400);
2079 QCOMPARE(o->property("bindingHeight").toInt(), 500);
2083 void tst_qquicktextedit::pastingRichText_QTBUG_14003()
2085 #ifndef QT_NO_CLIPBOARD
2086 QString componentStr = "import QtQuick 2.0\nTextEdit { textFormat: TextEdit.PlainText }";
2087 QDeclarativeComponent component(&engine);
2088 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
2089 QQuickTextEdit *obj = qobject_cast<QQuickTextEdit*>(component.create());
2091 QTRY_VERIFY(obj != 0);
2092 QTRY_VERIFY(obj->textFormat() == QQuickTextEdit::PlainText);
2094 QMimeData *mData = new QMimeData;
2095 mData->setHtml("<font color=\"red\">Hello</font>");
2096 QGuiApplication::clipboard()->setMimeData(mData);
2099 QTRY_VERIFY(obj->text() == "");
2100 QTRY_VERIFY(obj->textFormat() == QQuickTextEdit::PlainText);
2104 void tst_qquicktextedit::implicitSize_data()
2106 QTest::addColumn<QString>("text");
2107 QTest::addColumn<QString>("wrap");
2108 QTest::newRow("plain") << "The quick red fox jumped over the lazy brown dog" << "TextEdit.NoWrap";
2109 QTest::newRow("richtext") << "<b>The quick red fox jumped over the lazy brown dog</b>" << "TextEdit.NoWrap";
2110 QTest::newRow("plain_wrap") << "The quick red fox jumped over the lazy brown dog" << "TextEdit.Wrap";
2111 QTest::newRow("richtext_wrap") << "<b>The quick red fox jumped over the lazy brown dog</b>" << "TextEdit.Wrap";
2114 void tst_qquicktextedit::implicitSize()
2116 QFETCH(QString, text);
2117 QFETCH(QString, wrap);
2118 QString componentStr = "import QtQuick 2.0\nTextEdit { text: \"" + text + "\"; width: 50; wrapMode: " + wrap + " }";
2119 QDeclarativeComponent textComponent(&engine);
2120 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
2121 QQuickTextEdit *textObject = qobject_cast<QQuickTextEdit*>(textComponent.create());
2123 QVERIFY(textObject->width() < textObject->implicitWidth());
2124 QVERIFY(textObject->height() == textObject->implicitHeight());
2126 textObject->resetWidth();
2127 QVERIFY(textObject->width() == textObject->implicitWidth());
2128 QVERIFY(textObject->height() == textObject->implicitHeight());
2131 void tst_qquicktextedit::testQtQuick11Attributes()
2133 QFETCH(QString, code);
2134 QFETCH(QString, warning);
2135 QFETCH(QString, error);
2137 QDeclarativeEngine engine;
2140 QDeclarativeComponent valid(&engine);
2141 valid.setData("import QtQuick 2.0; TextEdit { " + code.toUtf8() + " }", QUrl(""));
2142 obj = valid.create();
2144 QVERIFY(valid.errorString().isEmpty());
2147 QDeclarativeComponent invalid(&engine);
2148 invalid.setData("import QtQuick 1.0; TextEdit { " + code.toUtf8() + " }", QUrl(""));
2149 QTest::ignoreMessage(QtWarningMsg, warning.toUtf8());
2150 obj = invalid.create();
2151 QCOMPARE(invalid.errorString(), error);
2155 void tst_qquicktextedit::testQtQuick11Attributes_data()
2157 QTest::addColumn<QString>("code");
2158 QTest::addColumn<QString>("warning");
2159 QTest::addColumn<QString>("error");
2161 QTest::newRow("canPaste") << "property bool foo: canPaste"
2162 << "<Unknown File>:1: ReferenceError: Can't find variable: canPaste"
2165 QTest::newRow("lineCount") << "property int foo: lineCount"
2166 << "<Unknown File>:1: ReferenceError: Can't find variable: lineCount"
2169 QTest::newRow("moveCursorSelection") << "Component.onCompleted: moveCursorSelection(0, TextEdit.SelectCharacters)"
2170 << "<Unknown File>:1: ReferenceError: Can't find variable: moveCursorSelection"
2173 QTest::newRow("deselect") << "Component.onCompleted: deselect()"
2174 << "<Unknown File>:1: ReferenceError: Can't find variable: deselect"
2177 QTest::newRow("onLinkActivated") << "onLinkActivated: {}"
2178 << "QDeclarativeComponent: Component is not ready"
2179 << ":1 \"TextEdit.onLinkActivated\" is not available in QtQuick 1.0.\n";
2182 void tst_qquicktextedit::preeditMicroFocus()
2185 QEXPECT_FAIL("", QTBUG_21691_MESSAGE, Abort);
2188 QString preeditText = "super";
2190 QQuickView view(QUrl::fromLocalFile(TESTDATA("inputMethodEvent.qml")));
2192 view.requestActivateWindow();
2193 QTest::qWaitForWindowShown(&view);
2195 QTRY_COMPARE(&view, qGuiApp->focusWindow());
2196 QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(view.rootObject());
2199 QSignalSpy cursorRectangleSpy(edit, SIGNAL(cursorRectangleChanged()));
2202 QRect previousRect = edit->inputMethodQuery(Qt::ImCursorRectangle).toRect();
2204 // Verify that the micro focus rect is positioned the same for position 0 as
2205 // it would be if there was no preedit text.
2206 ic.updateReceived = false;
2207 ic.sendPreeditText(preeditText, 0);
2208 currentRect = edit->inputMethodQuery(Qt::ImCursorRectangle).toRect();
2209 QCOMPARE(currentRect, previousRect);
2210 QCOMPARE(ic.updateReceived, false); // The cursor position hasn't changed.
2211 QCOMPARE(cursorRectangleSpy.count(), 0);
2213 // Verify that the micro focus rect moves to the left as the cursor position
2215 for (int i = 1; i <= 5; ++i) {
2216 ic.updateReceived = false;
2217 ic.sendPreeditText(preeditText, i);
2218 currentRect = edit->inputMethodQuery(Qt::ImCursorRectangle).toRect();
2219 QVERIFY(previousRect.left() < currentRect.left());
2220 QCOMPARE(ic.updateReceived, true);
2221 QVERIFY(cursorRectangleSpy.count() > 0);
2222 cursorRectangleSpy.clear();
2223 previousRect = currentRect;
2226 // Verify that if there is no preedit cursor then the micro focus rect is the
2227 // same as it would be if it were positioned at the end of the preedit text.
2228 ic.sendPreeditText(preeditText, 0);
2229 ic.updateReceived = false;
2230 ic.sendEvent(QInputMethodEvent(preeditText, QList<QInputMethodEvent::Attribute>()));
2231 currentRect = edit->inputMethodQuery(Qt::ImCursorRectangle).toRect();
2232 QCOMPARE(currentRect, previousRect);
2233 QCOMPARE(ic.updateReceived, true);
2234 QVERIFY(cursorRectangleSpy.count() > 0);
2238 void tst_qquicktextedit::inputContextMouseHandler()
2242 QEXPECT_FAIL("", QTBUG_21691_MESSAGE, Abort);
2245 QString text = "supercalifragisiticexpialidocious!";
2247 QQuickView view(QUrl::fromLocalFile(TESTDATA("inputContext.qml")));
2249 // QQuickCanvas won't set the Qt::WA_InputMethodEnabled flag unless a suitable item has focus
2250 // and QWidget won't allow an input context to be set when the flag is not set.
2251 view.setAttribute(Qt::WA_InputMethodEnabled, true);
2252 view.setInputContext(&ic);
2253 view.setAttribute(Qt::WA_InputMethodEnabled, false);
2255 view.requestActivateWindow();
2256 QTest::qWaitForWindowShown(&view);
2258 QTRY_COMPARE(&view, qGuiApp->focusWindow());
2259 QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(view.rootObject());
2261 edit->setCursorPosition(12);
2263 QFontMetricsF fm(edit->font());
2264 const qreal y = fm.height() / 2;
2266 QPoint position2 = edit->mapToScene(QPointF(fm.width(text.mid(0, 2)), y)).toPoint();
2267 QPoint position8 = edit->mapToScene(QPointF(fm.width(text.mid(0, 8)), y)).toPoint();
2268 QPoint position20 = edit->mapToScene(QPointF(fm.width(text.mid(0, 20)), y)).toPoint();
2269 QPoint position27 = edit->mapToScene(QPointF(fm.width(text.mid(0, 27)), y)).toPoint();
2270 QPoint globalPosition2 = view.mapToGlobal(position2);
2271 QPoint globalposition8 = view.mapToGlobal(position8);
2272 QPoint globalposition20 = view.mapToGlobal(position20);
2273 QPoint globalposition27 = view.mapToGlobal(position27);
2275 ic.sendEvent(QInputMethodEvent(text.mid(12), QList<QInputMethodEvent::Attribute>()));
2277 QTest::mouseDClick(&view, Qt::LeftButton, Qt::NoModifier, position2);
2278 QCOMPARE(ic.eventType, QEvent::MouseButtonDblClick);
2279 QCOMPARE(ic.eventPosition, position2);
2280 QCOMPARE(ic.eventGlobalPosition, globalPosition2);
2281 QCOMPARE(ic.eventButton, Qt::LeftButton);
2282 QCOMPARE(ic.eventModifiers, Qt::NoModifier);
2283 QVERIFY(ic.cursor < 0);
2284 ic.eventType = QEvent::None;
2286 QTest::mousePress(&view, Qt::LeftButton, Qt::NoModifier, position2);
2287 QCOMPARE(ic.eventType, QEvent::MouseButtonPress);
2288 QCOMPARE(ic.eventPosition, position2);
2289 QCOMPARE(ic.eventGlobalPosition, globalPosition2);
2290 QCOMPARE(ic.eventButton, Qt::LeftButton);
2291 QCOMPARE(ic.eventModifiers, Qt::NoModifier);
2292 QVERIFY(ic.cursor < 0);
2293 ic.eventType = QEvent::None;
2295 { QMouseEvent mv(QEvent::MouseMove, position8, globalposition8, Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
2296 QGuiApplication::sendEvent(&view, &mv); }
2297 QCOMPARE(ic.eventType, QEvent::None);
2299 { QMouseEvent mv(QEvent::MouseMove, position27, globalposition27, Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
2300 QGuiApplication::sendEvent(&view, &mv); }
2301 QCOMPARE(ic.eventType, QEvent::MouseMove);
2302 QCOMPARE(ic.eventPosition, position27);
2303 QCOMPARE(ic.eventGlobalPosition, globalposition27);
2304 QCOMPARE(ic.eventButton, Qt::LeftButton);
2305 QCOMPARE(ic.eventModifiers, Qt::NoModifier);
2306 QVERIFY(ic.cursor >= 14 && ic.cursor <= 16); // 15 is expected but some platforms may be off by one.
2307 ic.eventType = QEvent::None;
2309 QTest::mouseRelease(&view, Qt::LeftButton, Qt::NoModifier, position27);
2310 QCOMPARE(ic.eventType, QEvent::MouseButtonRelease);
2311 QCOMPARE(ic.eventPosition, position27);
2312 QCOMPARE(ic.eventGlobalPosition, globalposition27);
2313 QCOMPARE(ic.eventButton, Qt::LeftButton);
2314 QCOMPARE(ic.eventModifiers, Qt::NoModifier);
2315 QVERIFY(ic.cursor >= 14 && ic.cursor <= 16);
2316 ic.eventType = QEvent::None;
2318 // And in the other direction.
2319 QTest::mouseDClick(&view, Qt::LeftButton, Qt::ControlModifier, position27);
2320 QCOMPARE(ic.eventType, QEvent::MouseButtonDblClick);
2321 QCOMPARE(ic.eventPosition, position27);
2322 QCOMPARE(ic.eventGlobalPosition, globalposition27);
2323 QCOMPARE(ic.eventButton, Qt::LeftButton);
2324 QCOMPARE(ic.eventModifiers, Qt::ControlModifier);
2325 QVERIFY(ic.cursor >= 14 && ic.cursor <= 16);
2326 ic.eventType = QEvent::None;
2328 QTest::mousePress(&view, Qt::RightButton, Qt::ControlModifier, position27);
2329 QCOMPARE(ic.eventType, QEvent::MouseButtonPress);
2330 QCOMPARE(ic.eventPosition, position27);
2331 QCOMPARE(ic.eventGlobalPosition, globalposition27);
2332 QCOMPARE(ic.eventButton, Qt::RightButton);
2333 QCOMPARE(ic.eventModifiers, Qt::ControlModifier);
2334 QVERIFY(ic.cursor >= 14 && ic.cursor <= 16);
2335 ic.eventType = QEvent::None;
2337 { QMouseEvent mv(QEvent::MouseMove, position20, globalposition20, Qt::RightButton, Qt::RightButton,Qt::ControlModifier);
2338 QGuiApplication::sendEvent(&view, &mv); }
2339 QCOMPARE(ic.eventType, QEvent::MouseMove);
2340 QCOMPARE(ic.eventPosition, position20);
2341 QCOMPARE(ic.eventGlobalPosition, globalposition20);
2342 QCOMPARE(ic.eventButton, Qt::RightButton);
2343 QCOMPARE(ic.eventModifiers, Qt::ControlModifier);
2344 QVERIFY(ic.cursor >= 7 && ic.cursor <= 9);
2345 ic.eventType = QEvent::None;
2347 { QMouseEvent mv(QEvent::MouseMove, position2, globalPosition2, Qt::RightButton, Qt::RightButton,Qt::ControlModifier);
2348 QGuiApplication::sendEvent(&view, &mv); }
2349 QCOMPARE(ic.eventType, QEvent::None);
2351 QTest::mouseRelease(&view, Qt::RightButton, Qt::ControlModifier, position2);
2352 QCOMPARE(ic.eventType, QEvent::MouseButtonRelease);
2353 QCOMPARE(ic.eventPosition, position2);
2354 QCOMPARE(ic.eventGlobalPosition, globalPosition2);
2355 QCOMPARE(ic.eventButton, Qt::RightButton);
2356 QCOMPARE(ic.eventModifiers, Qt::ControlModifier);
2357 QVERIFY(ic.cursor < 0);
2358 ic.eventType = QEvent::None;
2362 void tst_qquicktextedit::inputMethodComposing()
2364 QString text = "supercalifragisiticexpialidocious!";
2366 QQuickView view(QUrl::fromLocalFile(TESTDATA("inputContext.qml")));
2368 view.requestActivateWindow();
2369 QTest::qWaitForWindowShown(&view);
2370 QTRY_COMPARE(&view, qGuiApp->focusWindow());
2371 QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(view.rootObject());
2373 QSignalSpy spy(edit, SIGNAL(inputMethodComposingChanged()));
2374 edit->setCursorPosition(12);
2376 QCOMPARE(edit->isInputMethodComposing(), false);
2379 QInputMethodEvent event(text.mid(3), QList<QInputMethodEvent::Attribute>());
2380 QGuiApplication::sendEvent(edit, &event);
2383 QCOMPARE(edit->isInputMethodComposing(), true);
2384 QCOMPARE(spy.count(), 1);
2387 QInputMethodEvent event(text.mid(12), QList<QInputMethodEvent::Attribute>());
2388 QGuiApplication::sendEvent(edit, &event);
2390 QCOMPARE(spy.count(), 1);
2393 QInputMethodEvent event;
2394 QGuiApplication::sendEvent(edit, &event);
2396 QCOMPARE(edit->isInputMethodComposing(), false);
2397 QCOMPARE(spy.count(), 2);
2400 void tst_qquicktextedit::cursorRectangleSize()
2402 QQuickView *canvas = new QQuickView(QUrl::fromLocalFile(TESTDATA("CursorRect.qml")));
2403 QVERIFY(canvas->rootObject() != 0);
2405 canvas->requestActivateWindow();
2406 QTest::qWaitForWindowShown(canvas);
2408 QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit *>(canvas->rootObject());
2409 QVERIFY(textEdit != 0);
2410 textEdit->setFocus(Qt::OtherFocusReason);
2411 QRectF cursorRect = textEdit->positionToRectangle(textEdit->cursorPosition());
2412 QRectF microFocusFromScene = canvas->inputMethodQuery(Qt::ImCursorRectangle).toRectF();
2413 QInputMethodQueryEvent event(Qt::ImCursorRectangle);
2414 qApp->sendEvent(qApp->inputPanel()->inputItem(), &event);
2416 QRectF microFocusFromApp = event.value(Qt::ImCursorRectangle).toRectF();
2418 QCOMPARE(microFocusFromScene.size(), cursorRect.size());
2419 QCOMPARE(microFocusFromApp.size(), cursorRect.size());
2424 void tst_qquicktextedit::emptytags_QTBUG_22058()
2426 QQuickView canvas(QUrl::fromLocalFile(TESTDATA("qtbug-22058.qml")));
2427 QVERIFY(canvas.rootObject() != 0);
2430 canvas.requestActivateWindow();
2431 QTest::qWaitForWindowShown(&canvas);
2432 QQuickTextEdit *input = qobject_cast<QQuickTextEdit *>(qvariant_cast<QObject *>(canvas.rootObject()->property("inputField")));
2433 QVERIFY(input->hasActiveFocus());
2435 QInputMethodEvent event("", QList<QInputMethodEvent::Attribute>());
2436 event.setCommitString("<b>Bold<");
2437 QGuiApplication::sendEvent(input, &event);
2438 QCOMPARE(input->text(), QString("<b>Bold<"));
2439 event.setCommitString(">");
2440 QEXPECT_FAIL("", "Entering empty tags into a TextEdit asserts - QTBUG-22058", Abort);
2442 QGuiApplication::sendEvent(input, &event);
2443 QCOMPARE(input->text(), QString("<b>Bold<>"));
2446 QTEST_MAIN(tst_qquicktextedit)
2448 #include "tst_qquicktextedit.moc"