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 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
42 #include <QtTest/QSignalSpy>
43 #include "../../../shared/util.h"
44 #include "../shared/testhttpserver.h"
47 #include <QTextDocument>
48 #include <QtDeclarative/qdeclarativeengine.h>
49 #include <QtDeclarative/qdeclarativecontext.h>
50 #include <QtDeclarative/qdeclarativeexpression.h>
51 #include <QtDeclarative/qdeclarativecomponent.h>
52 #include <private/qdeclarativetextedit_p.h>
53 #include <private/qdeclarativetextedit_p_p.h>
54 #include <QFontMetrics>
55 #include <QDeclarativeView>
58 #include <QInputContext>
61 #include <private/qapplication_p.h>
62 #include <private/qtextcontrol_p.h>
65 // In Symbian OS test data is located in applications private dir
69 Q_DECLARE_METATYPE(QDeclarativeTextEdit::SelectionMode)
71 QString createExpectedFileIfNotFound(const QString& filebasename, const QImage& actual)
73 // XXX This will be replaced by some clever persistent platform image store.
74 QString persistent_dir = SRCDIR "/data";
75 QString arch = "unknown-architecture"; // QTest needs to help with this.
77 QString expectfile = persistent_dir + QDir::separator() + filebasename + "-" + arch + ".png";
79 if (!QFile::exists(expectfile)) {
80 actual.save(expectfile);
81 qWarning() << "created" << expectfile;
88 class tst_qdeclarativetextedit : public QObject
93 tst_qdeclarativetextedit();
101 void alignments_data();
103 // ### these tests may be trivial
105 void hAlign_RightToLeft();
110 void persistentSelection();
113 void isRightToLeft_data();
114 void isRightToLeft();
116 void moveCursorSelection_data();
117 void moveCursorSelection();
118 void moveCursorSelectionSequence_data();
119 void moveCursorSelectionSequence();
120 void mouseSelection_data();
121 void mouseSelection();
122 void deferEnableSelectByMouse_data();
123 void deferEnableSelectByMouse();
124 void deferDisableSelectByMouse_data();
125 void deferDisableSelectByMouse();
126 void mouseSelectionMode_data();
127 void mouseSelectionMode();
128 void dragMouseSelection();
129 void inputMethodHints();
133 void cursorDelegate();
134 void cursorVisible();
135 void delegateLoading_data();
136 void delegateLoading();
141 void canPasteEmpty();
143 void openInputPanelOnClick();
144 void openInputPanelOnFocus();
145 void geometrySignals();
146 void pastingRichText_QTBUG_14003();
147 void implicitSize_data();
149 void testQtQuick11Attributes();
150 void testQtQuick11Attributes_data();
152 void preeditMicroFocus();
153 void inputContextMouseHandler();
154 void inputMethodComposing();
155 void cursorRectangleSize();
158 void simulateKey(QDeclarativeView *, int key, Qt::KeyboardModifiers modifiers = 0);
159 QDeclarativeView *createView(const QString &filename);
161 QStringList standard;
162 QStringList richText;
164 QStringList hAlignmentStrings;
165 QStringList vAlignmentStrings;
167 QList<Qt::Alignment> vAlignments;
168 QList<Qt::Alignment> hAlignments;
170 QStringList colorStrings;
172 QDeclarativeEngine engine;
175 tst_qdeclarativetextedit::tst_qdeclarativetextedit()
177 standard << "the quick brown fox jumped over the lazy dog"
178 << "the quick brown fox\n jumped over the lazy dog"
182 richText << "<i>the <b>quick</b> brown <a href=\\\"http://www.google.com\\\">fox</a> jumped over the <b>lazy</b> dog</i>"
183 << "<i>the <b>quick</b> brown <a href=\\\"http://www.google.com\\\">fox</a><br>jumped over the <b>lazy</b> dog</i>";
185 hAlignmentStrings << "AlignLeft"
189 vAlignmentStrings << "AlignTop"
193 hAlignments << Qt::AlignLeft
197 vAlignments << Qt::AlignTop
201 colorStrings << "aliceblue"
214 // need a different test to do alpha channel test
220 void tst_qdeclarativetextedit::text()
223 QDeclarativeComponent texteditComponent(&engine);
224 texteditComponent.setData("import QtQuick 1.0\nTextEdit { text: \"\" }", QUrl());
225 QDeclarativeTextEdit *textEditObject = qobject_cast<QDeclarativeTextEdit*>(texteditComponent.create());
227 QVERIFY(textEditObject != 0);
228 QCOMPARE(textEditObject->text(), QString(""));
231 for (int i = 0; i < standard.size(); i++)
233 QString componentStr = "import QtQuick 1.0\nTextEdit { text: \"" + standard.at(i) + "\" }";
234 QDeclarativeComponent texteditComponent(&engine);
235 texteditComponent.setData(componentStr.toLatin1(), QUrl());
236 QDeclarativeTextEdit *textEditObject = qobject_cast<QDeclarativeTextEdit*>(texteditComponent.create());
238 QVERIFY(textEditObject != 0);
239 QCOMPARE(textEditObject->text(), standard.at(i));
242 for (int i = 0; i < richText.size(); i++)
244 QString componentStr = "import QtQuick 1.0\nTextEdit { text: \"" + richText.at(i) + "\" }";
245 QDeclarativeComponent texteditComponent(&engine);
246 texteditComponent.setData(componentStr.toLatin1(), QUrl());
247 QDeclarativeTextEdit *textEditObject = qobject_cast<QDeclarativeTextEdit*>(texteditComponent.create());
249 QVERIFY(textEditObject != 0);
250 QString actual = textEditObject->text();
251 QString expected = richText.at(i);
252 actual.replace(QRegExp(".*<body[^>]*>"),"");
253 actual.replace(QRegExp("(<[^>]*>)+"),"<>");
254 expected.replace(QRegExp("(<[^>]*>)+"),"<>");
255 QCOMPARE(actual.simplified(),expected.simplified());
259 void tst_qdeclarativetextedit::width()
261 // uses Font metrics to find the width for standard and document to find the width for rich
263 QDeclarativeComponent texteditComponent(&engine);
264 texteditComponent.setData("import QtQuick 1.0\nTextEdit { text: \"\" }", QUrl());
265 QDeclarativeTextEdit *textEditObject = qobject_cast<QDeclarativeTextEdit*>(texteditComponent.create());
267 QVERIFY(textEditObject != 0);
268 QCOMPARE(textEditObject->width(), 0.0);
271 for (int i = 0; i < standard.size(); i++)
275 qreal metricWidth = fm.size(Qt::TextExpandTabs && Qt::TextShowMnemonic, standard.at(i)).width();
276 metricWidth = ceil(metricWidth);
278 QString componentStr = "import QtQuick 1.0\nTextEdit { text: \"" + standard.at(i) + "\" }";
279 QDeclarativeComponent texteditComponent(&engine);
280 texteditComponent.setData(componentStr.toLatin1(), QUrl());
281 QDeclarativeTextEdit *textEditObject = qobject_cast<QDeclarativeTextEdit*>(texteditComponent.create());
283 QVERIFY(textEditObject != 0);
284 QCOMPARE(textEditObject->width(), qreal(metricWidth));
287 for (int i = 0; i < richText.size(); i++)
289 QTextDocument document;
290 document.setHtml(richText.at(i));
291 document.setDocumentMargin(0);
293 int documentWidth = ceil(document.idealWidth());
295 QString componentStr = "import QtQuick 1.0\nTextEdit { text: \"" + richText.at(i) + "\" }";
296 QDeclarativeComponent texteditComponent(&engine);
297 texteditComponent.setData(componentStr.toLatin1(), QUrl());
298 QDeclarativeTextEdit *textEditObject = qobject_cast<QDeclarativeTextEdit*>(texteditComponent.create());
300 QVERIFY(textEditObject != 0);
301 QCOMPARE(textEditObject->width(), qreal(documentWidth));
305 void tst_qdeclarativetextedit::wrap()
307 // for specified width and wrap set true
309 QDeclarativeComponent texteditComponent(&engine);
310 texteditComponent.setData("import QtQuick 1.0\nTextEdit { text: \"\"; wrapMode: TextEdit.WordWrap; width: 300 }", QUrl());
311 QDeclarativeTextEdit *textEditObject = qobject_cast<QDeclarativeTextEdit*>(texteditComponent.create());
313 QVERIFY(textEditObject != 0);
314 QCOMPARE(textEditObject->width(), 300.);
317 for (int i = 0; i < standard.size(); i++)
319 QString componentStr = "import QtQuick 1.0\nTextEdit { wrapMode: TextEdit.WordWrap; width: 300; text: \"" + standard.at(i) + "\" }";
320 QDeclarativeComponent texteditComponent(&engine);
321 texteditComponent.setData(componentStr.toLatin1(), QUrl());
322 QDeclarativeTextEdit *textEditObject = qobject_cast<QDeclarativeTextEdit*>(texteditComponent.create());
324 QVERIFY(textEditObject != 0);
325 QCOMPARE(textEditObject->width(), 300.);
328 for (int i = 0; i < richText.size(); i++)
330 QString componentStr = "import QtQuick 1.0\nTextEdit { wrapMode: TextEdit.WordWrap; width: 300; text: \"" + richText.at(i) + "\" }";
331 QDeclarativeComponent texteditComponent(&engine);
332 texteditComponent.setData(componentStr.toLatin1(), QUrl());
333 QDeclarativeTextEdit *textEditObject = qobject_cast<QDeclarativeTextEdit*>(texteditComponent.create());
335 QVERIFY(textEditObject != 0);
336 QCOMPARE(textEditObject->width(), 300.);
341 void tst_qdeclarativetextedit::textFormat()
344 QDeclarativeComponent textComponent(&engine);
345 textComponent.setData("import QtQuick 1.0\nTextEdit { text: \"Hello\"; textFormat: Text.RichText }", QUrl::fromLocalFile(""));
346 QDeclarativeTextEdit *textObject = qobject_cast<QDeclarativeTextEdit*>(textComponent.create());
348 QVERIFY(textObject != 0);
349 QVERIFY(textObject->textFormat() == QDeclarativeTextEdit::RichText);
352 QDeclarativeComponent textComponent(&engine);
353 textComponent.setData("import QtQuick 1.0\nTextEdit { text: \"<b>Hello</b>\"; textFormat: Text.PlainText }", QUrl::fromLocalFile(""));
354 QDeclarativeTextEdit *textObject = qobject_cast<QDeclarativeTextEdit*>(textComponent.create());
356 QVERIFY(textObject != 0);
357 QVERIFY(textObject->textFormat() == QDeclarativeTextEdit::PlainText);
361 void tst_qdeclarativetextedit::alignments_data()
363 QTest::addColumn<int>("hAlign");
364 QTest::addColumn<int>("vAlign");
365 QTest::addColumn<QString>("expectfile");
367 QTest::newRow("LT") << int(Qt::AlignLeft) << int(Qt::AlignTop) << "alignments_lt";
368 QTest::newRow("RT") << int(Qt::AlignRight) << int(Qt::AlignTop) << "alignments_rt";
369 QTest::newRow("CT") << int(Qt::AlignHCenter) << int(Qt::AlignTop) << "alignments_ct";
371 QTest::newRow("LB") << int(Qt::AlignLeft) << int(Qt::AlignBottom) << "alignments_lb";
372 QTest::newRow("RB") << int(Qt::AlignRight) << int(Qt::AlignBottom) << "alignments_rb";
373 QTest::newRow("CB") << int(Qt::AlignHCenter) << int(Qt::AlignBottom) << "alignments_cb";
375 QTest::newRow("LC") << int(Qt::AlignLeft) << int(Qt::AlignVCenter) << "alignments_lc";
376 QTest::newRow("RC") << int(Qt::AlignRight) << int(Qt::AlignVCenter) << "alignments_rc";
377 QTest::newRow("CC") << int(Qt::AlignHCenter) << int(Qt::AlignVCenter) << "alignments_cc";
381 void tst_qdeclarativetextedit::alignments()
385 QFETCH(QString, expectfile);
387 QDeclarativeView *canvas = createView(SRCDIR "/data/alignments.qml");
390 QApplication::setActiveWindow(canvas);
391 QTest::qWaitForWindowShown(canvas);
392 QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(canvas));
394 QObject *ob = canvas->rootObject();
396 ob->setProperty("horizontalAlignment",hAlign);
397 ob->setProperty("verticalAlignment",vAlign);
398 QTRY_COMPARE(ob->property("running").toBool(),false);
399 QImage actual(canvas->width(), canvas->height(), QImage::Format_RGB32);
400 actual.fill(qRgb(255,255,255));
404 expectfile = createExpectedFileIfNotFound(expectfile, actual);
406 QImage expect(expectfile);
408 QCOMPARE(actual,expect);
414 //the alignment tests may be trivial o.oa
415 void tst_qdeclarativetextedit::hAlign()
417 //test one align each, and then test if two align fails.
419 for (int i = 0; i < standard.size(); i++)
421 for (int j=0; j < hAlignmentStrings.size(); j++)
423 QString componentStr = "import QtQuick 1.0\nTextEdit { horizontalAlignment: \"" + hAlignmentStrings.at(j) + "\"; text: \"" + standard.at(i) + "\" }";
424 QDeclarativeComponent texteditComponent(&engine);
425 texteditComponent.setData(componentStr.toLatin1(), QUrl());
426 QDeclarativeTextEdit *textEditObject = qobject_cast<QDeclarativeTextEdit*>(texteditComponent.create());
428 QVERIFY(textEditObject != 0);
429 QCOMPARE((int)textEditObject->hAlign(), (int)hAlignments.at(j));
433 for (int i = 0; i < richText.size(); i++)
435 for (int j=0; j < hAlignmentStrings.size(); j++)
437 QString componentStr = "import QtQuick 1.0\nTextEdit { horizontalAlignment: \"" + hAlignmentStrings.at(j) + "\"; text: \"" + richText.at(i) + "\" }";
438 QDeclarativeComponent texteditComponent(&engine);
439 texteditComponent.setData(componentStr.toLatin1(), QUrl());
440 QDeclarativeTextEdit *textEditObject = qobject_cast<QDeclarativeTextEdit*>(texteditComponent.create());
442 QVERIFY(textEditObject != 0);
443 QCOMPARE((int)textEditObject->hAlign(), (int)hAlignments.at(j));
449 void tst_qdeclarativetextedit::hAlign_RightToLeft()
451 QDeclarativeView *canvas = createView(SRCDIR "/data/horizontalAlignment_RightToLeft.qml");
452 QDeclarativeTextEdit *textEdit = canvas->rootObject()->findChild<QDeclarativeTextEdit*>("text");
453 QVERIFY(textEdit != 0);
456 // implicit alignment should follow the reading direction of text
457 QCOMPARE(textEdit->hAlign(), QDeclarativeTextEdit::AlignRight);
458 QVERIFY(textEdit->positionToRectangle(0).x() > canvas->width()/2);
460 // explicitly left aligned
461 textEdit->setHAlign(QDeclarativeTextEdit::AlignLeft);
462 QCOMPARE(textEdit->hAlign(), QDeclarativeTextEdit::AlignLeft);
463 QVERIFY(textEdit->positionToRectangle(0).x() < canvas->width()/2);
465 // explicitly right aligned
466 textEdit->setHAlign(QDeclarativeTextEdit::AlignRight);
467 QCOMPARE(textEdit->hAlign(), QDeclarativeTextEdit::AlignRight);
468 QVERIFY(textEdit->positionToRectangle(0).x() > canvas->width()/2);
470 QString textString = textEdit->text();
471 textEdit->setText(QString("<i>") + textString + QString("</i>"));
472 textEdit->resetHAlign();
474 // implicitly aligned rich text should follow the reading direction of RTL text
475 QCOMPARE(textEdit->hAlign(), QDeclarativeTextEdit::AlignRight);
476 QCOMPARE(textEdit->effectiveHAlign(), textEdit->hAlign());
477 QVERIFY(textEdit->positionToRectangle(0).x() > canvas->width()/2);
479 // explicitly left aligned rich text
480 textEdit->setHAlign(QDeclarativeTextEdit::AlignLeft);
481 QCOMPARE(textEdit->hAlign(), QDeclarativeTextEdit::AlignLeft);
482 QCOMPARE(textEdit->effectiveHAlign(), textEdit->hAlign());
483 QVERIFY(textEdit->positionToRectangle(0).x() < canvas->width()/2);
485 // explicitly right aligned rich text
486 textEdit->setHAlign(QDeclarativeTextEdit::AlignRight);
487 QCOMPARE(textEdit->hAlign(), QDeclarativeTextEdit::AlignRight);
488 QCOMPARE(textEdit->effectiveHAlign(), textEdit->hAlign());
489 QVERIFY(textEdit->positionToRectangle(0).x() > canvas->width()/2);
491 textEdit->setText(textString);
493 // explicitly center aligned
494 textEdit->setHAlign(QDeclarativeTextEdit::AlignHCenter);
495 QCOMPARE(textEdit->hAlign(), QDeclarativeTextEdit::AlignHCenter);
496 QVERIFY(textEdit->positionToRectangle(0).x() > canvas->width()/2);
498 // reseted alignment should go back to following the text reading direction
499 textEdit->resetHAlign();
500 QCOMPARE(textEdit->hAlign(), QDeclarativeTextEdit::AlignRight);
501 QVERIFY(textEdit->positionToRectangle(0).x() > canvas->width()/2);
503 // mirror the text item
504 QDeclarativeItemPrivate::get(textEdit)->setLayoutMirror(true);
506 // mirrored implicit alignment should continue to follow the reading direction of the text
507 QCOMPARE(textEdit->hAlign(), QDeclarativeTextEdit::AlignRight);
508 QCOMPARE(textEdit->effectiveHAlign(), QDeclarativeTextEdit::AlignRight);
509 QVERIFY(textEdit->positionToRectangle(0).x() > canvas->width()/2);
511 // mirrored explicitly right aligned behaves as left aligned
512 textEdit->setHAlign(QDeclarativeTextEdit::AlignRight);
513 QCOMPARE(textEdit->hAlign(), QDeclarativeTextEdit::AlignRight);
514 QCOMPARE(textEdit->effectiveHAlign(), QDeclarativeTextEdit::AlignLeft);
515 QVERIFY(textEdit->positionToRectangle(0).x() < canvas->width()/2);
517 // mirrored explicitly left aligned behaves as right aligned
518 textEdit->setHAlign(QDeclarativeTextEdit::AlignLeft);
519 QCOMPARE(textEdit->hAlign(), QDeclarativeTextEdit::AlignLeft);
520 QCOMPARE(textEdit->effectiveHAlign(), QDeclarativeTextEdit::AlignRight);
521 QVERIFY(textEdit->positionToRectangle(0).x() > canvas->width()/2);
524 QDeclarativeItemPrivate::get(textEdit)->setLayoutMirror(false);
525 textEdit->resetHAlign();
527 // English text should be implicitly left aligned
528 textEdit->setText("Hello world!");
529 QCOMPARE(textEdit->hAlign(), QDeclarativeTextEdit::AlignLeft);
530 QVERIFY(textEdit->positionToRectangle(0).x() < canvas->width()/2);
532 #ifndef Q_OS_MAC // QTBUG-18040
533 // empty text with implicit alignment follows the system locale-based
534 // keyboard input direction from QApplication::keyboardInputDirection
535 textEdit->setText("");
536 QCOMPARE(textEdit->hAlign(), QApplication::keyboardInputDirection() == Qt::LeftToRight ?
537 QDeclarativeTextEdit::AlignLeft : QDeclarativeTextEdit::AlignRight);
538 if (QApplication::keyboardInputDirection() == Qt::LeftToRight)
539 QVERIFY(textEdit->positionToRectangle(0).x() < canvas->width()/2);
541 QVERIFY(textEdit->positionToRectangle(0).x() > canvas->width()/2);
542 textEdit->setHAlign(QDeclarativeTextEdit::AlignRight);
543 QCOMPARE(textEdit->hAlign(), QDeclarativeTextEdit::AlignRight);
544 QVERIFY(textEdit->positionToRectangle(0).x() > canvas->width()/2);
549 #ifndef Q_OS_MAC // QTBUG-18040
550 // alignment of TextEdit with no text set to it
551 QString componentStr = "import QtQuick 1.0\nTextEdit {}";
552 QDeclarativeComponent textComponent(&engine);
553 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
554 QDeclarativeTextEdit *textObject = qobject_cast<QDeclarativeTextEdit*>(textComponent.create());
555 QCOMPARE(textObject->hAlign(), QApplication::keyboardInputDirection() == Qt::LeftToRight ?
556 QDeclarativeTextEdit::AlignLeft : QDeclarativeTextEdit::AlignRight);
561 void tst_qdeclarativetextedit::vAlign()
563 //test one align each, and then test if two align fails.
565 for (int i = 0; i < standard.size(); i++)
567 for (int j=0; j < vAlignmentStrings.size(); j++)
569 QString componentStr = "import QtQuick 1.0\nTextEdit { verticalAlignment: \"" + vAlignmentStrings.at(j) + "\"; text: \"" + standard.at(i) + "\" }";
570 QDeclarativeComponent texteditComponent(&engine);
571 texteditComponent.setData(componentStr.toLatin1(), QUrl());
572 QDeclarativeTextEdit *textEditObject = qobject_cast<QDeclarativeTextEdit*>(texteditComponent.create());
574 QVERIFY(textEditObject != 0);
575 QCOMPARE((int)textEditObject->vAlign(), (int)vAlignments.at(j));
579 for (int i = 0; i < richText.size(); i++)
581 for (int j=0; j < vAlignmentStrings.size(); j++)
583 QString componentStr = "import QtQuick 1.0\nTextEdit { verticalAlignment: \"" + vAlignmentStrings.at(j) + "\"; text: \"" + richText.at(i) + "\" }";
584 QDeclarativeComponent texteditComponent(&engine);
585 texteditComponent.setData(componentStr.toLatin1(), QUrl());
586 QDeclarativeTextEdit *textEditObject = qobject_cast<QDeclarativeTextEdit*>(texteditComponent.create());
588 QVERIFY(textEditObject != 0);
589 QCOMPARE((int)textEditObject->vAlign(), (int)vAlignments.at(j));
595 void tst_qdeclarativetextedit::font()
597 //test size, then bold, then italic, then family
599 QString componentStr = "import QtQuick 1.0\nTextEdit { font.pointSize: 40; text: \"Hello World\" }";
600 QDeclarativeComponent texteditComponent(&engine);
601 texteditComponent.setData(componentStr.toLatin1(), QUrl());
602 QDeclarativeTextEdit *textEditObject = qobject_cast<QDeclarativeTextEdit*>(texteditComponent.create());
604 QVERIFY(textEditObject != 0);
605 QCOMPARE(textEditObject->font().pointSize(), 40);
606 QCOMPARE(textEditObject->font().bold(), false);
607 QCOMPARE(textEditObject->font().italic(), false);
611 QString componentStr = "import QtQuick 1.0\nTextEdit { font.bold: true; text: \"Hello World\" }";
612 QDeclarativeComponent texteditComponent(&engine);
613 texteditComponent.setData(componentStr.toLatin1(), QUrl());
614 QDeclarativeTextEdit *textEditObject = qobject_cast<QDeclarativeTextEdit*>(texteditComponent.create());
616 QVERIFY(textEditObject != 0);
617 QCOMPARE(textEditObject->font().bold(), true);
618 QCOMPARE(textEditObject->font().italic(), false);
622 QString componentStr = "import QtQuick 1.0\nTextEdit { font.italic: true; text: \"Hello World\" }";
623 QDeclarativeComponent texteditComponent(&engine);
624 texteditComponent.setData(componentStr.toLatin1(), QUrl());
625 QDeclarativeTextEdit *textEditObject = qobject_cast<QDeclarativeTextEdit*>(texteditComponent.create());
627 QVERIFY(textEditObject != 0);
628 QCOMPARE(textEditObject->font().italic(), true);
629 QCOMPARE(textEditObject->font().bold(), false);
633 QString componentStr = "import QtQuick 1.0\nTextEdit { font.family: \"Helvetica\"; text: \"Hello World\" }";
634 QDeclarativeComponent texteditComponent(&engine);
635 texteditComponent.setData(componentStr.toLatin1(), QUrl());
636 QDeclarativeTextEdit *textEditObject = qobject_cast<QDeclarativeTextEdit*>(texteditComponent.create());
638 QVERIFY(textEditObject != 0);
639 QCOMPARE(textEditObject->font().family(), QString("Helvetica"));
640 QCOMPARE(textEditObject->font().bold(), false);
641 QCOMPARE(textEditObject->font().italic(), false);
645 QString componentStr = "import QtQuick 1.0\nTextEdit { font.family: \"\"; text: \"Hello World\" }";
646 QDeclarativeComponent texteditComponent(&engine);
647 texteditComponent.setData(componentStr.toLatin1(), QUrl());
648 QDeclarativeTextEdit *textEditObject = qobject_cast<QDeclarativeTextEdit*>(texteditComponent.create());
650 QVERIFY(textEditObject != 0);
651 QCOMPARE(textEditObject->font().family(), QString(""));
655 void tst_qdeclarativetextedit::color()
659 QString componentStr = "import QtQuick 1.0\nTextEdit { text: \"Hello World\" }";
660 QDeclarativeComponent texteditComponent(&engine);
661 texteditComponent.setData(componentStr.toLatin1(), QUrl());
662 QDeclarativeTextEdit *textEditObject = qobject_cast<QDeclarativeTextEdit*>(texteditComponent.create());
664 QDeclarativeTextEditPrivate *textEditPrivate = static_cast<QDeclarativeTextEditPrivate*>(QDeclarativeItemPrivate::get(textEditObject));
666 QVERIFY(textEditObject);
667 QVERIFY(textEditPrivate);
668 QVERIFY(textEditPrivate->control);
670 QPalette pal = textEditPrivate->control->palette();
671 QCOMPARE(textEditPrivate->color, QColor("black"));
672 QCOMPARE(textEditPrivate->color, pal.color(QPalette::Text));
675 for (int i = 0; i < colorStrings.size(); i++)
677 QString componentStr = "import QtQuick 1.0\nTextEdit { color: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
678 QDeclarativeComponent texteditComponent(&engine);
679 texteditComponent.setData(componentStr.toLatin1(), QUrl());
680 QDeclarativeTextEdit *textEditObject = qobject_cast<QDeclarativeTextEdit*>(texteditComponent.create());
681 //qDebug() << "textEditObject: " << textEditObject->color() << "vs. " << QColor(colorStrings.at(i));
682 QVERIFY(textEditObject != 0);
683 QCOMPARE(textEditObject->color(), QColor(colorStrings.at(i)));
687 for (int i = 0; i < colorStrings.size(); i++)
689 QString componentStr = "import QtQuick 1.0\nTextEdit { selectionColor: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
690 QDeclarativeComponent texteditComponent(&engine);
691 texteditComponent.setData(componentStr.toLatin1(), QUrl());
692 QDeclarativeTextEdit *textEditObject = qobject_cast<QDeclarativeTextEdit*>(texteditComponent.create());
693 QVERIFY(textEditObject != 0);
694 QCOMPARE(textEditObject->selectionColor(), QColor(colorStrings.at(i)));
698 for (int i = 0; i < colorStrings.size(); i++)
700 QString componentStr = "import QtQuick 1.0\nTextEdit { selectedTextColor: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
701 QDeclarativeComponent texteditComponent(&engine);
702 texteditComponent.setData(componentStr.toLatin1(), QUrl());
703 QDeclarativeTextEdit *textEditObject = qobject_cast<QDeclarativeTextEdit*>(texteditComponent.create());
704 QVERIFY(textEditObject != 0);
705 QCOMPARE(textEditObject->selectedTextColor(), QColor(colorStrings.at(i)));
709 QString colorStr = "#AA001234";
710 QColor testColor("#001234");
711 testColor.setAlpha(170);
713 QString componentStr = "import QtQuick 1.0\nTextEdit { color: \"" + colorStr + "\"; text: \"Hello World\" }";
714 QDeclarativeComponent texteditComponent(&engine);
715 texteditComponent.setData(componentStr.toLatin1(), QUrl());
716 QDeclarativeTextEdit *textEditObject = qobject_cast<QDeclarativeTextEdit*>(texteditComponent.create());
718 QVERIFY(textEditObject != 0);
719 QCOMPARE(textEditObject->color(), testColor);
723 void tst_qdeclarativetextedit::textMargin()
725 for(qreal i=0; i<=10; i+=0.3){
726 QString componentStr = "import QtQuick 1.0\nTextEdit { textMargin: " + QString::number(i) + "; text: \"Hello World\" }";
727 QDeclarativeComponent texteditComponent(&engine);
728 texteditComponent.setData(componentStr.toLatin1(), QUrl());
729 QDeclarativeTextEdit *textEditObject = qobject_cast<QDeclarativeTextEdit*>(texteditComponent.create());
730 QVERIFY(textEditObject != 0);
731 QCOMPARE(textEditObject->textMargin(), i);
735 void tst_qdeclarativetextedit::persistentSelection()
738 QString componentStr = "import QtQuick 1.0\nTextEdit { persistentSelection: true; text: \"Hello World\" }";
739 QDeclarativeComponent texteditComponent(&engine);
740 texteditComponent.setData(componentStr.toLatin1(), QUrl());
741 QDeclarativeTextEdit *textEditObject = qobject_cast<QDeclarativeTextEdit*>(texteditComponent.create());
742 QVERIFY(textEditObject != 0);
743 QCOMPARE(textEditObject->persistentSelection(), true);
747 QString componentStr = "import QtQuick 1.0\nTextEdit { persistentSelection: false; text: \"Hello World\" }";
748 QDeclarativeComponent texteditComponent(&engine);
749 texteditComponent.setData(componentStr.toLatin1(), QUrl());
750 QDeclarativeTextEdit *textEditObject = qobject_cast<QDeclarativeTextEdit*>(texteditComponent.create());
751 QVERIFY(textEditObject != 0);
752 QCOMPARE(textEditObject->persistentSelection(), false);
756 void tst_qdeclarativetextedit::focusOnPress()
759 QString componentStr = "import QtQuick 1.0\nTextEdit { activeFocusOnPress: true; text: \"Hello World\" }";
760 QDeclarativeComponent texteditComponent(&engine);
761 texteditComponent.setData(componentStr.toLatin1(), QUrl());
762 QDeclarativeTextEdit *textEditObject = qobject_cast<QDeclarativeTextEdit*>(texteditComponent.create());
763 QVERIFY(textEditObject != 0);
764 QCOMPARE(textEditObject->focusOnPress(), true);
768 QString componentStr = "import QtQuick 1.0\nTextEdit { activeFocusOnPress: false; text: \"Hello World\" }";
769 QDeclarativeComponent texteditComponent(&engine);
770 texteditComponent.setData(componentStr.toLatin1(), QUrl());
771 QDeclarativeTextEdit *textEditObject = qobject_cast<QDeclarativeTextEdit*>(texteditComponent.create());
772 QVERIFY(textEditObject != 0);
773 QCOMPARE(textEditObject->focusOnPress(), false);
777 void tst_qdeclarativetextedit::selection()
779 QString testStr = standard[0];//TODO: What should happen for multiline/rich text?
780 QString componentStr = "import QtQuick 1.0\nTextEdit { text: \""+ testStr +"\"; }";
781 QDeclarativeComponent texteditComponent(&engine);
782 texteditComponent.setData(componentStr.toLatin1(), QUrl());
783 QDeclarativeTextEdit *textEditObject = qobject_cast<QDeclarativeTextEdit*>(texteditComponent.create());
784 QVERIFY(textEditObject != 0);
787 //Test selection follows cursor
788 for(int i=0; i<= testStr.size(); i++) {
789 textEditObject->setCursorPosition(i);
790 QCOMPARE(textEditObject->cursorPosition(), i);
791 QCOMPARE(textEditObject->selectionStart(), i);
792 QCOMPARE(textEditObject->selectionEnd(), i);
793 QVERIFY(textEditObject->selectedText().isNull());
795 //Test cursor follows selection
796 for(int i=0; i<= testStr.size(); i++) {
797 textEditObject->select(i,i);
798 QCOMPARE(textEditObject->cursorPosition(), i);
799 QCOMPARE(textEditObject->selectionStart(), i);
800 QCOMPARE(textEditObject->selectionEnd(), i);
804 textEditObject->setCursorPosition(0);
805 QVERIFY(textEditObject->cursorPosition() == 0);
806 QVERIFY(textEditObject->selectionStart() == 0);
807 QVERIFY(textEditObject->selectionEnd() == 0);
808 QVERIFY(textEditObject->selectedText().isNull());
810 // Verify invalid positions are ignored.
811 textEditObject->setCursorPosition(-1);
812 QVERIFY(textEditObject->cursorPosition() == 0);
813 QVERIFY(textEditObject->selectionStart() == 0);
814 QVERIFY(textEditObject->selectionEnd() == 0);
815 QVERIFY(textEditObject->selectedText().isNull());
817 textEditObject->setCursorPosition(textEditObject->text().count()+1);
818 QVERIFY(textEditObject->cursorPosition() == 0);
819 QVERIFY(textEditObject->selectionStart() == 0);
820 QVERIFY(textEditObject->selectionEnd() == 0);
821 QVERIFY(textEditObject->selectedText().isNull());
824 for(int i=0; i<= testStr.size(); i++) {
825 textEditObject->select(0,i);
826 QCOMPARE(testStr.mid(0,i), textEditObject->selectedText());
827 QCOMPARE(textEditObject->cursorPosition(), i);
829 for(int i=0; i<= testStr.size(); i++) {
830 textEditObject->select(i,testStr.size());
831 QCOMPARE(testStr.mid(i,testStr.size()-i), textEditObject->selectedText());
832 QCOMPARE(textEditObject->cursorPosition(), testStr.size());
835 textEditObject->setCursorPosition(0);
836 QVERIFY(textEditObject->cursorPosition() == 0);
837 QVERIFY(textEditObject->selectionStart() == 0);
838 QVERIFY(textEditObject->selectionEnd() == 0);
839 QVERIFY(textEditObject->selectedText().isNull());
841 //Test Error Ignoring behaviour
842 textEditObject->setCursorPosition(0);
843 QVERIFY(textEditObject->selectedText().isNull());
844 textEditObject->select(-10,0);
845 QVERIFY(textEditObject->selectedText().isNull());
846 textEditObject->select(100,101);
847 QVERIFY(textEditObject->selectedText().isNull());
848 textEditObject->select(0,-10);
849 QVERIFY(textEditObject->selectedText().isNull());
850 textEditObject->select(0,100);
851 QVERIFY(textEditObject->selectedText().isNull());
852 textEditObject->select(0,10);
853 QVERIFY(textEditObject->selectedText().size() == 10);
854 textEditObject->select(-10,0);
855 QVERIFY(textEditObject->selectedText().size() == 10);
856 textEditObject->select(100,101);
857 QVERIFY(textEditObject->selectedText().size() == 10);
858 textEditObject->select(0,-10);
859 QVERIFY(textEditObject->selectedText().size() == 10);
860 textEditObject->select(0,100);
861 QVERIFY(textEditObject->selectedText().size() == 10);
863 textEditObject->deselect();
864 QVERIFY(textEditObject->selectedText().isNull());
865 textEditObject->select(0,10);
866 QVERIFY(textEditObject->selectedText().size() == 10);
867 textEditObject->deselect();
868 QVERIFY(textEditObject->selectedText().isNull());
871 void tst_qdeclarativetextedit::isRightToLeft_data()
873 QTest::addColumn<QString>("text");
874 QTest::addColumn<bool>("emptyString");
875 QTest::addColumn<bool>("firstCharacter");
876 QTest::addColumn<bool>("lastCharacter");
877 QTest::addColumn<bool>("middleCharacter");
878 QTest::addColumn<bool>("startString");
879 QTest::addColumn<bool>("midString");
880 QTest::addColumn<bool>("endString");
882 const quint16 arabic_str[] = { 0x0638, 0x0643, 0x00646, 0x0647, 0x0633, 0x0638, 0x0643, 0x00646, 0x0647, 0x0633, 0x0647};
883 QTest::newRow("Empty") << "" << false << false << false << false << false << false << false;
884 QTest::newRow("Neutral") << "23244242" << false << false << false << false << false << false << false;
885 QTest::newRow("LTR") << "Hello world" << false << false << false << false << false << false << false;
886 QTest::newRow("RTL") << QString::fromUtf16(arabic_str, 11) << false << true << true << true << true << true << true;
887 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;
888 QTest::newRow("Bidi LTR + RTL + LTR") << QString("Hello world") + QString::fromUtf16(arabic_str, 11) + QString("Hello world") << false << false << false << true << false << false << false;
891 void tst_qdeclarativetextedit::isRightToLeft()
893 QFETCH(QString, text);
894 QFETCH(bool, emptyString);
895 QFETCH(bool, firstCharacter);
896 QFETCH(bool, lastCharacter);
897 QFETCH(bool, middleCharacter);
898 QFETCH(bool, startString);
899 QFETCH(bool, midString);
900 QFETCH(bool, endString);
902 QDeclarativeTextEdit textEdit;
903 textEdit.setText(text);
905 // first test that the right string is delivered to the QString::isRightToLeft()
906 QCOMPARE(textEdit.isRightToLeft(0,0), text.mid(0,0).isRightToLeft());
907 QCOMPARE(textEdit.isRightToLeft(0,1), text.mid(0,1).isRightToLeft());
908 QCOMPARE(textEdit.isRightToLeft(text.count()-2, text.count()-1), text.mid(text.count()-2, text.count()-1).isRightToLeft());
909 QCOMPARE(textEdit.isRightToLeft(text.count()/2, text.count()/2 + 1), text.mid(text.count()/2, text.count()/2 + 1).isRightToLeft());
910 QCOMPARE(textEdit.isRightToLeft(0,text.count()/4), text.mid(0,text.count()/4).isRightToLeft());
911 QCOMPARE(textEdit.isRightToLeft(text.count()/4,3*text.count()/4), text.mid(text.count()/4,3*text.count()/4).isRightToLeft());
913 QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML TextEdit: isRightToLeft(start, end) called with the end property being smaller than the start.");
914 QCOMPARE(textEdit.isRightToLeft(3*text.count()/4,text.count()-1), text.mid(3*text.count()/4,text.count()-1).isRightToLeft());
916 // then test that the feature actually works
917 QCOMPARE(textEdit.isRightToLeft(0,0), emptyString);
918 QCOMPARE(textEdit.isRightToLeft(0,1), firstCharacter);
919 QCOMPARE(textEdit.isRightToLeft(text.count()-2, text.count()-1), lastCharacter);
920 QCOMPARE(textEdit.isRightToLeft(text.count()/2, text.count()/2 + 1), middleCharacter);
921 QCOMPARE(textEdit.isRightToLeft(0,text.count()/4), startString);
922 QCOMPARE(textEdit.isRightToLeft(text.count()/4,3*text.count()/4), midString);
924 QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML TextEdit: isRightToLeft(start, end) called with the end property being smaller than the start.");
925 QCOMPARE(textEdit.isRightToLeft(3*text.count()/4,text.count()-1), endString);
928 void tst_qdeclarativetextedit::keySelection()
930 QDeclarativeView *canvas = createView(SRCDIR "/data/navigation.qml");
932 QApplication::setActiveWindow(canvas);
933 QTest::qWaitForWindowShown(canvas);
934 QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(canvas));
937 QVERIFY(canvas->rootObject() != 0);
939 QDeclarativeTextEdit *input = qobject_cast<QDeclarativeTextEdit *>(qvariant_cast<QObject *>(canvas->rootObject()->property("myInput")));
942 QTRY_VERIFY(input->hasActiveFocus() == true);
944 QSignalSpy spy(input, SIGNAL(selectionChanged()));
946 simulateKey(canvas, Qt::Key_Right, Qt::ShiftModifier);
947 QVERIFY(input->hasActiveFocus() == true);
948 QCOMPARE(input->selectedText(), QString("a"));
949 QCOMPARE(spy.count(), 1);
950 simulateKey(canvas, Qt::Key_Right);
951 QVERIFY(input->hasActiveFocus() == true);
952 QCOMPARE(input->selectedText(), QString());
953 QCOMPARE(spy.count(), 2);
954 simulateKey(canvas, Qt::Key_Right);
955 QVERIFY(input->hasActiveFocus() == false);
956 QCOMPARE(input->selectedText(), QString());
957 QCOMPARE(spy.count(), 2);
959 simulateKey(canvas, Qt::Key_Left);
960 QVERIFY(input->hasActiveFocus() == true);
961 QCOMPARE(spy.count(), 2);
962 simulateKey(canvas, Qt::Key_Left, Qt::ShiftModifier);
963 QVERIFY(input->hasActiveFocus() == true);
964 QCOMPARE(input->selectedText(), QString("a"));
965 QCOMPARE(spy.count(), 3);
966 simulateKey(canvas, Qt::Key_Left);
967 QVERIFY(input->hasActiveFocus() == true);
968 QCOMPARE(input->selectedText(), QString());
969 QCOMPARE(spy.count(), 4);
970 simulateKey(canvas, Qt::Key_Left);
971 QVERIFY(input->hasActiveFocus() == false);
972 QCOMPARE(input->selectedText(), QString());
973 QCOMPARE(spy.count(), 4);
978 void tst_qdeclarativetextedit::moveCursorSelection_data()
980 QTest::addColumn<QString>("testStr");
981 QTest::addColumn<int>("cursorPosition");
982 QTest::addColumn<int>("movePosition");
983 QTest::addColumn<QDeclarativeTextEdit::SelectionMode>("mode");
984 QTest::addColumn<int>("selectionStart");
985 QTest::addColumn<int>("selectionEnd");
986 QTest::addColumn<bool>("reversible");
988 QTest::newRow("(t)he|characters")
989 << standard[0] << 0 << 1 << QDeclarativeTextEdit::SelectCharacters << 0 << 1 << true;
990 QTest::newRow("do(g)|characters")
991 << standard[0] << 43 << 44 << QDeclarativeTextEdit::SelectCharacters << 43 << 44 << true;
992 QTest::newRow("jum(p)ed|characters")
993 << standard[0] << 23 << 24 << QDeclarativeTextEdit::SelectCharacters << 23 << 24 << true;
994 QTest::newRow("jumped( )over|characters")
995 << standard[0] << 26 << 27 << QDeclarativeTextEdit::SelectCharacters << 26 << 27 << true;
996 QTest::newRow("(the )|characters")
997 << standard[0] << 0 << 4 << QDeclarativeTextEdit::SelectCharacters << 0 << 4 << true;
998 QTest::newRow("( dog)|characters")
999 << standard[0] << 40 << 44 << QDeclarativeTextEdit::SelectCharacters << 40 << 44 << true;
1000 QTest::newRow("( jumped )|characters")
1001 << standard[0] << 19 << 27 << QDeclarativeTextEdit::SelectCharacters << 19 << 27 << true;
1002 QTest::newRow("th(e qu)ick|characters")
1003 << standard[0] << 2 << 6 << QDeclarativeTextEdit::SelectCharacters << 2 << 6 << true;
1004 QTest::newRow("la(zy d)og|characters")
1005 << standard[0] << 38 << 42 << QDeclarativeTextEdit::SelectCharacters << 38 << 42 << true;
1006 QTest::newRow("jum(ped ov)er|characters")
1007 << standard[0] << 23 << 29 << QDeclarativeTextEdit::SelectCharacters << 23 << 29 << true;
1008 QTest::newRow("()the|characters")
1009 << standard[0] << 0 << 0 << QDeclarativeTextEdit::SelectCharacters << 0 << 0 << true;
1010 QTest::newRow("dog()|characters")
1011 << standard[0] << 44 << 44 << QDeclarativeTextEdit::SelectCharacters << 44 << 44 << true;
1012 QTest::newRow("jum()ped|characters")
1013 << standard[0] << 23 << 23 << QDeclarativeTextEdit::SelectCharacters << 23 << 23 << true;
1015 QTest::newRow("<(t)he>|words")
1016 << standard[0] << 0 << 1 << QDeclarativeTextEdit::SelectWords << 0 << 3 << true;
1017 QTest::newRow("<do(g)>|words")
1018 << standard[0] << 43 << 44 << QDeclarativeTextEdit::SelectWords << 41 << 44 << true;
1019 QTest::newRow("<jum(p)ed>|words")
1020 << standard[0] << 23 << 24 << QDeclarativeTextEdit::SelectWords << 20 << 26 << true;
1021 QTest::newRow("<jumped( )>over|words")
1022 << standard[0] << 26 << 27 << QDeclarativeTextEdit::SelectWords << 20 << 27 << false;
1023 QTest::newRow("jumped<( )over>|words,reversed")
1024 << standard[0] << 27 << 26 << QDeclarativeTextEdit::SelectWords << 26 << 31 << false;
1025 QTest::newRow("<(the )>quick|words")
1026 << standard[0] << 0 << 4 << QDeclarativeTextEdit::SelectWords << 0 << 4 << false;
1027 QTest::newRow("<(the )quick>|words,reversed")
1028 << standard[0] << 4 << 0 << QDeclarativeTextEdit::SelectWords << 0 << 9 << false;
1029 QTest::newRow("<lazy( dog)>|words")
1030 << standard[0] << 40 << 44 << QDeclarativeTextEdit::SelectWords << 36 << 44 << false;
1031 QTest::newRow("lazy<( dog)>|words,reversed")
1032 << standard[0] << 44 << 40 << QDeclarativeTextEdit::SelectWords << 40 << 44 << false;
1033 QTest::newRow("<fox( jumped )>over|words")
1034 << standard[0] << 19 << 27 << QDeclarativeTextEdit::SelectWords << 16 << 27 << false;
1035 QTest::newRow("fox<( jumped )over>|words,reversed")
1036 << standard[0] << 27 << 19 << QDeclarativeTextEdit::SelectWords << 19 << 31 << false;
1037 QTest::newRow("<th(e qu)ick>|words")
1038 << standard[0] << 2 << 6 << QDeclarativeTextEdit::SelectWords << 0 << 9 << true;
1039 QTest::newRow("<la(zy d)og|words>")
1040 << standard[0] << 38 << 42 << QDeclarativeTextEdit::SelectWords << 36 << 44 << true;
1041 QTest::newRow("<jum(ped ov)er>|words")
1042 << standard[0] << 23 << 29 << QDeclarativeTextEdit::SelectWords << 20 << 31 << true;
1043 QTest::newRow("<()>the|words")
1044 << standard[0] << 0 << 0 << QDeclarativeTextEdit::SelectWords << 0 << 0 << true;
1045 QTest::newRow("dog<()>|words")
1046 << standard[0] << 44 << 44 << QDeclarativeTextEdit::SelectWords << 44 << 44 << true;
1047 QTest::newRow("jum<()>ped|words")
1048 << standard[0] << 23 << 23 << QDeclarativeTextEdit::SelectWords << 23 << 23 << true;
1050 QTest::newRow("Hello<(,)> |words")
1051 << standard[2] << 5 << 6 << QDeclarativeTextEdit::SelectWords << 5 << 6 << true;
1052 QTest::newRow("Hello<(, )>world|words")
1053 << standard[2] << 5 << 7 << QDeclarativeTextEdit::SelectWords << 5 << 7 << false;
1054 QTest::newRow("Hello<(, )world>|words,reversed")
1055 << standard[2] << 7 << 5 << QDeclarativeTextEdit::SelectWords << 5 << 12 << false;
1056 QTest::newRow("<Hel(lo, )>world|words")
1057 << standard[2] << 3 << 7 << QDeclarativeTextEdit::SelectWords << 0 << 7 << false;
1058 QTest::newRow("<Hel(lo, )world>|words,reversed")
1059 << standard[2] << 7 << 3 << QDeclarativeTextEdit::SelectWords << 0 << 12 << false;
1060 QTest::newRow("<Hel(lo)>,|words")
1061 << standard[2] << 3 << 5 << QDeclarativeTextEdit::SelectWords << 0 << 5 << true;
1062 QTest::newRow("Hello<()>,|words")
1063 << standard[2] << 5 << 5 << QDeclarativeTextEdit::SelectWords << 5 << 5 << true;
1064 QTest::newRow("Hello,<()>|words")
1065 << standard[2] << 6 << 6 << QDeclarativeTextEdit::SelectWords << 6 << 6 << true;
1066 QTest::newRow("Hello<,( )>world|words")
1067 << standard[2] << 6 << 7 << QDeclarativeTextEdit::SelectWords << 5 << 7 << false;
1068 QTest::newRow("Hello,<( )world>|words,reversed")
1069 << standard[2] << 7 << 6 << QDeclarativeTextEdit::SelectWords << 6 << 12 << false;
1070 QTest::newRow("Hello<,( world)>|words")
1071 << standard[2] << 6 << 12 << QDeclarativeTextEdit::SelectWords << 5 << 12 << false;
1072 QTest::newRow("Hello,<( world)>|words,reversed")
1073 << standard[2] << 12 << 6 << QDeclarativeTextEdit::SelectWords << 6 << 12 << false;
1074 QTest::newRow("Hello<,( world!)>|words")
1075 << standard[2] << 6 << 13 << QDeclarativeTextEdit::SelectWords << 5 << 13 << false;
1076 QTest::newRow("Hello,<( world!)>|words,reversed")
1077 << standard[2] << 13 << 6 << QDeclarativeTextEdit::SelectWords << 6 << 13 << false;
1078 QTest::newRow("Hello<(, world!)>|words")
1079 << standard[2] << 5 << 13 << QDeclarativeTextEdit::SelectWords << 5 << 13 << true;
1080 QTest::newRow("world<(!)>|words")
1081 << standard[2] << 12 << 13 << QDeclarativeTextEdit::SelectWords << 12 << 13 << true;
1082 QTest::newRow("world!<()>)|words")
1083 << standard[2] << 13 << 13 << QDeclarativeTextEdit::SelectWords << 13 << 13 << true;
1084 QTest::newRow("world<()>!)|words")
1085 << standard[2] << 12 << 12 << QDeclarativeTextEdit::SelectWords << 12 << 12 << true;
1087 QTest::newRow("<(,)>olleH |words")
1088 << standard[3] << 7 << 8 << QDeclarativeTextEdit::SelectWords << 7 << 8 << true;
1089 QTest::newRow("<dlrow( ,)>olleH|words")
1090 << standard[3] << 6 << 8 << QDeclarativeTextEdit::SelectWords << 1 << 8 << false;
1091 QTest::newRow("dlrow<( ,)>olleH|words,reversed")
1092 << standard[3] << 8 << 6 << QDeclarativeTextEdit::SelectWords << 6 << 8 << false;
1093 QTest::newRow("<dlrow( ,ol)leH>|words")
1094 << standard[3] << 6 << 10 << QDeclarativeTextEdit::SelectWords << 1 << 13 << false;
1095 QTest::newRow("dlrow<( ,ol)leH>|words,reversed")
1096 << standard[3] << 10 << 6 << QDeclarativeTextEdit::SelectWords << 6 << 13 << false;
1097 QTest::newRow(",<(ol)leH>,|words")
1098 << standard[3] << 8 << 10 << QDeclarativeTextEdit::SelectWords << 8 << 13 << true;
1099 QTest::newRow(",<()>olleH|words")
1100 << standard[3] << 8 << 8 << QDeclarativeTextEdit::SelectWords << 8 << 8 << true;
1101 QTest::newRow("<()>,olleH|words")
1102 << standard[3] << 7 << 7 << QDeclarativeTextEdit::SelectWords << 7 << 7 << true;
1103 QTest::newRow("<dlrow( )>,olleH|words")
1104 << standard[3] << 6 << 7 << QDeclarativeTextEdit::SelectWords << 1 << 7 << false;
1105 QTest::newRow("dlrow<( ),>olleH|words,reversed")
1106 << standard[3] << 7 << 6 << QDeclarativeTextEdit::SelectWords << 6 << 8 << false;
1107 QTest::newRow("<(dlrow )>,olleH|words")
1108 << standard[3] << 1 << 7 << QDeclarativeTextEdit::SelectWords << 1 << 7 << false;
1109 QTest::newRow("<(dlrow ),>olleH|words,reversed")
1110 << standard[3] << 7 << 1 << QDeclarativeTextEdit::SelectWords << 1 << 8 << false;
1111 QTest::newRow("<(!dlrow )>,olleH|words")
1112 << standard[3] << 0 << 7 << QDeclarativeTextEdit::SelectWords << 0 << 7 << false;
1113 QTest::newRow("<(!dlrow ),>olleH|words,reversed")
1114 << standard[3] << 7 << 0 << QDeclarativeTextEdit::SelectWords << 0 << 8 << false;
1115 QTest::newRow("(!dlrow ,)olleH|words")
1116 << standard[3] << 0 << 8 << QDeclarativeTextEdit::SelectWords << 0 << 8 << true;
1117 QTest::newRow("<(!)>dlrow|words")
1118 << standard[3] << 0 << 1 << QDeclarativeTextEdit::SelectWords << 0 << 1 << true;
1119 QTest::newRow("<()>!dlrow|words")
1120 << standard[3] << 0 << 0 << QDeclarativeTextEdit::SelectWords << 0 << 0 << true;
1121 QTest::newRow("!<()>dlrow|words")
1122 << standard[3] << 1 << 1 << QDeclarativeTextEdit::SelectWords << 1 << 1 << true;
1125 void tst_qdeclarativetextedit::moveCursorSelection()
1127 QFETCH(QString, testStr);
1128 QFETCH(int, cursorPosition);
1129 QFETCH(int, movePosition);
1130 QFETCH(QDeclarativeTextEdit::SelectionMode, mode);
1131 QFETCH(int, selectionStart);
1132 QFETCH(int, selectionEnd);
1133 QFETCH(bool, reversible);
1135 QString componentStr = "import QtQuick 1.1\nTextEdit { text: \""+ testStr +"\"; }";
1136 QDeclarativeComponent textinputComponent(&engine);
1137 textinputComponent.setData(componentStr.toLatin1(), QUrl());
1138 QDeclarativeTextEdit *texteditObject = qobject_cast<QDeclarativeTextEdit*>(textinputComponent.create());
1139 QVERIFY(texteditObject != 0);
1141 texteditObject->setCursorPosition(cursorPosition);
1142 texteditObject->moveCursorSelection(movePosition, mode);
1144 QCOMPARE(texteditObject->selectedText(), testStr.mid(selectionStart, selectionEnd - selectionStart));
1145 QCOMPARE(texteditObject->selectionStart(), selectionStart);
1146 QCOMPARE(texteditObject->selectionEnd(), selectionEnd);
1149 texteditObject->setCursorPosition(movePosition);
1150 texteditObject->moveCursorSelection(cursorPosition, mode);
1152 QCOMPARE(texteditObject->selectedText(), testStr.mid(selectionStart, selectionEnd - selectionStart));
1153 QCOMPARE(texteditObject->selectionStart(), selectionStart);
1154 QCOMPARE(texteditObject->selectionEnd(), selectionEnd);
1158 void tst_qdeclarativetextedit::moveCursorSelectionSequence_data()
1160 QTest::addColumn<QString>("testStr");
1161 QTest::addColumn<int>("cursorPosition");
1162 QTest::addColumn<int>("movePosition1");
1163 QTest::addColumn<int>("movePosition2");
1164 QTest::addColumn<int>("selection1Start");
1165 QTest::addColumn<int>("selection1End");
1166 QTest::addColumn<int>("selection2Start");
1167 QTest::addColumn<int>("selection2End");
1169 QTest::newRow("the {<quick( bro)wn> f^ox} jumped|ltr")
1174 QTest::newRow("the quick<( {bro)wn> f^ox} jumped|rtl")
1179 QTest::newRow("the {<quick( bro)wn> ^}fox jumped|ltr")
1184 QTest::newRow("the quick<( {bro)wn> ^}fox jumped|rtl")
1189 QTest::newRow("the {<quick( bro)wn^>} fox jumped|ltr")
1194 QTest::newRow("the quick<( {bro)wn^>} f^ox jumped|rtl")
1199 QTest::newRow("the {<quick() ^}bro)wn> fox|ltr")
1204 QTest::newRow("the quick<(^ {^bro)wn>} fox|rtl")
1209 QTest::newRow("the {<quick^}( bro)wn> fox|ltr")
1214 QTest::newRow("the quick{<(^ bro)wn>} fox|rtl")
1219 QTest::newRow("the {<qui^ck}( bro)wn> fox|ltr")
1224 QTest::newRow("the {<qui^ck}( bro)wn> fox|rtl")
1229 QTest::newRow("the {<^quick}( bro)wn> fox|ltr")
1234 QTest::newRow("the {<^quick}( bro)wn> fox|rtl")
1239 QTest::newRow("the{^ <quick}( bro)wn> fox|ltr")
1244 QTest::newRow("the{^ <quick}( bro)wn> fox|rtl")
1249 QTest::newRow("{t^he <quick}( bro)wn> fox|ltr")
1254 QTest::newRow("{t^he <quick}( bro)wn> fox|rtl")
1260 QTest::newRow("{<He(ll)o>, w^orld}!|ltr")
1265 QTest::newRow("{<He(ll)o>, w^orld}!|rtl")
1271 QTest::newRow("!{dlro^w ,<o(ll)eH>}|ltr")
1276 QTest::newRow("!{dlro^w ,<o(ll)eH>}|rtl")
1283 void tst_qdeclarativetextedit::moveCursorSelectionSequence()
1285 QFETCH(QString, testStr);
1286 QFETCH(int, cursorPosition);
1287 QFETCH(int, movePosition1);
1288 QFETCH(int, movePosition2);
1289 QFETCH(int, selection1Start);
1290 QFETCH(int, selection1End);
1291 QFETCH(int, selection2Start);
1292 QFETCH(int, selection2End);
1294 QString componentStr = "import QtQuick 1.1\nTextEdit { text: \""+ testStr +"\"; }";
1295 QDeclarativeComponent texteditComponent(&engine);
1296 texteditComponent.setData(componentStr.toLatin1(), QUrl());
1297 QDeclarativeTextEdit *texteditObject = qobject_cast<QDeclarativeTextEdit*>(texteditComponent.create());
1298 QVERIFY(texteditObject != 0);
1300 texteditObject->setCursorPosition(cursorPosition);
1302 texteditObject->moveCursorSelection(movePosition1, QDeclarativeTextEdit::SelectWords);
1303 QCOMPARE(texteditObject->selectedText(), testStr.mid(selection1Start, selection1End - selection1Start));
1304 QCOMPARE(texteditObject->selectionStart(), selection1Start);
1305 QCOMPARE(texteditObject->selectionEnd(), selection1End);
1307 texteditObject->moveCursorSelection(movePosition2, QDeclarativeTextEdit::SelectWords);
1308 QCOMPARE(texteditObject->selectedText(), testStr.mid(selection2Start, selection2End - selection2Start));
1309 QCOMPARE(texteditObject->selectionStart(), selection2Start);
1310 QCOMPARE(texteditObject->selectionEnd(), selection2End);
1314 void tst_qdeclarativetextedit::mouseSelection_data()
1316 QTest::addColumn<QString>("qmlfile");
1317 QTest::addColumn<bool>("expectSelection");
1320 QTest::newRow("on") << SRCDIR "/data/mouseselection_true.qml" << true;
1321 QTest::newRow("off") << SRCDIR "/data/mouseselection_false.qml" << false;
1322 QTest::newRow("default") << SRCDIR "/data/mouseselection_default.qml" << false;
1323 QTest::newRow("on word selection") << SRCDIR "/data/mouseselection_true_words.qml" << true;
1324 QTest::newRow("off word selection") << SRCDIR "/data/mouseselection_false_words.qml" << false;
1327 void tst_qdeclarativetextedit::mouseSelection()
1329 QFETCH(QString, qmlfile);
1330 QFETCH(bool, expectSelection);
1332 QDeclarativeView *canvas = createView(qmlfile);
1335 QApplication::setActiveWindow(canvas);
1336 QTest::qWaitForWindowShown(canvas);
1337 QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(canvas));
1339 QVERIFY(canvas->rootObject() != 0);
1340 QDeclarativeTextEdit *textEditObject = qobject_cast<QDeclarativeTextEdit *>(canvas->rootObject());
1341 QVERIFY(textEditObject != 0);
1343 // press-and-drag-and-release from x1 to x2
1346 int y = textEditObject->height()/2;
1347 QTest::mousePress(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(x1,y)));
1348 //QTest::mouseMove(canvas->viewport(), canvas->mapFromScene(QPoint(x2,y))); // doesn't work
1349 QMouseEvent mv(QEvent::MouseMove, canvas->mapFromScene(QPoint(x2,y)), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
1350 QApplication::sendEvent(canvas->viewport(), &mv);
1351 QTest::mouseRelease(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(x2,y)));
1352 QString str = textEditObject->selectedText();
1353 if (expectSelection)
1354 QVERIFY(str.length() > 3); // don't reallly care *what* was selected (and it's too sensitive to platform)
1356 QVERIFY(str.isEmpty());
1358 // Clicking and shift to clicking between the same points should select the same text.
1359 textEditObject->setCursorPosition(0);
1360 QTest::mouseClick(canvas->viewport(), Qt::LeftButton, Qt::NoModifier, canvas->mapFromScene(QPoint(x1,y)));
1361 QTest::mouseClick(canvas->viewport(), Qt::LeftButton, Qt::ShiftModifier, canvas->mapFromScene(QPoint(x2,y)));
1362 QCOMPARE(textEditObject->selectedText(), str);
1367 void tst_qdeclarativetextedit::deferEnableSelectByMouse_data()
1369 QTest::addColumn<QString>("qmlfile");
1371 QTest::newRow("writable") << SRCDIR "/data/mouseselection_false.qml";
1372 QTest::newRow("read only") << SRCDIR "/data/mouseselection_false_readonly.qml";
1375 void tst_qdeclarativetextedit::deferEnableSelectByMouse()
1377 // Verify text isn't selected if selectByMouse is enabled after the mouse button has been pressed.
1378 QFETCH(QString, qmlfile);
1380 QDeclarativeView *canvas = createView(qmlfile);
1383 QApplication::setActiveWindow(canvas);
1384 QTest::qWaitForWindowShown(canvas);
1385 QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(canvas));
1387 QVERIFY(canvas->rootObject() != 0);
1388 QDeclarativeTextEdit *textEditObject = qobject_cast<QDeclarativeTextEdit *>(canvas->rootObject());
1389 QVERIFY(textEditObject != 0);
1391 // press-and-drag-and-release from x1 to x2
1394 int y = textEditObject->height()/2;
1396 QTest::mousePress(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(x1,y)));
1397 textEditObject->setSelectByMouse(true);
1398 //QTest::mouseMove(canvas->viewport(), canvas->mapFromScene(QPoint(x2,y))); // doesn't work
1399 QMouseEvent mv(QEvent::MouseMove, canvas->mapFromScene(QPoint(x2,y)), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
1400 QApplication::sendEvent(canvas->viewport(), &mv);
1401 QTest::mouseRelease(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(x2,y)));
1402 QVERIFY(textEditObject->selectedText().isEmpty());
1407 void tst_qdeclarativetextedit::deferDisableSelectByMouse_data()
1409 QTest::addColumn<QString>("qmlfile");
1411 QTest::newRow("writable") << SRCDIR "/data/mouseselection_true.qml";
1412 QTest::newRow("read only") << SRCDIR "/data/mouseselection_true_readonly.qml";
1415 void tst_qdeclarativetextedit::deferDisableSelectByMouse()
1417 // Verify text isn't selected if selectByMouse is enabled after the mouse button has been pressed.
1418 QFETCH(QString, qmlfile);
1420 QDeclarativeView *canvas = createView(qmlfile);
1423 QApplication::setActiveWindow(canvas);
1424 QTest::qWaitForWindowShown(canvas);
1425 QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(canvas));
1427 QVERIFY(canvas->rootObject() != 0);
1428 QDeclarativeTextEdit *textEditObject = qobject_cast<QDeclarativeTextEdit *>(canvas->rootObject());
1429 QVERIFY(textEditObject != 0);
1431 // press-and-drag-and-release from x1 to x2
1434 int y = textEditObject->height()/2;
1436 QTest::mousePress(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(x1,y)));
1437 textEditObject->setSelectByMouse(false);
1438 //QTest::mouseMove(canvas->viewport(), canvas->mapFromScene(QPoint(x2,y))); // doesn't work
1439 QMouseEvent mv(QEvent::MouseMove, canvas->mapFromScene(QPoint(x2,y)), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
1440 QApplication::sendEvent(canvas->viewport(), &mv);
1441 QTest::mouseRelease(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(x2,y)));
1442 QVERIFY(textEditObject->selectedText().length() > 3);
1447 void tst_qdeclarativetextedit::dragMouseSelection()
1449 QString qmlfile = SRCDIR "/data/mouseselection_true.qml";
1451 QDeclarativeView *canvas = createView(qmlfile);
1454 QApplication::setActiveWindow(canvas);
1455 QTest::qWaitForWindowShown(canvas);
1456 QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(canvas));
1458 QVERIFY(canvas->rootObject() != 0);
1459 QDeclarativeTextEdit *textEditObject = qobject_cast<QDeclarativeTextEdit *>(canvas->rootObject());
1460 QVERIFY(textEditObject != 0);
1462 textEditObject->setAcceptDrops(true);
1464 // press-and-drag-and-release from x1 to x2
1467 int y = textEditObject->height()/2;
1468 QTest::mousePress(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(x1,y)));
1470 QMouseEvent mv(QEvent::MouseMove, canvas->mapFromScene(QPoint(x2,y)), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
1471 QApplication::sendEvent(canvas->viewport(), &mv);
1473 QTest::mouseRelease(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(x2,y)));
1474 QString str1 = textEditObject->selectedText();
1475 QVERIFY(str1.length() > 3);
1477 // press and drag the current selection.
1480 QTest::mousePress(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(x1,y)));
1482 QMouseEvent mv(QEvent::MouseMove, canvas->mapFromScene(QPoint(x2,y)), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
1483 QApplication::sendEvent(canvas->viewport(), &mv);
1485 QTest::mouseRelease(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(x2,y)));
1486 QString str2 = textEditObject->selectedText();
1487 QVERIFY(str2.length() > 3);
1489 QVERIFY(str1 != str2); // Verify the second press and drag is a new selection and doesn't not the first moved.
1494 void tst_qdeclarativetextedit::mouseSelectionMode_data()
1496 QTest::addColumn<QString>("qmlfile");
1497 QTest::addColumn<bool>("selectWords");
1500 QTest::newRow("SelectWords") << SRCDIR "/data/mouseselectionmode_words.qml" << true;
1501 QTest::newRow("SelectCharacters") << SRCDIR "/data/mouseselectionmode_characters.qml" << false;
1502 QTest::newRow("default") << SRCDIR "/data/mouseselectionmode_default.qml" << false;
1505 void tst_qdeclarativetextedit::mouseSelectionMode()
1507 QFETCH(QString, qmlfile);
1508 QFETCH(bool, selectWords);
1510 QString text = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1512 QDeclarativeView *canvas = createView(qmlfile);
1515 QApplication::setActiveWindow(canvas);
1516 QTest::qWaitForWindowShown(canvas);
1517 QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(canvas));
1519 QVERIFY(canvas->rootObject() != 0);
1520 QDeclarativeTextEdit *textEditObject = qobject_cast<QDeclarativeTextEdit *>(canvas->rootObject());
1521 QVERIFY(textEditObject != 0);
1523 // press-and-drag-and-release from x1 to x2
1526 int y = textEditObject->height()/2;
1527 QTest::mousePress(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(x1,y)));
1528 //QTest::mouseMove(canvas->viewport(), canvas->mapFromScene(QPoint(x2,y))); // doesn't work
1529 QMouseEvent mv(QEvent::MouseMove, canvas->mapFromScene(QPoint(x2,y)), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
1530 QApplication::sendEvent(canvas->viewport(), &mv);
1531 QTest::mouseRelease(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(x2,y)));
1532 QString str = textEditObject->selectedText();
1534 QCOMPARE(str, text);
1536 QVERIFY(str.length() > 3);
1537 QVERIFY(str != text);
1540 // Clicking and shift to clicking between the same points should select the same text.
1541 textEditObject->setCursorPosition(0);
1542 QTest::mouseClick(canvas->viewport(), Qt::LeftButton, Qt::NoModifier, canvas->mapFromScene(QPoint(x1,y)));
1543 QTest::mouseClick(canvas->viewport(), Qt::LeftButton, Qt::ShiftModifier, canvas->mapFromScene(QPoint(x2,y)));
1544 QCOMPARE(textEditObject->selectedText(), str);
1549 void tst_qdeclarativetextedit::inputMethodHints()
1551 QDeclarativeView *canvas = createView(SRCDIR "/data/inputmethodhints.qml");
1555 QVERIFY(canvas->rootObject() != 0);
1556 QDeclarativeTextEdit *textEditObject = qobject_cast<QDeclarativeTextEdit *>(canvas->rootObject());
1557 QVERIFY(textEditObject != 0);
1558 QVERIFY(textEditObject->inputMethodHints() & Qt::ImhNoPredictiveText);
1559 textEditObject->setInputMethodHints(Qt::ImhUppercaseOnly);
1560 QVERIFY(textEditObject->inputMethodHints() & Qt::ImhUppercaseOnly);
1565 void tst_qdeclarativetextedit::positionAt()
1567 QDeclarativeView *canvas = createView(SRCDIR "/data/positionAt.qml");
1568 QVERIFY(canvas->rootObject() != 0);
1571 QApplication::setActiveWindow(canvas);
1572 QTest::qWaitForWindowShown(canvas);
1574 QDeclarativeTextEdit *texteditObject = qobject_cast<QDeclarativeTextEdit *>(canvas->rootObject());
1575 QVERIFY(texteditObject != 0);
1577 QFontMetrics fm(texteditObject->font());
1578 const int y0 = fm.height() / 2;
1579 const int y1 = fm.height() * 3 / 2;
1581 int pos = texteditObject->positionAt(texteditObject->width()/2, y0);
1582 int diff = abs(int(fm.width(texteditObject->text().left(pos))-texteditObject->width()/2));
1584 // some tollerance for different fonts.
1591 const qreal x0 = texteditObject->positionToRectangle(pos).x();
1592 const qreal x1 = texteditObject->positionToRectangle(pos + 1).x();
1594 QString preeditText = texteditObject->text().mid(0, pos);
1595 texteditObject->setText(texteditObject->text().mid(pos));
1596 texteditObject->setCursorPosition(0);
1598 QInputMethodEvent inputEvent(preeditText, QList<QInputMethodEvent::Attribute>());
1599 QApplication::sendEvent(canvas, &inputEvent);
1601 // Check all points within the preedit text return the same position.
1602 QCOMPARE(texteditObject->positionAt(0, y0), 0);
1603 QCOMPARE(texteditObject->positionAt(x0 / 2, y0), 0);
1604 QCOMPARE(texteditObject->positionAt(x0, y0), 0);
1606 // Verify positioning returns to normal after the preedit text.
1607 QCOMPARE(texteditObject->positionAt(x1, y0), 1);
1608 QCOMPARE(texteditObject->positionToRectangle(1).x(), x1);
1610 QVERIFY(texteditObject->positionAt(x0 / 2, y1) > 0);
1615 void tst_qdeclarativetextedit::cursorDelegate()
1617 QDeclarativeView* view = createView(SRCDIR "/data/cursorTest.qml");
1620 QDeclarativeTextEdit *textEditObject = view->rootObject()->findChild<QDeclarativeTextEdit*>("textEditObject");
1621 QVERIFY(textEditObject != 0);
1622 QVERIFY(textEditObject->findChild<QDeclarativeItem*>("cursorInstance"));
1623 //Test Delegate gets created
1624 textEditObject->setFocus(true);
1625 QDeclarativeItem* delegateObject = textEditObject->findChild<QDeclarativeItem*>("cursorInstance");
1626 QVERIFY(delegateObject);
1627 //Test Delegate gets moved
1628 for(int i=0; i<= textEditObject->text().length(); i++){
1629 textEditObject->setCursorPosition(i);
1630 QCOMPARE(textEditObject->cursorRectangle().x(), qRound(delegateObject->x()));
1631 QCOMPARE(textEditObject->cursorRectangle().y(), qRound(delegateObject->y()));
1633 const QString preedit = "preedit";
1634 for (int i = 0; i <= preedit.length(); i++) {
1635 QInputMethodEvent event(preedit, QList<QInputMethodEvent::Attribute>()
1636 << QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, i, 1, QVariant()));
1637 QApplication::sendEvent(view, &event);
1639 QCOMPARE(textEditObject->cursorRectangle().x(), qRound(delegateObject->x()));
1640 QCOMPARE(textEditObject->cursorRectangle().y(), qRound(delegateObject->y()));
1642 textEditObject->setCursorPosition(0);
1643 QCOMPARE(textEditObject->cursorRectangle().x(), qRound(delegateObject->x()));
1644 QCOMPARE(textEditObject->cursorRectangle().y(), qRound(delegateObject->y()));
1645 QVERIFY(textEditObject->cursorRectangle().y() >= 0);
1646 QVERIFY(textEditObject->cursorRectangle().y() < textEditObject->cursorRectangle().height());
1647 textEditObject->setVAlign(QDeclarativeTextEdit::AlignVCenter);
1648 QCOMPARE(textEditObject->cursorRectangle().x(), qRound(delegateObject->x()));
1649 QCOMPARE(textEditObject->cursorRectangle().y(), qRound(delegateObject->y()));
1650 QVERIFY(textEditObject->cursorRectangle().y() > (textEditObject->height() / 2) - textEditObject->cursorRectangle().height());
1651 QVERIFY(textEditObject->cursorRectangle().y() < (textEditObject->height() / 2) + textEditObject->cursorRectangle().height());
1652 textEditObject->setVAlign(QDeclarativeTextEdit::AlignBottom);
1653 QCOMPARE(textEditObject->cursorRectangle().x(), qRound(delegateObject->x()));
1654 QCOMPARE(textEditObject->cursorRectangle().y(), qRound(delegateObject->y()));
1655 QVERIFY(textEditObject->cursorRectangle().y() > textEditObject->height() - (textEditObject->cursorRectangle().height() * 2));
1656 QVERIFY(textEditObject->cursorRectangle().y() < textEditObject->height());
1658 //Test Delegate gets deleted
1659 textEditObject->setCursorDelegate(0);
1660 QVERIFY(!textEditObject->findChild<QDeclarativeItem*>("cursorInstance"));
1665 void tst_qdeclarativetextedit::cursorVisible()
1667 QGraphicsScene scene;
1668 QGraphicsView view(&scene);
1670 QApplication::setActiveWindow(&view);
1671 QTest::qWaitForWindowShown(&view);
1672 QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
1675 QDeclarativeTextEdit edit;
1676 QSignalSpy spy(&edit, SIGNAL(cursorVisibleChanged(bool)));
1678 QCOMPARE(edit.isCursorVisible(), false);
1680 edit.setCursorVisible(true);
1681 QCOMPARE(edit.isCursorVisible(), true);
1682 QCOMPARE(spy.count(), 1);
1684 edit.setCursorVisible(false);
1685 QCOMPARE(edit.isCursorVisible(), false);
1686 QCOMPARE(spy.count(), 2);
1688 edit.setFocus(true);
1689 QCOMPARE(edit.isCursorVisible(), false);
1690 QCOMPARE(spy.count(), 2);
1692 scene.addItem(&edit);
1693 QCOMPARE(edit.isCursorVisible(), true);
1694 QCOMPARE(spy.count(), 3);
1696 edit.setFocus(false);
1697 QCOMPARE(edit.isCursorVisible(), false);
1698 QCOMPARE(spy.count(), 4);
1700 edit.setFocus(true);
1701 QCOMPARE(edit.isCursorVisible(), true);
1702 QCOMPARE(spy.count(), 5);
1705 QCOMPARE(edit.isCursorVisible(), false);
1706 QCOMPARE(spy.count(), 6);
1709 QCOMPARE(edit.isCursorVisible(), true);
1710 QCOMPARE(spy.count(), 7);
1713 QCOMPARE(edit.isCursorVisible(), false);
1714 QCOMPARE(spy.count(), 8);
1717 QCOMPARE(edit.isCursorVisible(), true);
1718 QCOMPARE(spy.count(), 9);
1720 // on mac, setActiveWindow(0) on mac does not deactivate the current application
1721 // (you have to switch to a different app or hide the current app to trigger this)
1722 #if !defined(Q_WS_MAC)
1723 QApplication::setActiveWindow(0);
1724 QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(0));
1725 QCOMPARE(edit.isCursorVisible(), false);
1726 QCOMPARE(spy.count(), 10);
1728 QApplication::setActiveWindow(&view);
1729 QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
1730 QCOMPARE(edit.isCursorVisible(), true);
1731 QCOMPARE(spy.count(), 11);
1735 void tst_qdeclarativetextedit::delegateLoading_data()
1737 QTest::addColumn<QString>("qmlfile");
1738 QTest::addColumn<QString>("error");
1741 QTest::newRow("pass") << "cursorHttpTestPass.qml" << "";
1742 QTest::newRow("fail1") << "cursorHttpTestFail1.qml" << "http://localhost:42332/FailItem.qml: Remote host closed the connection ";
1743 QTest::newRow("fail2") << "cursorHttpTestFail2.qml" << "http://localhost:42332/ErrItem.qml:4:5: Fungus is not a type ";
1746 void tst_qdeclarativetextedit::delegateLoading()
1748 QFETCH(QString, qmlfile);
1749 QFETCH(QString, error);
1751 TestHTTPServer server(42332);
1752 server.serveDirectory(SRCDIR "/data/httpfail", TestHTTPServer::Disconnect);
1753 server.serveDirectory(SRCDIR "/data/httpslow", TestHTTPServer::Delay);
1754 server.serveDirectory(SRCDIR "/data/http");
1756 QDeclarativeView* view = new QDeclarativeView(0);
1758 view->setSource(QUrl(QLatin1String("http://localhost:42332/") + qmlfile));
1762 if (!error.isEmpty()) {
1763 QTest::ignoreMessage(QtWarningMsg, error.toUtf8());
1764 QTRY_VERIFY(view->status()==QDeclarativeView::Error);
1765 QTRY_VERIFY(!view->rootObject()); // there is fail item inside this test
1767 QTRY_VERIFY(view->rootObject());//Wait for loading to finish.
1768 QDeclarativeTextEdit *textEditObject = view->rootObject()->findChild<QDeclarativeTextEdit*>("textEditObject");
1769 // view->rootObject()->dumpObjectTree();
1770 QVERIFY(textEditObject != 0);
1771 textEditObject->setFocus(true);
1772 QDeclarativeItem *delegate;
1773 delegate = view->rootObject()->findChild<QDeclarativeItem*>("delegateOkay");
1775 delegate = view->rootObject()->findChild<QDeclarativeItem*>("delegateSlow");
1782 //A test should be added here with a component which is ready but component.create() returns null
1783 //Not sure how to accomplish this with QDeclarativeTextEdits cursor delegate
1784 //###This was only needed for code coverage, and could be a case of overzealous defensive programming
1785 //delegate = view->rootObject()->findChild<QDeclarativeItem*>("delegateErrorB");
1786 //QVERIFY(!delegate);
1792 TextEdit element should only handle left/right keys until the cursor reaches
1793 the extent of the text, then they should ignore the keys.
1795 void tst_qdeclarativetextedit::navigation()
1797 QDeclarativeView *canvas = createView(SRCDIR "/data/navigation.qml");
1801 QVERIFY(canvas->rootObject() != 0);
1803 QDeclarativeItem *input = qobject_cast<QDeclarativeItem *>(qvariant_cast<QObject *>(canvas->rootObject()->property("myInput")));
1805 QVERIFY(input != 0);
1806 QTRY_VERIFY(input->hasActiveFocus() == true);
1807 simulateKey(canvas, Qt::Key_Left);
1808 QVERIFY(input->hasActiveFocus() == false);
1809 simulateKey(canvas, Qt::Key_Right);
1810 QVERIFY(input->hasActiveFocus() == true);
1811 simulateKey(canvas, Qt::Key_Right);
1812 QVERIFY(input->hasActiveFocus() == true);
1813 simulateKey(canvas, Qt::Key_Right);
1814 QVERIFY(input->hasActiveFocus() == false);
1815 simulateKey(canvas, Qt::Key_Left);
1816 QVERIFY(input->hasActiveFocus() == true);
1821 void tst_qdeclarativetextedit::copyAndPaste() {
1822 #ifndef QT_NO_CLIPBOARD
1826 PasteboardRef pasteboard;
1827 OSStatus status = PasteboardCreate(0, &pasteboard);
1828 if (status == noErr)
1829 CFRelease(pasteboard);
1831 QSKIP("This machine doesn't support the clipboard", SkipAll);
1835 QString componentStr = "import QtQuick 1.0\nTextEdit { text: \"Hello world!\" }";
1836 QDeclarativeComponent textEditComponent(&engine);
1837 textEditComponent.setData(componentStr.toLatin1(), QUrl());
1838 QDeclarativeTextEdit *textEdit = qobject_cast<QDeclarativeTextEdit*>(textEditComponent.create());
1839 QVERIFY(textEdit != 0);
1842 QCOMPARE(textEdit->text().length(), 12);
1843 textEdit->select(0, textEdit->text().length());;
1845 QCOMPARE(textEdit->selectedText(), QString("Hello world!"));
1846 QCOMPARE(textEdit->selectedText().length(), 12);
1847 textEdit->setCursorPosition(0);
1848 QVERIFY(textEdit->canPaste());
1850 QCOMPARE(textEdit->text(), QString("Hello world!Hello world!"));
1851 QCOMPARE(textEdit->text().length(), 24);
1854 QVERIFY(textEdit->canPaste());
1855 textEdit->setReadOnly(true);
1856 QVERIFY(!textEdit->canPaste());
1857 textEdit->setReadOnly(false);
1858 QVERIFY(textEdit->canPaste());
1861 // test that document and internal text attribute are in sync
1862 QDeclarativeItemPrivate* pri = QDeclarativeItemPrivate::get(textEdit);
1863 QDeclarativeTextEditPrivate *editPrivate = static_cast<QDeclarativeTextEditPrivate*>(pri);
1864 QCOMPARE(textEdit->text(), editPrivate->text);
1867 textEdit->setCursorPosition(0);
1868 textEdit->selectWord();
1869 QCOMPARE(textEdit->selectedText(), QString("Hello"));
1871 // select all and cut
1872 textEdit->selectAll();
1874 QCOMPARE(textEdit->text().length(), 0);
1876 QCOMPARE(textEdit->text(), QString("Hello world!Hello world!"));
1877 QCOMPARE(textEdit->text().length(), 24);
1881 void tst_qdeclarativetextedit::canPaste() {
1882 #ifndef QT_NO_CLIPBOARD
1884 QApplication::clipboard()->setText("Some text");
1886 QString componentStr = "import QtQuick 1.0\nTextEdit { text: \"Hello world!\" }";
1887 QDeclarativeComponent textEditComponent(&engine);
1888 textEditComponent.setData(componentStr.toLatin1(), QUrl());
1889 QDeclarativeTextEdit *textEdit = qobject_cast<QDeclarativeTextEdit*>(textEditComponent.create());
1890 QVERIFY(textEdit != 0);
1892 // check initial value - QTBUG-17765
1894 QCOMPARE(textEdit->canPaste(), tc.canPaste());
1899 void tst_qdeclarativetextedit::canPasteEmpty() {
1900 #ifndef QT_NO_CLIPBOARD
1902 QApplication::clipboard()->clear();
1904 QString componentStr = "import QtQuick 1.0\nTextEdit { text: \"Hello world!\" }";
1905 QDeclarativeComponent textEditComponent(&engine);
1906 textEditComponent.setData(componentStr.toLatin1(), QUrl());
1907 QDeclarativeTextEdit *textEdit = qobject_cast<QDeclarativeTextEdit*>(textEditComponent.create());
1908 QVERIFY(textEdit != 0);
1910 // check initial value - QTBUG-17765
1912 QCOMPARE(textEdit->canPaste(), tc.canPaste());
1917 void tst_qdeclarativetextedit::readOnly()
1919 QDeclarativeView *canvas = createView(SRCDIR "/data/readOnly.qml");
1923 QVERIFY(canvas->rootObject() != 0);
1925 QDeclarativeTextEdit *edit = qobject_cast<QDeclarativeTextEdit *>(qvariant_cast<QObject *>(canvas->rootObject()->property("myInput")));
1928 QTRY_VERIFY(edit->hasActiveFocus() == true);
1929 QVERIFY(edit->isReadOnly() == true);
1930 QString initial = edit->text();
1931 for(int k=Qt::Key_0; k<=Qt::Key_Z; k++)
1932 simulateKey(canvas, k);
1933 simulateKey(canvas, Qt::Key_Return);
1934 simulateKey(canvas, Qt::Key_Space);
1935 simulateKey(canvas, Qt::Key_Escape);
1936 QCOMPARE(edit->text(), initial);
1941 void tst_qdeclarativetextedit::simulateKey(QDeclarativeView *view, int key, Qt::KeyboardModifiers modifiers)
1943 QKeyEvent press(QKeyEvent::KeyPress, key, modifiers);
1944 QKeyEvent release(QKeyEvent::KeyRelease, key, modifiers);
1946 QApplication::sendEvent(view, &press);
1947 QApplication::sendEvent(view, &release);
1950 QDeclarativeView *tst_qdeclarativetextedit::createView(const QString &filename)
1952 QDeclarativeView *canvas = new QDeclarativeView(0);
1954 canvas->setSource(QUrl::fromLocalFile(filename));
1958 class MyInputContext : public QInputContext
1961 MyInputContext() : openInputPanelReceived(false), closeInputPanelReceived(false), updateReceived(false), eventType(QEvent::None) {}
1962 ~MyInputContext() {}
1964 QString identifierName() { return QString(); }
1965 QString language() { return QString(); }
1969 bool isComposing() const { return false; }
1971 bool filterEvent( const QEvent *event )
1973 if (event->type() == QEvent::RequestSoftwareInputPanel)
1974 openInputPanelReceived = true;
1975 if (event->type() == QEvent::CloseSoftwareInputPanel)
1976 closeInputPanelReceived = true;
1977 return QInputContext::filterEvent(event);
1980 void update() { updateReceived = true; }
1982 void sendPreeditText(const QString &text, int cursor)
1984 QList<QInputMethodEvent::Attribute> attributes;
1985 attributes.append(QInputMethodEvent::Attribute(
1986 QInputMethodEvent::Cursor, cursor, text.length(), QVariant()));
1988 QInputMethodEvent event(text, attributes);
1992 void mouseHandler(int x, QMouseEvent *event)
1995 eventType = event->type();
1996 eventPosition = event->pos();
1997 eventGlobalPosition = event->globalPos();
1998 eventButton = event->button();
1999 eventButtons = event->buttons();
2000 eventModifiers = event->modifiers();
2003 bool openInputPanelReceived;
2004 bool closeInputPanelReceived;
2005 bool updateReceived;
2007 QEvent::Type eventType;
2008 QPoint eventPosition;
2009 QPoint eventGlobalPosition;
2010 Qt::MouseButton eventButton;
2011 Qt::MouseButtons eventButtons;
2012 Qt::KeyboardModifiers eventModifiers;
2015 void tst_qdeclarativetextedit::textInput()
2017 QGraphicsScene scene;
2018 QGraphicsView view(&scene);
2019 QDeclarativeTextEdit edit;
2020 QDeclarativeItemPrivate* pri = QDeclarativeItemPrivate::get(&edit);
2021 QDeclarativeTextEditPrivate *editPrivate = static_cast<QDeclarativeTextEditPrivate*>(pri);
2023 scene.addItem(&edit);
2025 QApplication::setActiveWindow(&view);
2026 QTest::qWaitForWindowShown(&view);
2027 QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
2028 edit.setFocus(true);
2029 QVERIFY(edit.hasActiveFocus() == true);
2031 // test that input method event is committed
2032 QInputMethodEvent event;
2033 event.setCommitString( "Hello world!", 0, 0);
2034 QApplication::sendEvent(&view, &event);
2035 QCOMPARE(edit.text(), QString("Hello world!"));
2038 // test that document and internal text attribute are in sync
2039 QCOMPARE(editPrivate->text, QString("Hello world!"));
2042 void tst_qdeclarativetextedit::openInputPanelOnClick()
2044 QGraphicsScene scene;
2045 QGraphicsView view(&scene);
2047 view.setInputContext(&ic);
2048 QDeclarativeTextEdit edit;
2049 QSignalSpy focusOnPressSpy(&edit, SIGNAL(activeFocusOnPressChanged(bool)));
2050 edit.setText("Hello world");
2052 scene.addItem(&edit);
2054 qApp->setAutoSipEnabled(true);
2055 QApplication::setActiveWindow(&view);
2056 QTest::qWaitForWindowShown(&view);
2057 QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
2059 QDeclarativeItemPrivate* pri = QDeclarativeItemPrivate::get(&edit);
2060 QDeclarativeTextEditPrivate *editPrivate = static_cast<QDeclarativeTextEditPrivate*>(pri);
2062 // input panel on click
2063 editPrivate->showInputPanelOnFocus = false;
2065 QStyle::RequestSoftwareInputPanel behavior = QStyle::RequestSoftwareInputPanel(
2066 view.style()->styleHint(QStyle::SH_RequestSoftwareInputPanel));
2067 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(edit.scenePos()));
2068 QApplication::processEvents();
2069 if (behavior == QStyle::RSIP_OnMouseClickAndAlreadyFocused) {
2070 QCOMPARE(ic.openInputPanelReceived, false);
2071 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(edit.scenePos()));
2072 QApplication::processEvents();
2073 QCOMPARE(ic.openInputPanelReceived, true);
2074 } else if (behavior == QStyle::RSIP_OnMouseClick) {
2075 QCOMPARE(ic.openInputPanelReceived, true);
2077 ic.openInputPanelReceived = false;
2079 // focus should not cause input panels to open or close
2080 edit.setFocus(false);
2081 edit.setFocus(true);
2082 edit.setFocus(false);
2083 edit.setFocus(true);
2084 edit.setFocus(false);
2085 QApplication::processEvents();
2086 QCOMPARE(ic.openInputPanelReceived, false);
2087 QCOMPARE(ic.closeInputPanelReceived, false);
2090 void tst_qdeclarativetextedit::openInputPanelOnFocus()
2092 QGraphicsScene scene;
2093 QGraphicsView view(&scene);
2095 view.setInputContext(&ic);
2096 QDeclarativeTextEdit edit;
2097 QSignalSpy focusOnPressSpy(&edit, SIGNAL(activeFocusOnPressChanged(bool)));
2098 edit.setText("Hello world");
2100 scene.addItem(&edit);
2102 qApp->setAutoSipEnabled(true);
2103 QApplication::setActiveWindow(&view);
2104 QTest::qWaitForWindowShown(&view);
2105 QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
2107 QDeclarativeItemPrivate* pri = QDeclarativeItemPrivate::get(&edit);
2108 QDeclarativeTextEditPrivate *editPrivate = static_cast<QDeclarativeTextEditPrivate*>(pri);
2109 editPrivate->showInputPanelOnFocus = true;
2111 // test default values
2112 QVERIFY(edit.focusOnPress());
2113 QCOMPARE(ic.openInputPanelReceived, false);
2114 QCOMPARE(ic.closeInputPanelReceived, false);
2116 // focus on press, input panel on focus
2117 QTest::mousePress(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(edit.scenePos()));
2118 QApplication::processEvents();
2119 QVERIFY(edit.hasActiveFocus());
2120 QCOMPARE(ic.openInputPanelReceived, true);
2121 ic.openInputPanelReceived = false;
2123 // no events on release
2124 QTest::mouseRelease(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(edit.scenePos()));
2125 QCOMPARE(ic.openInputPanelReceived, false);
2126 ic.openInputPanelReceived = false;
2128 // if already focused, input panel can be opened on press
2129 QVERIFY(edit.hasActiveFocus());
2130 QTest::mousePress(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(edit.scenePos()));
2131 QApplication::processEvents();
2132 QCOMPARE(ic.openInputPanelReceived, true);
2133 ic.openInputPanelReceived = false;
2135 // input method should stay enabled if focus
2136 // is lost to an item that also accepts inputs
2137 QDeclarativeTextEdit anotherEdit;
2138 scene.addItem(&anotherEdit);
2139 anotherEdit.setFocus(true);
2140 QApplication::processEvents();
2141 QCOMPARE(ic.openInputPanelReceived, true);
2142 ic.openInputPanelReceived = false;
2143 QCOMPARE(view.inputContext(), (QInputContext*)&ic);
2144 QVERIFY(view.testAttribute(Qt::WA_InputMethodEnabled));
2146 // input method should be disabled if focus
2147 // is lost to an item that doesn't accept inputs
2148 QDeclarativeItem item;
2149 scene.addItem(&item);
2150 item.setFocus(true);
2151 QApplication::processEvents();
2152 QCOMPARE(ic.openInputPanelReceived, false);
2153 QVERIFY(view.inputContext() == 0);
2154 QVERIFY(!view.testAttribute(Qt::WA_InputMethodEnabled));
2156 // no automatic input panel events should
2157 // be sent if activeFocusOnPress is false
2158 edit.setFocusOnPress(false);
2159 QCOMPARE(focusOnPressSpy.count(),1);
2160 edit.setFocusOnPress(false);
2161 QCOMPARE(focusOnPressSpy.count(),1);
2162 edit.setFocus(false);
2163 edit.setFocus(true);
2164 QTest::mousePress(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(edit.scenePos()));
2165 QTest::mouseRelease(view.viewport(), Qt::LeftButton, 0, view.mapFromScene(edit.scenePos()));
2166 QApplication::processEvents();
2167 QCOMPARE(ic.openInputPanelReceived, false);
2168 QCOMPARE(ic.closeInputPanelReceived, false);
2170 // one show input panel event should
2171 // be set when openSoftwareInputPanel is called
2172 edit.openSoftwareInputPanel();
2173 QCOMPARE(ic.openInputPanelReceived, true);
2174 QCOMPARE(ic.closeInputPanelReceived, false);
2175 ic.openInputPanelReceived = false;
2177 // one close input panel event should
2178 // be sent when closeSoftwareInputPanel is called
2179 edit.closeSoftwareInputPanel();
2180 QCOMPARE(ic.openInputPanelReceived, false);
2181 QCOMPARE(ic.closeInputPanelReceived, true);
2182 ic.closeInputPanelReceived = false;
2184 // set activeFocusOnPress back to true
2185 edit.setFocusOnPress(true);
2186 QCOMPARE(focusOnPressSpy.count(),2);
2187 edit.setFocusOnPress(true);
2188 QCOMPARE(focusOnPressSpy.count(),2);
2189 edit.setFocus(false);
2190 QApplication::processEvents();
2191 QCOMPARE(ic.openInputPanelReceived, false);
2192 QCOMPARE(ic.closeInputPanelReceived, false);
2193 ic.closeInputPanelReceived = false;
2195 // input panel should not re-open
2196 // if focus has already been set
2197 edit.setFocus(true);
2198 QCOMPARE(ic.openInputPanelReceived, true);
2199 ic.openInputPanelReceived = false;
2200 edit.setFocus(true);
2201 QCOMPARE(ic.openInputPanelReceived, false);
2203 // input method should be disabled
2204 // if TextEdit loses focus
2205 edit.setFocus(false);
2206 QApplication::processEvents();
2207 QVERIFY(view.inputContext() == 0);
2208 QVERIFY(!view.testAttribute(Qt::WA_InputMethodEnabled));
2210 // input method should not be enabled
2211 // if TextEdit is read only.
2212 edit.setReadOnly(true);
2213 ic.openInputPanelReceived = false;
2214 edit.setFocus(true);
2215 QApplication::processEvents();
2216 QCOMPARE(ic.openInputPanelReceived, false);
2217 QVERIFY(view.inputContext() == 0);
2218 QVERIFY(!view.testAttribute(Qt::WA_InputMethodEnabled));
2221 void tst_qdeclarativetextedit::geometrySignals()
2223 QDeclarativeComponent component(&engine, SRCDIR "/data/geometrySignals.qml");
2224 QObject *o = component.create();
2226 QCOMPARE(o->property("bindingWidth").toInt(), 400);
2227 QCOMPARE(o->property("bindingHeight").toInt(), 500);
2231 void tst_qdeclarativetextedit::pastingRichText_QTBUG_14003()
2233 #ifndef QT_NO_CLIPBOARD
2234 QString componentStr = "import QtQuick 1.0\nTextEdit { textFormat: TextEdit.PlainText }";
2235 QDeclarativeComponent component(&engine);
2236 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
2237 QDeclarativeTextEdit *obj = qobject_cast<QDeclarativeTextEdit*>(component.create());
2239 QTRY_VERIFY(obj != 0);
2240 QTRY_VERIFY(obj->textFormat() == QDeclarativeTextEdit::PlainText);
2242 QMimeData *mData = new QMimeData;
2243 mData->setHtml("<font color=\"red\">Hello</font>");
2244 QApplication::clipboard()->setMimeData(mData);
2247 QTRY_VERIFY(obj->text() == "");
2248 QTRY_VERIFY(obj->textFormat() == QDeclarativeTextEdit::PlainText);
2252 void tst_qdeclarativetextedit::implicitSize_data()
2254 QTest::addColumn<QString>("text");
2255 QTest::addColumn<QString>("wrap");
2256 QTest::newRow("plain") << "The quick red fox jumped over the lazy brown dog" << "TextEdit.NoWrap";
2257 QTest::newRow("richtext") << "<b>The quick red fox jumped over the lazy brown dog</b>" << "TextEdit.NoWrap";
2258 QTest::newRow("plain_wrap") << "The quick red fox jumped over the lazy brown dog" << "TextEdit.Wrap";
2259 QTest::newRow("richtext_wrap") << "<b>The quick red fox jumped over the lazy brown dog</b>" << "TextEdit.Wrap";
2262 void tst_qdeclarativetextedit::implicitSize()
2264 QFETCH(QString, text);
2265 QFETCH(QString, wrap);
2266 QString componentStr = "import QtQuick 1.1\nTextEdit { text: \"" + text + "\"; width: 50; wrapMode: " + wrap + " }";
2267 QDeclarativeComponent textComponent(&engine);
2268 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
2269 QDeclarativeTextEdit *textObject = qobject_cast<QDeclarativeTextEdit*>(textComponent.create());
2271 QVERIFY(textObject->width() < textObject->implicitWidth());
2272 QVERIFY(textObject->height() == textObject->implicitHeight());
2274 textObject->resetWidth();
2275 QVERIFY(textObject->width() == textObject->implicitWidth());
2276 QVERIFY(textObject->height() == textObject->implicitHeight());
2279 void tst_qdeclarativetextedit::testQtQuick11Attributes()
2281 QFETCH(QString, code);
2282 QFETCH(QString, warning);
2283 QFETCH(QString, error);
2285 QDeclarativeEngine engine;
2288 QDeclarativeComponent valid(&engine);
2289 valid.setData("import QtQuick 1.1; TextEdit { " + code.toUtf8() + " }", QUrl(""));
2290 obj = valid.create();
2292 QVERIFY(valid.errorString().isEmpty());
2295 QDeclarativeComponent invalid(&engine);
2296 invalid.setData("import QtQuick 1.0; TextEdit { " + code.toUtf8() + " }", QUrl(""));
2297 QTest::ignoreMessage(QtWarningMsg, warning.toUtf8());
2298 obj = invalid.create();
2299 QCOMPARE(invalid.errorString(), error);
2303 void tst_qdeclarativetextedit::testQtQuick11Attributes_data()
2305 QTest::addColumn<QString>("code");
2306 QTest::addColumn<QString>("warning");
2307 QTest::addColumn<QString>("error");
2309 QTest::newRow("canPaste") << "property bool foo: canPaste"
2310 << "<Unknown File>:1: ReferenceError: Can't find variable: canPaste"
2313 QTest::newRow("lineCount") << "property int foo: lineCount"
2314 << "<Unknown File>:1: ReferenceError: Can't find variable: lineCount"
2317 QTest::newRow("moveCursorSelection") << "Component.onCompleted: moveCursorSelection(0, TextEdit.SelectCharacters)"
2318 << "<Unknown File>:1: ReferenceError: Can't find variable: moveCursorSelection"
2321 QTest::newRow("deselect") << "Component.onCompleted: deselect()"
2322 << "<Unknown File>:1: ReferenceError: Can't find variable: deselect"
2325 QTest::newRow("onLinkActivated") << "onLinkActivated: {}"
2326 << "QDeclarativeComponent: Component is not ready"
2327 << ":1 \"TextEdit.onLinkActivated\" is not available in QtQuick 1.0.\n";
2330 void tst_qdeclarativetextedit::preeditMicroFocus()
2332 QString preeditText = "super";
2334 QGraphicsScene scene;
2335 QGraphicsView view(&scene);
2337 view.setInputContext(&ic);
2338 QDeclarativeTextEdit edit;
2339 edit.setFocus(true);
2340 scene.addItem(&edit);
2342 QApplication::setActiveWindow(&view);
2343 QTest::qWaitForWindowShown(&view);
2344 QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
2346 QSignalSpy cursorRectangleSpy(&edit, SIGNAL(cursorRectangleChanged()));
2349 QRect previousRect = edit.inputMethodQuery(Qt::ImMicroFocus).toRect();
2351 // Verify that the micro focus rect is positioned the same for position 0 as
2352 // it would be if there was no preedit text.
2353 ic.updateReceived = false;
2354 ic.sendPreeditText(preeditText, 0);
2355 currentRect = edit.inputMethodQuery(Qt::ImMicroFocus).toRect();
2356 QCOMPARE(currentRect, previousRect);
2357 #if defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)
2358 QCOMPARE(ic.updateReceived, false); // The cursor position hasn't changed.
2360 QCOMPARE(cursorRectangleSpy.count(), 0);
2362 // Verify that the micro focus rect moves to the left as the cursor position
2364 for (int i = 1; i <= 5; ++i) {
2365 ic.updateReceived = false;
2366 ic.sendPreeditText(preeditText, i);
2367 currentRect = edit.inputMethodQuery(Qt::ImMicroFocus).toRect();
2368 QVERIFY(previousRect.left() < currentRect.left());
2369 #if defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)
2370 QCOMPARE(ic.updateReceived, true);
2372 QVERIFY(cursorRectangleSpy.count() > 0);
2373 cursorRectangleSpy.clear();
2374 previousRect = currentRect;
2377 // Verify that if there is no preedit cursor then the micro focus rect is the
2378 // same as it would be if it were positioned at the end of the preedit text.
2379 ic.sendPreeditText(preeditText, 0);
2380 ic.updateReceived = false;
2381 ic.sendEvent(QInputMethodEvent(preeditText, QList<QInputMethodEvent::Attribute>()));
2382 currentRect = edit.inputMethodQuery(Qt::ImMicroFocus).toRect();
2383 QCOMPARE(currentRect, previousRect);
2384 #if defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)
2385 QCOMPARE(ic.updateReceived, true);
2387 QVERIFY(cursorRectangleSpy.count() > 0);
2390 void tst_qdeclarativetextedit::inputContextMouseHandler()
2392 QString text = "supercalifragisiticexpialidocious!";
2394 QGraphicsScene scene;
2395 QGraphicsView view(&scene);
2397 view.setInputContext(&ic);
2398 QDeclarativeTextEdit edit;
2401 edit.setText(text.mid(0, 12));
2403 edit.setCursorPosition(12);
2404 edit.setFocus(true);
2405 scene.addItem(&edit);
2407 QApplication::setActiveWindow(&view);
2408 QTest::qWaitForWindowShown(&view);
2409 QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
2412 QFontMetricsF fm(edit.font());
2413 const qreal y = fm.height() / 2;
2415 QPoint position2 = view.mapFromScene(edit.mapToScene(QPointF(fm.width(text.mid(0, 2)), y)));
2416 QPoint position8 = view.mapFromScene(edit.mapToScene(QPointF(fm.width(text.mid(0, 8)), y)));
2417 QPoint position20 = view.mapFromScene(edit.mapToScene(QPointF(fm.width(text.mid(0, 20)), y)));
2418 QPoint position27 = view.mapFromScene(edit.mapToScene(QPointF(fm.width(text.mid(0, 27)), y)));
2419 QPoint globalPosition2 = view.viewport()->mapToGlobal(position2);
2420 QPoint globalposition8 = view.viewport()->mapToGlobal(position8);
2421 QPoint globalposition20 = view.viewport()->mapToGlobal(position20);
2422 QPoint globalposition27 = view.viewport()->mapToGlobal(position27);
2424 ic.sendEvent(QInputMethodEvent(text.mid(12), QList<QInputMethodEvent::Attribute>()));
2426 QTest::mouseDClick(view.viewport(), Qt::LeftButton, Qt::NoModifier, position2);
2427 QCOMPARE(ic.eventType, QEvent::MouseButtonDblClick);
2428 QCOMPARE(ic.eventPosition, position2);
2429 QCOMPARE(ic.eventGlobalPosition, globalPosition2);
2430 QCOMPARE(ic.eventButton, Qt::LeftButton);
2431 QCOMPARE(ic.eventModifiers, Qt::NoModifier);
2432 QVERIFY(ic.cursor < 0);
2433 ic.eventType = QEvent::None;
2435 QTest::mousePress(view.viewport(), Qt::LeftButton, Qt::NoModifier, position2);
2436 QCOMPARE(ic.eventType, QEvent::MouseButtonPress);
2437 QCOMPARE(ic.eventPosition, position2);
2438 QCOMPARE(ic.eventGlobalPosition, globalPosition2);
2439 QCOMPARE(ic.eventButton, Qt::LeftButton);
2440 QCOMPARE(ic.eventModifiers, Qt::NoModifier);
2441 QVERIFY(ic.cursor < 0);
2442 ic.eventType = QEvent::None;
2444 { QMouseEvent mv(QEvent::MouseMove, position8, globalposition8, Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
2445 QApplication::sendEvent(view.viewport(), &mv); }
2446 QCOMPARE(ic.eventType, QEvent::None);
2448 { QMouseEvent mv(QEvent::MouseMove, position27, globalposition27, Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
2449 QApplication::sendEvent(view.viewport(), &mv); }
2450 QCOMPARE(ic.eventType, QEvent::MouseMove);
2451 QCOMPARE(ic.eventPosition, position27);
2452 QCOMPARE(ic.eventGlobalPosition, globalposition27);
2453 QCOMPARE(ic.eventButton, Qt::LeftButton);
2454 QCOMPARE(ic.eventModifiers, Qt::NoModifier);
2455 QVERIFY(ic.cursor >= 14 && ic.cursor <= 16); // 15 is expected but some platforms may be off by one.
2456 ic.eventType = QEvent::None;
2458 QTest::mouseRelease(view.viewport(), Qt::LeftButton, Qt::NoModifier, position27);
2459 QCOMPARE(ic.eventType, QEvent::MouseButtonRelease);
2460 QCOMPARE(ic.eventPosition, position27);
2461 QCOMPARE(ic.eventGlobalPosition, globalposition27);
2462 QCOMPARE(ic.eventButton, Qt::LeftButton);
2463 QCOMPARE(ic.eventModifiers, Qt::NoModifier);
2464 QVERIFY(ic.cursor >= 14 && ic.cursor <= 16);
2465 ic.eventType = QEvent::None;
2467 // And in the other direction.
2468 QTest::mouseDClick(view.viewport(), Qt::LeftButton, Qt::ControlModifier, position27);
2469 QCOMPARE(ic.eventType, QEvent::MouseButtonDblClick);
2470 QCOMPARE(ic.eventPosition, position27);
2471 QCOMPARE(ic.eventGlobalPosition, globalposition27);
2472 QCOMPARE(ic.eventButton, Qt::LeftButton);
2473 QCOMPARE(ic.eventModifiers, Qt::ControlModifier);
2474 QVERIFY(ic.cursor >= 14 && ic.cursor <= 16);
2475 ic.eventType = QEvent::None;
2477 QTest::mousePress(view.viewport(), Qt::RightButton, Qt::ControlModifier, position27);
2478 QCOMPARE(ic.eventType, QEvent::MouseButtonPress);
2479 QCOMPARE(ic.eventPosition, position27);
2480 QCOMPARE(ic.eventGlobalPosition, globalposition27);
2481 QCOMPARE(ic.eventButton, Qt::RightButton);
2482 QCOMPARE(ic.eventModifiers, Qt::ControlModifier);
2483 QVERIFY(ic.cursor >= 14 && ic.cursor <= 16);
2484 ic.eventType = QEvent::None;
2486 { QMouseEvent mv(QEvent::MouseMove, position20, globalposition20, Qt::RightButton, Qt::RightButton,Qt::ControlModifier);
2487 QApplication::sendEvent(view.viewport(), &mv); }
2488 QCOMPARE(ic.eventType, QEvent::MouseMove);
2489 QCOMPARE(ic.eventPosition, position20);
2490 QCOMPARE(ic.eventGlobalPosition, globalposition20);
2491 QCOMPARE(ic.eventButton, Qt::RightButton);
2492 QCOMPARE(ic.eventModifiers, Qt::ControlModifier);
2493 QVERIFY(ic.cursor >= 7 && ic.cursor <= 9);
2494 ic.eventType = QEvent::None;
2496 { QMouseEvent mv(QEvent::MouseMove, position2, globalPosition2, Qt::RightButton, Qt::RightButton,Qt::ControlModifier);
2497 QApplication::sendEvent(view.viewport(), &mv); }
2498 QCOMPARE(ic.eventType, QEvent::None);
2500 QTest::mouseRelease(view.viewport(), Qt::RightButton, Qt::ControlModifier, position2);
2501 QCOMPARE(ic.eventType, QEvent::MouseButtonRelease);
2502 QCOMPARE(ic.eventPosition, position2);
2503 QCOMPARE(ic.eventGlobalPosition, globalPosition2);
2504 QCOMPARE(ic.eventButton, Qt::RightButton);
2505 QCOMPARE(ic.eventModifiers, Qt::ControlModifier);
2506 QVERIFY(ic.cursor < 0);
2507 ic.eventType = QEvent::None;
2510 void tst_qdeclarativetextedit::inputMethodComposing()
2512 QString text = "supercalifragisiticexpialidocious!";
2514 QGraphicsScene scene;
2515 QGraphicsView view(&scene);
2517 view.setInputContext(&ic);
2518 QDeclarativeTextEdit edit;
2520 edit.setText(text.mid(0, 12));
2521 edit.setCursorPosition(12);
2523 edit.setFocus(true);
2524 scene.addItem(&edit);
2526 QApplication::setActiveWindow(&view);
2527 QTest::qWaitForWindowShown(&view);
2528 QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
2530 QSignalSpy spy(&edit, SIGNAL(inputMethodComposingChanged()));
2532 QCOMPARE(edit.isInputMethodComposing(), false);
2534 ic.sendEvent(QInputMethodEvent(text.mid(3), QList<QInputMethodEvent::Attribute>()));
2535 QCOMPARE(edit.isInputMethodComposing(), true);
2536 QCOMPARE(spy.count(), 1);
2538 ic.sendEvent(QInputMethodEvent(text.mid(12), QList<QInputMethodEvent::Attribute>()));
2539 QCOMPARE(edit.isInputMethodComposing(), true);
2540 QCOMPARE(spy.count(), 1);
2542 ic.sendEvent(QInputMethodEvent());
2543 QCOMPARE(edit.isInputMethodComposing(), false);
2544 QCOMPARE(spy.count(), 2);
2547 void tst_qdeclarativetextedit::cursorRectangleSize()
2549 QDeclarativeView *canvas = createView(SRCDIR "/data/CursorRect.qml");
2550 QVERIFY(canvas->rootObject() != 0);
2553 QApplication::setActiveWindow(canvas);
2554 QTest::qWaitForWindowShown(canvas);
2556 QDeclarativeTextEdit *textEdit = qobject_cast<QDeclarativeTextEdit *>(canvas->rootObject());
2557 QVERIFY(textEdit != 0);
2558 textEdit->setFocus(Qt::OtherFocusReason);
2559 QRectF cursorRect = textEdit->positionToRectangle(textEdit->cursorPosition());
2560 QRectF microFocusFromScene = canvas->scene()->inputMethodQuery(Qt::ImMicroFocus).toRectF();
2561 QRectF microFocusFromApp= QApplication::focusWidget()->inputMethodQuery(Qt::ImMicroFocus).toRectF();
2563 QCOMPARE(microFocusFromScene.size(), cursorRect.size());
2564 QCOMPARE(microFocusFromApp.size(), cursorRect.size());
2566 QTEST_MAIN(tst_qdeclarativetextedit)
2568 #include "tst_qdeclarativetextedit.moc"