| 1 | /**************************************************************************** | 
| 2 | ** | 
| 3 | ** Copyright (C) 2016 The Qt Company Ltd. | 
| 4 | ** Contact: https://www.qt.io/licensing/ | 
| 5 | ** | 
| 6 | ** This file is part of the test suite of the Qt Toolkit. | 
| 7 | ** | 
| 8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ | 
| 9 | ** Commercial License Usage | 
| 10 | ** Licensees holding valid commercial Qt licenses may use this file in | 
| 11 | ** accordance with the commercial license agreement provided with the | 
| 12 | ** Software or, alternatively, in accordance with the terms contained in | 
| 13 | ** a written agreement between you and The Qt Company. For licensing terms | 
| 14 | ** and conditions see https://www.qt.io/terms-conditions. For further | 
| 15 | ** information use the contact form at https://www.qt.io/contact-us. | 
| 16 | ** | 
| 17 | ** GNU General Public License Usage | 
| 18 | ** Alternatively, this file may be used under the terms of the GNU | 
| 19 | ** General Public License version 3 as published by the Free Software | 
| 20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT | 
| 21 | ** included in the packaging of this file. Please review the following | 
| 22 | ** information to ensure the GNU General Public License requirements will | 
| 23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. | 
| 24 | ** | 
| 25 | ** $QT_END_LICENSE$ | 
| 26 | ** | 
| 27 | ****************************************************************************/ | 
| 28 | #include <qtest.h> | 
| 29 | #include <QtTest/QSignalSpy> | 
| 30 | #include "../../shared/util.h" | 
| 31 | #include "../../shared/testhttpserver.h" | 
| 32 | #include <private/qinputmethod_p.h> | 
| 33 | #include <QtQml/qqmlengine.h> | 
| 34 | #include <QtQml/qqmlexpression.h> | 
| 35 | #include <QFile> | 
| 36 | #include <QtQuick/qquickview.h> | 
| 37 | #include <QtGui/qguiapplication.h> | 
| 38 | #include <QtGui/qstylehints.h> | 
| 39 | #include <QtGui/qvalidator.h> | 
| 40 | #include <QInputMethod> | 
| 41 | #include <private/qquicktextinput_p.h> | 
| 42 | #include <private/qquicktextinput_p_p.h> | 
| 43 | #include <private/qquickvalidator_p.h> | 
| 44 | #include <QDebug> | 
| 45 | #include <QDir> | 
| 46 | #include <math.h> | 
| 47 | #include <qmath.h> | 
| 48 |  | 
| 49 | #ifdef Q_OS_OSX | 
| 50 | #include <Carbon/Carbon.h> | 
| 51 | #endif | 
| 52 |  | 
| 53 | #include "qplatformdefs.h" | 
| 54 | #include "../../shared/platformquirks.h" | 
| 55 | #include "../../shared/platforminputcontext.h" | 
| 56 |  | 
| 57 | Q_DECLARE_METATYPE(QQuickTextInput::SelectionMode) | 
| 58 | Q_DECLARE_METATYPE(QQuickTextInput::EchoMode) | 
| 59 | Q_DECLARE_METATYPE(Qt::Key) | 
| 60 |  | 
| 61 | DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD) | 
| 62 |  | 
| 63 | QString createExpectedFileIfNotFound(const QString& filebasename, const QImage& actual) | 
| 64 | { | 
| 65 |     // XXX This will be replaced by some clever persistent platform image store. | 
| 66 |     QString persistent_dir = QQmlDataTest::instance()->dataDirectory(); | 
| 67 |     QString arch = "unknown-architecture" ; // QTest needs to help with this. | 
| 68 |  | 
| 69 |     QString expectfile = persistent_dir + QDir::separator() + filebasename + QLatin1Char('-') + arch + ".png" ; | 
| 70 |  | 
| 71 |     if (!QFile::exists(fileName: expectfile)) { | 
| 72 |         actual.save(fileName: expectfile); | 
| 73 |         qWarning() << "created"  << expectfile; | 
| 74 |     } | 
| 75 |  | 
| 76 |     return expectfile; | 
| 77 | } | 
| 78 |  | 
| 79 | template <typename T> static T evaluate(QObject *scope, const QString &expression) | 
| 80 | { | 
| 81 |     QQmlExpression expr(qmlContext(scope), scope, expression); | 
| 82 |     T result = expr.evaluate().value<T>(); | 
| 83 |     if (expr.hasError()) | 
| 84 |         qWarning() << expr.error().toString(); | 
| 85 |     return result; | 
| 86 | } | 
| 87 |  | 
| 88 | template<typename T, int N> int lengthOf(const T (&)[N]) { return N; } | 
| 89 |  | 
| 90 | typedef QPair<int, QChar> Key; | 
| 91 |  | 
| 92 | class tst_qquicktextinput : public QQmlDataTest | 
| 93 |  | 
| 94 | { | 
| 95 |     Q_OBJECT | 
| 96 | public: | 
| 97 |     tst_qquicktextinput(); | 
| 98 |  | 
| 99 | private slots: | 
| 100 |     void cleanup(); | 
| 101 |     void text(); | 
| 102 |     void width(); | 
| 103 |     void font(); | 
| 104 |     void color(); | 
| 105 |     void wrap(); | 
| 106 |     void selection(); | 
| 107 |     void persistentSelection(); | 
| 108 |     void overwriteMode(); | 
| 109 |     void isRightToLeft_data(); | 
| 110 |     void isRightToLeft(); | 
| 111 |     void moveCursorSelection_data(); | 
| 112 |     void moveCursorSelection(); | 
| 113 |     void moveCursorSelectionSequence_data(); | 
| 114 |     void moveCursorSelectionSequence(); | 
| 115 |     void dragMouseSelection(); | 
| 116 |     void mouseSelectionMode_data(); | 
| 117 |     void mouseSelectionMode(); | 
| 118 |     void mouseSelectionMode_accessors(); | 
| 119 |     void selectByMouse(); | 
| 120 |     void renderType(); | 
| 121 |     void tripleClickSelectsAll(); | 
| 122 |  | 
| 123 |     void horizontalAlignment_RightToLeft(); | 
| 124 |     void verticalAlignment(); | 
| 125 |  | 
| 126 |     void clipRect(); | 
| 127 |     void boundingRect(); | 
| 128 |  | 
| 129 |     void positionAt(); | 
| 130 |  | 
| 131 |     void maxLength(); | 
| 132 |     void masks(); | 
| 133 |     void validators(); | 
| 134 |     void inputMethods(); | 
| 135 |  | 
| 136 |     void signal_accepted(); | 
| 137 |     void signal_editingfinished(); | 
| 138 |     void signal_textEdited(); | 
| 139 |  | 
| 140 |     void passwordCharacter(); | 
| 141 |     void cursorDelegate_data(); | 
| 142 |     void cursorDelegate(); | 
| 143 |     void remoteCursorDelegate(); | 
| 144 |     void cursorVisible(); | 
| 145 |     void cursorRectangle_data(); | 
| 146 |     void cursorRectangle(); | 
| 147 |     void navigation(); | 
| 148 |     void navigation_RTL(); | 
| 149 | #if QT_CONFIG(clipboard) && QT_CONFIG(shortcut) | 
| 150 |     void copyAndPaste(); | 
| 151 |     void copyAndPasteKeySequence(); | 
| 152 |     void canPasteEmpty(); | 
| 153 |     void canPaste(); | 
| 154 |     void middleClickPaste(); | 
| 155 | #endif | 
| 156 |     void readOnly(); | 
| 157 |     void focusOnPress(); | 
| 158 |     void focusOnPressOnlyOneItem(); | 
| 159 |  | 
| 160 |     void openInputPanel(); | 
| 161 |     void setHAlignClearCache(); | 
| 162 |     void focusOutClearSelection(); | 
| 163 |     void focusOutNotClearSelection(); | 
| 164 |  | 
| 165 |     void echoMode(); | 
| 166 |     void passwordEchoDelay(); | 
| 167 |     void geometrySignals(); | 
| 168 |     void contentSize(); | 
| 169 |  | 
| 170 |     void preeditAutoScroll(); | 
| 171 |     void preeditCursorRectangle(); | 
| 172 |     void inputContextMouseHandler(); | 
| 173 |     void inputMethodComposing(); | 
| 174 |     void inputMethodUpdate(); | 
| 175 |     void cursorRectangleSize(); | 
| 176 |  | 
| 177 |     void getText_data(); | 
| 178 |     void getText(); | 
| 179 |     void insert_data(); | 
| 180 |     void insert(); | 
| 181 |     void remove_data(); | 
| 182 |     void remove(); | 
| 183 |  | 
| 184 | #if QT_CONFIG(shortcut) | 
| 185 |     void keySequence_data(); | 
| 186 |     void keySequence(); | 
| 187 | #endif | 
| 188 |  | 
| 189 |     void undo_data(); | 
| 190 |     void undo(); | 
| 191 |     void redo_data(); | 
| 192 |     void redo(); | 
| 193 | #if QT_CONFIG(shortcut) | 
| 194 |     void undo_keypressevents_data(); | 
| 195 |     void undo_keypressevents(); | 
| 196 | #endif | 
| 197 |     void clear(); | 
| 198 |  | 
| 199 |     void backspaceSurrogatePairs(); | 
| 200 |  | 
| 201 |     void QTBUG_19956(); | 
| 202 |     void QTBUG_19956_data(); | 
| 203 |     void QTBUG_19956_regexp(); | 
| 204 |  | 
| 205 |     void implicitSize_data(); | 
| 206 |     void implicitSize(); | 
| 207 |     void implicitSizeBinding_data(); | 
| 208 |     void implicitSizeBinding(); | 
| 209 |     void implicitResize_data(); | 
| 210 |     void implicitResize(); | 
| 211 |  | 
| 212 |     void negativeDimensions(); | 
| 213 |  | 
| 214 |  | 
| 215 |     void setInputMask_data(); | 
| 216 |     void setInputMask(); | 
| 217 |     void inputMask_data(); | 
| 218 |     void inputMask(); | 
| 219 |     void clearInputMask(); | 
| 220 |     void keypress_inputMask_data(); | 
| 221 |     void keypress_inputMask(); | 
| 222 |     void keypress_inputMethod_inputMask(); | 
| 223 |     void keypress_inputMask_withValidator_data(); | 
| 224 |     void keypress_inputMask_withValidator(); | 
| 225 |     void hasAcceptableInputMask_data(); | 
| 226 |     void hasAcceptableInputMask(); | 
| 227 |     void maskCharacter_data(); | 
| 228 |     void maskCharacter(); | 
| 229 |     void fixup(); | 
| 230 |     void baselineOffset_data(); | 
| 231 |     void baselineOffset(); | 
| 232 |  | 
| 233 |     void ensureVisible(); | 
| 234 |     void padding(); | 
| 235 |  | 
| 236 |     void QTBUG_51115_readOnlyResetsSelection(); | 
| 237 |     void QTBUG_77814_InsertRemoveNoSelection(); | 
| 238 |  | 
| 239 |     void checkCursorDelegateWhenPaddingChanged(); | 
| 240 |  | 
| 241 |     void focusReason(); | 
| 242 | private: | 
| 243 |     void simulateKey(QWindow *, int key); | 
| 244 |  | 
| 245 |     void simulateKeys(QWindow *window, const QList<Key> &keys); | 
| 246 | #if QT_CONFIG(shortcut) | 
| 247 |     void simulateKeys(QWindow *window, const QKeySequence &sequence); | 
| 248 | #endif | 
| 249 |  | 
| 250 |     QQmlEngine engine; | 
| 251 |     QStringList standard; | 
| 252 |     QStringList colorStrings; | 
| 253 | }; | 
| 254 |  | 
| 255 | typedef QList<int> IntList; | 
| 256 | Q_DECLARE_METATYPE(IntList) | 
| 257 |  | 
| 258 | typedef QList<Key> KeyList; | 
| 259 | Q_DECLARE_METATYPE(KeyList) | 
| 260 |  | 
| 261 | void tst_qquicktextinput::simulateKeys(QWindow *window, const QList<Key> &keys) | 
| 262 | { | 
| 263 |     for (int i = 0; i < keys.count(); ++i) { | 
| 264 |         const int key = keys.at(i).first & ~Qt::KeyboardModifierMask; | 
| 265 |         const int modifiers = keys.at(i).first & Qt::KeyboardModifierMask; | 
| 266 |         const QString text = !keys.at(i).second.isNull() ? QString(keys.at(i).second) : QString(); | 
| 267 |  | 
| 268 |         QKeyEvent press(QEvent::KeyPress, Qt::Key(key), Qt::KeyboardModifiers(modifiers), text); | 
| 269 |         QKeyEvent release(QEvent::KeyRelease, Qt::Key(key), Qt::KeyboardModifiers(modifiers), text); | 
| 270 |  | 
| 271 |         QGuiApplication::sendEvent(receiver: window, event: &press); | 
| 272 |         QGuiApplication::sendEvent(receiver: window, event: &release); | 
| 273 |     } | 
| 274 | } | 
| 275 |  | 
| 276 | #if QT_CONFIG(shortcut) | 
| 277 |  | 
| 278 | void tst_qquicktextinput::simulateKeys(QWindow *window, const QKeySequence &sequence) | 
| 279 | { | 
| 280 |     for (int i = 0; i < sequence.count(); ++i) { | 
| 281 |         const int key = sequence[i]; | 
| 282 |         const int modifiers = key & Qt::KeyboardModifierMask; | 
| 283 |  | 
| 284 |         QTest::keyClick(window, key: Qt::Key(key & ~modifiers), modifier: Qt::KeyboardModifiers(modifiers)); | 
| 285 |     } | 
| 286 | } | 
| 287 |  | 
| 288 | QList<Key> &operator <<(QList<Key> &keys, const QKeySequence &sequence) | 
| 289 | { | 
| 290 |     for (int i = 0; i < sequence.count(); ++i) | 
| 291 |         keys << Key(sequence[i], QChar()); | 
| 292 |     return keys; | 
| 293 | } | 
| 294 |  | 
| 295 | #endif // QT_CONFIG(shortcut) | 
| 296 |  | 
| 297 | template <int N> QList<Key> &operator <<(QList<Key> &keys, const char (&characters)[N]) | 
| 298 | { | 
| 299 |     for (int i = 0; i < N - 1; ++i) { | 
| 300 |         int key = QTest::asciiToKey(ascii: characters[i]); | 
| 301 |         QChar character = QLatin1Char(characters[i]); | 
| 302 |         keys << Key(key, character); | 
| 303 |     } | 
| 304 |     return keys; | 
| 305 | } | 
| 306 |  | 
| 307 | QList<Key> &operator <<(QList<Key> &keys, Qt::Key key) | 
| 308 | { | 
| 309 |     keys << Key(key, QChar()); | 
| 310 |     return keys; | 
| 311 | } | 
| 312 |  | 
| 313 | void tst_qquicktextinput::cleanup() | 
| 314 | { | 
| 315 |     // ensure not even skipped tests with custom input context leave it dangling | 
| 316 |     QInputMethodPrivate *inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod()); | 
| 317 |     inputMethodPrivate->testContext = nullptr; | 
| 318 | } | 
| 319 |  | 
| 320 | tst_qquicktextinput::tst_qquicktextinput() | 
| 321 | { | 
| 322 |     standard << "the quick brown fox jumped over the lazy dog"  | 
| 323 |         << "It's supercalifragisiticexpialidocious!"  | 
| 324 |         << "Hello, world!"  | 
| 325 |         << "!dlrow ,olleH"  | 
| 326 |         << " spacey   text " ; | 
| 327 |  | 
| 328 |     colorStrings << "aliceblue"  | 
| 329 |                  << "antiquewhite"  | 
| 330 |                  << "aqua"  | 
| 331 |                  << "darkkhaki"  | 
| 332 |                  << "darkolivegreen"  | 
| 333 |                  << "dimgray"  | 
| 334 |                  << "palevioletred"  | 
| 335 |                  << "lightsteelblue"  | 
| 336 |                  << "#000000"  | 
| 337 |                  << "#AAAAAA"  | 
| 338 |                  << "#FFFFFF"  | 
| 339 |                  << "#2AC05F" ; | 
| 340 | } | 
| 341 |  | 
| 342 | void tst_qquicktextinput::text() | 
| 343 | { | 
| 344 |     { | 
| 345 |         QQmlComponent textinputComponent(&engine); | 
| 346 |         textinputComponent.setData("import QtQuick 2.0\nTextInput {  text: \"\"  }" , baseUrl: QUrl()); | 
| 347 |         QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput*>(object: textinputComponent.create()); | 
| 348 |  | 
| 349 |         QVERIFY(textinputObject != nullptr); | 
| 350 |         QCOMPARE(textinputObject->text(), QString("" )); | 
| 351 |         QCOMPARE(textinputObject->length(), 0); | 
| 352 |  | 
| 353 |         delete textinputObject; | 
| 354 |     } | 
| 355 |  | 
| 356 |     for (int i = 0; i < standard.size(); i++) | 
| 357 |     { | 
| 358 |         QString componentStr = "import QtQuick 2.0\nTextInput { text: \""  + standard.at(i) + "\" }" ; | 
| 359 |         QQmlComponent textinputComponent(&engine); | 
| 360 |         textinputComponent.setData(componentStr.toLatin1(), baseUrl: QUrl()); | 
| 361 |         QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput*>(object: textinputComponent.create()); | 
| 362 |  | 
| 363 |         QVERIFY(textinputObject != nullptr); | 
| 364 |         QCOMPARE(textinputObject->text(), standard.at(i)); | 
| 365 |         QCOMPARE(textinputObject->length(), standard.at(i).length()); | 
| 366 |  | 
| 367 |         delete textinputObject; | 
| 368 |     } | 
| 369 |  | 
| 370 | } | 
| 371 |  | 
| 372 | void tst_qquicktextinput::width() | 
| 373 | { | 
| 374 |     // uses Font metrics to find the width for standard | 
| 375 |     { | 
| 376 |         QQmlComponent textinputComponent(&engine); | 
| 377 |         textinputComponent.setData("import QtQuick 2.0\nTextInput {  text: \"\" }" , baseUrl: QUrl()); | 
| 378 |         QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput*>(object: textinputComponent.create()); | 
| 379 |  | 
| 380 |         QVERIFY(textinputObject != nullptr); | 
| 381 |         QCOMPARE(textinputObject->width(), 0.0); | 
| 382 |  | 
| 383 |         delete textinputObject; | 
| 384 |     } | 
| 385 |  | 
| 386 |     bool requiresUnhintedMetrics = !qmlDisableDistanceField(); | 
| 387 |  | 
| 388 |     for (int i = 0; i < standard.size(); i++) | 
| 389 |     { | 
| 390 |         QString componentStr = "import QtQuick 2.0\nTextInput { text: \""  + standard.at(i) + "\" }" ; | 
| 391 |         QQmlComponent textinputComponent(&engine); | 
| 392 |         textinputComponent.setData(componentStr.toLatin1(), baseUrl: QUrl()); | 
| 393 |         QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput*>(object: textinputComponent.create()); | 
| 394 |  | 
| 395 |         QString s = standard.at(i); | 
| 396 |         s.replace(before: QLatin1Char('\n'), after: QChar::LineSeparator); | 
| 397 |  | 
| 398 |         QTextLayout layout(s); | 
| 399 |         layout.setFont(textinputObject->font()); | 
| 400 |         layout.setFlags(Qt::TextExpandTabs | Qt::TextShowMnemonic); | 
| 401 |         if (requiresUnhintedMetrics) { | 
| 402 |             QTextOption option; | 
| 403 |             option.setUseDesignMetrics(true); | 
| 404 |             layout.setTextOption(option); | 
| 405 |         } | 
| 406 |  | 
| 407 |         layout.beginLayout(); | 
| 408 |         forever { | 
| 409 |             QTextLine line = layout.createLine(); | 
| 410 |             if (!line.isValid()) | 
| 411 |                 break; | 
| 412 |         } | 
| 413 |  | 
| 414 |         layout.endLayout(); | 
| 415 |  | 
| 416 |         qreal metricWidth = ceil(x: layout.boundingRect().width()); | 
| 417 |  | 
| 418 |         QVERIFY(textinputObject != nullptr); | 
| 419 |         int delta = abs(x: int(int(textinputObject->width()) - metricWidth)); | 
| 420 |         QVERIFY(delta <= 3.0); // As best as we can hope for cross-platform. | 
| 421 |  | 
| 422 |         delete textinputObject; | 
| 423 |     } | 
| 424 | } | 
| 425 |  | 
| 426 | void tst_qquicktextinput::font() | 
| 427 | { | 
| 428 |     //test size, then bold, then italic, then family | 
| 429 |     { | 
| 430 |         QString componentStr = "import QtQuick 2.0\nTextInput {  font.pointSize: 40; text: \"Hello World\" }" ; | 
| 431 |         QQmlComponent textinputComponent(&engine); | 
| 432 |         textinputComponent.setData(componentStr.toLatin1(), baseUrl: QUrl()); | 
| 433 |         QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput*>(object: textinputComponent.create()); | 
| 434 |  | 
| 435 |         QVERIFY(textinputObject != nullptr); | 
| 436 |         QCOMPARE(textinputObject->font().pointSize(), 40); | 
| 437 |         QCOMPARE(textinputObject->font().bold(), false); | 
| 438 |         QCOMPARE(textinputObject->font().italic(), false); | 
| 439 |  | 
| 440 |         delete textinputObject; | 
| 441 |     } | 
| 442 |  | 
| 443 |     { | 
| 444 |         QString componentStr = "import QtQuick 2.0\nTextInput {  font.bold: true; text: \"Hello World\" }" ; | 
| 445 |         QQmlComponent textinputComponent(&engine); | 
| 446 |         textinputComponent.setData(componentStr.toLatin1(), baseUrl: QUrl()); | 
| 447 |         QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput*>(object: textinputComponent.create()); | 
| 448 |  | 
| 449 |         QVERIFY(textinputObject != nullptr); | 
| 450 |         QCOMPARE(textinputObject->font().bold(), true); | 
| 451 |         QCOMPARE(textinputObject->font().italic(), false); | 
| 452 |  | 
| 453 |         delete textinputObject; | 
| 454 |     } | 
| 455 |  | 
| 456 |     { | 
| 457 |         QString componentStr = "import QtQuick 2.0\nTextInput {  font.italic: true; text: \"Hello World\" }" ; | 
| 458 |         QQmlComponent textinputComponent(&engine); | 
| 459 |         textinputComponent.setData(componentStr.toLatin1(), baseUrl: QUrl()); | 
| 460 |         QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput*>(object: textinputComponent.create()); | 
| 461 |  | 
| 462 |         QVERIFY(textinputObject != nullptr); | 
| 463 |         QCOMPARE(textinputObject->font().italic(), true); | 
| 464 |         QCOMPARE(textinputObject->font().bold(), false); | 
| 465 |  | 
| 466 |         delete textinputObject; | 
| 467 |     } | 
| 468 |  | 
| 469 |     { | 
| 470 |         QString componentStr = "import QtQuick 2.0\nTextInput {  font.family: \"Helvetica\"; text: \"Hello World\" }" ; | 
| 471 |         QQmlComponent textinputComponent(&engine); | 
| 472 |         textinputComponent.setData(componentStr.toLatin1(), baseUrl: QUrl()); | 
| 473 |         QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput*>(object: textinputComponent.create()); | 
| 474 |  | 
| 475 |         QVERIFY(textinputObject != nullptr); | 
| 476 |         QCOMPARE(textinputObject->font().family(), QString("Helvetica" )); | 
| 477 |         QCOMPARE(textinputObject->font().bold(), false); | 
| 478 |         QCOMPARE(textinputObject->font().italic(), false); | 
| 479 |  | 
| 480 |         delete textinputObject; | 
| 481 |     } | 
| 482 |  | 
| 483 |     { | 
| 484 |         QString componentStr = "import QtQuick 2.0\nTextInput {  font.family: \"\"; text: \"Hello World\" }" ; | 
| 485 |         QQmlComponent textinputComponent(&engine); | 
| 486 |         textinputComponent.setData(componentStr.toLatin1(), baseUrl: QUrl()); | 
| 487 |         QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput*>(object: textinputComponent.create()); | 
| 488 |  | 
| 489 |         QVERIFY(textinputObject != nullptr); | 
| 490 |         QCOMPARE(textinputObject->font().family(), QString("" )); | 
| 491 |  | 
| 492 |         delete textinputObject; | 
| 493 |     } | 
| 494 | } | 
| 495 |  | 
| 496 | void tst_qquicktextinput::color() | 
| 497 | { | 
| 498 |     //test initial color | 
| 499 |     { | 
| 500 |         QString componentStr = "import QtQuick 2.0\nTextInput { text: \"Hello World\" }" ; | 
| 501 |         QQmlComponent texteditComponent(&engine); | 
| 502 |         texteditComponent.setData(componentStr.toLatin1(), baseUrl: QUrl()); | 
| 503 |         QScopedPointer<QObject> object(texteditComponent.create()); | 
| 504 |         QQuickTextInput *textInputObject = qobject_cast<QQuickTextInput*>(object: object.data()); | 
| 505 |  | 
| 506 |         QVERIFY(textInputObject); | 
| 507 |         QCOMPARE(textInputObject->color(), QColor("black" )); | 
| 508 |         QCOMPARE(textInputObject->selectionColor(), QColor::fromRgba(0xFF000080)); | 
| 509 |         QCOMPARE(textInputObject->selectedTextColor(), QColor("white" )); | 
| 510 |  | 
| 511 |         QSignalSpy colorSpy(textInputObject, SIGNAL(colorChanged())); | 
| 512 |         QSignalSpy selectionColorSpy(textInputObject, SIGNAL(selectionColorChanged())); | 
| 513 |         QSignalSpy selectedTextColorSpy(textInputObject, SIGNAL(selectedTextColorChanged())); | 
| 514 |  | 
| 515 |         textInputObject->setColor(QColor("white" )); | 
| 516 |         QCOMPARE(textInputObject->color(), QColor("white" )); | 
| 517 |         QCOMPARE(colorSpy.count(), 1); | 
| 518 |  | 
| 519 |         textInputObject->setSelectionColor(QColor("black" )); | 
| 520 |         QCOMPARE(textInputObject->selectionColor(), QColor("black" )); | 
| 521 |         QCOMPARE(selectionColorSpy.count(), 1); | 
| 522 |  | 
| 523 |         textInputObject->setSelectedTextColor(QColor("blue" )); | 
| 524 |         QCOMPARE(textInputObject->selectedTextColor(), QColor("blue" )); | 
| 525 |         QCOMPARE(selectedTextColorSpy.count(), 1); | 
| 526 |  | 
| 527 |         textInputObject->setColor(QColor("white" )); | 
| 528 |         QCOMPARE(colorSpy.count(), 1); | 
| 529 |  | 
| 530 |         textInputObject->setSelectionColor(QColor("black" )); | 
| 531 |         QCOMPARE(selectionColorSpy.count(), 1); | 
| 532 |  | 
| 533 |         textInputObject->setSelectedTextColor(QColor("blue" )); | 
| 534 |         QCOMPARE(selectedTextColorSpy.count(), 1); | 
| 535 |  | 
| 536 |         textInputObject->setColor(QColor("black" )); | 
| 537 |         QCOMPARE(textInputObject->color(), QColor("black" )); | 
| 538 |         QCOMPARE(colorSpy.count(), 2); | 
| 539 |  | 
| 540 |         textInputObject->setSelectionColor(QColor("blue" )); | 
| 541 |         QCOMPARE(textInputObject->selectionColor(), QColor("blue" )); | 
| 542 |         QCOMPARE(selectionColorSpy.count(), 2); | 
| 543 |  | 
| 544 |         textInputObject->setSelectedTextColor(QColor("white" )); | 
| 545 |         QCOMPARE(textInputObject->selectedTextColor(), QColor("white" )); | 
| 546 |         QCOMPARE(selectedTextColorSpy.count(), 2); | 
| 547 |     } | 
| 548 |  | 
| 549 |     //test color | 
| 550 |     for (int i = 0; i < colorStrings.size(); i++) | 
| 551 |     { | 
| 552 |         QString componentStr = "import QtQuick 2.0\nTextInput {  color: \""  + colorStrings.at(i) + "\"; text: \"Hello World\" }" ; | 
| 553 |         QQmlComponent textinputComponent(&engine); | 
| 554 |         textinputComponent.setData(componentStr.toLatin1(), baseUrl: QUrl()); | 
| 555 |         QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput*>(object: textinputComponent.create()); | 
| 556 |         QVERIFY(textinputObject != nullptr); | 
| 557 |         QCOMPARE(textinputObject->color(), QColor(colorStrings.at(i))); | 
| 558 |  | 
| 559 |         delete textinputObject; | 
| 560 |     } | 
| 561 |  | 
| 562 |     //test selection color | 
| 563 |     for (int i = 0; i < colorStrings.size(); i++) | 
| 564 |     { | 
| 565 |         QString componentStr = "import QtQuick 2.0\nTextInput {  selectionColor: \""  + colorStrings.at(i) + "\"; text: \"Hello World\" }" ; | 
| 566 |         QQmlComponent textinputComponent(&engine); | 
| 567 |         textinputComponent.setData(componentStr.toLatin1(), baseUrl: QUrl()); | 
| 568 |         QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput*>(object: textinputComponent.create()); | 
| 569 |         QVERIFY(textinputObject != nullptr); | 
| 570 |         QCOMPARE(textinputObject->selectionColor(), QColor(colorStrings.at(i))); | 
| 571 |  | 
| 572 |         delete textinputObject; | 
| 573 |     } | 
| 574 |  | 
| 575 |     //test selected text color | 
| 576 |     for (int i = 0; i < colorStrings.size(); i++) | 
| 577 |     { | 
| 578 |         QString componentStr = "import QtQuick 2.0\nTextInput {  selectedTextColor: \""  + colorStrings.at(i) + "\"; text: \"Hello World\" }" ; | 
| 579 |         QQmlComponent textinputComponent(&engine); | 
| 580 |         textinputComponent.setData(componentStr.toLatin1(), baseUrl: QUrl()); | 
| 581 |         QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput*>(object: textinputComponent.create()); | 
| 582 |         QVERIFY(textinputObject != nullptr); | 
| 583 |         QCOMPARE(textinputObject->selectedTextColor(), QColor(colorStrings.at(i))); | 
| 584 |  | 
| 585 |         delete textinputObject; | 
| 586 |     } | 
| 587 |  | 
| 588 |     { | 
| 589 |         QString colorStr = "#AA001234" ; | 
| 590 |         QColor testColor("#001234" ); | 
| 591 |         testColor.setAlpha(170); | 
| 592 |  | 
| 593 |         QString componentStr = "import QtQuick 2.0\nTextInput {  color: \""  + colorStr + "\"; text: \"Hello World\" }" ; | 
| 594 |         QQmlComponent textinputComponent(&engine); | 
| 595 |         textinputComponent.setData(componentStr.toLatin1(), baseUrl: QUrl()); | 
| 596 |         QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput*>(object: textinputComponent.create()); | 
| 597 |  | 
| 598 |         QVERIFY(textinputObject != nullptr); | 
| 599 |         QCOMPARE(textinputObject->color(), testColor); | 
| 600 |  | 
| 601 |         delete textinputObject; | 
| 602 |     } | 
| 603 | } | 
| 604 |  | 
| 605 | void tst_qquicktextinput::wrap() | 
| 606 | { | 
| 607 |     int textHeight = 0; | 
| 608 |     // for specified width and wrap set true | 
| 609 |     { | 
| 610 |         QQmlComponent textComponent(&engine); | 
| 611 |         textComponent.setData("import QtQuick 2.0\nTextInput { text: \"Hello\"; wrapMode: Text.WrapAnywhere; width: 300 }" , baseUrl: QUrl::fromLocalFile(localfile: "" )); | 
| 612 |         QQuickTextInput *textObject = qobject_cast<QQuickTextInput*>(object: textComponent.create()); | 
| 613 |         textHeight = textObject->height(); | 
| 614 |  | 
| 615 |         QVERIFY(textObject != nullptr); | 
| 616 |         QCOMPARE(textObject->wrapMode(), QQuickTextInput::WrapAnywhere); | 
| 617 |         QCOMPARE(textObject->width(), 300.); | 
| 618 |  | 
| 619 |         delete textObject; | 
| 620 |     } | 
| 621 |  | 
| 622 |     for (int i = 0; i < standard.count(); i++) { | 
| 623 |         QString componentStr = "import QtQuick 2.0\nTextInput { wrapMode: Text.WrapAnywhere; width: 30; text: \""  + standard.at(i) + "\" }" ; | 
| 624 |         QQmlComponent textComponent(&engine); | 
| 625 |         textComponent.setData(componentStr.toLatin1(), baseUrl: QUrl::fromLocalFile(localfile: "" )); | 
| 626 |         QQuickTextInput *textObject = qobject_cast<QQuickTextInput*>(object: textComponent.create()); | 
| 627 |  | 
| 628 |         QVERIFY(textObject != nullptr); | 
| 629 |         QCOMPARE(textObject->width(), 30.); | 
| 630 |         QVERIFY(textObject->height() > textHeight); | 
| 631 |  | 
| 632 |         int oldHeight = textObject->height(); | 
| 633 |         textObject->setWidth(100); | 
| 634 |         QVERIFY(textObject->height() < oldHeight); | 
| 635 |  | 
| 636 |         delete textObject; | 
| 637 |     } | 
| 638 |  | 
| 639 |     { | 
| 640 |         QQmlComponent component(&engine); | 
| 641 |         component.setData("import QtQuick 2.0\n TextInput {}" , baseUrl: QUrl()); | 
| 642 |         QScopedPointer<QObject> object(component.create()); | 
| 643 |         QQuickTextInput *input = qobject_cast<QQuickTextInput *>(object: object.data()); | 
| 644 |         QVERIFY(input); | 
| 645 |  | 
| 646 |         QSignalSpy spy(input, SIGNAL(wrapModeChanged())); | 
| 647 |  | 
| 648 |         QCOMPARE(input->wrapMode(), QQuickTextInput::NoWrap); | 
| 649 |  | 
| 650 |         input->setWrapMode(QQuickTextInput::Wrap); | 
| 651 |         QCOMPARE(input->wrapMode(), QQuickTextInput::Wrap); | 
| 652 |         QCOMPARE(spy.count(), 1); | 
| 653 |  | 
| 654 |         input->setWrapMode(QQuickTextInput::Wrap); | 
| 655 |         QCOMPARE(spy.count(), 1); | 
| 656 |  | 
| 657 |         input->setWrapMode(QQuickTextInput::NoWrap); | 
| 658 |         QCOMPARE(input->wrapMode(), QQuickTextInput::NoWrap); | 
| 659 |         QCOMPARE(spy.count(), 2); | 
| 660 |     } | 
| 661 | } | 
| 662 |  | 
| 663 | void tst_qquicktextinput::selection() | 
| 664 | { | 
| 665 |     QString testStr = standard[0]; | 
| 666 |     QString componentStr = "import QtQuick 2.0\nTextInput {  text: \"" + testStr +"\"; }" ; | 
| 667 |     QQmlComponent textinputComponent(&engine); | 
| 668 |     textinputComponent.setData(componentStr.toLatin1(), baseUrl: QUrl()); | 
| 669 |     QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput*>(object: textinputComponent.create()); | 
| 670 |     QVERIFY(textinputObject != nullptr); | 
| 671 |  | 
| 672 |  | 
| 673 |     //Test selection follows cursor | 
| 674 |     for (int i=0; i<= testStr.size(); i++) { | 
| 675 |         textinputObject->setCursorPosition(i); | 
| 676 |         QCOMPARE(textinputObject->cursorPosition(), i); | 
| 677 |         QCOMPARE(textinputObject->selectionStart(), i); | 
| 678 |         QCOMPARE(textinputObject->selectionEnd(), i); | 
| 679 |         QVERIFY(textinputObject->selectedText().isNull()); | 
| 680 |     } | 
| 681 |  | 
| 682 |     textinputObject->setCursorPosition(0); | 
| 683 |     QCOMPARE(textinputObject->cursorPosition(), 0); | 
| 684 |     QCOMPARE(textinputObject->selectionStart(), 0); | 
| 685 |     QCOMPARE(textinputObject->selectionEnd(), 0); | 
| 686 |     QVERIFY(textinputObject->selectedText().isNull()); | 
| 687 |  | 
| 688 |     // Verify invalid positions are ignored. | 
| 689 |     textinputObject->setCursorPosition(-1); | 
| 690 |     QCOMPARE(textinputObject->cursorPosition(), 0); | 
| 691 |     QCOMPARE(textinputObject->selectionStart(), 0); | 
| 692 |     QCOMPARE(textinputObject->selectionEnd(), 0); | 
| 693 |     QVERIFY(textinputObject->selectedText().isNull()); | 
| 694 |  | 
| 695 |     textinputObject->setCursorPosition(textinputObject->text().count()+1); | 
| 696 |     QCOMPARE(textinputObject->cursorPosition(), 0); | 
| 697 |     QCOMPARE(textinputObject->selectionStart(), 0); | 
| 698 |     QCOMPARE(textinputObject->selectionEnd(), 0); | 
| 699 |     QVERIFY(textinputObject->selectedText().isNull()); | 
| 700 |  | 
| 701 |     //Test selection | 
| 702 |     for (int i=0; i<= testStr.size(); i++) { | 
| 703 |         textinputObject->select(start: 0,end: i); | 
| 704 |         QCOMPARE(testStr.mid(0,i), textinputObject->selectedText()); | 
| 705 |     } | 
| 706 |     for (int i=0; i<= testStr.size(); i++) { | 
| 707 |         textinputObject->select(start: i,end: testStr.size()); | 
| 708 |         QCOMPARE(testStr.mid(i,testStr.size()-i), textinputObject->selectedText()); | 
| 709 |     } | 
| 710 |  | 
| 711 |     textinputObject->setCursorPosition(0); | 
| 712 |     QCOMPARE(textinputObject->cursorPosition(), 0); | 
| 713 |     QCOMPARE(textinputObject->selectionStart(), 0); | 
| 714 |     QCOMPARE(textinputObject->selectionEnd(), 0); | 
| 715 |     QVERIFY(textinputObject->selectedText().isNull()); | 
| 716 |  | 
| 717 |     //Test Error Ignoring behaviour | 
| 718 |     textinputObject->setCursorPosition(0); | 
| 719 |     QVERIFY(textinputObject->selectedText().isNull()); | 
| 720 |     textinputObject->select(start: -10,end: 0); | 
| 721 |     QVERIFY(textinputObject->selectedText().isNull()); | 
| 722 |     textinputObject->select(start: 100,end: 110); | 
| 723 |     QVERIFY(textinputObject->selectedText().isNull()); | 
| 724 |     textinputObject->select(start: 0,end: -10); | 
| 725 |     QVERIFY(textinputObject->selectedText().isNull()); | 
| 726 |     textinputObject->select(start: 0,end: 100); | 
| 727 |     QVERIFY(textinputObject->selectedText().isNull()); | 
| 728 |     textinputObject->select(start: 0,end: 10); | 
| 729 |     QCOMPARE(textinputObject->selectedText().size(), 10); | 
| 730 |     textinputObject->select(start: -10,end: 10); | 
| 731 |     QCOMPARE(textinputObject->selectedText().size(), 10); | 
| 732 |     textinputObject->select(start: 100,end: 101); | 
| 733 |     QCOMPARE(textinputObject->selectedText().size(), 10); | 
| 734 |     textinputObject->select(start: 0,end: -10); | 
| 735 |     QCOMPARE(textinputObject->selectedText().size(), 10); | 
| 736 |     textinputObject->select(start: 0,end: 100); | 
| 737 |     QCOMPARE(textinputObject->selectedText().size(), 10); | 
| 738 |  | 
| 739 |     textinputObject->deselect(); | 
| 740 |     QVERIFY(textinputObject->selectedText().isNull()); | 
| 741 |     textinputObject->select(start: 0,end: 10); | 
| 742 |     QCOMPARE(textinputObject->selectedText().size(), 10); | 
| 743 |     textinputObject->deselect(); | 
| 744 |     QVERIFY(textinputObject->selectedText().isNull()); | 
| 745 |  | 
| 746 |     // test input method selection | 
| 747 |     QSignalSpy selectionSpy(textinputObject, SIGNAL(selectedTextChanged())); | 
| 748 |     textinputObject->setFocus(true); | 
| 749 |     { | 
| 750 |         QList<QInputMethodEvent::Attribute> attributes; | 
| 751 |         attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 12, 5, QVariant()); | 
| 752 |         QInputMethodEvent event("" , attributes); | 
| 753 |         QGuiApplication::sendEvent(receiver: textinputObject, event: &event); | 
| 754 |     } | 
| 755 |     QCOMPARE(selectionSpy.count(), 1); | 
| 756 |     QCOMPARE(textinputObject->selectionStart(), 12); | 
| 757 |     QCOMPARE(textinputObject->selectionEnd(), 17); | 
| 758 |  | 
| 759 |     delete textinputObject; | 
| 760 | } | 
| 761 |  | 
| 762 | void tst_qquicktextinput::persistentSelection() | 
| 763 | { | 
| 764 |     QQuickView window(testFileUrl(fileName: "persistentSelection.qml" )); | 
| 765 |     window.show(); | 
| 766 |     window.requestActivate(); | 
| 767 |     QVERIFY(QTest::qWaitForWindowActive(&window)); | 
| 768 |  | 
| 769 |     QQuickTextInput *input = qobject_cast<QQuickTextInput *>(object: window.rootObject()); | 
| 770 |     QVERIFY(input); | 
| 771 |     QVERIFY(input->hasActiveFocus()); | 
| 772 |  | 
| 773 |     QSignalSpy spy(input, SIGNAL(persistentSelectionChanged())); | 
| 774 |  | 
| 775 |     QCOMPARE(input->persistentSelection(), false); | 
| 776 |  | 
| 777 |     input->setPersistentSelection(false); | 
| 778 |     QCOMPARE(input->persistentSelection(), false); | 
| 779 |     QCOMPARE(spy.count(), 0); | 
| 780 |  | 
| 781 |     input->select(start: 1, end: 4); | 
| 782 |     QCOMPARE(input->property("selected" ).toString(), QLatin1String("ell" )); | 
| 783 |  | 
| 784 |     input->setFocus(false); | 
| 785 |     QCOMPARE(input->property("selected" ).toString(), QString()); | 
| 786 |  | 
| 787 |     input->setFocus(true); | 
| 788 |     QCOMPARE(input->property("selected" ).toString(), QString()); | 
| 789 |  | 
| 790 |     input->setPersistentSelection(true); | 
| 791 |     QCOMPARE(input->persistentSelection(), true); | 
| 792 |     QCOMPARE(spy.count(), 1); | 
| 793 |  | 
| 794 |     input->select(start: 1, end: 4); | 
| 795 |     QCOMPARE(input->property("selected" ).toString(), QLatin1String("ell" )); | 
| 796 |  | 
| 797 |     input->setFocus(false); | 
| 798 |     QCOMPARE(input->property("selected" ).toString(), QLatin1String("ell" )); | 
| 799 |  | 
| 800 |     input->setFocus(true); | 
| 801 |     QCOMPARE(input->property("selected" ).toString(), QLatin1String("ell" )); | 
| 802 | } | 
| 803 |  | 
| 804 | void tst_qquicktextinput::overwriteMode() | 
| 805 | { | 
| 806 |     QString componentStr = "import QtQuick 2.0\nTextInput { focus: true; }" ; | 
| 807 |     QQmlComponent textInputComponent(&engine); | 
| 808 |     textInputComponent.setData(componentStr.toLatin1(), baseUrl: QUrl()); | 
| 809 |     QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(object: textInputComponent.create()); | 
| 810 |     QVERIFY(textInput != nullptr); | 
| 811 |  | 
| 812 |     QSignalSpy spy(textInput, SIGNAL(overwriteModeChanged(bool))); | 
| 813 |  | 
| 814 |     QQuickWindow window; | 
| 815 |     textInput->setParentItem(window.contentItem()); | 
| 816 |     window.show(); | 
| 817 |     window.requestActivate(); | 
| 818 |     QVERIFY(QTest::qWaitForWindowActive(&window)); | 
| 819 |  | 
| 820 |     QVERIFY(textInput->hasActiveFocus()); | 
| 821 |  | 
| 822 |     textInput->setOverwriteMode(true); | 
| 823 |     QCOMPARE(spy.count(), 1); | 
| 824 |     QCOMPARE(true, textInput->overwriteMode()); | 
| 825 |     textInput->setOverwriteMode(false); | 
| 826 |     QCOMPARE(spy.count(), 2); | 
| 827 |     QCOMPARE(false, textInput->overwriteMode()); | 
| 828 |  | 
| 829 |     QVERIFY(!textInput->overwriteMode()); | 
| 830 |     QString insertString = "Some first text" ; | 
| 831 |     for (int j = 0; j < insertString.length(); j++) | 
| 832 |         QTest::keyClick(window: &window, key: insertString.at(i: j).toLatin1()); | 
| 833 |  | 
| 834 |     QCOMPARE(textInput->text(), QString("Some first text" )); | 
| 835 |  | 
| 836 |     textInput->setOverwriteMode(true); | 
| 837 |     QCOMPARE(spy.count(), 3); | 
| 838 |     textInput->setCursorPosition(5); | 
| 839 |  | 
| 840 |     insertString = "shiny" ; | 
| 841 |     for (int j = 0; j < insertString.length(); j++) | 
| 842 |         QTest::keyClick(window: &window, key: insertString.at(i: j).toLatin1()); | 
| 843 |     QCOMPARE(textInput->text(), QString("Some shiny text" )); | 
| 844 | } | 
| 845 |  | 
| 846 | void tst_qquicktextinput::isRightToLeft_data() | 
| 847 | { | 
| 848 |     QTest::addColumn<QString>(name: "text" ); | 
| 849 |     QTest::addColumn<bool>(name: "emptyString" ); | 
| 850 |     QTest::addColumn<bool>(name: "firstCharacter" ); | 
| 851 |     QTest::addColumn<bool>(name: "lastCharacter" ); | 
| 852 |     QTest::addColumn<bool>(name: "middleCharacter" ); | 
| 853 |     QTest::addColumn<bool>(name: "startString" ); | 
| 854 |     QTest::addColumn<bool>(name: "midString" ); | 
| 855 |     QTest::addColumn<bool>(name: "endString" ); | 
| 856 |  | 
| 857 |     const quint16 arabic_str[] = { 0x0638, 0x0643, 0x00646, 0x0647, 0x0633, 0x0638, 0x0643, 0x00646, 0x0647, 0x0633, 0x0647}; | 
| 858 |     QTest::newRow(dataTag: "Empty" ) << ""  << false << false << false << false << false << false << false; | 
| 859 |     QTest::newRow(dataTag: "Neutral" ) << "23244242"  << false << false << false << false << false << false << false; | 
| 860 |     QTest::newRow(dataTag: "LTR" ) << "Hello world"  << false << false << false << false << false << false << false; | 
| 861 |     QTest::newRow(dataTag: "RTL" ) << QString::fromUtf16(arabic_str, size: 11) << false << true << true << true << true << true << true; | 
| 862 |     QTest::newRow(dataTag: "Bidi RTL + LTR + RTL" ) << QString::fromUtf16(arabic_str, size: 11) + QString("Hello world" ) + QString::fromUtf16(arabic_str, size: 11) << false << true << true << false << true << true << true; | 
| 863 |     QTest::newRow(dataTag: "Bidi LTR + RTL + LTR" ) << QString("Hello world" ) + QString::fromUtf16(arabic_str, size: 11) + QString("Hello world" ) << false << false << false << true << false << false << false; | 
| 864 | } | 
| 865 |  | 
| 866 | void tst_qquicktextinput::isRightToLeft() | 
| 867 | { | 
| 868 |     QFETCH(QString, text); | 
| 869 |     QFETCH(bool, emptyString); | 
| 870 |     QFETCH(bool, firstCharacter); | 
| 871 |     QFETCH(bool, lastCharacter); | 
| 872 |     QFETCH(bool, middleCharacter); | 
| 873 |     QFETCH(bool, startString); | 
| 874 |     QFETCH(bool, midString); | 
| 875 |     QFETCH(bool, endString); | 
| 876 |  | 
| 877 |     QQuickTextInput textInput; | 
| 878 |     textInput.setText(text); | 
| 879 |  | 
| 880 |     // first test that the right string is delivered to the QString::isRightToLeft() | 
| 881 |     QCOMPARE(textInput.isRightToLeft(0,0), text.mid(0,0).isRightToLeft()); | 
| 882 |     QCOMPARE(textInput.isRightToLeft(0,1), text.mid(0,1).isRightToLeft()); | 
| 883 |     QCOMPARE(textInput.isRightToLeft(text.count()-2, text.count()-1), text.mid(text.count()-2, text.count()-1).isRightToLeft()); | 
| 884 |     QCOMPARE(textInput.isRightToLeft(text.count()/2, text.count()/2 + 1), text.mid(text.count()/2, text.count()/2 + 1).isRightToLeft()); | 
| 885 |     QCOMPARE(textInput.isRightToLeft(0,text.count()/4), text.mid(0,text.count()/4).isRightToLeft()); | 
| 886 |     QCOMPARE(textInput.isRightToLeft(text.count()/4,3*text.count()/4), text.mid(text.count()/4,3*text.count()/4).isRightToLeft()); | 
| 887 |     if (text.isEmpty()) | 
| 888 |         QTest::ignoreMessage(type: QtWarningMsg, message: "<Unknown File>: QML TextInput: isRightToLeft(start, end) called with the end property being smaller than the start." ); | 
| 889 |     QCOMPARE(textInput.isRightToLeft(3*text.count()/4,text.count()-1), text.mid(3*text.count()/4,text.count()-1).isRightToLeft()); | 
| 890 |  | 
| 891 |     // then test that the feature actually works | 
| 892 |     QCOMPARE(textInput.isRightToLeft(0,0), emptyString); | 
| 893 |     QCOMPARE(textInput.isRightToLeft(0,1), firstCharacter); | 
| 894 |     QCOMPARE(textInput.isRightToLeft(text.count()-2, text.count()-1), lastCharacter); | 
| 895 |     QCOMPARE(textInput.isRightToLeft(text.count()/2, text.count()/2 + 1), middleCharacter); | 
| 896 |     QCOMPARE(textInput.isRightToLeft(0,text.count()/4), startString); | 
| 897 |     QCOMPARE(textInput.isRightToLeft(text.count()/4,3*text.count()/4), midString); | 
| 898 |     if (text.isEmpty()) | 
| 899 |         QTest::ignoreMessage(type: QtWarningMsg, message: "<Unknown File>: QML TextInput: isRightToLeft(start, end) called with the end property being smaller than the start." ); | 
| 900 |     QCOMPARE(textInput.isRightToLeft(3*text.count()/4,text.count()-1), endString); | 
| 901 | } | 
| 902 |  | 
| 903 | void tst_qquicktextinput::moveCursorSelection_data() | 
| 904 | { | 
| 905 |     QTest::addColumn<QString>(name: "testStr" ); | 
| 906 |     QTest::addColumn<int>(name: "cursorPosition" ); | 
| 907 |     QTest::addColumn<int>(name: "movePosition" ); | 
| 908 |     QTest::addColumn<QQuickTextInput::SelectionMode>(name: "mode" ); | 
| 909 |     QTest::addColumn<int>(name: "selectionStart" ); | 
| 910 |     QTest::addColumn<int>(name: "selectionEnd" ); | 
| 911 |     QTest::addColumn<bool>(name: "reversible" ); | 
| 912 |  | 
| 913 |     // () contains the text selected by the cursor. | 
| 914 |     // <> contains the actual selection. | 
| 915 |  | 
| 916 |     QTest::newRow(dataTag: "(t)he|characters" ) | 
| 917 |             << standard[0] << 0 << 1 << QQuickTextInput::SelectCharacters << 0 << 1 << true; | 
| 918 |     QTest::newRow(dataTag: "do(g)|characters" ) | 
| 919 |             << standard[0] << 43 << 44 << QQuickTextInput::SelectCharacters << 43 << 44 << true; | 
| 920 |     QTest::newRow(dataTag: "jum(p)ed|characters" ) | 
| 921 |             << standard[0] << 23 << 24 << QQuickTextInput::SelectCharacters << 23 << 24 << true; | 
| 922 |     QTest::newRow(dataTag: "jumped( )over|characters" ) | 
| 923 |             << standard[0] << 26 << 27 << QQuickTextInput::SelectCharacters << 26 << 27 << true; | 
| 924 |     QTest::newRow(dataTag: "(the )|characters" ) | 
| 925 |             << standard[0] << 0 << 4 << QQuickTextInput::SelectCharacters << 0 << 4 << true; | 
| 926 |     QTest::newRow(dataTag: "( dog)|characters" ) | 
| 927 |             << standard[0] << 40 << 44 << QQuickTextInput::SelectCharacters << 40 << 44 << true; | 
| 928 |     QTest::newRow(dataTag: "( jumped )|characters" ) | 
| 929 |             << standard[0] << 19 << 27 << QQuickTextInput::SelectCharacters << 19 << 27 << true; | 
| 930 |     QTest::newRow(dataTag: "th(e qu)ick|characters" ) | 
| 931 |             << standard[0] << 2 << 6 << QQuickTextInput::SelectCharacters << 2 << 6 << true; | 
| 932 |     QTest::newRow(dataTag: "la(zy d)og|characters" ) | 
| 933 |             << standard[0] << 38 << 42 << QQuickTextInput::SelectCharacters << 38 << 42 << true; | 
| 934 |     QTest::newRow(dataTag: "jum(ped ov)er|characters" ) | 
| 935 |             << standard[0] << 23 << 29 << QQuickTextInput::SelectCharacters << 23 << 29 << true; | 
| 936 |     QTest::newRow(dataTag: "()the|characters" ) | 
| 937 |             << standard[0] << 0 << 0 << QQuickTextInput::SelectCharacters << 0 << 0 << true; | 
| 938 |     QTest::newRow(dataTag: "dog()|characters" ) | 
| 939 |             << standard[0] << 44 << 44 << QQuickTextInput::SelectCharacters << 44 << 44 << true; | 
| 940 |     QTest::newRow(dataTag: "jum()ped|characters" ) | 
| 941 |             << standard[0] << 23 << 23 << QQuickTextInput::SelectCharacters << 23 << 23 << true; | 
| 942 |  | 
| 943 |     QTest::newRow(dataTag: "<(t)he>|words" ) | 
| 944 |             << standard[0] << 0 << 1 << QQuickTextInput::SelectWords << 0 << 3 << true; | 
| 945 |     QTest::newRow(dataTag: "<do(g)>|words" ) | 
| 946 |             << standard[0] << 43 << 44 << QQuickTextInput::SelectWords << 41 << 44 << true; | 
| 947 |     QTest::newRow(dataTag: "<jum(p)ed>|words" ) | 
| 948 |             << standard[0] << 23 << 24 << QQuickTextInput::SelectWords << 20 << 26 << true; | 
| 949 |     QTest::newRow(dataTag: "<jumped( )>over|words,ltr" ) | 
| 950 |             << standard[0] << 26 << 27 << QQuickTextInput::SelectWords << 20 << 27 << false; | 
| 951 |     QTest::newRow(dataTag: "jumped<( )over>|words,rtl" ) | 
| 952 |             << standard[0] << 27 << 26 << QQuickTextInput::SelectWords << 26 << 31 << false; | 
| 953 |     QTest::newRow(dataTag: "<(the )>quick|words,ltr" ) | 
| 954 |             << standard[0] << 0 << 4 << QQuickTextInput::SelectWords << 0 << 4 << false; | 
| 955 |     QTest::newRow(dataTag: "<(the )quick>|words,rtl" ) | 
| 956 |             << standard[0] << 4 << 0 << QQuickTextInput::SelectWords << 0 << 9 << false; | 
| 957 |     QTest::newRow(dataTag: "<lazy( dog)>|words,ltr" ) | 
| 958 |             << standard[0] << 40 << 44 << QQuickTextInput::SelectWords << 36 << 44 << false; | 
| 959 |     QTest::newRow(dataTag: "lazy<( dog)>|words,rtl" ) | 
| 960 |             << standard[0] << 44 << 40 << QQuickTextInput::SelectWords << 40 << 44 << false; | 
| 961 |     QTest::newRow(dataTag: "<fox( jumped )>over|words,ltr" ) | 
| 962 |             << standard[0] << 19 << 27 << QQuickTextInput::SelectWords << 16 << 27 << false; | 
| 963 |     QTest::newRow(dataTag: "fox<( jumped )over>|words,rtl" ) | 
| 964 |             << standard[0] << 27 << 19 << QQuickTextInput::SelectWords << 19 << 31 << false; | 
| 965 |     QTest::newRow(dataTag: "<th(e qu)ick>|words" ) | 
| 966 |             << standard[0] << 2 << 6 << QQuickTextInput::SelectWords << 0 << 9 << true; | 
| 967 |     QTest::newRow(dataTag: "<la(zy d)og|words>" ) | 
| 968 |             << standard[0] << 38 << 42 << QQuickTextInput::SelectWords << 36 << 44 << true; | 
| 969 |     QTest::newRow(dataTag: "<jum(ped ov)er>|words" ) | 
| 970 |             << standard[0] << 23 << 29 << QQuickTextInput::SelectWords << 20 << 31 << true; | 
| 971 |     QTest::newRow(dataTag: "<()>the|words" ) | 
| 972 |             << standard[0] << 0 << 0 << QQuickTextInput::SelectWords << 0 << 0 << true; | 
| 973 |     QTest::newRow(dataTag: "dog<()>|words" ) | 
| 974 |             << standard[0] << 44 << 44 << QQuickTextInput::SelectWords << 44 << 44 << true; | 
| 975 |     QTest::newRow(dataTag: "jum<()>ped|words" ) | 
| 976 |             << standard[0] << 23 << 23 << QQuickTextInput::SelectWords << 23 << 23 << true; | 
| 977 |  | 
| 978 |     QTest::newRow(dataTag: "<Hello(,)> |words,ltr" ) | 
| 979 |             << standard[2] << 5 << 6 << QQuickTextInput::SelectWords << 0 << 6 << false; | 
| 980 |     QTest::newRow(dataTag: "Hello<(,)> |words,rtl" ) | 
| 981 |             << standard[2] << 6 << 5 << QQuickTextInput::SelectWords << 5 << 6 << false; | 
| 982 |     QTest::newRow(dataTag: "<Hello(, )>world|words,ltr" ) | 
| 983 |             << standard[2] << 5 << 7 << QQuickTextInput::SelectWords << 0 << 7 << false; | 
| 984 |     QTest::newRow(dataTag: "Hello<(, )world>|words,rtl" ) | 
| 985 |             << standard[2] << 7 << 5 << QQuickTextInput::SelectWords << 5 << 12 << false; | 
| 986 |     QTest::newRow(dataTag: "<Hel(lo, )>world|words,ltr" ) | 
| 987 |             << standard[2] << 3 << 7 << QQuickTextInput::SelectWords << 0 << 7 << false; | 
| 988 |     QTest::newRow(dataTag: "<Hel(lo, )world>|words,rtl" ) | 
| 989 |             << standard[2] << 7 << 3 << QQuickTextInput::SelectWords << 0 << 12 << false; | 
| 990 |     QTest::newRow(dataTag: "<Hel(lo)>,|words" ) | 
| 991 |             << standard[2] << 3 << 5 << QQuickTextInput::SelectWords << 0 << 5 << true; | 
| 992 |     QTest::newRow(dataTag: "Hello<()>,|words" ) | 
| 993 |             << standard[2] << 5 << 5 << QQuickTextInput::SelectWords << 5 << 5 << true; | 
| 994 |     QTest::newRow(dataTag: "Hello,<()>|words" ) | 
| 995 |             << standard[2] << 6 << 6 << QQuickTextInput::SelectWords << 6 << 6 << true; | 
| 996 |     QTest::newRow(dataTag: "Hello,<( )>world|words,ltr" ) | 
| 997 |             << standard[2] << 6 << 7 << QQuickTextInput::SelectWords << 6 << 7 << false; | 
| 998 |     QTest::newRow(dataTag: "Hello,<( )world>|words,rtl" ) | 
| 999 |             << standard[2] << 7 << 6 << QQuickTextInput::SelectWords << 6 << 12 << false; | 
| 1000 |     QTest::newRow(dataTag: "Hello,<( world)>|words" ) | 
| 1001 |             << standard[2] << 6 << 12 << QQuickTextInput::SelectWords << 6 << 12 << true; | 
| 1002 |     QTest::newRow(dataTag: "Hello,<( world!)>|words" ) | 
| 1003 |             << standard[2] << 6 << 13 << QQuickTextInput::SelectWords << 6 << 13 << true; | 
| 1004 |     QTest::newRow(dataTag: "<Hello(, world!)>|words,ltr" ) | 
| 1005 |             << standard[2] << 5 << 13 << QQuickTextInput::SelectWords << 0 << 13 << false; | 
| 1006 |     QTest::newRow(dataTag: "Hello<(, world!)>|words,rtl" ) | 
| 1007 |             << standard[2] << 13 << 5 << QQuickTextInput::SelectWords << 5 << 13 << false; | 
| 1008 |     QTest::newRow(dataTag: "<world(!)>|words,ltr" ) | 
| 1009 |             << standard[2] << 12 << 13 << QQuickTextInput::SelectWords << 7 << 13 << false; | 
| 1010 |     QTest::newRow(dataTag: "world<(!)>|words,rtl" ) | 
| 1011 |             << standard[2] << 13 << 12 << QQuickTextInput::SelectWords << 12 << 13 << false; | 
| 1012 |     QTest::newRow(dataTag: "world!<()>)|words" ) | 
| 1013 |             << standard[2] << 13 << 13 << QQuickTextInput::SelectWords << 13 << 13 << true; | 
| 1014 |     QTest::newRow(dataTag: "world<()>!)|words" ) | 
| 1015 |             << standard[2] << 12 << 12 << QQuickTextInput::SelectWords << 12 << 12 << true; | 
| 1016 |  | 
| 1017 |     QTest::newRow(dataTag: "<(,)>olleH |words,ltr" ) | 
| 1018 |             << standard[3] << 7 << 8 << QQuickTextInput::SelectWords << 7 << 8 << false; | 
| 1019 |     QTest::newRow(dataTag: "<(,)olleH> |words,rtl" ) | 
| 1020 |             << standard[3] << 8 << 7 << QQuickTextInput::SelectWords << 7 << 13 << false; | 
| 1021 |     QTest::newRow(dataTag: "<dlrow( ,)>olleH|words,ltr" ) | 
| 1022 |             << standard[3] << 6 << 8 << QQuickTextInput::SelectWords << 1 << 8 << false; | 
| 1023 |     QTest::newRow(dataTag: "dlrow<( ,)olleH>|words,rtl" ) | 
| 1024 |             << standard[3] << 8 << 6 << QQuickTextInput::SelectWords << 6 << 13 << false; | 
| 1025 |     QTest::newRow(dataTag: "<dlrow( ,ol)leH>|words,ltr" ) | 
| 1026 |             << standard[3] << 6 << 10 << QQuickTextInput::SelectWords << 1 << 13 << false; | 
| 1027 |     QTest::newRow(dataTag: "dlrow<( ,ol)leH>|words,rtl" ) | 
| 1028 |             << standard[3] << 10 << 6 << QQuickTextInput::SelectWords << 6 << 13 << false; | 
| 1029 |     QTest::newRow(dataTag: ",<(ol)leH>,|words" ) | 
| 1030 |             << standard[3] << 8 << 10 << QQuickTextInput::SelectWords << 8 << 13 << true; | 
| 1031 |     QTest::newRow(dataTag: ",<()>olleH|words" ) | 
| 1032 |             << standard[3] << 8 << 8 << QQuickTextInput::SelectWords << 8 << 8 << true; | 
| 1033 |     QTest::newRow(dataTag: "<()>,olleH|words" ) | 
| 1034 |             << standard[3] << 7 << 7 << QQuickTextInput::SelectWords << 7 << 7 << true; | 
| 1035 |     QTest::newRow(dataTag: "<dlrow( )>,olleH|words,ltr" ) | 
| 1036 |             << standard[3] << 6 << 7 << QQuickTextInput::SelectWords << 1 << 7 << false; | 
| 1037 |     QTest::newRow(dataTag: "dlrow<( )>,olleH|words,rtl" ) | 
| 1038 |             << standard[3] << 7 << 6 << QQuickTextInput::SelectWords << 6 << 7 << false; | 
| 1039 |     QTest::newRow(dataTag: "<(dlrow )>,olleH|words" ) | 
| 1040 |             << standard[3] << 1 << 7 << QQuickTextInput::SelectWords << 1 << 7 << true; | 
| 1041 |     QTest::newRow(dataTag: "<(!dlrow )>,olleH|words" ) | 
| 1042 |             << standard[3] << 0 << 7 << QQuickTextInput::SelectWords << 0 << 7 << true; | 
| 1043 |     QTest::newRow(dataTag: "<(!dlrow ,)>olleH|words,ltr" ) | 
| 1044 |             << standard[3] << 0 << 8 << QQuickTextInput::SelectWords << 0 << 8 << false; | 
| 1045 |     QTest::newRow(dataTag: "<(!dlrow ,)olleH>|words,rtl" ) | 
| 1046 |             << standard[3] << 8 << 0 << QQuickTextInput::SelectWords << 0 << 13 << false; | 
| 1047 |     QTest::newRow(dataTag: "<(!)>dlrow|words,ltr" ) | 
| 1048 |             << standard[3] << 0 << 1 << QQuickTextInput::SelectWords << 0 << 1 << false; | 
| 1049 |     QTest::newRow(dataTag: "<(!)dlrow|words,rtl" ) | 
| 1050 |             << standard[3] << 1 << 0 << QQuickTextInput::SelectWords << 0 << 6 << false; | 
| 1051 |     QTest::newRow(dataTag: "<()>!dlrow|words" ) | 
| 1052 |             << standard[3] << 0 << 0 << QQuickTextInput::SelectWords << 0 << 0 << true; | 
| 1053 |     QTest::newRow(dataTag: "!<()>dlrow|words" ) | 
| 1054 |             << standard[3] << 1 << 1 << QQuickTextInput::SelectWords << 1 << 1 << true; | 
| 1055 |  | 
| 1056 |     QTest::newRow(dataTag: " <s(pac)ey>   text |words" ) | 
| 1057 |             << standard[4] << 1 << 4 << QQuickTextInput::SelectWords << 1 << 7 << true; | 
| 1058 |     QTest::newRow(dataTag: " spacey   <t(ex)t> |words" ) | 
| 1059 |             << standard[4] << 11 << 13 << QQuickTextInput::SelectWords << 10 << 14 << true; | 
| 1060 |     QTest::newRow(dataTag: "<( )>spacey   text |words|ltr" ) | 
| 1061 |             << standard[4] << 0 << 1 << QQuickTextInput::SelectWords << 0 << 1 << false; | 
| 1062 |     QTest::newRow(dataTag: "<( )spacey>   text |words|rtl" ) | 
| 1063 |             << standard[4] << 1 << 0 << QQuickTextInput::SelectWords << 0 << 7 << false; | 
| 1064 |     QTest::newRow(dataTag: "spacey   <text( )>|words|ltr" ) | 
| 1065 |             << standard[4] << 14 << 15 << QQuickTextInput::SelectWords << 10 << 15 << false; | 
| 1066 |     QTest::newRow(dataTag: "spacey   text<( )>|words|rtl" ) | 
| 1067 |             << standard[4] << 15 << 14 << QQuickTextInput::SelectWords << 14 << 15 << false; | 
| 1068 |     QTest::newRow(dataTag: "<()> spacey   text |words" ) | 
| 1069 |             << standard[4] << 0 << 0 << QQuickTextInput::SelectWords << 0 << 0 << false; | 
| 1070 |     QTest::newRow(dataTag: " spacey   text <()>|words" ) | 
| 1071 |             << standard[4] << 15 << 15 << QQuickTextInput::SelectWords << 15 << 15 << false; | 
| 1072 | } | 
| 1073 |  | 
| 1074 | void tst_qquicktextinput::moveCursorSelection() | 
| 1075 | { | 
| 1076 |     QFETCH(QString, testStr); | 
| 1077 |     QFETCH(int, cursorPosition); | 
| 1078 |     QFETCH(int, movePosition); | 
| 1079 |     QFETCH(QQuickTextInput::SelectionMode, mode); | 
| 1080 |     QFETCH(int, selectionStart); | 
| 1081 |     QFETCH(int, selectionEnd); | 
| 1082 |     QFETCH(bool, reversible); | 
| 1083 |  | 
| 1084 |     QString componentStr = "import QtQuick 2.0\nTextInput {  text: \"" + testStr +"\"; }" ; | 
| 1085 |     QQmlComponent textinputComponent(&engine); | 
| 1086 |     textinputComponent.setData(componentStr.toLatin1(), baseUrl: QUrl()); | 
| 1087 |     QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput*>(object: textinputComponent.create()); | 
| 1088 |     QVERIFY(textinputObject != nullptr); | 
| 1089 |  | 
| 1090 |     textinputObject->setCursorPosition(cursorPosition); | 
| 1091 |     textinputObject->moveCursorSelection(pos: movePosition, mode); | 
| 1092 |  | 
| 1093 |     QCOMPARE(textinputObject->selectedText(), testStr.mid(selectionStart, selectionEnd - selectionStart)); | 
| 1094 |     QCOMPARE(textinputObject->selectionStart(), selectionStart); | 
| 1095 |     QCOMPARE(textinputObject->selectionEnd(), selectionEnd); | 
| 1096 |  | 
| 1097 |     if (reversible) { | 
| 1098 |         textinputObject->setCursorPosition(movePosition); | 
| 1099 |         textinputObject->moveCursorSelection(pos: cursorPosition, mode); | 
| 1100 |  | 
| 1101 |         QCOMPARE(textinputObject->selectedText(), testStr.mid(selectionStart, selectionEnd - selectionStart)); | 
| 1102 |         QCOMPARE(textinputObject->selectionStart(), selectionStart); | 
| 1103 |         QCOMPARE(textinputObject->selectionEnd(), selectionEnd); | 
| 1104 |     } | 
| 1105 |  | 
| 1106 |     delete textinputObject; | 
| 1107 | } | 
| 1108 |  | 
| 1109 | void tst_qquicktextinput::moveCursorSelectionSequence_data() | 
| 1110 | { | 
| 1111 |     QTest::addColumn<QString>(name: "testStr" ); | 
| 1112 |     QTest::addColumn<int>(name: "cursorPosition" ); | 
| 1113 |     QTest::addColumn<int>(name: "movePosition1" ); | 
| 1114 |     QTest::addColumn<int>(name: "movePosition2" ); | 
| 1115 |     QTest::addColumn<int>(name: "selection1Start" ); | 
| 1116 |     QTest::addColumn<int>(name: "selection1End" ); | 
| 1117 |     QTest::addColumn<int>(name: "selection2Start" ); | 
| 1118 |     QTest::addColumn<int>(name: "selection2End" ); | 
| 1119 |  | 
| 1120 |     // () contains the text selected by the cursor. | 
| 1121 |     // <> contains the actual selection. | 
| 1122 |     // ^ is the revised cursor position. | 
| 1123 |     // {} contains the revised selection. | 
| 1124 |  | 
| 1125 |     QTest::newRow(dataTag: "the {<quick( bro)wn> f^ox} jumped|ltr" ) | 
| 1126 |             << standard[0] | 
| 1127 |             << 9 << 13 << 17 | 
| 1128 |             << 4 << 15 | 
| 1129 |             << 4 << 19; | 
| 1130 |     QTest::newRow(dataTag: "the quick<( {bro)wn> f^ox} jumped|rtl" ) | 
| 1131 |             << standard[0] | 
| 1132 |             << 13 << 9 << 17 | 
| 1133 |             << 9 << 15 | 
| 1134 |             << 10 << 19; | 
| 1135 |     QTest::newRow(dataTag: "the {<quick( bro)wn> ^}fox jumped|ltr" ) | 
| 1136 |             << standard[0] | 
| 1137 |             << 9 << 13 << 16 | 
| 1138 |             << 4 << 15 | 
| 1139 |             << 4 << 16; | 
| 1140 |     QTest::newRow(dataTag: "the quick<( {bro)wn> ^}fox jumped|rtl" ) | 
| 1141 |             << standard[0] | 
| 1142 |             << 13 << 9 << 16 | 
| 1143 |             << 9 << 15 | 
| 1144 |             << 10 << 16; | 
| 1145 |     QTest::newRow(dataTag: "the {<quick( bro)wn^>} fox jumped|ltr" ) | 
| 1146 |             << standard[0] | 
| 1147 |             << 9 << 13 << 15 | 
| 1148 |             << 4 << 15 | 
| 1149 |             << 4 << 15; | 
| 1150 |     QTest::newRow(dataTag: "the quick<( {bro)wn^>} f^ox jumped|rtl" ) | 
| 1151 |             << standard[0] | 
| 1152 |             << 13 << 9 << 15 | 
| 1153 |             << 9 << 15 | 
| 1154 |             << 10 << 15; | 
| 1155 |     QTest::newRow(dataTag: "the {<quick() ^}bro)wn> fox|ltr" ) | 
| 1156 |             << standard[0] | 
| 1157 |             << 9 << 13 << 10 | 
| 1158 |             << 4 << 15 | 
| 1159 |             << 4 << 10; | 
| 1160 |     QTest::newRow(dataTag: "the quick<( {^bro)wn>} fox|rtl" ) | 
| 1161 |             << standard[0] | 
| 1162 |             << 13 << 9 << 10 | 
| 1163 |             << 9 << 15 | 
| 1164 |             << 10 << 15; | 
| 1165 |     QTest::newRow(dataTag: "the {<quick^}( bro)wn> fox|ltr" ) | 
| 1166 |             << standard[0] | 
| 1167 |             << 9 << 13 << 9 | 
| 1168 |             << 4 << 15 | 
| 1169 |             << 4 << 9; | 
| 1170 |     QTest::newRow(dataTag: "the quick{<(^ bro)wn>} fox|rtl" ) | 
| 1171 |             << standard[0] | 
| 1172 |             << 13 << 9 << 9 | 
| 1173 |             << 9 << 15 | 
| 1174 |             << 9 << 15; | 
| 1175 |     QTest::newRow(dataTag: "the {<qui^ck}( bro)wn> fox|ltr" ) | 
| 1176 |             << standard[0] | 
| 1177 |             << 9 << 13 << 7 | 
| 1178 |             << 4 << 15 | 
| 1179 |             << 4 << 9; | 
| 1180 |     QTest::newRow(dataTag: "the {<qui^ck}( bro)wn> fox|rtl" ) | 
| 1181 |             << standard[0] | 
| 1182 |             << 13 << 9 << 7 | 
| 1183 |             << 9 << 15 | 
| 1184 |             << 4 << 15; | 
| 1185 |     QTest::newRow(dataTag: "the {<^quick}( bro)wn> fox|ltr" ) | 
| 1186 |             << standard[0] | 
| 1187 |             << 9 << 13 << 4 | 
| 1188 |             << 4 << 15 | 
| 1189 |             << 4 << 9; | 
| 1190 |     QTest::newRow(dataTag: "the {<^quick}( bro)wn> fox|rtl" ) | 
| 1191 |             << standard[0] | 
| 1192 |             << 13 << 9 << 4 | 
| 1193 |             << 9 << 15 | 
| 1194 |             << 4 << 15; | 
| 1195 |     QTest::newRow(dataTag: "the{^ <quick}( bro)wn> fox|ltr" ) | 
| 1196 |             << standard[0] | 
| 1197 |             << 9 << 13 << 3 | 
| 1198 |             << 4 << 15 | 
| 1199 |             << 3 << 9; | 
| 1200 |     QTest::newRow(dataTag: "the{^ <quick}( bro)wn> fox|rtl" ) | 
| 1201 |             << standard[0] | 
| 1202 |             << 13 << 9 << 3 | 
| 1203 |             << 9 << 15 | 
| 1204 |             << 3 << 15; | 
| 1205 |     QTest::newRow(dataTag: "{t^he <quick}( bro)wn> fox|ltr" ) | 
| 1206 |             << standard[0] | 
| 1207 |             << 9 << 13 << 1 | 
| 1208 |             << 4 << 15 | 
| 1209 |             << 0 << 9; | 
| 1210 |     QTest::newRow(dataTag: "{t^he <quick}( bro)wn> fox|rtl" ) | 
| 1211 |             << standard[0] | 
| 1212 |             << 13 << 9 << 1 | 
| 1213 |             << 9 << 15 | 
| 1214 |             << 0 << 15; | 
| 1215 |  | 
| 1216 |     QTest::newRow(dataTag: "{<He(ll)o>, w^orld}!|ltr" ) | 
| 1217 |             << standard[2] | 
| 1218 |             << 2 << 4 << 8 | 
| 1219 |             << 0 << 5 | 
| 1220 |             << 0 << 12; | 
| 1221 |     QTest::newRow(dataTag: "{<He(ll)o>, w^orld}!|rtl" ) | 
| 1222 |             << standard[2] | 
| 1223 |             << 4 << 2 << 8 | 
| 1224 |             << 0 << 5 | 
| 1225 |             << 0 << 12; | 
| 1226 |  | 
| 1227 |     QTest::newRow(dataTag: "!{dlro^w ,<o(ll)eH>}|ltr" ) | 
| 1228 |             << standard[3] | 
| 1229 |             << 9 << 11 << 5 | 
| 1230 |             << 8 << 13 | 
| 1231 |             << 1 << 13; | 
| 1232 |     QTest::newRow(dataTag: "!{dlro^w ,<o(ll)eH>}|rtl" ) | 
| 1233 |             << standard[3] | 
| 1234 |             << 11 << 9 << 5 | 
| 1235 |             << 8 << 13 | 
| 1236 |             << 1 << 13; | 
| 1237 |  | 
| 1238 |     QTest::newRow(dataTag: "{<(^} sp)acey>   text |ltr" ) | 
| 1239 |             << standard[4] | 
| 1240 |             << 0 << 3 << 0 | 
| 1241 |             << 0 << 7 | 
| 1242 |             << 0 << 0; | 
| 1243 |     QTest::newRow(dataTag: "{<( ^}sp)acey>   text |ltr" ) | 
| 1244 |             << standard[4] | 
| 1245 |             << 0 << 3 << 1 | 
| 1246 |             << 0 << 7 | 
| 1247 |             << 0 << 1; | 
| 1248 |     QTest::newRow(dataTag: "<( {s^p)acey>}   text |rtl" ) | 
| 1249 |             << standard[4] | 
| 1250 |             << 3 << 0 << 2 | 
| 1251 |             << 0 << 7 | 
| 1252 |             << 1 << 7; | 
| 1253 |     QTest::newRow(dataTag: "<( {^sp)acey>}   text |rtl" ) | 
| 1254 |             << standard[4] | 
| 1255 |             << 3 << 0 << 1 | 
| 1256 |             << 0 << 7 | 
| 1257 |             << 1 << 7; | 
| 1258 |  | 
| 1259 |     QTest::newRow(dataTag: " spacey   <te(xt {^)>}|rtl" ) | 
| 1260 |             << standard[4] | 
| 1261 |             << 15 << 12 << 15 | 
| 1262 |             << 10 << 15 | 
| 1263 |             << 15 << 15; | 
| 1264 |     QTest::newRow(dataTag: " spacey   <te(xt{^ )>}|rtl" ) | 
| 1265 |             << standard[4] | 
| 1266 |             << 15 << 12 << 14 | 
| 1267 |             << 10 << 15 | 
| 1268 |             << 14 << 15; | 
| 1269 |     QTest::newRow(dataTag: " spacey   {<te(x^t} )>|ltr" ) | 
| 1270 |             << standard[4] | 
| 1271 |             << 12 << 15 << 13 | 
| 1272 |             << 10 << 15 | 
| 1273 |             << 10 << 14; | 
| 1274 |     QTest::newRow(dataTag: " spacey   {<te(xt^} )>|ltr" ) | 
| 1275 |             << standard[4] | 
| 1276 |             << 12 << 15 << 14 | 
| 1277 |             << 10 << 15 | 
| 1278 |             << 10 << 14; | 
| 1279 | } | 
| 1280 |  | 
| 1281 | void tst_qquicktextinput::moveCursorSelectionSequence() | 
| 1282 | { | 
| 1283 |     QFETCH(QString, testStr); | 
| 1284 |     QFETCH(int, cursorPosition); | 
| 1285 |     QFETCH(int, movePosition1); | 
| 1286 |     QFETCH(int, movePosition2); | 
| 1287 |     QFETCH(int, selection1Start); | 
| 1288 |     QFETCH(int, selection1End); | 
| 1289 |     QFETCH(int, selection2Start); | 
| 1290 |     QFETCH(int, selection2End); | 
| 1291 |  | 
| 1292 |     QString componentStr = "import QtQuick 2.0\nTextInput {  text: \"" + testStr +"\"; }" ; | 
| 1293 |     QQmlComponent textinputComponent(&engine); | 
| 1294 |     textinputComponent.setData(componentStr.toLatin1(), baseUrl: QUrl()); | 
| 1295 |     QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput*>(object: textinputComponent.create()); | 
| 1296 |     QVERIFY(textinputObject != nullptr); | 
| 1297 |  | 
| 1298 |     textinputObject->setCursorPosition(cursorPosition); | 
| 1299 |  | 
| 1300 |     textinputObject->moveCursorSelection(pos: movePosition1, mode: QQuickTextInput::SelectWords); | 
| 1301 |     QCOMPARE(textinputObject->selectedText(), testStr.mid(selection1Start, selection1End - selection1Start)); | 
| 1302 |     QCOMPARE(textinputObject->selectionStart(), selection1Start); | 
| 1303 |     QCOMPARE(textinputObject->selectionEnd(), selection1End); | 
| 1304 |  | 
| 1305 |     textinputObject->moveCursorSelection(pos: movePosition2, mode: QQuickTextInput::SelectWords); | 
| 1306 |     QCOMPARE(textinputObject->selectedText(), testStr.mid(selection2Start, selection2End - selection2Start)); | 
| 1307 |     QCOMPARE(textinputObject->selectionStart(), selection2Start); | 
| 1308 |     QCOMPARE(textinputObject->selectionEnd(), selection2End); | 
| 1309 |  | 
| 1310 |     delete textinputObject; | 
| 1311 | } | 
| 1312 |  | 
| 1313 | void tst_qquicktextinput::dragMouseSelection() | 
| 1314 | { | 
| 1315 |     QString qmlfile = testFile(fileName: "mouseselection_true.qml" ); | 
| 1316 |  | 
| 1317 |     QQuickView window(QUrl::fromLocalFile(localfile: qmlfile)); | 
| 1318 |  | 
| 1319 |     window.show(); | 
| 1320 |     window.requestActivate(); | 
| 1321 |     QVERIFY(QTest::qWaitForWindowActive(&window)); | 
| 1322 |  | 
| 1323 |     QVERIFY(window.rootObject() != nullptr); | 
| 1324 |     QQuickTextInput *textInputObject = qobject_cast<QQuickTextInput *>(object: window.rootObject()); | 
| 1325 |     QVERIFY(textInputObject != nullptr); | 
| 1326 |  | 
| 1327 |     // press-and-drag-and-release from x1 to x2 | 
| 1328 |     int x1 = 10; | 
| 1329 |     int x2 = 70; | 
| 1330 |     int y = textInputObject->height()/2; | 
| 1331 |     QTest::mousePress(window: &window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: QPoint(x1,y)); | 
| 1332 |     QTest::mouseMove(window: &window, pos: QPoint(x2, y)); | 
| 1333 |     QTest::mouseRelease(window: &window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: QPoint(x2,y)); | 
| 1334 |     QString str1; | 
| 1335 |     QTRY_VERIFY((str1 = textInputObject->selectedText()).length() > 3); | 
| 1336 |     QTRY_VERIFY(str1.length() > 3); | 
| 1337 |  | 
| 1338 |     // press and drag the current selection. | 
| 1339 |     x1 = 40; | 
| 1340 |     x2 = 100; | 
| 1341 |     QTest::mousePress(window: &window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: QPoint(x1,y)); | 
| 1342 |     QTest::mouseMove(window: &window, pos: QPoint(x2, y)); | 
| 1343 |     QTest::mouseRelease(window: &window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: QPoint(x2,y)); | 
| 1344 |     QString str2 = textInputObject->selectedText(); | 
| 1345 |     QTRY_VERIFY(str2.length() > 3); | 
| 1346 |  | 
| 1347 |     QTRY_VERIFY(str1 != str2); | 
| 1348 | } | 
| 1349 |  | 
| 1350 | void tst_qquicktextinput::mouseSelectionMode_data() | 
| 1351 | { | 
| 1352 |     QTest::addColumn<QString>(name: "qmlfile" ); | 
| 1353 |     QTest::addColumn<bool>(name: "selectWords" ); | 
| 1354 |     QTest::addColumn<bool>(name: "focus" ); | 
| 1355 |     QTest::addColumn<bool>(name: "focusOnPress" ); | 
| 1356 |  | 
| 1357 |     // import installed | 
| 1358 |     QTest::newRow(dataTag: "SelectWords focused" ) << testFile(fileName: "mouseselectionmode_words.qml" ) << true << true << true; | 
| 1359 |     QTest::newRow(dataTag: "SelectCharacters focused" ) << testFile(fileName: "mouseselectionmode_characters.qml" ) << false << true << true; | 
| 1360 |     QTest::newRow(dataTag: "default focused" ) << testFile(fileName: "mouseselectionmode_default.qml" ) << false << true << true; | 
| 1361 |     QTest::newRow(dataTag: "SelectWords unfocused" ) << testFile(fileName: "mouseselectionmode_words.qml" ) << true << false << false; | 
| 1362 |     QTest::newRow(dataTag: "SelectCharacters unfocused" ) << testFile(fileName: "mouseselectionmode_characters.qml" ) << false << false << false; | 
| 1363 |     QTest::newRow(dataTag: "default unfocused" ) << testFile(fileName: "mouseselectionmode_default.qml" ) << false << true << false; | 
| 1364 |     QTest::newRow(dataTag: "SelectWords focuss on press" ) << testFile(fileName: "mouseselectionmode_words.qml" ) << true << false << true; | 
| 1365 |     QTest::newRow(dataTag: "SelectCharacters focus on press" ) << testFile(fileName: "mouseselectionmode_characters.qml" ) << false << false << true; | 
| 1366 |     QTest::newRow(dataTag: "default focus on press" ) << testFile(fileName: "mouseselectionmode_default.qml" ) << false << false << true; | 
| 1367 | } | 
| 1368 |  | 
| 1369 | void tst_qquicktextinput::mouseSelectionMode() | 
| 1370 | { | 
| 1371 |     QFETCH(QString, qmlfile); | 
| 1372 |     QFETCH(bool, selectWords); | 
| 1373 |     QFETCH(bool, focus); | 
| 1374 |     QFETCH(bool, focusOnPress); | 
| 1375 |  | 
| 1376 |     QString text = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" ; | 
| 1377 |  | 
| 1378 |     QQuickView window(QUrl::fromLocalFile(localfile: qmlfile)); | 
| 1379 |  | 
| 1380 |     window.show(); | 
| 1381 |     window.requestActivate(); | 
| 1382 |     QVERIFY(QTest::qWaitForWindowActive(&window)); | 
| 1383 |  | 
| 1384 |     QVERIFY(window.rootObject() != nullptr); | 
| 1385 |     QQuickTextInput *textInputObject = qobject_cast<QQuickTextInput *>(object: window.rootObject()); | 
| 1386 |     QVERIFY(textInputObject != nullptr); | 
| 1387 |  | 
| 1388 |     textInputObject->setFocus(focus); | 
| 1389 |     textInputObject->setFocusOnPress(focusOnPress); | 
| 1390 |  | 
| 1391 |     // press-and-drag-and-release from x1 to x2 | 
| 1392 |     int x1 = 10; | 
| 1393 |     int x2 = 70; | 
| 1394 |     int y = textInputObject->height()/2; | 
| 1395 |     QTest::mousePress(window: &window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: QPoint(x1,y)); | 
| 1396 |     QTest::mouseMove(window: &window, pos: QPoint(x2,y)); // doesn't work | 
| 1397 |     QTest::mouseRelease(window: &window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: QPoint(x2,y)); | 
| 1398 |     if (selectWords) { | 
| 1399 |         QTRY_COMPARE(textInputObject->selectedText(), text); | 
| 1400 |     } else { | 
| 1401 |         QTRY_VERIFY(textInputObject->selectedText().length() > 3); | 
| 1402 |         QVERIFY(textInputObject->selectedText() != text); | 
| 1403 |     } | 
| 1404 | } | 
| 1405 |  | 
| 1406 | void tst_qquicktextinput::mouseSelectionMode_accessors() | 
| 1407 | { | 
| 1408 |     QQmlComponent component(&engine); | 
| 1409 |     component.setData("import QtQuick 2.0\n TextInput {}" , baseUrl: QUrl()); | 
| 1410 |     QScopedPointer<QObject> object(component.create()); | 
| 1411 |     QQuickTextInput *input = qobject_cast<QQuickTextInput *>(object: object.data()); | 
| 1412 |     QVERIFY(input); | 
| 1413 |  | 
| 1414 |     QSignalSpy spy(input, &QQuickTextInput::mouseSelectionModeChanged); | 
| 1415 |  | 
| 1416 |     QCOMPARE(input->mouseSelectionMode(), QQuickTextInput::SelectCharacters); | 
| 1417 |  | 
| 1418 |     input->setMouseSelectionMode(QQuickTextInput::SelectWords); | 
| 1419 |     QCOMPARE(input->mouseSelectionMode(), QQuickTextInput::SelectWords); | 
| 1420 |     QCOMPARE(spy.count(), 1); | 
| 1421 |  | 
| 1422 |     input->setMouseSelectionMode(QQuickTextInput::SelectWords); | 
| 1423 |     QCOMPARE(spy.count(), 1); | 
| 1424 |  | 
| 1425 |     input->setMouseSelectionMode(QQuickTextInput::SelectCharacters); | 
| 1426 |     QCOMPARE(input->mouseSelectionMode(), QQuickTextInput::SelectCharacters); | 
| 1427 |     QCOMPARE(spy.count(), 2); | 
| 1428 | } | 
| 1429 |  | 
| 1430 | void tst_qquicktextinput::selectByMouse() | 
| 1431 | { | 
| 1432 |     QQmlComponent component(&engine); | 
| 1433 |     component.setData("import QtQuick 2.0\n TextInput {}" , baseUrl: QUrl()); | 
| 1434 |     QScopedPointer<QObject> object(component.create()); | 
| 1435 |     QQuickTextInput *input = qobject_cast<QQuickTextInput *>(object: object.data()); | 
| 1436 |     QVERIFY(input); | 
| 1437 |  | 
| 1438 |     QSignalSpy spy(input, SIGNAL(selectByMouseChanged(bool))); | 
| 1439 |  | 
| 1440 |     QCOMPARE(input->selectByMouse(), false); | 
| 1441 |  | 
| 1442 |     input->setSelectByMouse(true); | 
| 1443 |     QCOMPARE(input->selectByMouse(), true); | 
| 1444 |     QCOMPARE(spy.count(), 1); | 
| 1445 |     QCOMPARE(spy.at(0).at(0).toBool(), true); | 
| 1446 |  | 
| 1447 |     input->setSelectByMouse(true); | 
| 1448 |     QCOMPARE(spy.count(), 1); | 
| 1449 |  | 
| 1450 |     input->setSelectByMouse(false); | 
| 1451 |     QCOMPARE(input->selectByMouse(), false); | 
| 1452 |     QCOMPARE(spy.count(), 2); | 
| 1453 |     QCOMPARE(spy.at(1).at(0).toBool(), false); | 
| 1454 | } | 
| 1455 |  | 
| 1456 | void tst_qquicktextinput::renderType() | 
| 1457 | { | 
| 1458 |     QQmlComponent component(&engine); | 
| 1459 |     component.setData("import QtQuick 2.0\n TextInput {}" , baseUrl: QUrl()); | 
| 1460 |     QScopedPointer<QObject> object(component.create()); | 
| 1461 |     QQuickTextInput *input = qobject_cast<QQuickTextInput *>(object: object.data()); | 
| 1462 |     QVERIFY(input); | 
| 1463 |  | 
| 1464 |     QSignalSpy spy(input, SIGNAL(renderTypeChanged())); | 
| 1465 |  | 
| 1466 |     QCOMPARE(input->renderType(), QQuickTextInput::QtRendering); | 
| 1467 |  | 
| 1468 |     input->setRenderType(QQuickTextInput::NativeRendering); | 
| 1469 |     QCOMPARE(input->renderType(), QQuickTextInput::NativeRendering); | 
| 1470 |     QCOMPARE(spy.count(), 1); | 
| 1471 |  | 
| 1472 |     input->setRenderType(QQuickTextInput::NativeRendering); | 
| 1473 |     QCOMPARE(spy.count(), 1); | 
| 1474 |  | 
| 1475 |     input->setRenderType(QQuickTextInput::QtRendering); | 
| 1476 |     QCOMPARE(input->renderType(), QQuickTextInput::QtRendering); | 
| 1477 |     QCOMPARE(spy.count(), 2); | 
| 1478 | } | 
| 1479 |  | 
| 1480 | void tst_qquicktextinput::horizontalAlignment_RightToLeft() | 
| 1481 | { | 
| 1482 |     PlatformInputContext platformInputContext; | 
| 1483 |     QInputMethodPrivate *inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod()); | 
| 1484 |     inputMethodPrivate->testContext = &platformInputContext; | 
| 1485 |  | 
| 1486 |     QQuickView window(testFileUrl(fileName: "horizontalAlignment_RightToLeft.qml" )); | 
| 1487 |     QQuickTextInput *textInput = window.rootObject()->findChild<QQuickTextInput*>(aName: "text" ); | 
| 1488 |     QVERIFY(textInput != nullptr); | 
| 1489 |     window.show(); | 
| 1490 |  | 
| 1491 |     const QString rtlText = textInput->text(); | 
| 1492 |  | 
| 1493 |     QVERIFY(textInput->boundingRect().right() >= textInput->width() - 1); | 
| 1494 |     QVERIFY(textInput->boundingRect().right() <= textInput->width() + 1); | 
| 1495 |  | 
| 1496 |     // implicit alignment should follow the reading direction of RTL text | 
| 1497 |     QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignRight); | 
| 1498 |     QCOMPARE(textInput->effectiveHAlign(), textInput->hAlign()); | 
| 1499 |     QVERIFY(textInput->boundingRect().right() >= textInput->width() - 1); | 
| 1500 |     QVERIFY(textInput->boundingRect().right() <= textInput->width() + 1); | 
| 1501 |  | 
| 1502 |     // explicitly left aligned | 
| 1503 |     textInput->setHAlign(QQuickTextInput::AlignLeft); | 
| 1504 |     QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignLeft); | 
| 1505 |     QCOMPARE(textInput->effectiveHAlign(), textInput->hAlign()); | 
| 1506 |     QCOMPARE(textInput->boundingRect().left(), qreal(0)); | 
| 1507 |  | 
| 1508 |     // explicitly right aligned | 
| 1509 |     textInput->setHAlign(QQuickTextInput::AlignRight); | 
| 1510 |     QCOMPARE(textInput->effectiveHAlign(), textInput->hAlign()); | 
| 1511 |     QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignRight); | 
| 1512 |     QVERIFY(textInput->boundingRect().right() >= textInput->width() - 1); | 
| 1513 |     QVERIFY(textInput->boundingRect().right() <= textInput->width() + 1); | 
| 1514 |  | 
| 1515 |     // explicitly center aligned | 
| 1516 |     textInput->setHAlign(QQuickTextInput::AlignHCenter); | 
| 1517 |     QCOMPARE(textInput->effectiveHAlign(), textInput->hAlign()); | 
| 1518 |     QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignHCenter); | 
| 1519 |     QVERIFY(textInput->boundingRect().left() > 0); | 
| 1520 |     QVERIFY(textInput->boundingRect().right() < textInput->width()); | 
| 1521 |  | 
| 1522 |     // reseted alignment should go back to following the text reading direction | 
| 1523 |     textInput->resetHAlign(); | 
| 1524 |     QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignRight); | 
| 1525 |     QCOMPARE(textInput->effectiveHAlign(), textInput->hAlign()); | 
| 1526 |     QVERIFY(textInput->boundingRect().right() >= textInput->width() - 1); | 
| 1527 |     QVERIFY(textInput->boundingRect().right() <= textInput->width() + 1); | 
| 1528 |  | 
| 1529 |     // mirror the text item | 
| 1530 |     QQuickItemPrivate::get(item: textInput)->setLayoutMirror(true); | 
| 1531 |  | 
| 1532 |     // mirrored implicit alignment should continue to follow the reading direction of the text | 
| 1533 |     QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignRight); | 
| 1534 |     QCOMPARE(textInput->effectiveHAlign(), textInput->hAlign()); | 
| 1535 |     QVERIFY(textInput->boundingRect().right() >= textInput->width() - 1); | 
| 1536 |     QVERIFY(textInput->boundingRect().right() <= textInput->width() + 1); | 
| 1537 |  | 
| 1538 |     // explicitly right aligned behaves as left aligned | 
| 1539 |     textInput->setHAlign(QQuickTextInput::AlignRight); | 
| 1540 |     QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignRight); | 
| 1541 |     QCOMPARE(textInput->effectiveHAlign(), QQuickTextInput::AlignLeft); | 
| 1542 |     QCOMPARE(textInput->boundingRect().left(), qreal(0)); | 
| 1543 |  | 
| 1544 |     // mirrored explicitly left aligned behaves as right aligned | 
| 1545 |     textInput->setHAlign(QQuickTextInput::AlignLeft); | 
| 1546 |     QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignLeft); | 
| 1547 |     QCOMPARE(textInput->effectiveHAlign(), QQuickTextInput::AlignRight); | 
| 1548 |     QVERIFY(textInput->boundingRect().right() >= textInput->width() - 1); | 
| 1549 |     QVERIFY(textInput->boundingRect().right() <= textInput->width() + 1); | 
| 1550 |  | 
| 1551 |     // disable mirroring | 
| 1552 |     QQuickItemPrivate::get(item: textInput)->setLayoutMirror(false); | 
| 1553 |     QCOMPARE(textInput->effectiveHAlign(), textInput->hAlign()); | 
| 1554 |     textInput->resetHAlign(); | 
| 1555 |  | 
| 1556 |     // English text should be implicitly left aligned | 
| 1557 |     textInput->setText("Hello world!" ); | 
| 1558 |     QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignLeft); | 
| 1559 |     QCOMPARE(textInput->boundingRect().left(), qreal(0)); | 
| 1560 |  | 
| 1561 |     window.requestActivate(); | 
| 1562 |     QVERIFY(QTest::qWaitForWindowActive(&window)); | 
| 1563 |     QVERIFY(textInput->hasActiveFocus()); | 
| 1564 |  | 
| 1565 |     // If there is no committed text, the preedit text should determine the alignment. | 
| 1566 |     textInput->setText(QString()); | 
| 1567 |     { QInputMethodEvent ev(rtlText, QList<QInputMethodEvent::Attribute>()); QGuiApplication::sendEvent(receiver: textInput, event: &ev); } | 
| 1568 |     QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignRight); | 
| 1569 |     { QInputMethodEvent ev("Hello world!" , QList<QInputMethodEvent::Attribute>()); QGuiApplication::sendEvent(receiver: textInput, event: &ev); } | 
| 1570 |     QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignLeft); | 
| 1571 |  | 
| 1572 |     // Clear pre-edit text.  TextInput should maybe do this itself on setText, but that may be | 
| 1573 |     // redundant as an actual input method may take care of it. | 
| 1574 |     { QInputMethodEvent ev; QGuiApplication::sendEvent(receiver: textInput, event: &ev); } | 
| 1575 |  | 
| 1576 |     // empty text with implicit alignment follows the system locale-based | 
| 1577 |     // keyboard input direction from QInputMethod::inputDirection() | 
| 1578 |     textInput->setText("" ); | 
| 1579 |     platformInputContext.setInputDirection(Qt::LeftToRight); | 
| 1580 |     QCOMPARE(qApp->inputMethod()->inputDirection(), Qt::LeftToRight); | 
| 1581 |     QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignLeft); | 
| 1582 |     QCOMPARE(textInput->boundingRect().left(), qreal(0)); | 
| 1583 |  | 
| 1584 |     QSignalSpy cursorRectangleSpy(textInput, SIGNAL(cursorRectangleChanged())); | 
| 1585 |     platformInputContext.setInputDirection(Qt::RightToLeft); | 
| 1586 |     QCOMPARE(qApp->inputMethod()->inputDirection(), Qt::RightToLeft); | 
| 1587 |     QCOMPARE(cursorRectangleSpy.count(), 1); | 
| 1588 |     QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignRight); | 
| 1589 |     QVERIFY(textInput->boundingRect().right() >= textInput->width() - 1); | 
| 1590 |     QVERIFY(textInput->boundingRect().right() <= textInput->width() + 1); | 
| 1591 |  | 
| 1592 |     // set input direction while having content | 
| 1593 |     platformInputContext.setInputDirection(Qt::LeftToRight); | 
| 1594 |     textInput->setText("a" ); | 
| 1595 |     platformInputContext.setInputDirection(Qt::RightToLeft); | 
| 1596 |     QTest::keyClick(window: &window, key: Qt::Key_Backspace); | 
| 1597 |     QVERIFY(textInput->text().isEmpty()); | 
| 1598 |     QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignRight); | 
| 1599 |     QVERIFY(textInput->boundingRect().right() >= textInput->width() - 1); | 
| 1600 |     QVERIFY(textInput->boundingRect().right() <= textInput->width() + 1); | 
| 1601 |  | 
| 1602 |     // input direction changed while not having focus | 
| 1603 |     platformInputContext.setInputDirection(Qt::LeftToRight); | 
| 1604 |     textInput->setFocus(false); | 
| 1605 |     platformInputContext.setInputDirection(Qt::RightToLeft); | 
| 1606 |     textInput->setFocus(true); | 
| 1607 |     QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignRight); | 
| 1608 |     QVERIFY(textInput->boundingRect().right() >= textInput->width() - 1); | 
| 1609 |     QVERIFY(textInput->boundingRect().right() <= textInput->width() + 1); | 
| 1610 |  | 
| 1611 |     textInput->setHAlign(QQuickTextInput::AlignRight); | 
| 1612 |     QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignRight); | 
| 1613 |     QVERIFY(textInput->boundingRect().right() >= textInput->width() - 1); | 
| 1614 |     QVERIFY(textInput->boundingRect().right() <= textInput->width() + 1); | 
| 1615 |  | 
| 1616 |     // neutral text should fall back to input direction | 
| 1617 |     textInput->setFocus(true); | 
| 1618 |     textInput->resetHAlign(); | 
| 1619 |     textInput->setText(" ()((=<>" ); | 
| 1620 |     platformInputContext.setInputDirection(Qt::LeftToRight); | 
| 1621 |     QCOMPARE(textInput->effectiveHAlign(), QQuickTextInput::AlignLeft); | 
| 1622 |     platformInputContext.setInputDirection(Qt::RightToLeft); | 
| 1623 |     QCOMPARE(textInput->effectiveHAlign(), QQuickTextInput::AlignRight); | 
| 1624 |  | 
| 1625 |     // changing width keeps right aligned cursor on proper position | 
| 1626 |     textInput->setText("" ); | 
| 1627 |     textInput->setWidth(500); | 
| 1628 |     QVERIFY(textInput->positionToRectangle(0).x() > textInput->width() / 2); | 
| 1629 | } | 
| 1630 |  | 
| 1631 | void tst_qquicktextinput::verticalAlignment() | 
| 1632 | { | 
| 1633 |     QQuickView window(testFileUrl(fileName: "horizontalAlignment.qml" )); | 
| 1634 |     QQuickTextInput *textInput = window.rootObject()->findChild<QQuickTextInput*>(aName: "text" ); | 
| 1635 |     QVERIFY(textInput != nullptr); | 
| 1636 |     window.showNormal(); | 
| 1637 |  | 
| 1638 |     QCOMPARE(textInput->vAlign(), QQuickTextInput::AlignTop); | 
| 1639 |     QVERIFY(textInput->boundingRect().bottom() < window.height() / 2); | 
| 1640 |     QVERIFY(textInput->cursorRectangle().bottom() < window.height() / 2); | 
| 1641 |     QVERIFY(textInput->positionToRectangle(0).bottom() < window.height() / 2); | 
| 1642 |  | 
| 1643 |     // bottom aligned | 
| 1644 |     textInput->setVAlign(QQuickTextInput::AlignBottom); | 
| 1645 |     QCOMPARE(textInput->vAlign(), QQuickTextInput::AlignBottom); | 
| 1646 |     QVERIFY(textInput->boundingRect().top() > window.height() / 2); | 
| 1647 |     QVERIFY(textInput->cursorRectangle().top() > window.height() / 2); | 
| 1648 |     QVERIFY(textInput->positionToRectangle(0).top() > window.height() / 2); | 
| 1649 |  | 
| 1650 |     // explicitly center aligned | 
| 1651 |     textInput->setVAlign(QQuickTextInput::AlignVCenter); | 
| 1652 |     QCOMPARE(textInput->vAlign(), QQuickTextInput::AlignVCenter); | 
| 1653 |     QVERIFY(textInput->boundingRect().top() < window.height() / 2); | 
| 1654 |     QVERIFY(textInput->boundingRect().bottom() > window.height() / 2); | 
| 1655 |     QVERIFY(textInput->cursorRectangle().top() < window.height() / 2); | 
| 1656 |     QVERIFY(textInput->cursorRectangle().bottom() > window.height() / 2); | 
| 1657 |     QVERIFY(textInput->positionToRectangle(0).top() < window.height() / 2); | 
| 1658 |     QVERIFY(textInput->positionToRectangle(0).bottom() > window.height() / 2); | 
| 1659 | } | 
| 1660 |  | 
| 1661 | void tst_qquicktextinput::clipRect() | 
| 1662 | { | 
| 1663 |     QQmlComponent component(&engine); | 
| 1664 |     component.setData("import QtQuick 2.0\n TextInput {}" , baseUrl: QUrl()); | 
| 1665 |     QScopedPointer<QObject> object(component.create()); | 
| 1666 |     QQuickTextInput *input = qobject_cast<QQuickTextInput *>(object: object.data()); | 
| 1667 |     QVERIFY(input); | 
| 1668 |  | 
| 1669 |     QCOMPARE(input->clipRect().x(), qreal(0)); | 
| 1670 |     QCOMPARE(input->clipRect().y(), qreal(0)); | 
| 1671 |     QCOMPARE(input->clipRect().width(), input->width() + input->cursorRectangle().width()); | 
| 1672 |     QCOMPARE(input->clipRect().height(), input->height()); | 
| 1673 |  | 
| 1674 |     input->setText("Hello World" ); | 
| 1675 |     QCOMPARE(input->clipRect().x(), qreal(0)); | 
| 1676 |     QCOMPARE(input->clipRect().y(), qreal(0)); | 
| 1677 |     QCOMPARE(input->clipRect().width(), input->width() + input->cursorRectangle().width()); | 
| 1678 |     QCOMPARE(input->clipRect().height(), input->height()); | 
| 1679 |  | 
| 1680 |     // clip rect shouldn't exceed the size of the item, expect for the cursor width; | 
| 1681 |     input->setWidth(input->width() / 2); | 
| 1682 |     QCOMPARE(input->clipRect().x(), qreal(0)); | 
| 1683 |     QCOMPARE(input->clipRect().y(), qreal(0)); | 
| 1684 |     QCOMPARE(input->clipRect().width(), input->width() + input->cursorRectangle().width()); | 
| 1685 |     QCOMPARE(input->clipRect().height(), input->height()); | 
| 1686 |  | 
| 1687 |     input->setHeight(input->height() * 2); | 
| 1688 |     QCOMPARE(input->clipRect().x(), qreal(0)); | 
| 1689 |     QCOMPARE(input->clipRect().y(), qreal(0)); | 
| 1690 |     QCOMPARE(input->clipRect().width(), input->width() + input->cursorRectangle().width()); | 
| 1691 |     QCOMPARE(input->clipRect().height(), input->height()); | 
| 1692 |  | 
| 1693 |     QQmlComponent cursorComponent(&engine); | 
| 1694 |     cursorComponent.setData("import QtQuick 2.0\nRectangle { height: 20; width: 8 }" , baseUrl: QUrl()); | 
| 1695 |  | 
| 1696 |     input->setCursorDelegate(&cursorComponent); | 
| 1697 |     input->setCursorVisible(true); | 
| 1698 |  | 
| 1699 |     // If a cursor delegate is used it's size should determine the excess width. | 
| 1700 |     QCOMPARE(input->clipRect().x(), qreal(0)); | 
| 1701 |     QCOMPARE(input->clipRect().y(), qreal(0)); | 
| 1702 |     QCOMPARE(input->clipRect().width(), input->width() + 8); | 
| 1703 |     QCOMPARE(input->clipRect().height(), input->height()); | 
| 1704 |  | 
| 1705 |     // Alignment, auto scroll, wrapping all don't affect the clip rect. | 
| 1706 |     input->setAutoScroll(false); | 
| 1707 |     QCOMPARE(input->clipRect().x(), qreal(0)); | 
| 1708 |     QCOMPARE(input->clipRect().y(), qreal(0)); | 
| 1709 |     QCOMPARE(input->clipRect().width(), input->width() + 8); | 
| 1710 |     QCOMPARE(input->clipRect().height(), input->height()); | 
| 1711 |  | 
| 1712 |     input->setHAlign(QQuickTextInput::AlignRight); | 
| 1713 |     QCOMPARE(input->clipRect().x(), qreal(0)); | 
| 1714 |     QCOMPARE(input->clipRect().y(), qreal(0)); | 
| 1715 |     QCOMPARE(input->clipRect().width(), input->width() + 8); | 
| 1716 |     QCOMPARE(input->clipRect().height(), input->height()); | 
| 1717 |  | 
| 1718 |     input->setWrapMode(QQuickTextInput::Wrap); | 
| 1719 |     QCOMPARE(input->clipRect().x(), qreal(0)); | 
| 1720 |     QCOMPARE(input->clipRect().y(), qreal(0)); | 
| 1721 |     QCOMPARE(input->clipRect().width(), input->width() + 8); | 
| 1722 |     QCOMPARE(input->clipRect().height(), input->height()); | 
| 1723 |  | 
| 1724 |     input->setVAlign(QQuickTextInput::AlignBottom); | 
| 1725 |     QCOMPARE(input->clipRect().x(), qreal(0)); | 
| 1726 |     QCOMPARE(input->clipRect().y(), qreal(0)); | 
| 1727 |     QCOMPARE(input->clipRect().width(), input->width() + 8); | 
| 1728 |     QCOMPARE(input->clipRect().height(), input->height()); | 
| 1729 | } | 
| 1730 |  | 
| 1731 | void tst_qquicktextinput::boundingRect() | 
| 1732 | { | 
| 1733 |     QQmlComponent component(&engine); | 
| 1734 |     component.setData("import QtQuick 2.0\n TextInput {}" , baseUrl: QUrl()); | 
| 1735 |     QScopedPointer<QObject> object(component.create()); | 
| 1736 |     QQuickTextInput *input = qobject_cast<QQuickTextInput *>(object: object.data()); | 
| 1737 |     QVERIFY(input); | 
| 1738 |  | 
| 1739 |     QTextLayout layout; | 
| 1740 |     layout.setFont(input->font()); | 
| 1741 |  | 
| 1742 |     if (!qmlDisableDistanceField()) { | 
| 1743 |         QTextOption option; | 
| 1744 |         option.setUseDesignMetrics(true); | 
| 1745 |         layout.setTextOption(option); | 
| 1746 |     } | 
| 1747 |     layout.beginLayout(); | 
| 1748 |     QTextLine line = layout.createLine(); | 
| 1749 |     layout.endLayout(); | 
| 1750 |  | 
| 1751 |     QCOMPARE(input->boundingRect().x(), qreal(0)); | 
| 1752 |     QCOMPARE(input->boundingRect().y(), qreal(0)); | 
| 1753 |     QCOMPARE(input->boundingRect().width(), input->cursorRectangle().width()); | 
| 1754 |     QCOMPARE(input->boundingRect().height(), line.height()); | 
| 1755 |  | 
| 1756 |     input->setText("Hello World" ); | 
| 1757 |  | 
| 1758 |     layout.setText(input->text()); | 
| 1759 |     layout.beginLayout(); | 
| 1760 |     line = layout.createLine(); | 
| 1761 |     layout.endLayout(); | 
| 1762 |  | 
| 1763 |     QCOMPARE(input->boundingRect().x(), qreal(0)); | 
| 1764 |     QCOMPARE(input->boundingRect().y(), qreal(0)); | 
| 1765 |     QCOMPARE(input->boundingRect().width(), line.naturalTextWidth() + input->cursorRectangle().width()); | 
| 1766 |     QCOMPARE(input->boundingRect().height(), line.height()); | 
| 1767 |  | 
| 1768 |     // the size of the bounding rect shouldn't be bounded by the size of item. | 
| 1769 |     input->setWidth(input->width() / 2); | 
| 1770 |     QCOMPARE(input->boundingRect().x(), input->width() - line.naturalTextWidth()); | 
| 1771 |     QCOMPARE(input->boundingRect().y(), qreal(0)); | 
| 1772 |     QCOMPARE(input->boundingRect().width(), line.naturalTextWidth() + input->cursorRectangle().width()); | 
| 1773 |     QCOMPARE(input->boundingRect().height(), line.height()); | 
| 1774 |  | 
| 1775 |     input->setHeight(input->height() * 2); | 
| 1776 |     QCOMPARE(input->boundingRect().x(), input->width() - line.naturalTextWidth()); | 
| 1777 |     QCOMPARE(input->boundingRect().y(), qreal(0)); | 
| 1778 |     QCOMPARE(input->boundingRect().width(), line.naturalTextWidth() + input->cursorRectangle().width()); | 
| 1779 |     QCOMPARE(input->boundingRect().height(), line.height()); | 
| 1780 |  | 
| 1781 |     QQmlComponent cursorComponent(&engine); | 
| 1782 |     cursorComponent.setData("import QtQuick 2.0\nRectangle { height: 20; width: 8 }" , baseUrl: QUrl()); | 
| 1783 |  | 
| 1784 |     input->setCursorDelegate(&cursorComponent); | 
| 1785 |     input->setCursorVisible(true); | 
| 1786 |  | 
| 1787 |     // Don't include the size of a cursor delegate as it has its own bounding rect. | 
| 1788 |     QCOMPARE(input->boundingRect().x(), input->width() - line.naturalTextWidth()); | 
| 1789 |     QCOMPARE(input->boundingRect().y(), qreal(0)); | 
| 1790 |     QCOMPARE(input->boundingRect().width(), line.naturalTextWidth()); | 
| 1791 |     QCOMPARE(input->boundingRect().height(), line.height()); | 
| 1792 |  | 
| 1793 |     // Bounding rect left aligned when auto scroll is disabled; | 
| 1794 |     input->setAutoScroll(false); | 
| 1795 |     QCOMPARE(input->boundingRect().x(), qreal(0)); | 
| 1796 |     QCOMPARE(input->boundingRect().y(), qreal(0)); | 
| 1797 |     QCOMPARE(input->boundingRect().width(), line.naturalTextWidth()); | 
| 1798 |     QCOMPARE(input->boundingRect().height(), line.height()); | 
| 1799 |  | 
| 1800 |     input->setHAlign(QQuickTextInput::AlignRight); | 
| 1801 |     QCOMPARE(input->boundingRect().x(), input->width() - line.naturalTextWidth()); | 
| 1802 |     QCOMPARE(input->boundingRect().y(), qreal(0)); | 
| 1803 |     QCOMPARE(input->boundingRect().width(), line.naturalTextWidth()); | 
| 1804 |     QCOMPARE(input->boundingRect().height(), line.height()); | 
| 1805 |  | 
| 1806 |     input->setWrapMode(QQuickTextInput::Wrap); | 
| 1807 |     QCOMPARE(input->boundingRect().right(), input->width()); | 
| 1808 |     QCOMPARE(input->boundingRect().y(), qreal(0)); | 
| 1809 |     QVERIFY(input->boundingRect().width() < line.naturalTextWidth()); | 
| 1810 |     QVERIFY(input->boundingRect().height() > line.height()); | 
| 1811 |  | 
| 1812 |     input->setVAlign(QQuickTextInput::AlignBottom); | 
| 1813 |     QCOMPARE(input->boundingRect().right(), input->width()); | 
| 1814 |     QCOMPARE(input->boundingRect().bottom(), input->height()); | 
| 1815 |     QVERIFY(input->boundingRect().width() < line.naturalTextWidth()); | 
| 1816 |     QVERIFY(input->boundingRect().height() > line.height()); | 
| 1817 | } | 
| 1818 |  | 
| 1819 | void tst_qquicktextinput::positionAt() | 
| 1820 | { | 
| 1821 |     QQuickView window(testFileUrl(fileName: "positionAt.qml" )); | 
| 1822 |     QVERIFY(window.rootObject() != nullptr); | 
| 1823 |     window.show(); | 
| 1824 |     window.requestActivate(); | 
| 1825 |     QVERIFY(QTest::qWaitForWindowActive(&window)); | 
| 1826 |  | 
| 1827 |     QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput *>(object: window.rootObject()); | 
| 1828 |     QVERIFY(textinputObject != nullptr); | 
| 1829 |  | 
| 1830 |     // Check autoscrolled... | 
| 1831 |  | 
| 1832 |     int pos = evaluate<int>(scope: textinputObject, expression: QString("positionAt(%1)" ).arg(a: textinputObject->width()/2)); | 
| 1833 |  | 
| 1834 |     QTextLayout layout(textinputObject->text()); | 
| 1835 |     layout.setFont(textinputObject->font()); | 
| 1836 |  | 
| 1837 |     if (!qmlDisableDistanceField()) { | 
| 1838 |         QTextOption option; | 
| 1839 |         option.setUseDesignMetrics(true); | 
| 1840 |         layout.setTextOption(option); | 
| 1841 |     } | 
| 1842 |     layout.beginLayout(); | 
| 1843 |     QTextLine line = layout.createLine(); | 
| 1844 |     layout.endLayout(); | 
| 1845 |  | 
| 1846 |     int textLeftWidthBegin = floor(x: line.cursorToX(cursorPos: pos - 1)); | 
| 1847 |     int textLeftWidthEnd = ceil(x: line.cursorToX(cursorPos: pos + 1)); | 
| 1848 |     int textWidth = floor(x: line.horizontalAdvance()); | 
| 1849 |  | 
| 1850 |     QVERIFY(textLeftWidthBegin <= textWidth - textinputObject->width() / 2); | 
| 1851 |     QVERIFY(textLeftWidthEnd >= textWidth - textinputObject->width() / 2); | 
| 1852 |  | 
| 1853 |     int x = textinputObject->positionToRectangle(pos: pos + 1).x() - 1; | 
| 1854 |     QCOMPARE(evaluate<int>(textinputObject, QString("positionAt(%1, 0, TextInput.CursorBetweenCharacters)" ).arg(x)), pos + 1); | 
| 1855 |     QCOMPARE(evaluate<int>(textinputObject, QString("positionAt(%1, 0, TextInput.CursorOnCharacter)" ).arg(x)), pos); | 
| 1856 |  | 
| 1857 |     // Check without autoscroll... | 
| 1858 |     textinputObject->setAutoScroll(false); | 
| 1859 |     pos = evaluate<int>(scope: textinputObject, expression: QString("positionAt(%1)" ).arg(a: textinputObject->width() / 2)); | 
| 1860 |  | 
| 1861 |     textLeftWidthBegin = floor(x: line.cursorToX(cursorPos: pos - 1)); | 
| 1862 |     textLeftWidthEnd = ceil(x: line.cursorToX(cursorPos: pos + 1)); | 
| 1863 |  | 
| 1864 |     QVERIFY(textLeftWidthBegin <= textinputObject->width() / 2); | 
| 1865 |     QVERIFY(textLeftWidthEnd >= textinputObject->width() / 2); | 
| 1866 |  | 
| 1867 |     x = textinputObject->positionToRectangle(pos: pos + 1).x() - 1; | 
| 1868 |     QCOMPARE(evaluate<int>(textinputObject, QString("positionAt(%1, 0, TextInput.CursorBetweenCharacters)" ).arg(x)), pos + 1); | 
| 1869 |     QCOMPARE(evaluate<int>(textinputObject, QString("positionAt(%1, 0, TextInput.CursorOnCharacter)" ).arg(x)), pos); | 
| 1870 |  | 
| 1871 |     const qreal x0 = textinputObject->positionToRectangle(pos).x(); | 
| 1872 |     const qreal x1 = textinputObject->positionToRectangle(pos: pos + 1).x(); | 
| 1873 |  | 
| 1874 |     QString preeditText = textinputObject->text().mid(position: 0, n: pos); | 
| 1875 |     textinputObject->setText(textinputObject->text().mid(position: pos)); | 
| 1876 |     textinputObject->setCursorPosition(0); | 
| 1877 |  | 
| 1878 |     {   QInputMethodEvent inputEvent(preeditText, QList<QInputMethodEvent::Attribute>()); | 
| 1879 |         QVERIFY(qGuiApp->focusObject()); | 
| 1880 |         QGuiApplication::sendEvent(receiver: textinputObject, event: &inputEvent); } | 
| 1881 |  | 
| 1882 |     // Check all points within the preedit text return the same position. | 
| 1883 |     QCOMPARE(evaluate<int>(textinputObject, QString("positionAt(%1)" ).arg(0)), 0); | 
| 1884 |     QCOMPARE(evaluate<int>(textinputObject, QString("positionAt(%1)" ).arg(x0 / 2)), 0); | 
| 1885 |     QCOMPARE(evaluate<int>(textinputObject, QString("positionAt(%1)" ).arg(x0)), 0); | 
| 1886 |  | 
| 1887 |     // Verify positioning returns to normal after the preedit text. | 
| 1888 |     QCOMPARE(evaluate<int>(textinputObject, QString("positionAt(%1)" ).arg(x1)), 1); | 
| 1889 |     QCOMPARE(textinputObject->positionToRectangle(1).x(), x1); | 
| 1890 |  | 
| 1891 |     {   QInputMethodEvent inputEvent; | 
| 1892 |         QVERIFY(qGuiApp->focusObject()); | 
| 1893 |         QGuiApplication::sendEvent(receiver: textinputObject, event: &inputEvent); } | 
| 1894 |  | 
| 1895 |     // With wrapping. | 
| 1896 |     textinputObject->setWrapMode(QQuickTextInput::WrapAnywhere); | 
| 1897 |  | 
| 1898 |     const qreal y0 = line.height() / 2; | 
| 1899 |     const qreal y1 = line.height() * 3 / 2; | 
| 1900 |  | 
| 1901 |     QCOMPARE(evaluate<int>(textinputObject, QString("positionAt(%1, %2)" ).arg(x0).arg(y0)), pos); | 
| 1902 |     QCOMPARE(evaluate<int>(textinputObject, QString("positionAt(%1, %2)" ).arg(x1).arg(y0)), pos + 1); | 
| 1903 |  | 
| 1904 |     int newLinePos = evaluate<int>(scope: textinputObject, expression: QString("positionAt(%1, %2)" ).arg(a: x0).arg(a: y1)); | 
| 1905 |     QVERIFY(newLinePos > pos); | 
| 1906 |     QCOMPARE(evaluate<int>(textinputObject, QString("positionAt(%1, %2)" ).arg(x1).arg(y1)), newLinePos + 1); | 
| 1907 | } | 
| 1908 |  | 
| 1909 | void tst_qquicktextinput::maxLength() | 
| 1910 | { | 
| 1911 |     QQuickView window(testFileUrl(fileName: "maxLength.qml" )); | 
| 1912 |     QVERIFY(window.rootObject() != nullptr); | 
| 1913 |     window.show(); | 
| 1914 |     window.requestActivate(); | 
| 1915 |     QVERIFY(QTest::qWaitForWindowActive(&window)); | 
| 1916 |  | 
| 1917 |     QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput *>(object: window.rootObject()); | 
| 1918 |     QVERIFY(textinputObject != nullptr); | 
| 1919 |     QVERIFY(textinputObject->text().isEmpty()); | 
| 1920 |     QCOMPARE(textinputObject->maxLength(), 10); | 
| 1921 |     foreach (const QString &str, standard) { | 
| 1922 |         QVERIFY(textinputObject->text().length() <= 10); | 
| 1923 |         textinputObject->setText(str); | 
| 1924 |         QVERIFY(textinputObject->text().length() <= 10); | 
| 1925 |     } | 
| 1926 |  | 
| 1927 |     textinputObject->setText("" ); | 
| 1928 |     QTRY_VERIFY(textinputObject->hasActiveFocus()); | 
| 1929 |     for (int i=0; i<20; i++) { | 
| 1930 |         QTRY_COMPARE(textinputObject->text().length(), qMin(i,10)); | 
| 1931 |         //simulateKey(&window, Qt::Key_A); | 
| 1932 |         QTest::keyPress(window: &window, key: Qt::Key_A); | 
| 1933 |         QTest::keyRelease(window: &window, key: Qt::Key_A, modifier: Qt::NoModifier); | 
| 1934 |     } | 
| 1935 | } | 
| 1936 |  | 
| 1937 | void tst_qquicktextinput::masks() | 
| 1938 | { | 
| 1939 |     //Not a comprehensive test of the possible masks, that's done elsewhere (QLineEdit) | 
| 1940 |     //QString componentStr = "import QtQuick 2.0\nTextInput {  inputMask: 'HHHHhhhh'; }"; | 
| 1941 |     QQuickView window(testFileUrl(fileName: "masks.qml" )); | 
| 1942 |     window.show(); | 
| 1943 |     window.requestActivate(); | 
| 1944 |     QVERIFY(window.rootObject() != nullptr); | 
| 1945 |     QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput *>(object: window.rootObject()); | 
| 1946 |     QVERIFY(textinputObject != nullptr); | 
| 1947 |     QTRY_VERIFY(textinputObject->hasActiveFocus()); | 
| 1948 |     QCOMPARE(textinputObject->text().length(), 0); | 
| 1949 |     QCOMPARE(textinputObject->inputMask(), QString("HHHHhhhh; " )); | 
| 1950 |     QCOMPARE(textinputObject->length(), 8); | 
| 1951 |     for (int i=0; i<10; i++) { | 
| 1952 |         QTRY_COMPARE(qMin(i,8), textinputObject->text().length()); | 
| 1953 |         QCOMPARE(textinputObject->length(), 8); | 
| 1954 |         QCOMPARE(textinputObject->getText(0, qMin(i, 8)), QString(qMin(i, 8), 'a')); | 
| 1955 |         QCOMPARE(textinputObject->getText(qMin(i, 8), 8), QString(8 - qMin(i, 8), ' ')); | 
| 1956 |         QCOMPARE(i>=4, textinputObject->hasAcceptableInput()); | 
| 1957 |         //simulateKey(&window, Qt::Key_A); | 
| 1958 |         QTest::keyPress(window: &window, key: Qt::Key_A); | 
| 1959 |         QTest::keyRelease(window: &window, key: Qt::Key_A, modifier: Qt::NoModifier); | 
| 1960 |     } | 
| 1961 | } | 
| 1962 |  | 
| 1963 | void tst_qquicktextinput::validators() | 
| 1964 | { | 
| 1965 |     // Note that this test assumes that the validators are working properly | 
| 1966 |     // so you may need to run their tests first. All validators are checked | 
| 1967 |     // here to ensure that their exposure to QML is working. | 
| 1968 |  | 
| 1969 |     QLocale::setDefault(QLocale(QStringLiteral("C" ))); | 
| 1970 |  | 
| 1971 |     QQuickView window(testFileUrl(fileName: "validators.qml" )); | 
| 1972 |     window.show(); | 
| 1973 |     window.requestActivate(); | 
| 1974 |     QVERIFY(QTest::qWaitForWindowActive(&window)); | 
| 1975 |  | 
| 1976 |     QVERIFY(window.rootObject() != nullptr); | 
| 1977 |  | 
| 1978 |     QLocale defaultLocale; | 
| 1979 |     QLocale enLocale("en" ); | 
| 1980 |     QLocale deLocale("de_DE" ); | 
| 1981 |  | 
| 1982 |     QQuickTextInput *intInput = qobject_cast<QQuickTextInput *>(object: qvariant_cast<QObject *>(v: window.rootObject()->property(name: "intInput" ))); | 
| 1983 |     QVERIFY(intInput); | 
| 1984 |     QSignalSpy intSpy(intInput, SIGNAL(acceptableInputChanged())); | 
| 1985 |  | 
| 1986 |     QQuickIntValidator *intValidator = qobject_cast<QQuickIntValidator *>(object: intInput->validator()); | 
| 1987 |     QVERIFY(intValidator); | 
| 1988 |     QCOMPARE(intValidator->localeName(), defaultLocale.name()); | 
| 1989 |     QCOMPARE(intInput->validator()->locale(), defaultLocale); | 
| 1990 |     intValidator->setLocaleName(enLocale.name()); | 
| 1991 |     QCOMPARE(intValidator->localeName(), enLocale.name()); | 
| 1992 |     QCOMPARE(intInput->validator()->locale(), enLocale); | 
| 1993 |     intValidator->resetLocaleName(); | 
| 1994 |     QCOMPARE(intValidator->localeName(), defaultLocale.name()); | 
| 1995 |     QCOMPARE(intInput->validator()->locale(), defaultLocale); | 
| 1996 |  | 
| 1997 |     intInput->setFocus(true); | 
| 1998 |     QTRY_VERIFY(intInput->hasActiveFocus()); | 
| 1999 |     QCOMPARE(intInput->hasAcceptableInput(), false); | 
| 2000 |     QCOMPARE(intInput->property("acceptable" ).toBool(), false); | 
| 2001 |     QTest::keyPress(window: &window, key: Qt::Key_1); | 
| 2002 |     QTest::keyRelease(window: &window, key: Qt::Key_1, modifier: Qt::NoModifier); | 
| 2003 |     QTRY_COMPARE(intInput->text(), QLatin1String("1" )); | 
| 2004 |     QCOMPARE(intInput->hasAcceptableInput(), false); | 
| 2005 |     QCOMPARE(intInput->property("acceptable" ).toBool(), false); | 
| 2006 |     QCOMPARE(intSpy.count(), 0); | 
| 2007 |     QCOMPARE(intInput->hasAcceptableInput(), false); | 
| 2008 |     QCOMPARE(intInput->property("acceptable" ).toBool(), false); | 
| 2009 |     QCOMPARE(intSpy.count(), 0); | 
| 2010 |     QTest::keyPress(window: &window, key: Qt::Key_Period); | 
| 2011 |     QTest::keyRelease(window: &window, key: Qt::Key_Period, modifier: Qt::NoModifier); | 
| 2012 |     QTRY_COMPARE(intInput->text(), QLatin1String("1" )); | 
| 2013 |     QCOMPARE(intInput->hasAcceptableInput(), false); | 
| 2014 |     QTest::keyPress(window: &window, key: Qt::Key_Comma); | 
| 2015 |     QTest::keyRelease(window: &window, key: Qt::Key_Comma, modifier: Qt::NoModifier); | 
| 2016 |     QTRY_COMPARE(intInput->text(), QLatin1String("1," )); | 
| 2017 |     QCOMPARE(intInput->hasAcceptableInput(), false); | 
| 2018 |     QTest::keyPress(window: &window, key: Qt::Key_Backspace); | 
| 2019 |     QTest::keyRelease(window: &window, key: Qt::Key_Backspace, modifier: Qt::NoModifier); | 
| 2020 |     QTRY_COMPARE(intInput->text(), QLatin1String("1" )); | 
| 2021 |     QCOMPARE(intInput->hasAcceptableInput(), false); | 
| 2022 |     intValidator->setLocaleName(deLocale.name()); | 
| 2023 |     QTest::keyPress(window: &window, key: Qt::Key_Period); | 
| 2024 |     QTest::keyRelease(window: &window, key: Qt::Key_Period, modifier: Qt::NoModifier); | 
| 2025 |     QTRY_COMPARE(intInput->text(), QLatin1String("1." )); | 
| 2026 |     QCOMPARE(intInput->hasAcceptableInput(), false); | 
| 2027 |     QTest::keyPress(window: &window, key: Qt::Key_Backspace); | 
| 2028 |     QTest::keyRelease(window: &window, key: Qt::Key_Backspace, modifier: Qt::NoModifier); | 
| 2029 |     QTRY_COMPARE(intInput->text(), QLatin1String("1" )); | 
| 2030 |     QCOMPARE(intInput->hasAcceptableInput(), false); | 
| 2031 |     intValidator->resetLocaleName(); | 
| 2032 |     QTest::keyPress(window: &window, key: Qt::Key_1); | 
| 2033 |     QTest::keyRelease(window: &window, key: Qt::Key_1, modifier: Qt::NoModifier); | 
| 2034 |     QCOMPARE(intInput->text(), QLatin1String("11" )); | 
| 2035 |     QCOMPARE(intInput->hasAcceptableInput(), true); | 
| 2036 |     QCOMPARE(intInput->property("acceptable" ).toBool(), true); | 
| 2037 |     QCOMPARE(intSpy.count(), 1); | 
| 2038 |     QTest::keyPress(window: &window, key: Qt::Key_0); | 
| 2039 |     QTest::keyRelease(window: &window, key: Qt::Key_0, modifier: Qt::NoModifier); | 
| 2040 |     QCOMPARE(intInput->text(), QLatin1String("11" )); | 
| 2041 |     QCOMPARE(intInput->hasAcceptableInput(), true); | 
| 2042 |     QCOMPARE(intInput->property("acceptable" ).toBool(), true); | 
| 2043 |     QCOMPARE(intSpy.count(), 1); | 
| 2044 |  | 
| 2045 |     QQuickTextInput *dblInput = qobject_cast<QQuickTextInput *>(object: qvariant_cast<QObject *>(v: window.rootObject()->property(name: "dblInput" ))); | 
| 2046 |     QVERIFY(dblInput); | 
| 2047 |     QSignalSpy dblSpy(dblInput, SIGNAL(acceptableInputChanged())); | 
| 2048 |  | 
| 2049 |     QQuickDoubleValidator *dblValidator = qobject_cast<QQuickDoubleValidator *>(object: dblInput->validator()); | 
| 2050 |     QVERIFY(dblValidator); | 
| 2051 |     QCOMPARE(dblValidator->localeName(), defaultLocale.name()); | 
| 2052 |     QCOMPARE(dblInput->validator()->locale(), defaultLocale); | 
| 2053 |     dblValidator->setLocaleName(enLocale.name()); | 
| 2054 |     QCOMPARE(dblValidator->localeName(), enLocale.name()); | 
| 2055 |     QCOMPARE(dblInput->validator()->locale(), enLocale); | 
| 2056 |     dblValidator->resetLocaleName(); | 
| 2057 |     QCOMPARE(dblValidator->localeName(), defaultLocale.name()); | 
| 2058 |     QCOMPARE(dblInput->validator()->locale(), defaultLocale); | 
| 2059 |  | 
| 2060 |     dblInput->setFocus(true); | 
| 2061 |     QVERIFY(dblInput->hasActiveFocus()); | 
| 2062 |     QCOMPARE(dblInput->hasAcceptableInput(), false); | 
| 2063 |     QCOMPARE(dblInput->property("acceptable" ).toBool(), false); | 
| 2064 |     QTest::keyPress(window: &window, key: Qt::Key_1); | 
| 2065 |     QTest::keyRelease(window: &window, key: Qt::Key_1, modifier: Qt::NoModifier); | 
| 2066 |     QTRY_COMPARE(dblInput->text(), QLatin1String("1" )); | 
| 2067 |     QCOMPARE(dblInput->hasAcceptableInput(), false); | 
| 2068 |     QCOMPARE(dblInput->property("acceptable" ).toBool(), false); | 
| 2069 |     QCOMPARE(dblSpy.count(), 0); | 
| 2070 |     QTest::keyPress(window: &window, key: Qt::Key_2); | 
| 2071 |     QTest::keyRelease(window: &window, key: Qt::Key_2, modifier: Qt::NoModifier); | 
| 2072 |     QTRY_COMPARE(dblInput->text(), QLatin1String("12" )); | 
| 2073 |     QCOMPARE(dblInput->hasAcceptableInput(), true); | 
| 2074 |     QCOMPARE(dblInput->property("acceptable" ).toBool(), true); | 
| 2075 |     QCOMPARE(dblSpy.count(), 1); | 
| 2076 |     QTest::keyPress(window: &window, key: Qt::Key_Comma); | 
| 2077 |     QTest::keyRelease(window: &window, key: Qt::Key_Comma, modifier: Qt::NoModifier); | 
| 2078 |     QTRY_COMPARE(dblInput->text(), QLatin1String("12," )); | 
| 2079 |     int  = 2; | 
| 2080 |     if (dblInput->hasAcceptableInput()) { | 
| 2081 |         // TODO: old behavior of QDoubleValidator - remove when merged from qtbase | 
| 2082 |         QTest::keyPress(window: &window, key: Qt::Key_1); | 
| 2083 |         QTest::keyRelease(window: &window, key: Qt::Key_1, modifier: Qt::NoModifier); | 
| 2084 |         QTRY_COMPARE(dblInput->text(), QLatin1String("12," )); | 
| 2085 |         QCOMPARE(dblInput->hasAcceptableInput(), true); | 
| 2086 |         extraSignals = 0; | 
| 2087 |     } | 
| 2088 |     dblValidator->setLocaleName(deLocale.name()); | 
| 2089 |     QCOMPARE(dblInput->hasAcceptableInput(), true); | 
| 2090 |     QTest::keyPress(window: &window, key: Qt::Key_1); | 
| 2091 |     QTest::keyRelease(window: &window, key: Qt::Key_1, modifier: Qt::NoModifier); | 
| 2092 |     QTRY_COMPARE(dblInput->text(), QLatin1String("12,1" )); | 
| 2093 |     QCOMPARE(dblInput->hasAcceptableInput(), true); | 
| 2094 |     QTest::keyPress(window: &window, key: Qt::Key_1); | 
| 2095 |     QTest::keyRelease(window: &window, key: Qt::Key_1, modifier: Qt::NoModifier); | 
| 2096 |     QTRY_COMPARE(dblInput->text(), QLatin1String("12,11" )); | 
| 2097 |     QCOMPARE(dblInput->hasAcceptableInput(), true); | 
| 2098 |     QTest::keyPress(window: &window, key: Qt::Key_Backspace); | 
| 2099 |     QTest::keyRelease(window: &window, key: Qt::Key_Backspace, modifier: Qt::NoModifier); | 
| 2100 |     QTRY_COMPARE(dblInput->text(), QLatin1String("12,1" )); | 
| 2101 |     QCOMPARE(dblInput->hasAcceptableInput(), true); | 
| 2102 |     QTest::keyPress(window: &window, key: Qt::Key_Backspace); | 
| 2103 |     QTest::keyRelease(window: &window, key: Qt::Key_Backspace, modifier: Qt::NoModifier); | 
| 2104 |     QTRY_COMPARE(dblInput->text(), QLatin1String("12," )); | 
| 2105 |     QCOMPARE(dblInput->hasAcceptableInput(), true); | 
| 2106 |     QTest::keyPress(window: &window, key: Qt::Key_Backspace); | 
| 2107 |     QTest::keyRelease(window: &window, key: Qt::Key_Backspace, modifier: Qt::NoModifier); | 
| 2108 |     QTRY_COMPARE(dblInput->text(), QLatin1String("12" )); | 
| 2109 |     QCOMPARE(dblInput->hasAcceptableInput(), true); | 
| 2110 |     dblValidator->resetLocaleName(); | 
| 2111 |     QTest::keyPress(window: &window, key: Qt::Key_Period); | 
| 2112 |     QTest::keyRelease(window: &window, key: Qt::Key_Period, modifier: Qt::NoModifier); | 
| 2113 |     QTRY_COMPARE(dblInput->text(), QLatin1String("12." )); | 
| 2114 |     QCOMPARE(dblInput->hasAcceptableInput(), true); | 
| 2115 |     QCOMPARE(dblInput->property("acceptable" ).toBool(), true); | 
| 2116 |     QCOMPARE(dblSpy.count(), 1 + extraSignals); | 
| 2117 |     QTest::keyPress(window: &window, key: Qt::Key_1); | 
| 2118 |     QTest::keyRelease(window: &window, key: Qt::Key_1, modifier: Qt::NoModifier); | 
| 2119 |     QTRY_COMPARE(dblInput->text(), QLatin1String("12.1" )); | 
| 2120 |     QCOMPARE(dblInput->hasAcceptableInput(), true); | 
| 2121 |     QCOMPARE(dblInput->property("acceptable" ).toBool(), true); | 
| 2122 |     QCOMPARE(dblSpy.count(), 1 + extraSignals); | 
| 2123 |     QTest::keyPress(window: &window, key: Qt::Key_1); | 
| 2124 |     QTest::keyRelease(window: &window, key: Qt::Key_1, modifier: Qt::NoModifier); | 
| 2125 |     QTRY_COMPARE(dblInput->text(), QLatin1String("12.11" )); | 
| 2126 |     QCOMPARE(dblInput->hasAcceptableInput(), true); | 
| 2127 |     QCOMPARE(dblInput->property("acceptable" ).toBool(), true); | 
| 2128 |     QCOMPARE(dblSpy.count(), 1 + extraSignals); | 
| 2129 |     QTest::keyPress(window: &window, key: Qt::Key_1); | 
| 2130 |     QTest::keyRelease(window: &window, key: Qt::Key_1, modifier: Qt::NoModifier); | 
| 2131 |     QTRY_COMPARE(dblInput->text(), QLatin1String("12.11" )); | 
| 2132 |     QCOMPARE(dblInput->hasAcceptableInput(), true); | 
| 2133 |     QCOMPARE(dblInput->property("acceptable" ).toBool(), true); | 
| 2134 |     QCOMPARE(dblSpy.count(), 1 + extraSignals); | 
| 2135 |  | 
| 2136 |     // Ensure the validator doesn't prevent characters being removed. | 
| 2137 |     dblInput->setValidator(intInput->validator()); | 
| 2138 |     QCOMPARE(dblInput->text(), QLatin1String("12.11" )); | 
| 2139 |     QCOMPARE(dblInput->hasAcceptableInput(), false); | 
| 2140 |     QCOMPARE(dblInput->property("acceptable" ).toBool(), false); | 
| 2141 |     QCOMPARE(dblSpy.count(), 2 + extraSignals); | 
| 2142 |     QTest::keyPress(window: &window, key: Qt::Key_Backspace); | 
| 2143 |     QTest::keyRelease(window: &window, key: Qt::Key_Backspace, modifier: Qt::NoModifier); | 
| 2144 |     QTRY_COMPARE(dblInput->text(), QLatin1String("12.1" )); | 
| 2145 |     QCOMPARE(dblInput->hasAcceptableInput(), false); | 
| 2146 |     QCOMPARE(dblInput->property("acceptable" ).toBool(), false); | 
| 2147 |     QCOMPARE(dblSpy.count(), 2 + extraSignals); | 
| 2148 |     // Once unacceptable input is in anything goes until it reaches an acceptable state again. | 
| 2149 |     QTest::keyPress(window: &window, key: Qt::Key_1); | 
| 2150 |     QTest::keyRelease(window: &window, key: Qt::Key_1, modifier: Qt::NoModifier); | 
| 2151 |     QTRY_COMPARE(dblInput->text(), QLatin1String("12.11" )); | 
| 2152 |     QCOMPARE(dblInput->hasAcceptableInput(), false); | 
| 2153 |     QCOMPARE(dblSpy.count(), 2 + extraSignals); | 
| 2154 |     QTest::keyPress(window: &window, key: Qt::Key_Backspace); | 
| 2155 |     QTest::keyRelease(window: &window, key: Qt::Key_Backspace, modifier: Qt::NoModifier); | 
| 2156 |     QTRY_COMPARE(dblInput->text(), QLatin1String("12.1" )); | 
| 2157 |     QCOMPARE(dblInput->hasAcceptableInput(), false); | 
| 2158 |     QCOMPARE(dblInput->property("acceptable" ).toBool(), false); | 
| 2159 |     QCOMPARE(dblSpy.count(), 2 + extraSignals); | 
| 2160 |     QTest::keyPress(window: &window, key: Qt::Key_Backspace); | 
| 2161 |     QTest::keyRelease(window: &window, key: Qt::Key_Backspace, modifier: Qt::NoModifier); | 
| 2162 |     QTRY_COMPARE(dblInput->text(), QLatin1String("12." )); | 
| 2163 |     QCOMPARE(dblInput->hasAcceptableInput(), false); | 
| 2164 |     QCOMPARE(dblInput->property("acceptable" ).toBool(), false); | 
| 2165 |     QCOMPARE(dblSpy.count(), 2 + extraSignals); | 
| 2166 |     QTest::keyPress(window: &window, key: Qt::Key_Backspace); | 
| 2167 |     QTest::keyRelease(window: &window, key: Qt::Key_Backspace, modifier: Qt::NoModifier); | 
| 2168 |     QTRY_COMPARE(dblInput->text(), QLatin1String("12" )); | 
| 2169 |     QCOMPARE(dblInput->hasAcceptableInput(), false); | 
| 2170 |     QCOMPARE(dblInput->property("acceptable" ).toBool(), false); | 
| 2171 |     QCOMPARE(dblSpy.count(), 2 + extraSignals); | 
| 2172 |     QTest::keyPress(window: &window, key: Qt::Key_Backspace); | 
| 2173 |     QTest::keyRelease(window: &window, key: Qt::Key_Backspace, modifier: Qt::NoModifier); | 
| 2174 |     QTRY_COMPARE(dblInput->text(), QLatin1String("1" )); | 
| 2175 |     QCOMPARE(dblInput->hasAcceptableInput(), false); | 
| 2176 |     QCOMPARE(dblInput->property("acceptable" ).toBool(), false); | 
| 2177 |     QCOMPARE(dblSpy.count(), 2 + extraSignals); | 
| 2178 |     QTest::keyPress(window: &window, key: Qt::Key_1); | 
| 2179 |     QTest::keyRelease(window: &window, key: Qt::Key_1, modifier: Qt::NoModifier); | 
| 2180 |     QCOMPARE(dblInput->text(), QLatin1String("11" )); | 
| 2181 |     QCOMPARE(dblInput->property("acceptable" ).toBool(), true); | 
| 2182 |     QCOMPARE(dblInput->hasAcceptableInput(), true); | 
| 2183 |     QCOMPARE(dblSpy.count(), 3 + extraSignals); | 
| 2184 |  | 
| 2185 |     // Changing the validator properties will re-evaluate whether the input is acceptable. | 
| 2186 |     intValidator->setTop(10); | 
| 2187 |     QCOMPARE(dblInput->property("acceptable" ).toBool(), false); | 
| 2188 |     QCOMPARE(dblInput->hasAcceptableInput(), false); | 
| 2189 |     QCOMPARE(dblSpy.count(), 4 + extraSignals); | 
| 2190 |     intValidator->setTop(12); | 
| 2191 |     QCOMPARE(dblInput->property("acceptable" ).toBool(), true); | 
| 2192 |     QCOMPARE(dblInput->hasAcceptableInput(), true); | 
| 2193 |     QCOMPARE(dblSpy.count(), 5 + extraSignals); | 
| 2194 |  | 
| 2195 |     QQuickTextInput *strInput = qobject_cast<QQuickTextInput *>(object: qvariant_cast<QObject *>(v: window.rootObject()->property(name: "strInput" ))); | 
| 2196 |     QVERIFY(strInput); | 
| 2197 |     QSignalSpy strSpy(strInput, SIGNAL(acceptableInputChanged())); | 
| 2198 |     strInput->setFocus(true); | 
| 2199 |     QVERIFY(strInput->hasActiveFocus()); | 
| 2200 |     QCOMPARE(strInput->hasAcceptableInput(), false); | 
| 2201 |     QCOMPARE(strInput->property("acceptable" ).toBool(), false); | 
| 2202 |     QTest::keyPress(window: &window, key: Qt::Key_1); | 
| 2203 |     QTest::keyRelease(window: &window, key: Qt::Key_1, modifier: Qt::NoModifier); | 
| 2204 |     QTRY_COMPARE(strInput->text(), QLatin1String("" )); | 
| 2205 |     QCOMPARE(strInput->hasAcceptableInput(), false); | 
| 2206 |     QCOMPARE(strInput->property("acceptable" ).toBool(), false); | 
| 2207 |     QCOMPARE(strSpy.count(), 0); | 
| 2208 |     QTest::keyPress(window: &window, key: Qt::Key_A); | 
| 2209 |     QTest::keyRelease(window: &window, key: Qt::Key_A, modifier: Qt::NoModifier); | 
| 2210 |     QTRY_COMPARE(strInput->text(), QLatin1String("a" )); | 
| 2211 |     QCOMPARE(strInput->hasAcceptableInput(), false); | 
| 2212 |     QCOMPARE(strInput->property("acceptable" ).toBool(), false); | 
| 2213 |     QCOMPARE(strSpy.count(), 0); | 
| 2214 |     QTest::keyPress(window: &window, key: Qt::Key_A); | 
| 2215 |     QTest::keyRelease(window: &window, key: Qt::Key_A, modifier: Qt::NoModifier); | 
| 2216 |     QTRY_COMPARE(strInput->text(), QLatin1String("aa" )); | 
| 2217 |     QCOMPARE(strInput->hasAcceptableInput(), true); | 
| 2218 |     QCOMPARE(strInput->property("acceptable" ).toBool(), true); | 
| 2219 |     QCOMPARE(strSpy.count(), 1); | 
| 2220 |     QTest::keyPress(window: &window, key: Qt::Key_A); | 
| 2221 |     QTest::keyRelease(window: &window, key: Qt::Key_A, modifier: Qt::NoModifier); | 
| 2222 |     QTRY_COMPARE(strInput->text(), QLatin1String("aaa" )); | 
| 2223 |     QCOMPARE(strInput->hasAcceptableInput(), true); | 
| 2224 |     QCOMPARE(strInput->property("acceptable" ).toBool(), true); | 
| 2225 |     QCOMPARE(strSpy.count(), 1); | 
| 2226 |     QTest::keyPress(window: &window, key: Qt::Key_A); | 
| 2227 |     QTest::keyRelease(window: &window, key: Qt::Key_A, modifier: Qt::NoModifier); | 
| 2228 |     QTRY_COMPARE(strInput->text(), QLatin1String("aaaa" )); | 
| 2229 |     QCOMPARE(strInput->hasAcceptableInput(), true); | 
| 2230 |     QCOMPARE(strInput->property("acceptable" ).toBool(), true); | 
| 2231 |     QCOMPARE(strSpy.count(), 1); | 
| 2232 |     QTest::keyPress(window: &window, key: Qt::Key_A); | 
| 2233 |     QTest::keyRelease(window: &window, key: Qt::Key_A, modifier: Qt::NoModifier); | 
| 2234 |     QTRY_COMPARE(strInput->text(), QLatin1String("aaaa" )); | 
| 2235 |     QCOMPARE(strInput->hasAcceptableInput(), true); | 
| 2236 |     QCOMPARE(strInput->property("acceptable" ).toBool(), true); | 
| 2237 |     QCOMPARE(strSpy.count(), 1); | 
| 2238 |  | 
| 2239 |     QQuickTextInput *unvalidatedInput = qobject_cast<QQuickTextInput *>(object: qvariant_cast<QObject *>(v: window.rootObject()->property(name: "unvalidatedInput" ))); | 
| 2240 |     QVERIFY(unvalidatedInput); | 
| 2241 |     QSignalSpy unvalidatedSpy(unvalidatedInput, SIGNAL(acceptableInputChanged())); | 
| 2242 |     unvalidatedInput->setFocus(true); | 
| 2243 |     QVERIFY(unvalidatedInput->hasActiveFocus()); | 
| 2244 |     QCOMPARE(unvalidatedInput->hasAcceptableInput(), true); | 
| 2245 |     QCOMPARE(unvalidatedInput->property("acceptable" ).toBool(), true); | 
| 2246 |     QTest::keyPress(window: &window, key: Qt::Key_1); | 
| 2247 |     QTest::keyRelease(window: &window, key: Qt::Key_1, modifier: Qt::NoModifier); | 
| 2248 |     QTRY_COMPARE(unvalidatedInput->text(), QLatin1String("1" )); | 
| 2249 |     QCOMPARE(unvalidatedInput->hasAcceptableInput(), true); | 
| 2250 |     QCOMPARE(unvalidatedInput->property("acceptable" ).toBool(), true); | 
| 2251 |     QCOMPARE(unvalidatedSpy.count(), 0); | 
| 2252 |     QTest::keyPress(window: &window, key: Qt::Key_A); | 
| 2253 |     QTest::keyRelease(window: &window, key: Qt::Key_A, modifier: Qt::NoModifier); | 
| 2254 |     QTRY_COMPARE(unvalidatedInput->text(), QLatin1String("1a" )); | 
| 2255 |     QCOMPARE(unvalidatedInput->hasAcceptableInput(), true); | 
| 2256 |     QCOMPARE(unvalidatedInput->property("acceptable" ).toBool(), true); | 
| 2257 |     QCOMPARE(unvalidatedSpy.count(), 0); | 
| 2258 | } | 
| 2259 |  | 
| 2260 | void tst_qquicktextinput::inputMethods() | 
| 2261 | { | 
| 2262 |     QQuickView window(testFileUrl(fileName: "inputmethods.qml" )); | 
| 2263 |     window.show(); | 
| 2264 |     window.requestActivate(); | 
| 2265 |     QVERIFY(QTest::qWaitForWindowActive(&window)); | 
| 2266 |  | 
| 2267 |     // test input method hints | 
| 2268 |     QVERIFY(window.rootObject() != nullptr); | 
| 2269 |     QQuickTextInput *input = qobject_cast<QQuickTextInput *>(object: window.rootObject()); | 
| 2270 |     QVERIFY(input != nullptr); | 
| 2271 |     QVERIFY(input->inputMethodHints() & Qt::ImhNoPredictiveText); | 
| 2272 |     QSignalSpy inputMethodHintSpy(input, SIGNAL(inputMethodHintsChanged())); | 
| 2273 |     input->setInputMethodHints(Qt::ImhUppercaseOnly); | 
| 2274 |     QVERIFY(input->inputMethodHints() & Qt::ImhUppercaseOnly); | 
| 2275 |     QCOMPARE(inputMethodHintSpy.count(), 1); | 
| 2276 |     input->setInputMethodHints(Qt::ImhUppercaseOnly); | 
| 2277 |     QCOMPARE(inputMethodHintSpy.count(), 1); | 
| 2278 |  | 
| 2279 |     // default value | 
| 2280 |     QQuickTextInput plainInput; | 
| 2281 |     QCOMPARE(plainInput.inputMethodHints(), Qt::ImhNone); | 
| 2282 |  | 
| 2283 |     input->setFocus(true); | 
| 2284 |     QVERIFY(input->hasActiveFocus()); | 
| 2285 |     // test that input method event is committed | 
| 2286 |     QInputMethodEvent event; | 
| 2287 |     event.setCommitString( commitString: "My " , replaceFrom: -12, replaceLength: 0); | 
| 2288 |     QTRY_COMPARE(qGuiApp->focusObject(), input); | 
| 2289 |     QGuiApplication::sendEvent(receiver: input, event: &event); | 
| 2290 |     QCOMPARE(input->text(), QString("My Hello world!" )); | 
| 2291 |     QCOMPARE(input->displayText(), QString("My Hello world!" )); | 
| 2292 |  | 
| 2293 |     input->setCursorPosition(2); | 
| 2294 |     event.setCommitString(commitString: "Your" , replaceFrom: -2, replaceLength: 2); | 
| 2295 |     QGuiApplication::sendEvent(receiver: input, event: &event); | 
| 2296 |     QCOMPARE(input->text(), QString("Your Hello world!" )); | 
| 2297 |     QCOMPARE(input->displayText(), QString("Your Hello world!" )); | 
| 2298 |     QCOMPARE(input->cursorPosition(), 4); | 
| 2299 |  | 
| 2300 |     input->setCursorPosition(7); | 
| 2301 |     event.setCommitString(commitString: "Goodbye" , replaceFrom: -2, replaceLength: 5); | 
| 2302 |     QGuiApplication::sendEvent(receiver: input, event: &event); | 
| 2303 |     QCOMPARE(input->text(), QString("Your Goodbye world!" )); | 
| 2304 |     QCOMPARE(input->displayText(), QString("Your Goodbye world!" )); | 
| 2305 |     QCOMPARE(input->cursorPosition(), 12); | 
| 2306 |  | 
| 2307 |     input->setCursorPosition(8); | 
| 2308 |     event.setCommitString(commitString: "Our" , replaceFrom: -8, replaceLength: 4); | 
| 2309 |     QGuiApplication::sendEvent(receiver: input, event: &event); | 
| 2310 |     QCOMPARE(input->text(), QString("Our Goodbye world!" )); | 
| 2311 |     QCOMPARE(input->displayText(), QString("Our Goodbye world!" )); | 
| 2312 |     QCOMPARE(input->cursorPosition(), 3); | 
| 2313 |  | 
| 2314 |     input->setCursorPosition(7); | 
| 2315 |     QInputMethodEvent preeditEvent("PREEDIT" , QList<QInputMethodEvent::Attribute>()); | 
| 2316 |     QGuiApplication::sendEvent(receiver: input, event: &preeditEvent); | 
| 2317 |     QCOMPARE(input->text(), QString("Our Goodbye world!" )); | 
| 2318 |     QCOMPARE(input->displayText(), QString("Our GooPREEDITdbye world!" )); | 
| 2319 |     QCOMPARE(input->preeditText(), QString("PREEDIT" )); | 
| 2320 |  | 
| 2321 |     QInputMethodEvent preeditEvent2("PREEDIT2" , QList<QInputMethodEvent::Attribute>()); | 
| 2322 |     QGuiApplication::sendEvent(receiver: input, event: &preeditEvent2); | 
| 2323 |     QCOMPARE(input->text(), QString("Our Goodbye world!" )); | 
| 2324 |     QCOMPARE(input->displayText(), QString("Our GooPREEDIT2dbye world!" )); | 
| 2325 |     QCOMPARE(input->preeditText(), QString("PREEDIT2" )); | 
| 2326 |  | 
| 2327 |     QInputMethodEvent preeditEvent3("" , QList<QInputMethodEvent::Attribute>()); | 
| 2328 |     QGuiApplication::sendEvent(receiver: input, event: &preeditEvent3); | 
| 2329 |     QCOMPARE(input->text(), QString("Our Goodbye world!" )); | 
| 2330 |     QCOMPARE(input->displayText(), QString("Our Goodbye world!" )); | 
| 2331 |     QCOMPARE(input->preeditText(), QString("" )); | 
| 2332 |  | 
| 2333 |     // input should reset selection even if replacement parameters are out of bounds | 
| 2334 |     input->setText("text" ); | 
| 2335 |     input->setCursorPosition(0); | 
| 2336 |     input->moveCursorSelection(pos: input->text().length()); | 
| 2337 |     event.setCommitString(commitString: "replacement" , replaceFrom: -input->text().length(), replaceLength: input->text().length()); | 
| 2338 |     QGuiApplication::sendEvent(receiver: input, event: &event); | 
| 2339 |     QCOMPARE(input->selectionStart(), input->selectionEnd()); | 
| 2340 |     QCOMPARE(input->text(), QString("replacement" )); | 
| 2341 |     QCOMPARE(input->displayText(), QString("replacement" )); | 
| 2342 |  | 
| 2343 |     QInputMethodQueryEvent enabledQueryEvent(Qt::ImEnabled); | 
| 2344 |     QGuiApplication::sendEvent(receiver: input, event: &enabledQueryEvent); | 
| 2345 |     QCOMPARE(enabledQueryEvent.value(Qt::ImEnabled).toBool(), true); | 
| 2346 |  | 
| 2347 |     input->setReadOnly(true); | 
| 2348 |     QGuiApplication::sendEvent(receiver: input, event: &enabledQueryEvent); | 
| 2349 |     QCOMPARE(enabledQueryEvent.value(Qt::ImEnabled).toBool(), false); | 
| 2350 | } | 
| 2351 |  | 
| 2352 | void tst_qquicktextinput::signal_accepted() | 
| 2353 | { | 
| 2354 |     QQuickView window(testFileUrl(fileName: "signal_accepted.qml" )); | 
| 2355 |     window.show(); | 
| 2356 |     window.requestActivate(); | 
| 2357 |     QVERIFY(QTest::qWaitForWindowActive(&window)); | 
| 2358 |  | 
| 2359 |     QVERIFY(window.rootObject() != nullptr); | 
| 2360 |  | 
| 2361 |     QQuickTextInput *input = qobject_cast<QQuickTextInput *>(object: qvariant_cast<QObject *>(v: window.rootObject()->property(name: "input" ))); | 
| 2362 |     QVERIFY(input); | 
| 2363 |     QSignalSpy acceptedSpy(input, SIGNAL(accepted())); | 
| 2364 |     QSignalSpy inputSpy(input, SIGNAL(acceptableInputChanged())); | 
| 2365 |  | 
| 2366 |     input->setFocus(true); | 
| 2367 |     QTRY_VERIFY(input->hasActiveFocus()); | 
| 2368 |     QCOMPARE(input->hasAcceptableInput(), false); | 
| 2369 |     QCOMPARE(input->property("acceptable" ).toBool(), false); | 
| 2370 |  | 
| 2371 |     QTest::keyPress(window: &window, key: Qt::Key_A); | 
| 2372 |     QTest::keyRelease(window: &window, key: Qt::Key_A, modifier: Qt::NoModifier); | 
| 2373 |     QTRY_COMPARE(input->text(), QLatin1String("a" )); | 
| 2374 |     QCOMPARE(input->hasAcceptableInput(), false); | 
| 2375 |     QCOMPARE(input->property("acceptable" ).toBool(), false); | 
| 2376 |     QTRY_COMPARE(inputSpy.count(), 0); | 
| 2377 |  | 
| 2378 |     QTest::keyPress(window: &window, key: Qt::Key_Enter); | 
| 2379 |     QTest::keyRelease(window: &window, key: Qt::Key_Enter, modifier: Qt::NoModifier); | 
| 2380 |     QTRY_COMPARE(acceptedSpy.count(), 0); | 
| 2381 |  | 
| 2382 |     QTest::keyPress(window: &window, key: Qt::Key_A); | 
| 2383 |     QTest::keyRelease(window: &window, key: Qt::Key_A, modifier: Qt::NoModifier); | 
| 2384 |     QTRY_COMPARE(input->text(), QLatin1String("aa" )); | 
| 2385 |     QCOMPARE(input->hasAcceptableInput(), true); | 
| 2386 |     QCOMPARE(input->property("acceptable" ).toBool(), true); | 
| 2387 |     QTRY_COMPARE(inputSpy.count(), 1); | 
| 2388 |  | 
| 2389 |     QTest::keyPress(window: &window, key: Qt::Key_Enter); | 
| 2390 |     QTest::keyRelease(window: &window, key: Qt::Key_Enter, modifier: Qt::NoModifier); | 
| 2391 |     QTRY_COMPARE(acceptedSpy.count(), 1); | 
| 2392 | } | 
| 2393 |  | 
| 2394 | void tst_qquicktextinput::signal_editingfinished() | 
| 2395 | { | 
| 2396 |     QQuickView window(testFileUrl(fileName: "signal_editingfinished.qml" )); | 
| 2397 |     window.show(); | 
| 2398 |     window.requestActivate(); | 
| 2399 |     QVERIFY(QTest::qWaitForWindowActive(&window)); | 
| 2400 |  | 
| 2401 |     QVERIFY(window.rootObject() != nullptr); | 
| 2402 |  | 
| 2403 |     QQuickTextInput *input1 = qobject_cast<QQuickTextInput *>(object: qvariant_cast<QObject *>(v: window.rootObject()->property(name: "input1" ))); | 
| 2404 |     QVERIFY(input1); | 
| 2405 |     QQuickTextInput *input2 = qobject_cast<QQuickTextInput *>(object: qvariant_cast<QObject *>(v: window.rootObject()->property(name: "input2" ))); | 
| 2406 |     QVERIFY(input2); | 
| 2407 |     QSignalSpy editingFinished1Spy(input1, SIGNAL(editingFinished())); | 
| 2408 |     QSignalSpy input1Spy(input1, SIGNAL(acceptableInputChanged())); | 
| 2409 |  | 
| 2410 |     input1->setFocus(true); | 
| 2411 |     QTRY_VERIFY(input1->hasActiveFocus()); | 
| 2412 |     QTRY_VERIFY(!input2->hasActiveFocus()); | 
| 2413 |  | 
| 2414 |     QTest::keyPress(window: &window, key: Qt::Key_A); | 
| 2415 |     QTest::keyRelease(window: &window, key: Qt::Key_A, modifier: Qt::NoModifier); | 
| 2416 |     QTRY_COMPARE(input1->text(), QLatin1String("a" )); | 
| 2417 |     QCOMPARE(input1->hasAcceptableInput(), false); | 
| 2418 |     QCOMPARE(input1->property("acceptable" ).toBool(), false); | 
| 2419 |     QTRY_COMPARE(input1Spy.count(), 0); | 
| 2420 |  | 
| 2421 |     QTest::keyPress(window: &window, key: Qt::Key_Enter); | 
| 2422 |     QTest::keyRelease(window: &window, key: Qt::Key_Enter, modifier: Qt::NoModifier); | 
| 2423 |     QTRY_COMPARE(editingFinished1Spy.count(), 0); | 
| 2424 |  | 
| 2425 |     QTest::keyPress(window: &window, key: Qt::Key_A); | 
| 2426 |     QTest::keyRelease(window: &window, key: Qt::Key_A, modifier: Qt::NoModifier); | 
| 2427 |     QTRY_COMPARE(input1->text(), QLatin1String("aa" )); | 
| 2428 |     QCOMPARE(input1->hasAcceptableInput(), true); | 
| 2429 |     QCOMPARE(input1->property("acceptable" ).toBool(), true); | 
| 2430 |     QTRY_COMPARE(input1Spy.count(), 1); | 
| 2431 |  | 
| 2432 |     QTest::keyPress(window: &window, key: Qt::Key_Enter); | 
| 2433 |     QTest::keyRelease(window: &window, key: Qt::Key_Enter, modifier: Qt::NoModifier); | 
| 2434 |     QTRY_COMPARE(editingFinished1Spy.count(), 1); | 
| 2435 |     QTRY_COMPARE(input1Spy.count(), 1); | 
| 2436 |  | 
| 2437 |     QSignalSpy editingFinished2Spy(input2, SIGNAL(editingFinished())); | 
| 2438 |     QSignalSpy input2Spy(input2, SIGNAL(acceptableInputChanged())); | 
| 2439 |  | 
| 2440 |     input2->setFocus(true); | 
| 2441 |     QTRY_VERIFY(!input1->hasActiveFocus()); | 
| 2442 |     QTRY_VERIFY(input2->hasActiveFocus()); | 
| 2443 |  | 
| 2444 |     QTest::keyPress(window: &window, key: Qt::Key_A); | 
| 2445 |     QTest::keyRelease(window: &window, key: Qt::Key_A, modifier: Qt::NoModifier); | 
| 2446 |     QTRY_COMPARE(input2->text(), QLatin1String("a" )); | 
| 2447 |     QCOMPARE(input2->hasAcceptableInput(), false); | 
| 2448 |     QCOMPARE(input2->property("acceptable" ).toBool(), false); | 
| 2449 |     QTRY_COMPARE(input2Spy.count(), 0); | 
| 2450 |  | 
| 2451 |     QTest::keyPress(window: &window, key: Qt::Key_A); | 
| 2452 |     QTest::keyRelease(window: &window, key: Qt::Key_A, modifier: Qt::NoModifier); | 
| 2453 |     QTRY_COMPARE(input2->text(), QLatin1String("aa" )); | 
| 2454 |     QCOMPARE(input2->hasAcceptableInput(), true); | 
| 2455 |     QCOMPARE(input2->property("acceptable" ).toBool(), true); | 
| 2456 |     QTRY_COMPARE(input2Spy.count(), 1); | 
| 2457 |  | 
| 2458 |     input1->setFocus(true); | 
| 2459 |     QTRY_VERIFY(input1->hasActiveFocus()); | 
| 2460 |     QTRY_VERIFY(!input2->hasActiveFocus()); | 
| 2461 |     QTRY_COMPARE(editingFinished2Spy.count(), 1); | 
| 2462 | } | 
| 2463 |  | 
| 2464 | void tst_qquicktextinput::signal_textEdited() | 
| 2465 | { | 
| 2466 |     QQuickWindow window; | 
| 2467 |     window.show(); | 
| 2468 |     window.requestActivate(); | 
| 2469 |     QVERIFY(QTest::qWaitForWindowActive(&window)); | 
| 2470 |  | 
| 2471 |     QQuickTextInput *input = new QQuickTextInput(window.contentItem()); | 
| 2472 |     QVERIFY(input); | 
| 2473 |  | 
| 2474 |     QSignalSpy textChangedSpy(input, SIGNAL(textChanged())); | 
| 2475 |     QVERIFY(textChangedSpy.isValid()); | 
| 2476 |  | 
| 2477 |     QSignalSpy textEditedSpy(input, SIGNAL(textEdited())); | 
| 2478 |     QVERIFY(textEditedSpy.isValid()); | 
| 2479 |  | 
| 2480 |     input->forceActiveFocus(); | 
| 2481 |     QTRY_VERIFY(input->hasActiveFocus()); | 
| 2482 |  | 
| 2483 |     int textChanges = 0; | 
| 2484 |     int textEdits = 0; | 
| 2485 |  | 
| 2486 |     QTest::keyClick(window: &window, key: Qt::Key_A); | 
| 2487 |     QCOMPARE(textChangedSpy.count(), ++textChanges); | 
| 2488 |     QCOMPARE(textEditedSpy.count(), ++textEdits); | 
| 2489 |  | 
| 2490 |     QTest::keyClick(window: &window, key: Qt::Key_B); | 
| 2491 |     QCOMPARE(textChangedSpy.count(), ++textChanges); | 
| 2492 |     QCOMPARE(textEditedSpy.count(), ++textEdits); | 
| 2493 |  | 
| 2494 |     QTest::keyClick(window: &window, key: Qt::Key_C); | 
| 2495 |     QCOMPARE(textChangedSpy.count(), ++textChanges); | 
| 2496 |     QCOMPARE(textEditedSpy.count(), ++textEdits); | 
| 2497 |  | 
| 2498 |     QTest::keyClick(window: &window, key: Qt::Key_Space); | 
| 2499 |     QCOMPARE(textChangedSpy.count(), ++textChanges); | 
| 2500 |     QCOMPARE(textEditedSpy.count(), ++textEdits); | 
| 2501 |  | 
| 2502 |     QTest::keyClick(window: &window, key: Qt::Key_Backspace); | 
| 2503 |     QCOMPARE(textChangedSpy.count(), ++textChanges); | 
| 2504 |     QCOMPARE(textEditedSpy.count(), ++textEdits); | 
| 2505 |  | 
| 2506 |     input->clear(); | 
| 2507 |     QCOMPARE(textChangedSpy.count(), ++textChanges); | 
| 2508 |     QCOMPARE(textEditedSpy.count(), textEdits); | 
| 2509 |  | 
| 2510 |     input->setText("TextInput" ); | 
| 2511 |     QCOMPARE(textChangedSpy.count(), ++textChanges); | 
| 2512 |     QCOMPARE(textEditedSpy.count(), textEdits); | 
| 2513 | } | 
| 2514 |  | 
| 2515 | /* | 
| 2516 | TextInput element should only handle left/right keys until the cursor reaches | 
| 2517 | the extent of the text, then they should ignore the keys. | 
| 2518 |  | 
| 2519 | */ | 
| 2520 | void tst_qquicktextinput::navigation() | 
| 2521 | { | 
| 2522 |     QQuickView window(testFileUrl(fileName: "navigation.qml" )); | 
| 2523 |     window.show(); | 
| 2524 |     window.requestActivate(); | 
| 2525 |  | 
| 2526 |     QVERIFY(window.rootObject() != nullptr); | 
| 2527 |  | 
| 2528 |     QQuickTextInput *input = qobject_cast<QQuickTextInput *>(object: qvariant_cast<QObject *>(v: window.rootObject()->property(name: "myInput" ))); | 
| 2529 |  | 
| 2530 |     QVERIFY(input != nullptr); | 
| 2531 |     input->setCursorPosition(0); | 
| 2532 |     QTRY_VERIFY(input->hasActiveFocus()); | 
| 2533 |     simulateKey(&window, key: Qt::Key_Left); | 
| 2534 |     QVERIFY(!input->hasActiveFocus()); | 
| 2535 |     simulateKey(&window, key: Qt::Key_Right); | 
| 2536 |     QVERIFY(input->hasActiveFocus()); | 
| 2537 |     //QT-2944: If text is selected, ensure we deselect upon cursor motion | 
| 2538 |     input->setCursorPosition(input->text().length()); | 
| 2539 |     input->select(start: 0,end: input->text().length()); | 
| 2540 |     QVERIFY(input->selectionStart() != input->selectionEnd()); | 
| 2541 |     simulateKey(&window, key: Qt::Key_Right); | 
| 2542 |     QCOMPARE(input->selectionStart(), input->selectionEnd()); | 
| 2543 |     QCOMPARE(input->selectionStart(), input->text().length()); | 
| 2544 |     QVERIFY(input->hasActiveFocus()); | 
| 2545 |     simulateKey(&window, key: Qt::Key_Right); | 
| 2546 |     QVERIFY(!input->hasActiveFocus()); | 
| 2547 |     simulateKey(&window, key: Qt::Key_Left); | 
| 2548 |     QVERIFY(input->hasActiveFocus()); | 
| 2549 |  | 
| 2550 |     // Up and Down should NOT do Home/End, even on OS X (QTBUG-10438). | 
| 2551 |     input->setCursorPosition(2); | 
| 2552 |     QCOMPARE(input->cursorPosition(),2); | 
| 2553 |     simulateKey(&window, key: Qt::Key_Up); | 
| 2554 |     QCOMPARE(input->cursorPosition(),2); | 
| 2555 |     simulateKey(&window, key: Qt::Key_Down); | 
| 2556 |     QCOMPARE(input->cursorPosition(),2); | 
| 2557 |  | 
| 2558 |     // Test left and right navigation works if the TextInput is empty (QTBUG-25447). | 
| 2559 |     input->setText(QString()); | 
| 2560 |     QCOMPARE(input->cursorPosition(), 0); | 
| 2561 |     simulateKey(&window, key: Qt::Key_Right); | 
| 2562 |     QCOMPARE(input->hasActiveFocus(), false); | 
| 2563 |     simulateKey(&window, key: Qt::Key_Left); | 
| 2564 |     QCOMPARE(input->hasActiveFocus(), true); | 
| 2565 |     simulateKey(&window, key: Qt::Key_Left); | 
| 2566 |     QCOMPARE(input->hasActiveFocus(), false); | 
| 2567 | } | 
| 2568 |  | 
| 2569 | void tst_qquicktextinput::navigation_RTL() | 
| 2570 | { | 
| 2571 |     QQuickView window(testFileUrl(fileName: "navigation.qml" )); | 
| 2572 |     window.show(); | 
| 2573 |     window.requestActivate(); | 
| 2574 |  | 
| 2575 |     QVERIFY(window.rootObject() != nullptr); | 
| 2576 |  | 
| 2577 |     QQuickTextInput *input = qobject_cast<QQuickTextInput *>(object: qvariant_cast<QObject *>(v: window.rootObject()->property(name: "myInput" ))); | 
| 2578 |  | 
| 2579 |     QVERIFY(input != nullptr); | 
| 2580 |     const quint16 arabic_str[] = { 0x0638, 0x0643, 0x00646, 0x0647, 0x0633, 0x0638, 0x0643, 0x00646, 0x0647, 0x0633, 0x0647}; | 
| 2581 |     input->setText(QString::fromUtf16(arabic_str, size: 11)); | 
| 2582 |  | 
| 2583 |     input->setCursorPosition(0); | 
| 2584 |     QTRY_VERIFY(input->hasActiveFocus()); | 
| 2585 |  | 
| 2586 |     // move off | 
| 2587 |     simulateKey(&window, key: Qt::Key_Right); | 
| 2588 |     QVERIFY(!input->hasActiveFocus()); | 
| 2589 |  | 
| 2590 |     // move back | 
| 2591 |     simulateKey(&window, key: Qt::Key_Left); | 
| 2592 |     QVERIFY(input->hasActiveFocus()); | 
| 2593 |  | 
| 2594 |     input->setCursorPosition(input->text().length()); | 
| 2595 |     QVERIFY(input->hasActiveFocus()); | 
| 2596 |  | 
| 2597 |     // move off | 
| 2598 |     simulateKey(&window, key: Qt::Key_Left); | 
| 2599 |     QVERIFY(!input->hasActiveFocus()); | 
| 2600 |  | 
| 2601 |     // move back | 
| 2602 |     simulateKey(&window, key: Qt::Key_Right); | 
| 2603 |     QVERIFY(input->hasActiveFocus()); | 
| 2604 | } | 
| 2605 |  | 
| 2606 | #if QT_CONFIG(clipboard) && QT_CONFIG(shortcut) | 
| 2607 | void tst_qquicktextinput::copyAndPaste() | 
| 2608 | { | 
| 2609 |     if (!PlatformQuirks::isClipboardAvailable()) | 
| 2610 |         QSKIP("This machine doesn't support the clipboard" ); | 
| 2611 |  | 
| 2612 |     QString componentStr = "import QtQuick 2.0\nTextInput { text: \"Hello world!\" }" ; | 
| 2613 |     QQmlComponent textInputComponent(&engine); | 
| 2614 |     textInputComponent.setData(componentStr.toLatin1(), baseUrl: QUrl()); | 
| 2615 |     QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(object: textInputComponent.create()); | 
| 2616 |     QVERIFY(textInput != nullptr); | 
| 2617 |  | 
| 2618 |     // copy and paste | 
| 2619 |     QCOMPARE(textInput->text().length(), 12); | 
| 2620 |     textInput->select(start: 0, end: textInput->text().length()); | 
| 2621 |     textInput->copy(); | 
| 2622 |     QCOMPARE(textInput->selectedText(), QString("Hello world!" )); | 
| 2623 |     QCOMPARE(textInput->selectedText().length(), 12); | 
| 2624 |     textInput->setCursorPosition(0); | 
| 2625 |     QTRY_VERIFY(textInput->canPaste()); | 
| 2626 |     textInput->paste(); | 
| 2627 |     QCOMPARE(textInput->text(), QString("Hello world!Hello world!" )); | 
| 2628 |     QCOMPARE(textInput->text().length(), 24); | 
| 2629 |  | 
| 2630 |     // can paste | 
| 2631 |     QVERIFY(textInput->canPaste()); | 
| 2632 |     textInput->setReadOnly(true); | 
| 2633 |     QVERIFY(!textInput->canPaste()); | 
| 2634 |     textInput->paste(); | 
| 2635 |     QCOMPARE(textInput->text(), QString("Hello world!Hello world!" )); | 
| 2636 |     QCOMPARE(textInput->text().length(), 24); | 
| 2637 |     textInput->setReadOnly(false); | 
| 2638 |     QVERIFY(textInput->canPaste()); | 
| 2639 |  | 
| 2640 |     // cut: no selection | 
| 2641 |     textInput->cut(); | 
| 2642 |     QCOMPARE(textInput->text(), QString("Hello world!Hello world!" )); | 
| 2643 |  | 
| 2644 |     // select word | 
| 2645 |     textInput->setCursorPosition(0); | 
| 2646 |     textInput->selectWord(); | 
| 2647 |     QCOMPARE(textInput->selectedText(), QString("Hello" )); | 
| 2648 |  | 
| 2649 |     // cut: read only. | 
| 2650 |     textInput->setReadOnly(true); | 
| 2651 |     textInput->cut(); | 
| 2652 |     QCOMPARE(textInput->text(), QString("Hello world!Hello world!" )); | 
| 2653 |     textInput->setReadOnly(false); | 
| 2654 |  | 
| 2655 |     // select all and cut | 
| 2656 |     textInput->selectAll(); | 
| 2657 |     textInput->cut(); | 
| 2658 |     QCOMPARE(textInput->text().length(), 0); | 
| 2659 |     textInput->paste(); | 
| 2660 |     QCOMPARE(textInput->text(), QString("Hello world!Hello world!" )); | 
| 2661 |     QCOMPARE(textInput->text().length(), 24); | 
| 2662 |  | 
| 2663 |     // Copy first word. | 
| 2664 |     textInput->setCursorPosition(0); | 
| 2665 |     textInput->selectWord(); | 
| 2666 |     textInput->copy(); | 
| 2667 |     // copy: no selection, previous copy retained; | 
| 2668 |     textInput->setCursorPosition(0); | 
| 2669 |     QCOMPARE(textInput->selectedText(), QString()); | 
| 2670 |     textInput->copy(); | 
| 2671 |     textInput->setText(QString()); | 
| 2672 |     textInput->paste(); | 
| 2673 |     QCOMPARE(textInput->text(), QString("Hello" )); | 
| 2674 |  | 
| 2675 |     // clear copy buffer | 
| 2676 |     QClipboard *clipboard = QGuiApplication::clipboard(); | 
| 2677 |     QVERIFY(clipboard); | 
| 2678 |     clipboard->clear(); | 
| 2679 |     QTRY_VERIFY(!textInput->canPaste()); | 
| 2680 |  | 
| 2681 |     // test that copy functionality is disabled | 
| 2682 |     // when echo mode is set to hide text/password mode | 
| 2683 |     int index = 0; | 
| 2684 |     while (index < 4) { | 
| 2685 |         QQuickTextInput::EchoMode echoMode = QQuickTextInput::EchoMode(index); | 
| 2686 |         textInput->setEchoMode(echoMode); | 
| 2687 |         textInput->setText("My password" ); | 
| 2688 |         textInput->select(start: 0, end: textInput->text().length()); | 
| 2689 |         textInput->copy(); | 
| 2690 |         if (echoMode == QQuickTextInput::Normal) { | 
| 2691 |             QVERIFY(!clipboard->text().isEmpty()); | 
| 2692 |             QCOMPARE(clipboard->text(), QString("My password" )); | 
| 2693 |             clipboard->clear(); | 
| 2694 |         } else { | 
| 2695 |             QVERIFY(!clipboard->ownsSelection() || clipboard->text().isEmpty()); | 
| 2696 |         } | 
| 2697 |         index++; | 
| 2698 |     } | 
| 2699 |  | 
| 2700 |     delete textInput; | 
| 2701 | } | 
| 2702 | #endif | 
| 2703 |  | 
| 2704 | #if QT_CONFIG(clipboard) && QT_CONFIG(shortcut) | 
| 2705 | void tst_qquicktextinput::copyAndPasteKeySequence() | 
| 2706 | { | 
| 2707 |     if (!PlatformQuirks::isClipboardAvailable()) | 
| 2708 |         QSKIP("This machine doesn't support the clipboard" ); | 
| 2709 |  | 
| 2710 |     QString componentStr = "import QtQuick 2.0\nTextInput { text: \"Hello world!\"; focus: true }" ; | 
| 2711 |     QQmlComponent textInputComponent(&engine); | 
| 2712 |     textInputComponent.setData(componentStr.toLatin1(), baseUrl: QUrl()); | 
| 2713 |     QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(object: textInputComponent.create()); | 
| 2714 |     QVERIFY(textInput != nullptr); | 
| 2715 |  | 
| 2716 |     QQuickWindow window; | 
| 2717 |     textInput->setParentItem(window.contentItem()); | 
| 2718 |     window.show(); | 
| 2719 |     window.requestActivate(); | 
| 2720 |     QVERIFY(QTest::qWaitForWindowActive(&window)); | 
| 2721 |  | 
| 2722 |     // copy and paste | 
| 2723 |     QVERIFY(textInput->hasActiveFocus()); | 
| 2724 |     QCOMPARE(textInput->text().length(), 12); | 
| 2725 |     textInput->select(start: 0, end: textInput->text().length()); | 
| 2726 |     simulateKeys(window: &window, sequence: QKeySequence::Copy); | 
| 2727 |     QCOMPARE(textInput->selectedText(), QString("Hello world!" )); | 
| 2728 |     QCOMPARE(textInput->selectedText().length(), 12); | 
| 2729 |     textInput->setCursorPosition(0); | 
| 2730 |     QVERIFY(textInput->canPaste()); | 
| 2731 |     simulateKeys(window: &window, sequence: QKeySequence::Paste); | 
| 2732 |     QCOMPARE(textInput->text(), QString("Hello world!Hello world!" )); | 
| 2733 |     QCOMPARE(textInput->text().length(), 24); | 
| 2734 |  | 
| 2735 |     // select all and cut | 
| 2736 |     simulateKeys(window: &window, sequence: QKeySequence::SelectAll); | 
| 2737 |     simulateKeys(window: &window, sequence: QKeySequence::Cut); | 
| 2738 |     QCOMPARE(textInput->text().length(), 0); | 
| 2739 |     simulateKeys(window: &window, sequence: QKeySequence::Paste); | 
| 2740 |     QCOMPARE(textInput->text(), QString("Hello world!Hello world!" )); | 
| 2741 |     QCOMPARE(textInput->text().length(), 24); | 
| 2742 |  | 
| 2743 |     // clear copy buffer | 
| 2744 |     QClipboard *clipboard = QGuiApplication::clipboard(); | 
| 2745 |     QVERIFY(clipboard); | 
| 2746 |     clipboard->clear(); | 
| 2747 |     QTRY_VERIFY(!textInput->canPaste()); | 
| 2748 |  | 
| 2749 |     // test that copy functionality is disabled | 
| 2750 |     // when echo mode is set to hide text/password mode | 
| 2751 |     int index = 0; | 
| 2752 |     while (index < 4) { | 
| 2753 |         QQuickTextInput::EchoMode echoMode = QQuickTextInput::EchoMode(index); | 
| 2754 |         textInput->setEchoMode(echoMode); | 
| 2755 |         textInput->setText("My password" ); | 
| 2756 |         textInput->select(start: 0, end: textInput->text().length()); | 
| 2757 |         simulateKeys(window: &window, sequence: QKeySequence::Copy); | 
| 2758 |         if (echoMode == QQuickTextInput::Normal) { | 
| 2759 |             QVERIFY(!clipboard->text().isEmpty()); | 
| 2760 |             QCOMPARE(clipboard->text(), QString("My password" )); | 
| 2761 |             clipboard->clear(); | 
| 2762 |         } else { | 
| 2763 |             QVERIFY(!clipboard->ownsClipboard() || clipboard->text().isEmpty()); | 
| 2764 |         } | 
| 2765 |         index++; | 
| 2766 |     } | 
| 2767 |  | 
| 2768 |     delete textInput; | 
| 2769 | } | 
| 2770 | #endif | 
| 2771 |  | 
| 2772 | #if QT_CONFIG(clipboard) && QT_CONFIG(shortcut) | 
| 2773 | void tst_qquicktextinput::canPasteEmpty() | 
| 2774 | { | 
| 2775 |     QGuiApplication::clipboard()->clear(); | 
| 2776 |  | 
| 2777 |     QString componentStr = "import QtQuick 2.0\nTextInput { text: \"Hello world!\" }" ; | 
| 2778 |     QQmlComponent textInputComponent(&engine); | 
| 2779 |     textInputComponent.setData(componentStr.toLatin1(), baseUrl: QUrl()); | 
| 2780 |     QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(object: textInputComponent.create()); | 
| 2781 |     QVERIFY(textInput != nullptr); | 
| 2782 |  | 
| 2783 |     bool cp = !textInput->isReadOnly() && QGuiApplication::clipboard()->text().length() != 0; | 
| 2784 |     QCOMPARE(textInput->canPaste(), cp); | 
| 2785 | } | 
| 2786 | #endif | 
| 2787 |  | 
| 2788 | #if QT_CONFIG(clipboard) && QT_CONFIG(shortcut) | 
| 2789 | void tst_qquicktextinput::canPaste() | 
| 2790 | { | 
| 2791 |     QGuiApplication::clipboard()->setText("Some text" ); | 
| 2792 |  | 
| 2793 |     QString componentStr = "import QtQuick 2.0\nTextInput { text: \"Hello world!\" }" ; | 
| 2794 |     QQmlComponent textInputComponent(&engine); | 
| 2795 |     textInputComponent.setData(componentStr.toLatin1(), baseUrl: QUrl()); | 
| 2796 |     QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(object: textInputComponent.create()); | 
| 2797 |     QVERIFY(textInput != nullptr); | 
| 2798 |  | 
| 2799 |     bool cp = !textInput->isReadOnly() && QGuiApplication::clipboard()->text().length() != 0; | 
| 2800 |     QCOMPARE(textInput->canPaste(), cp); | 
| 2801 | } | 
| 2802 | #endif | 
| 2803 |  | 
| 2804 | #if QT_CONFIG(clipboard) && QT_CONFIG(shortcut) | 
| 2805 | void tst_qquicktextinput::middleClickPaste() | 
| 2806 | { | 
| 2807 |     if (!PlatformQuirks::isClipboardAvailable()) | 
| 2808 |         QSKIP("This machine doesn't support the clipboard" ); | 
| 2809 |  | 
| 2810 |     QQuickView window(testFileUrl(fileName: "mouseselection_true.qml" )); | 
| 2811 |  | 
| 2812 |     window.show(); | 
| 2813 |     window.requestActivate(); | 
| 2814 |     QVERIFY(QTest::qWaitForWindowActive(&window)); | 
| 2815 |  | 
| 2816 |     QVERIFY(window.rootObject() != nullptr); | 
| 2817 |     QQuickTextInput *textInputObject = qobject_cast<QQuickTextInput *>(object: window.rootObject()); | 
| 2818 |     QVERIFY(textInputObject != nullptr); | 
| 2819 |  | 
| 2820 |     textInputObject->setFocus(true); | 
| 2821 |  | 
| 2822 |     QString originalText = textInputObject->text(); | 
| 2823 |     QString selectedText = "234567" ; | 
| 2824 |  | 
| 2825 |     // press-and-drag-and-release from x1 to x2 | 
| 2826 |     const QPoint p1 = textInputObject->positionToRectangle(pos: 2).center().toPoint(); | 
| 2827 |     const QPoint p2 = textInputObject->positionToRectangle(pos: 8).center().toPoint(); | 
| 2828 |     const QPoint p3 = textInputObject->positionToRectangle(pos: 1).center().toPoint(); | 
| 2829 |     QTest::mousePress(window: &window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: p1); | 
| 2830 |     QTest::mouseMove(window: &window, pos: p2); | 
| 2831 |     QTest::mouseRelease(window: &window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: p2); | 
| 2832 |     QTRY_COMPARE(textInputObject->selectedText(), selectedText); | 
| 2833 |  | 
| 2834 |     // Middle click pastes the selected text, assuming the platform supports it. | 
| 2835 |     QTest::mouseClick(window: &window, button: Qt::MiddleButton, stateKey: Qt::NoModifier, pos: p3); | 
| 2836 |  | 
| 2837 |     // ### This is to prevent double click detection from carrying over to the next test. | 
| 2838 |     QTest::qWait(ms: QGuiApplication::styleHints()->mouseDoubleClickInterval() + 10); | 
| 2839 |  | 
| 2840 |     if (QGuiApplication::clipboard()->supportsSelection()) | 
| 2841 |         QCOMPARE(textInputObject->text().mid(1, selectedText.length()), selectedText); | 
| 2842 |     else | 
| 2843 |         QCOMPARE(textInputObject->text(), originalText); | 
| 2844 | } | 
| 2845 | #endif | 
| 2846 |  | 
| 2847 | void tst_qquicktextinput::passwordCharacter() | 
| 2848 | { | 
| 2849 |     QString componentStr = "import QtQuick 2.0\nTextInput { text: \"Hello world!\"; font.family: \"Helvetica\"; echoMode: TextInput.Password }" ; | 
| 2850 |     QQmlComponent textInputComponent(&engine); | 
| 2851 |     textInputComponent.setData(componentStr.toLatin1(), baseUrl: QUrl()); | 
| 2852 |     QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(object: textInputComponent.create()); | 
| 2853 |     QVERIFY(textInput != nullptr); | 
| 2854 |  | 
| 2855 |     textInput->setPasswordCharacter("X" ); | 
| 2856 |     qreal implicitWidth = textInput->implicitWidth(); | 
| 2857 |     textInput->setPasswordCharacter("." ); | 
| 2858 |  | 
| 2859 |     // QTBUG-12383 content is updated and redrawn | 
| 2860 |     QVERIFY(textInput->implicitWidth() < implicitWidth); | 
| 2861 |  | 
| 2862 |     delete textInput; | 
| 2863 | } | 
| 2864 |  | 
| 2865 | void tst_qquicktextinput::cursorDelegate_data() | 
| 2866 | { | 
| 2867 |     QTest::addColumn<QUrl>(name: "source" ); | 
| 2868 |     QTest::newRow(dataTag: "out of line" ) << testFileUrl(fileName: "cursorTest.qml" ); | 
| 2869 |     QTest::newRow(dataTag: "in line" ) << testFileUrl(fileName: "cursorTestInline.qml" ); | 
| 2870 |     QTest::newRow(dataTag: "external" ) << testFileUrl(fileName: "cursorTestExternal.qml" ); | 
| 2871 | } | 
| 2872 |  | 
| 2873 | void tst_qquicktextinput::cursorDelegate() | 
| 2874 | { | 
| 2875 |     QFETCH(QUrl, source); | 
| 2876 |     QQuickView view(source); | 
| 2877 |     view.show(); | 
| 2878 |     view.requestActivate(); | 
| 2879 |     QVERIFY(QTest::qWaitForWindowActive(&view)); | 
| 2880 |     QQuickTextInput *textInputObject = view.rootObject()->findChild<QQuickTextInput*>(aName: "textInputObject" ); | 
| 2881 |     QVERIFY(textInputObject != nullptr); | 
| 2882 |     // Delegate is created on demand, and so won't be available immediately.  Focus in or | 
| 2883 |     // setCursorVisible(true) will trigger creation. | 
| 2884 |     QTRY_VERIFY(!textInputObject->findChild<QQuickItem*>("cursorInstance" )); | 
| 2885 |     QVERIFY(!textInputObject->isCursorVisible()); | 
| 2886 |     //Test Delegate gets created | 
| 2887 |     textInputObject->setFocus(true); | 
| 2888 |     QVERIFY(textInputObject->isCursorVisible()); | 
| 2889 |     QQuickItem* delegateObject = textInputObject->findChild<QQuickItem*>(aName: "cursorInstance" ); | 
| 2890 |     QVERIFY(delegateObject); | 
| 2891 |     QCOMPARE(delegateObject->property("localProperty" ).toString(), QString("Hello" )); | 
| 2892 |     //Test Delegate gets moved | 
| 2893 |     for (int i=0; i<= textInputObject->text().length(); i++) { | 
| 2894 |         textInputObject->setCursorPosition(i); | 
| 2895 |         QCOMPARE(textInputObject->cursorRectangle().x(), delegateObject->x()); | 
| 2896 |         QCOMPARE(textInputObject->cursorRectangle().y(), delegateObject->y()); | 
| 2897 |     } | 
| 2898 |     textInputObject->setCursorPosition(0); | 
| 2899 |     QCOMPARE(textInputObject->cursorRectangle().x(), delegateObject->x()); | 
| 2900 |     QCOMPARE(textInputObject->cursorRectangle().y(), delegateObject->y()); | 
| 2901 |  | 
| 2902 |     // Test delegate gets moved on mouse press. | 
| 2903 |     textInputObject->setSelectByMouse(true); | 
| 2904 |     textInputObject->setCursorPosition(0); | 
| 2905 |     const QPoint point1 = textInputObject->positionToRectangle(pos: 5).center().toPoint(); | 
| 2906 |     QTest::qWait(ms: 400);  //ensure this isn't treated as a double-click | 
| 2907 |     QTest::mouseClick(window: &view, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: point1); | 
| 2908 |     QTest::qWait(ms: 50); | 
| 2909 |     QTRY_VERIFY(textInputObject->cursorPosition() != 0); | 
| 2910 |     QCOMPARE(textInputObject->cursorRectangle().x(), delegateObject->x()); | 
| 2911 |     QCOMPARE(textInputObject->cursorRectangle().y(), delegateObject->y()); | 
| 2912 |  | 
| 2913 |     // Test delegate gets moved on mouse drag | 
| 2914 |     textInputObject->setCursorPosition(0); | 
| 2915 |     const QPoint point2 = textInputObject->positionToRectangle(pos: 10).center().toPoint(); | 
| 2916 |     QTest::qWait(ms: 400);  //ensure this isn't treated as a double-click | 
| 2917 |     QTest::mousePress(window: &view, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: point1); | 
| 2918 |     QMouseEvent mv(QEvent::MouseMove, point2, Qt::LeftButton, Qt::LeftButton,Qt::NoModifier); | 
| 2919 |     QGuiApplication::sendEvent(receiver: &view, event: &mv); | 
| 2920 |     QTest::mouseRelease(window: &view, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: point2); | 
| 2921 |     QTest::qWait(ms: 50); | 
| 2922 |     QTRY_COMPARE(textInputObject->cursorRectangle().x(), delegateObject->x()); | 
| 2923 |     QCOMPARE(textInputObject->cursorRectangle().y(), delegateObject->y()); | 
| 2924 |  | 
| 2925 |     textInputObject->setReadOnly(true); | 
| 2926 |     textInputObject->setCursorPosition(0); | 
| 2927 |     QTest::qWait(ms: 400);  //ensure this isn't treated as a double-click | 
| 2928 |     QTest::mouseClick(window: &view, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: textInputObject->positionToRectangle(pos: 5).center().toPoint()); | 
| 2929 |     QTest::qWait(ms: 50); | 
| 2930 |     QTRY_VERIFY(textInputObject->cursorPosition() != 0); | 
| 2931 |     QCOMPARE(textInputObject->cursorRectangle().x(), delegateObject->x()); | 
| 2932 |     QCOMPARE(textInputObject->cursorRectangle().y(), delegateObject->y()); | 
| 2933 |  | 
| 2934 |     textInputObject->setCursorPosition(0); | 
| 2935 |     QTest::qWait(ms: 400);  //ensure this isn't treated as a double-click | 
| 2936 |     QTest::mouseClick(window: &view, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: textInputObject->positionToRectangle(pos: 5).center().toPoint()); | 
| 2937 |     QTest::qWait(ms: 50); | 
| 2938 |     QTRY_VERIFY(textInputObject->cursorPosition() != 0); | 
| 2939 |     QCOMPARE(textInputObject->cursorRectangle().x(), delegateObject->x()); | 
| 2940 |     QCOMPARE(textInputObject->cursorRectangle().y(), delegateObject->y()); | 
| 2941 |  | 
| 2942 |     textInputObject->setCursorPosition(0); | 
| 2943 |     QCOMPARE(textInputObject->cursorRectangle().x(), delegateObject->x()); | 
| 2944 |     QCOMPARE(textInputObject->cursorRectangle().y(), delegateObject->y()); | 
| 2945 |  | 
| 2946 |     textInputObject->setReadOnly(false); | 
| 2947 |  | 
| 2948 |     // Delegate moved when text is entered | 
| 2949 |     textInputObject->setText(QString()); | 
| 2950 |     for (int i = 0; i < 20; ++i) { | 
| 2951 |         QTest::keyClick(window: &view, key: Qt::Key_A); | 
| 2952 |         QCOMPARE(textInputObject->cursorRectangle().x(), delegateObject->x()); | 
| 2953 |         QCOMPARE(textInputObject->cursorRectangle().y(), delegateObject->y()); | 
| 2954 |     } | 
| 2955 |  | 
| 2956 |     // Delegate moved when text is entered by im. | 
| 2957 |     textInputObject->setText(QString()); | 
| 2958 |     for (int i = 0; i < 20; ++i) { | 
| 2959 |         QInputMethodEvent event; | 
| 2960 |         event.setCommitString(commitString: "w" ); | 
| 2961 |         QGuiApplication::sendEvent(receiver: textInputObject, event: &event); | 
| 2962 |         QCOMPARE(textInputObject->cursorRectangle().x(), delegateObject->x()); | 
| 2963 |         QCOMPARE(textInputObject->cursorRectangle().y(), delegateObject->y()); | 
| 2964 |     } | 
| 2965 |     // Delegate moved when text is removed by im. | 
| 2966 |     for (int i = 19; i > 1; --i) { | 
| 2967 |         QInputMethodEvent event; | 
| 2968 |         event.setCommitString(commitString: QString(), replaceFrom: -1, replaceLength: 1); | 
| 2969 |         QGuiApplication::sendEvent(receiver: textInputObject, event: &event); | 
| 2970 |         QCOMPARE(textInputObject->cursorRectangle().x(), delegateObject->x()); | 
| 2971 |         QCOMPARE(textInputObject->cursorRectangle().y(), delegateObject->y()); | 
| 2972 |     } | 
| 2973 |     {   // Delegate moved the text is changed in place by im. | 
| 2974 |         QInputMethodEvent event; | 
| 2975 |         event.setCommitString(commitString: "i" , replaceFrom: -1, replaceLength: 1); | 
| 2976 |         QGuiApplication::sendEvent(receiver: textInputObject, event: &event); | 
| 2977 |         QCOMPARE(textInputObject->cursorRectangle().x(), delegateObject->x()); | 
| 2978 |         QCOMPARE(textInputObject->cursorRectangle().y(), delegateObject->y()); | 
| 2979 |     } | 
| 2980 |  | 
| 2981 |     //Test Delegate gets deleted | 
| 2982 |     textInputObject->setCursorDelegate(nullptr); | 
| 2983 |     QVERIFY(!textInputObject->findChild<QQuickItem*>("cursorInstance" )); | 
| 2984 | } | 
| 2985 |  | 
| 2986 | void tst_qquicktextinput::remoteCursorDelegate() | 
| 2987 | { | 
| 2988 |     ThreadedTestHTTPServer server(dataDirectory(), TestHTTPServer::Delay); | 
| 2989 |     QQuickView view; | 
| 2990 |  | 
| 2991 |     QQmlComponent component(view.engine(), server.url(documentPath: "/RemoteCursor.qml" )); | 
| 2992 |  | 
| 2993 |     view.rootContext()->setContextProperty("contextDelegate" , &component); | 
| 2994 |     view.setSource(testFileUrl(fileName: "cursorTestRemote.qml" )); | 
| 2995 |     view.show(); | 
| 2996 |     view.requestActivate(); | 
| 2997 |     QVERIFY(QTest::qWaitForWindowActive(&view)); | 
| 2998 |     QQuickTextInput *textInputObject = view.rootObject()->findChild<QQuickTextInput*>(aName: "textInputObject" ); | 
| 2999 |     QVERIFY(textInputObject != nullptr); | 
| 3000 |  | 
| 3001 |     // Delegate is created on demand, and so won't be available immediately.  Focus in or | 
| 3002 |     // setCursorVisible(true) will trigger creation. | 
| 3003 |     QTRY_VERIFY(!textInputObject->findChild<QQuickItem*>("cursorInstance" )); | 
| 3004 |     QVERIFY(!textInputObject->isCursorVisible()); | 
| 3005 |  | 
| 3006 |     textInputObject->setFocus(true); | 
| 3007 |     QVERIFY(textInputObject->isCursorVisible()); | 
| 3008 |  | 
| 3009 |     // Wait for component to load. | 
| 3010 |     QTRY_COMPARE(component.status(), QQmlComponent::Ready); | 
| 3011 |     QVERIFY(textInputObject->findChild<QQuickItem*>("cursorInstance" )); | 
| 3012 | } | 
| 3013 |  | 
| 3014 | void tst_qquicktextinput::cursorVisible() | 
| 3015 | { | 
| 3016 |     QSKIP("This test is unstable" ); | 
| 3017 |     QQuickTextInput input; | 
| 3018 |     input.componentComplete(); | 
| 3019 |     QSignalSpy spy(&input, SIGNAL(cursorVisibleChanged(bool))); | 
| 3020 |  | 
| 3021 |     QQuickView view(testFileUrl(fileName: "cursorVisible.qml" )); | 
| 3022 |     view.show(); | 
| 3023 |     view.requestActivate(); | 
| 3024 |     QVERIFY(QTest::qWaitForWindowActive(&view)); | 
| 3025 |  | 
| 3026 |     QCOMPARE(input.isCursorVisible(), false); | 
| 3027 |  | 
| 3028 |     input.setCursorVisible(true); | 
| 3029 |     QCOMPARE(input.isCursorVisible(), true); | 
| 3030 |     QCOMPARE(spy.count(), 1); | 
| 3031 |  | 
| 3032 |     input.setCursorVisible(false); | 
| 3033 |     QCOMPARE(input.isCursorVisible(), false); | 
| 3034 |     QCOMPARE(spy.count(), 2); | 
| 3035 |  | 
| 3036 |     input.setFocus(true); | 
| 3037 |     QCOMPARE(input.isCursorVisible(), false); | 
| 3038 |     QCOMPARE(spy.count(), 2); | 
| 3039 |  | 
| 3040 |     input.setParentItem(view.rootObject()); | 
| 3041 |     QCOMPARE(input.isCursorVisible(), true); | 
| 3042 |     QCOMPARE(spy.count(), 3); | 
| 3043 |  | 
| 3044 |     input.setFocus(false); | 
| 3045 |     QCOMPARE(input.isCursorVisible(), false); | 
| 3046 |     QCOMPARE(spy.count(), 4); | 
| 3047 |  | 
| 3048 |     input.setFocus(true); | 
| 3049 |     QCOMPARE(input.isCursorVisible(), true); | 
| 3050 |     QCOMPARE(spy.count(), 5); | 
| 3051 |  | 
| 3052 |     QQuickView alternateView; | 
| 3053 |     alternateView.show(); | 
| 3054 |     alternateView.requestActivate(); | 
| 3055 |     QVERIFY(QTest::qWaitForWindowActive(&alternateView)); | 
| 3056 |  | 
| 3057 |     QCOMPARE(input.isCursorVisible(), false); | 
| 3058 |     QCOMPARE(spy.count(), 6); | 
| 3059 |  | 
| 3060 |     view.requestActivate(); | 
| 3061 |     QVERIFY(QTest::qWaitForWindowActive(&view)); | 
| 3062 |     QCOMPARE(input.isCursorVisible(), true); | 
| 3063 |     QCOMPARE(spy.count(), 7); | 
| 3064 |  | 
| 3065 |     {   // Cursor attribute with 0 length hides cursor. | 
| 3066 |         QInputMethodEvent ev(QString(), QList<QInputMethodEvent::Attribute>() | 
| 3067 |                 << QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, 0, 0, QVariant())); | 
| 3068 |         QCoreApplication::sendEvent(receiver: &input, event: &ev); | 
| 3069 |     } | 
| 3070 |     QCOMPARE(input.isCursorVisible(), false); | 
| 3071 |     QCOMPARE(spy.count(), 8); | 
| 3072 |  | 
| 3073 |     {   // Cursor attribute with non zero length shows cursor. | 
| 3074 |         QInputMethodEvent ev(QString(), QList<QInputMethodEvent::Attribute>() | 
| 3075 |                 << QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, 0, 1, QVariant())); | 
| 3076 |         QCoreApplication::sendEvent(receiver: &input, event: &ev); | 
| 3077 |     } | 
| 3078 |     QCOMPARE(input.isCursorVisible(), true); | 
| 3079 |     QCOMPARE(spy.count(), 9); | 
| 3080 |  | 
| 3081 |     {   // If the cursor is hidden by the input method and the text is changed it should be visible again. | 
| 3082 |         QInputMethodEvent ev(QString(), QList<QInputMethodEvent::Attribute>() | 
| 3083 |                 << QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, 0, 0, QVariant())); | 
| 3084 |         QCoreApplication::sendEvent(receiver: &input, event: &ev); | 
| 3085 |     } | 
| 3086 |     QCOMPARE(input.isCursorVisible(), false); | 
| 3087 |     QCOMPARE(spy.count(), 10); | 
| 3088 |  | 
| 3089 |     input.setText("something" ); | 
| 3090 |     QCOMPARE(input.isCursorVisible(), true); | 
| 3091 |     QCOMPARE(spy.count(), 11); | 
| 3092 |  | 
| 3093 |     {   // If the cursor is hidden by the input method and the cursor position is changed it should be visible again. | 
| 3094 |         QInputMethodEvent ev(QString(), QList<QInputMethodEvent::Attribute>() | 
| 3095 |                 << QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, 0, 0, QVariant())); | 
| 3096 |         QCoreApplication::sendEvent(receiver: &input, event: &ev); | 
| 3097 |     } | 
| 3098 |     QCOMPARE(input.isCursorVisible(), false); | 
| 3099 |     QCOMPARE(spy.count(), 12); | 
| 3100 |  | 
| 3101 |     input.setCursorPosition(5); | 
| 3102 |     QCOMPARE(input.isCursorVisible(), true); | 
| 3103 |     QCOMPARE(spy.count(), 13); | 
| 3104 | } | 
| 3105 |  | 
| 3106 | void tst_qquicktextinput::cursorRectangle_data() | 
| 3107 | { | 
| 3108 |     const quint16 arabic_str[] = { 0x0638, 0x0643, 0x00646, 0x0647, 0x0633, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0638, 0x0643, 0x00646, 0x0647, 0x0633, 0x0647}; | 
| 3109 |  | 
| 3110 |     QTest::addColumn<QString>(name: "text" ); | 
| 3111 |     QTest::addColumn<int>(name: "positionAtWidth" ); | 
| 3112 |     QTest::addColumn<int>(name: "wrapPosition" ); | 
| 3113 |     QTest::addColumn<QString>(name: "shortText" ); | 
| 3114 |     QTest::addColumn<bool>(name: "leftToRight" ); | 
| 3115 |  | 
| 3116 |     QTest::newRow(dataTag: "left to right" ) | 
| 3117 |             << "Hello      World!"  << 5 << 11 | 
| 3118 |             << "Hi"  | 
| 3119 |             << true; | 
| 3120 |     QTest::newRow(dataTag: "right to left" ) | 
| 3121 |             << QString::fromUtf16(arabic_str, size: lengthOf(arabic_str)) << 5 << 11 | 
| 3122 |             << QString::fromUtf16(arabic_str, size: 3) | 
| 3123 |             << false; | 
| 3124 | } | 
| 3125 |  | 
| 3126 | #if QT_CONFIG(im) | 
| 3127 | #define COMPARE_INPUT_METHOD_QUERY(type, input, property, method, result) \ | 
| 3128 |     QCOMPARE((type) input->inputMethodQuery(property).method(), result); | 
| 3129 | #else | 
| 3130 | #define COMPARE_INPUT_METHOD_QUERY(type, input, property, method, result) \ | 
| 3131 |     qt_noop() | 
| 3132 | #endif | 
| 3133 |  | 
| 3134 | void tst_qquicktextinput::cursorRectangle() | 
| 3135 | { | 
| 3136 |     QFETCH(QString, text); | 
| 3137 |     QFETCH(int, positionAtWidth); | 
| 3138 |     QFETCH(int, wrapPosition); | 
| 3139 |     QFETCH(QString, shortText); | 
| 3140 |     QFETCH(bool, leftToRight); | 
| 3141 |  | 
| 3142 |     QQuickTextInput input; | 
| 3143 |     input.setText(text); | 
| 3144 |     input.componentComplete(); | 
| 3145 |  | 
| 3146 |     QTextLayout layout(text); | 
| 3147 |     layout.setFont(input.font()); | 
| 3148 |     if (!qmlDisableDistanceField()) { | 
| 3149 |         QTextOption option; | 
| 3150 |         option.setUseDesignMetrics(true); | 
| 3151 |         layout.setTextOption(option); | 
| 3152 |     } | 
| 3153 |     layout.beginLayout(); | 
| 3154 |     QTextLine line = layout.createLine(); | 
| 3155 |     layout.endLayout(); | 
| 3156 |  | 
| 3157 |     qreal offset = 0; | 
| 3158 |     if (leftToRight) { | 
| 3159 |         input.setWidth(line.cursorToX(cursorPos: positionAtWidth, edge: QTextLine::Leading)); | 
| 3160 |     } else { | 
| 3161 |         input.setWidth(line.horizontalAdvance() - line.cursorToX(cursorPos: positionAtWidth, edge: QTextLine::Leading)); | 
| 3162 |         offset = line.horizontalAdvance() - input.width(); | 
| 3163 |     } | 
| 3164 |     input.setHeight(qCeil(v: line.height() * 3 / 2)); | 
| 3165 |  | 
| 3166 |     QRectF r; | 
| 3167 |  | 
| 3168 |     for (int i = 0; i <= positionAtWidth; ++i) { | 
| 3169 |         input.setCursorPosition(i); | 
| 3170 |         r = input.cursorRectangle(); | 
| 3171 |  | 
| 3172 |         QCOMPARE(r.left(), line.cursorToX(i, QTextLine::Leading) - offset); | 
| 3173 |         COMPARE_INPUT_METHOD_QUERY(QRectF, (&input), Qt::ImCursorRectangle, toRectF, r); | 
| 3174 |         QCOMPARE(input.positionToRectangle(i), r); | 
| 3175 |     } | 
| 3176 |  | 
| 3177 |     // Check the cursor rectangle remains within the input bounding rect when auto scrolling. | 
| 3178 |     QCOMPARE(r.left(), leftToRight ? input.width() : 0); | 
| 3179 |  | 
| 3180 |     for (int i = positionAtWidth + 1; i < text.length(); ++i) { | 
| 3181 |         input.setCursorPosition(i); | 
| 3182 |         QCOMPARE(r, input.cursorRectangle()); | 
| 3183 |         COMPARE_INPUT_METHOD_QUERY(QRectF, (&input), Qt::ImCursorRectangle, toRectF, r); | 
| 3184 |         QCOMPARE(input.positionToRectangle(i), r); | 
| 3185 |     } | 
| 3186 |  | 
| 3187 |     for (int i = text.length() - 2; i >= 0; --i) { | 
| 3188 |         input.setCursorPosition(i); | 
| 3189 |         r = input.cursorRectangle(); | 
| 3190 |         QCOMPARE(r.top(), 0.); | 
| 3191 |         if (leftToRight) { | 
| 3192 |             QVERIFY(r.right() >= 0); | 
| 3193 |         } else { | 
| 3194 |             QVERIFY(r.left() <= input.width()); | 
| 3195 |         } | 
| 3196 |         COMPARE_INPUT_METHOD_QUERY(QRectF, (&input), Qt::ImCursorRectangle, toRectF, r); | 
| 3197 |         QCOMPARE(input.positionToRectangle(i), r); | 
| 3198 |     } | 
| 3199 |  | 
| 3200 |     // Check position with word wrap. | 
| 3201 |     input.setWrapMode(QQuickTextInput::WordWrap); | 
| 3202 |     input.setAutoScroll(false); | 
| 3203 |     for (int i = 0; i < wrapPosition; ++i) { | 
| 3204 |         input.setCursorPosition(i); | 
| 3205 |         r = input.cursorRectangle(); | 
| 3206 |  | 
| 3207 |         QCOMPARE(r.left(), line.cursorToX(i, QTextLine::Leading) - offset); | 
| 3208 |         QCOMPARE(r.top(), 0.); | 
| 3209 |         COMPARE_INPUT_METHOD_QUERY(QRectF, (&input), Qt::ImCursorRectangle, toRectF, r); | 
| 3210 |         QCOMPARE(input.positionToRectangle(i), r); | 
| 3211 |     } | 
| 3212 |  | 
| 3213 |     input.setCursorPosition(wrapPosition); | 
| 3214 |     r = input.cursorRectangle(); | 
| 3215 |     if (leftToRight) { | 
| 3216 |         QCOMPARE(r.left(), 0.); | 
| 3217 |     } else { | 
| 3218 |         QCOMPARE(r.left(), input.width()); | 
| 3219 |     } | 
| 3220 |     // we can't be exact here, as the space character can have a different ascent/descent from the arabic chars | 
| 3221 |     // this then leads to different line heights between the wrapped and non wrapped texts | 
| 3222 |     QVERIFY(r.top() >= line.height() - 5); | 
| 3223 |     COMPARE_INPUT_METHOD_QUERY(QRectF, (&input), Qt::ImCursorRectangle, toRectF, r); | 
| 3224 |     QCOMPARE(input.positionToRectangle(11), r); | 
| 3225 |  | 
| 3226 |     for (int i = wrapPosition + 1; i < text.length(); ++i) { | 
| 3227 |         input.setCursorPosition(i); | 
| 3228 |         r = input.cursorRectangle(); | 
| 3229 |         QVERIFY(r.top() >= line.height() - 5); | 
| 3230 |         COMPARE_INPUT_METHOD_QUERY(QRectF, (&input), Qt::ImCursorRectangle, toRectF, r); | 
| 3231 |         QCOMPARE(input.positionToRectangle(i), r); | 
| 3232 |     } | 
| 3233 |  | 
| 3234 |     // Check vertical scrolling with word wrap. | 
| 3235 |     input.setAutoScroll(true); | 
| 3236 |     for (int i = 0; i <= positionAtWidth; ++i) { | 
| 3237 |         input.setCursorPosition(i); | 
| 3238 |         r = input.cursorRectangle(); | 
| 3239 |  | 
| 3240 |         QCOMPARE(r.left(), line.cursorToX(i, QTextLine::Leading) - offset); | 
| 3241 |         QCOMPARE(r.top(), 0.); | 
| 3242 |         COMPARE_INPUT_METHOD_QUERY(QRectF, (&input), Qt::ImCursorRectangle, toRectF, r); | 
| 3243 |         QCOMPARE(input.positionToRectangle(i), r); | 
| 3244 |     } | 
| 3245 |  | 
| 3246 |     // Whitespace doesn't wrap, so scroll horizontally until the until the cursor | 
| 3247 |     // reaches the next non-whitespace character. | 
| 3248 |     QCOMPARE(r.left(), leftToRight ? input.width() : 0); | 
| 3249 |     for (int i = positionAtWidth + 1; i < wrapPosition && leftToRight; ++i) { | 
| 3250 |         input.setCursorPosition(i); | 
| 3251 |         QCOMPARE(r, input.cursorRectangle()); | 
| 3252 |         COMPARE_INPUT_METHOD_QUERY(QRectF, (&input), Qt::ImCursorRectangle, toRectF, r); | 
| 3253 |         QCOMPARE(input.positionToRectangle(i), r); | 
| 3254 |     } | 
| 3255 |  | 
| 3256 |     input.setCursorPosition(wrapPosition); | 
| 3257 |     r = input.cursorRectangle(); | 
| 3258 |     if (leftToRight) { | 
| 3259 |         QCOMPARE(r.left(), 0.); | 
| 3260 |     } else { | 
| 3261 |         QCOMPARE(r.left(), input.width()); | 
| 3262 |     } | 
| 3263 |     QVERIFY(r.bottom() >= input.height()); | 
| 3264 |     COMPARE_INPUT_METHOD_QUERY(QRectF, (&input), Qt::ImCursorRectangle, toRectF, r); | 
| 3265 |     QCOMPARE(input.positionToRectangle(11), r); | 
| 3266 |  | 
| 3267 |     for (int i = wrapPosition + 1; i < text.length(); ++i) { | 
| 3268 |         input.setCursorPosition(i); | 
| 3269 |         r = input.cursorRectangle(); | 
| 3270 |         QVERIFY(r.bottom() >= input.height()); | 
| 3271 |         COMPARE_INPUT_METHOD_QUERY(QRectF, (&input), Qt::ImCursorRectangle, toRectF, r); | 
| 3272 |         QCOMPARE(input.positionToRectangle(i), r); | 
| 3273 |     } | 
| 3274 |  | 
| 3275 |     for (int i = text.length() - 2; i >= wrapPosition; --i) { | 
| 3276 |         input.setCursorPosition(i); | 
| 3277 |         r = input.cursorRectangle(); | 
| 3278 |         QVERIFY(r.bottom() >= input.height()); | 
| 3279 |         COMPARE_INPUT_METHOD_QUERY(QRectF, (&input), Qt::ImCursorRectangle, toRectF, r); | 
| 3280 |         QCOMPARE(input.positionToRectangle(i), r); | 
| 3281 |     } | 
| 3282 |  | 
| 3283 |     input.setCursorPosition(wrapPosition - 1); | 
| 3284 |     r = input.cursorRectangle(); | 
| 3285 |     QCOMPARE(r.top(), 0.); | 
| 3286 |     QCOMPARE(r.left(), leftToRight ? input.width() : 0); | 
| 3287 |     COMPARE_INPUT_METHOD_QUERY(QRectF, (&input), Qt::ImCursorRectangle, toRectF, r); | 
| 3288 |     QCOMPARE(input.positionToRectangle(10), r); | 
| 3289 |  | 
| 3290 |     for (int i = wrapPosition - 2; i >= positionAtWidth + 1; --i) { | 
| 3291 |         input.setCursorPosition(i); | 
| 3292 |         QCOMPARE(r, input.cursorRectangle()); | 
| 3293 |         COMPARE_INPUT_METHOD_QUERY(QRectF, (&input), Qt::ImCursorRectangle, toRectF, r); | 
| 3294 |         QCOMPARE(input.positionToRectangle(i), r); | 
| 3295 |     } | 
| 3296 |  | 
| 3297 |     for (int i = positionAtWidth; i >= 0; --i) { | 
| 3298 |         input.setCursorPosition(i); | 
| 3299 |         r = input.cursorRectangle(); | 
| 3300 |         QCOMPARE(r.top(), 0.); | 
| 3301 |         COMPARE_INPUT_METHOD_QUERY(QRectF, (&input), Qt::ImCursorRectangle, toRectF, r); | 
| 3302 |         QCOMPARE(input.positionToRectangle(i), r); | 
| 3303 |     } | 
| 3304 |  | 
| 3305 |     input.setText(shortText); | 
| 3306 |     input.setHAlign(leftToRight ? QQuickTextInput::AlignRight : QQuickTextInput::AlignLeft); | 
| 3307 |     r = input.cursorRectangle(); | 
| 3308 |     QCOMPARE(r.left(), leftToRight ? input.width() : 0); | 
| 3309 |  | 
| 3310 |     QSignalSpy cursorRectangleSpy(&input, SIGNAL(cursorRectangleChanged())); | 
| 3311 |  | 
| 3312 |     QString widerText = shortText; | 
| 3313 |     widerText[1] = 'W'; // Assumes shortText is at least two characters long. | 
| 3314 |     input.setText(widerText); | 
| 3315 |  | 
| 3316 |     QCOMPARE(cursorRectangleSpy.count(), 1); | 
| 3317 | } | 
| 3318 |  | 
| 3319 | void tst_qquicktextinput::readOnly() | 
| 3320 | { | 
| 3321 |     QQuickView window(testFileUrl(fileName: "readOnly.qml" )); | 
| 3322 |     window.show(); | 
| 3323 |     window.requestActivate(); | 
| 3324 |  | 
| 3325 |     QVERIFY(window.rootObject() != nullptr); | 
| 3326 |  | 
| 3327 |     QQuickTextInput *input = qobject_cast<QQuickTextInput *>(object: qvariant_cast<QObject *>(v: window.rootObject()->property(name: "myInput" ))); | 
| 3328 |  | 
| 3329 |     QVERIFY(input != nullptr); | 
| 3330 |     QTRY_VERIFY(input->hasActiveFocus()); | 
| 3331 |     QVERIFY(input->isReadOnly()); | 
| 3332 |     QVERIFY(!input->isCursorVisible()); | 
| 3333 |     QString initial = input->text(); | 
| 3334 |     for (int k=Qt::Key_0; k<=Qt::Key_Z; k++) | 
| 3335 |         simulateKey(&window, key: k); | 
| 3336 |     simulateKey(&window, key: Qt::Key_Return); | 
| 3337 |     simulateKey(&window, key: Qt::Key_Space); | 
| 3338 |     simulateKey(&window, key: Qt::Key_Escape); | 
| 3339 |     QCOMPARE(input->text(), initial); | 
| 3340 |  | 
| 3341 |     input->setCursorPosition(3); | 
| 3342 |     input->setReadOnly(false); | 
| 3343 |     QCOMPARE(input->isReadOnly(), false); | 
| 3344 |     QCOMPARE(input->cursorPosition(), input->text().length()); | 
| 3345 |     QVERIFY(input->isCursorVisible()); | 
| 3346 | } | 
| 3347 |  | 
| 3348 | void tst_qquicktextinput::echoMode() | 
| 3349 | { | 
| 3350 |     QQuickView window(testFileUrl(fileName: "echoMode.qml" )); | 
| 3351 |     window.show(); | 
| 3352 |     window.requestActivate(); | 
| 3353 |     QVERIFY(QTest::qWaitForWindowActive(&window)); | 
| 3354 |  | 
| 3355 |     QVERIFY(window.rootObject() != nullptr); | 
| 3356 |  | 
| 3357 |     QQuickTextInput *input = qobject_cast<QQuickTextInput *>(object: qvariant_cast<QObject *>(v: window.rootObject()->property(name: "myInput" ))); | 
| 3358 |  | 
| 3359 |     QVERIFY(input != nullptr); | 
| 3360 |     QTRY_VERIFY(input->hasActiveFocus()); | 
| 3361 |     QString initial = input->text(); | 
| 3362 |     Qt::InputMethodHints ref; | 
| 3363 |     QCOMPARE(initial, QLatin1String("ABCDefgh" )); | 
| 3364 |     QCOMPARE(input->echoMode(), QQuickTextInput::Normal); | 
| 3365 |     QCOMPARE(input->displayText(), input->text()); | 
| 3366 |     const QString passwordMaskCharacter = qApp->styleHints()->passwordMaskCharacter(); | 
| 3367 |     //Normal | 
| 3368 |     ref &= ~Qt::ImhHiddenText; | 
| 3369 |     ref &= ~(Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText | Qt::ImhSensitiveData); | 
| 3370 |     COMPARE_INPUT_METHOD_QUERY(Qt::InputMethodHints, input, Qt::ImHints, toInt, ref); | 
| 3371 |     input->setEchoMode(QQuickTextInput::NoEcho); | 
| 3372 |     QCOMPARE(input->text(), initial); | 
| 3373 |     QCOMPARE(input->displayText(), QLatin1String("" )); | 
| 3374 |     QCOMPARE(input->passwordCharacter(), passwordMaskCharacter); | 
| 3375 |     //NoEcho | 
| 3376 |     ref |= Qt::ImhHiddenText; | 
| 3377 |     ref |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText | Qt::ImhSensitiveData); | 
| 3378 |     COMPARE_INPUT_METHOD_QUERY(Qt::InputMethodHints, input, Qt::ImHints, toInt, ref); | 
| 3379 |     input->setEchoMode(QQuickTextInput::Password); | 
| 3380 |     //Password | 
| 3381 |     ref |= Qt::ImhHiddenText; | 
| 3382 |     ref |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText | Qt::ImhSensitiveData); | 
| 3383 |     QCOMPARE(input->text(), initial); | 
| 3384 |     QCOMPARE(input->displayText(), QString(8, passwordMaskCharacter.at(0))); | 
| 3385 |     COMPARE_INPUT_METHOD_QUERY(Qt::InputMethodHints, input, Qt::ImHints, toInt, ref); | 
| 3386 |     // clearing input hints do not clear bits set by echo mode | 
| 3387 |     input->setInputMethodHints(Qt::ImhNone); | 
| 3388 |     COMPARE_INPUT_METHOD_QUERY(Qt::InputMethodHints, input, Qt::ImHints, toInt, ref); | 
| 3389 |     input->setPasswordCharacter(QChar('Q')); | 
| 3390 |     QCOMPARE(input->passwordCharacter(), QLatin1String("Q" )); | 
| 3391 |     QCOMPARE(input->text(), initial); | 
| 3392 |     QCOMPARE(input->displayText(), QLatin1String("QQQQQQQQ" )); | 
| 3393 |     input->setEchoMode(QQuickTextInput::PasswordEchoOnEdit); | 
| 3394 |     //PasswordEchoOnEdit | 
| 3395 |     ref &= ~Qt::ImhHiddenText; | 
| 3396 |     ref |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText | Qt::ImhSensitiveData); | 
| 3397 |     COMPARE_INPUT_METHOD_QUERY(Qt::InputMethodHints, input, Qt::ImHints, toInt, ref); | 
| 3398 |     QCOMPARE(input->text(), initial); | 
| 3399 |     QCOMPARE(input->displayText(), QLatin1String("QQQQQQQQ" )); | 
| 3400 |     COMPARE_INPUT_METHOD_QUERY(QString, input, Qt::ImSurroundingText, toString, | 
| 3401 |                                QLatin1String("QQQQQQQQ" )); | 
| 3402 |     QTest::keyPress(window: &window, key: Qt::Key_A);//Clearing previous entry is part of PasswordEchoOnEdit | 
| 3403 |     QTest::keyRelease(window: &window, key: Qt::Key_A, modifier: Qt::NoModifier ,delay: 10); | 
| 3404 |     QCOMPARE(input->text(), QLatin1String("a" )); | 
| 3405 |     QCOMPARE(input->displayText(), QLatin1String("a" )); | 
| 3406 |     COMPARE_INPUT_METHOD_QUERY(QString, input, Qt::ImSurroundingText, toString, QLatin1String("a" )); | 
| 3407 |     input->setFocus(false); | 
| 3408 |     QVERIFY(!input->hasActiveFocus()); | 
| 3409 |     QCOMPARE(input->displayText(), QLatin1String("Q" )); | 
| 3410 |     COMPARE_INPUT_METHOD_QUERY(QString, input, Qt::ImSurroundingText, toString, QLatin1String("Q" )); | 
| 3411 |     input->setFocus(true); | 
| 3412 |     QVERIFY(input->hasActiveFocus()); | 
| 3413 |     QInputMethodEvent inputEvent; | 
| 3414 |     inputEvent.setCommitString(commitString: initial); | 
| 3415 |     QGuiApplication::sendEvent(receiver: input, event: &inputEvent); | 
| 3416 |     QCOMPARE(input->text(), initial); | 
| 3417 |     QCOMPARE(input->displayText(), initial); | 
| 3418 |     COMPARE_INPUT_METHOD_QUERY(QString, input, Qt::ImSurroundingText, toString, initial); | 
| 3419 | } | 
| 3420 |  | 
| 3421 | void tst_qquicktextinput::passwordEchoDelay() | 
| 3422 | { | 
| 3423 |     int maskDelay = qGuiApp->styleHints()->passwordMaskDelay(); | 
| 3424 |     if (maskDelay <= 0) | 
| 3425 |         QSKIP("No mask delay in use" ); | 
| 3426 |     QQuickView window(testFileUrl(fileName: "echoMode.qml" )); | 
| 3427 |     window.show(); | 
| 3428 |     window.requestActivate(); | 
| 3429 |     QVERIFY(QTest::qWaitForWindowActive(&window)); | 
| 3430 |  | 
| 3431 |     QVERIFY(window.rootObject() != nullptr); | 
| 3432 |  | 
| 3433 |     QQuickTextInput *input = qobject_cast<QQuickTextInput *>(object: qvariant_cast<QObject *>(v: window.rootObject()->property(name: "myInput" ))); | 
| 3434 |     QVERIFY(input); | 
| 3435 |     QVERIFY(input->hasActiveFocus()); | 
| 3436 |  | 
| 3437 |     QQuickItem *cursor = input->findChild<QQuickItem *>(aName: "cursor" ); | 
| 3438 |     QVERIFY(cursor); | 
| 3439 |  | 
| 3440 |     QChar fillChar = qApp->styleHints()->passwordMaskCharacter(); | 
| 3441 |  | 
| 3442 |     input->setEchoMode(QQuickTextInput::Password); | 
| 3443 |     QCOMPARE(input->displayText(), QString(8, fillChar)); | 
| 3444 |     input->setText(QString()); | 
| 3445 |     QCOMPARE(input->displayText(), QString()); | 
| 3446 |  | 
| 3447 |     QTest::keyPress(window: &window, key: '0'); | 
| 3448 |     QTest::keyPress(window: &window, key: '1'); | 
| 3449 |     QTest::keyPress(window: &window, key: '2'); | 
| 3450 |     QCOMPARE(input->displayText(), QString(2, fillChar) + QLatin1Char('2')); | 
| 3451 |     QTest::keyPress(window: &window, key: '3'); | 
| 3452 |     QTest::keyPress(window: &window, key: '4'); | 
| 3453 |     QCOMPARE(input->displayText(), QString(4, fillChar) + QLatin1Char('4')); | 
| 3454 |     QTest::keyPress(window: &window, key: Qt::Key_Backspace); | 
| 3455 |     QCOMPARE(input->displayText(), QString(4, fillChar)); | 
| 3456 |     QTest::keyPress(window: &window, key: '4'); | 
| 3457 |     QCOMPARE(input->displayText(), QString(4, fillChar) + QLatin1Char('4')); | 
| 3458 |     QCOMPARE(input->cursorRectangle().topLeft(), cursor->position()); | 
| 3459 |  | 
| 3460 |     // Verify the last character entered is replaced by the fill character after a delay. | 
| 3461 |     // Also check the cursor position is updated to accomdate a size difference between | 
| 3462 |     // the fill character and the replaced character. | 
| 3463 |     QSignalSpy cursorSpy(input, SIGNAL(cursorRectangleChanged())); | 
| 3464 |     QTest::qWait(ms: maskDelay); | 
| 3465 |     QTRY_COMPARE(input->displayText(), QString(5, fillChar)); | 
| 3466 |     QCOMPARE(cursorSpy.count(), 1); | 
| 3467 |     QCOMPARE(input->cursorRectangle().topLeft(), cursor->position()); | 
| 3468 |  | 
| 3469 |     QTest::keyPress(window: &window, key: '5'); | 
| 3470 |     QCOMPARE(input->displayText(), QString(5, fillChar) + QLatin1Char('5')); | 
| 3471 |     input->setFocus(false); | 
| 3472 |     QVERIFY(!input->hasFocus()); | 
| 3473 |     QCOMPARE(input->displayText(), QString(6, fillChar)); | 
| 3474 |     input->setFocus(true); | 
| 3475 |     QTRY_VERIFY(input->hasFocus()); | 
| 3476 |     QCOMPARE(input->displayText(), QString(6, fillChar)); | 
| 3477 |     QTest::keyPress(window: &window, key: '6'); | 
| 3478 |     QCOMPARE(input->displayText(), QString(6, fillChar) + QLatin1Char('6')); | 
| 3479 |  | 
| 3480 |     QInputMethodEvent ev; | 
| 3481 |     ev.setCommitString(commitString: QLatin1String("7" )); | 
| 3482 |     QGuiApplication::sendEvent(receiver: input, event: &ev); | 
| 3483 |     QCOMPARE(input->displayText(), QString(7, fillChar) + QLatin1Char('7')); | 
| 3484 |  | 
| 3485 |     input->setCursorPosition(3); | 
| 3486 |     QCOMPARE(input->displayText(), QString(7, fillChar) + QLatin1Char('7')); | 
| 3487 |     QTest::keyPress(window: &window, key: 'a'); | 
| 3488 |     QCOMPARE(input->displayText(), QString(3, fillChar) + QLatin1Char('a') + QString(5, fillChar)); | 
| 3489 |     QTest::keyPress(window: &window, key: Qt::Key_Backspace); | 
| 3490 |     QCOMPARE(input->displayText(), QString(8, fillChar)); | 
| 3491 | } | 
| 3492 |  | 
| 3493 |  | 
| 3494 | void tst_qquicktextinput::simulateKey(QWindow *view, int key) | 
| 3495 | { | 
| 3496 |     QKeyEvent press(QKeyEvent::KeyPress, key, nullptr); | 
| 3497 |     QKeyEvent release(QKeyEvent::KeyRelease, key, nullptr); | 
| 3498 |  | 
| 3499 |     QGuiApplication::sendEvent(receiver: view, event: &press); | 
| 3500 |     QGuiApplication::sendEvent(receiver: view, event: &release); | 
| 3501 | } | 
| 3502 |  | 
| 3503 |  | 
| 3504 | void tst_qquicktextinput::focusOnPress() | 
| 3505 | { | 
| 3506 |     QString componentStr = | 
| 3507 |             "import QtQuick 2.0\n"  | 
| 3508 |             "TextInput {\n"  | 
| 3509 |                 "property bool selectOnFocus: false\n"  | 
| 3510 |                 "width: 100; height: 50\n"  | 
| 3511 |                 "activeFocusOnPress: true\n"  | 
| 3512 |                 "text: \"Hello World\"\n"  | 
| 3513 |                 "onFocusChanged: { if (focus && selectOnFocus) selectAll() }"  | 
| 3514 |             " }" ; | 
| 3515 |     QQmlComponent texteditComponent(&engine); | 
| 3516 |     texteditComponent.setData(componentStr.toLatin1(), baseUrl: QUrl()); | 
| 3517 |     QQuickTextInput *textInputObject = qobject_cast<QQuickTextInput*>(object: texteditComponent.create()); | 
| 3518 |     QVERIFY(textInputObject != nullptr); | 
| 3519 |     QCOMPARE(textInputObject->focusOnPress(), true); | 
| 3520 |     QCOMPARE(textInputObject->hasFocus(), false); | 
| 3521 |  | 
| 3522 |     QSignalSpy focusSpy(textInputObject, SIGNAL(focusChanged(bool))); | 
| 3523 |     QSignalSpy activeFocusSpy(textInputObject, SIGNAL(focusChanged(bool))); | 
| 3524 |     QSignalSpy activeFocusOnPressSpy(textInputObject, SIGNAL(activeFocusOnPressChanged(bool))); | 
| 3525 |  | 
| 3526 |     textInputObject->setFocusOnPress(true); | 
| 3527 |     QCOMPARE(textInputObject->focusOnPress(), true); | 
| 3528 |     QCOMPARE(activeFocusOnPressSpy.count(), 0); | 
| 3529 |  | 
| 3530 |     QQuickWindow window; | 
| 3531 |     window.resize(w: 100, h: 50); | 
| 3532 |     textInputObject->setParentItem(window.contentItem()); | 
| 3533 |     window.showNormal(); | 
| 3534 |     window.requestActivate(); | 
| 3535 |     QVERIFY(QTest::qWaitForWindowActive(&window)); | 
| 3536 |  | 
| 3537 |     QCOMPARE(textInputObject->hasFocus(), false); | 
| 3538 |     QCOMPARE(textInputObject->hasActiveFocus(), false); | 
| 3539 |  | 
| 3540 |     Qt::KeyboardModifiers noModifiers = Qt::NoModifier; | 
| 3541 |     QTest::mousePress(window: &window, button: Qt::LeftButton, stateKey: noModifiers); | 
| 3542 |     QGuiApplication::processEvents(); | 
| 3543 |     QCOMPARE(textInputObject->hasFocus(), true); | 
| 3544 |     QCOMPARE(textInputObject->hasActiveFocus(), true); | 
| 3545 |     QCOMPARE(focusSpy.count(), 1); | 
| 3546 |     QCOMPARE(activeFocusSpy.count(), 1); | 
| 3547 |     QCOMPARE(textInputObject->selectedText(), QString()); | 
| 3548 |     QTest::mouseRelease(window: &window, button: Qt::LeftButton, stateKey: noModifiers); | 
| 3549 |  | 
| 3550 |     textInputObject->setFocusOnPress(false); | 
| 3551 |     QCOMPARE(textInputObject->focusOnPress(), false); | 
| 3552 |     QCOMPARE(activeFocusOnPressSpy.count(), 1); | 
| 3553 |  | 
| 3554 |     textInputObject->setFocus(false); | 
| 3555 |     QCOMPARE(textInputObject->hasFocus(), false); | 
| 3556 |     QCOMPARE(textInputObject->hasActiveFocus(), false); | 
| 3557 |     QCOMPARE(focusSpy.count(), 2); | 
| 3558 |     QCOMPARE(activeFocusSpy.count(), 2); | 
| 3559 |  | 
| 3560 |     // Wait for double click timeout to expire before clicking again. | 
| 3561 |     QTest::qWait(ms: 400); | 
| 3562 |     QTest::mousePress(window: &window, button: Qt::LeftButton, stateKey: noModifiers); | 
| 3563 |     QGuiApplication::processEvents(); | 
| 3564 |     QCOMPARE(textInputObject->hasFocus(), false); | 
| 3565 |     QCOMPARE(textInputObject->hasActiveFocus(), false); | 
| 3566 |     QCOMPARE(focusSpy.count(), 2); | 
| 3567 |     QCOMPARE(activeFocusSpy.count(), 2); | 
| 3568 |     QTest::mouseRelease(window: &window, button: Qt::LeftButton, stateKey: noModifiers); | 
| 3569 |  | 
| 3570 |     textInputObject->setFocusOnPress(true); | 
| 3571 |     QCOMPARE(textInputObject->focusOnPress(), true); | 
| 3572 |     QCOMPARE(activeFocusOnPressSpy.count(), 2); | 
| 3573 |  | 
| 3574 |     // Test a selection made in the on(Active)FocusChanged handler isn't overwritten. | 
| 3575 |     textInputObject->setProperty(name: "selectOnFocus" , value: true); | 
| 3576 |  | 
| 3577 |     QTest::qWait(ms: 400); | 
| 3578 |     QTest::mousePress(window: &window, button: Qt::LeftButton, stateKey: noModifiers); | 
| 3579 |     QGuiApplication::processEvents(); | 
| 3580 |     QCOMPARE(textInputObject->hasFocus(), true); | 
| 3581 |     QCOMPARE(textInputObject->hasActiveFocus(), true); | 
| 3582 |     QCOMPARE(focusSpy.count(), 3); | 
| 3583 |     QCOMPARE(activeFocusSpy.count(), 3); | 
| 3584 |     QCOMPARE(textInputObject->selectedText(), textInputObject->text()); | 
| 3585 |     QTest::mouseRelease(window: &window, button: Qt::LeftButton, stateKey: noModifiers); | 
| 3586 | } | 
| 3587 |  | 
| 3588 | void tst_qquicktextinput::focusOnPressOnlyOneItem() | 
| 3589 | { | 
| 3590 |     QQuickView window(testFileUrl(fileName: "focusOnlyOneOnPress.qml" )); | 
| 3591 |     window.show(); | 
| 3592 |     window.requestActivate(); | 
| 3593 |     QVERIFY(QTest::qWaitForWindowActive(&window)); | 
| 3594 |  | 
| 3595 |     QQuickTextInput *first = window.rootObject()->findChild<QQuickTextInput*>(aName: "first" ); | 
| 3596 |     QQuickTextInput *second = window.rootObject()->findChild<QQuickTextInput*>(aName: "second" ); | 
| 3597 |     QQuickTextInput *third = window.rootObject()->findChild<QQuickTextInput*>(aName: "third" ); | 
| 3598 |  | 
| 3599 |     // second is focused onComplete | 
| 3600 |     QVERIFY(second->hasActiveFocus()); | 
| 3601 |  | 
| 3602 |     // and first will try focus when we press it | 
| 3603 |     QVERIFY(first->focusOnPress()); | 
| 3604 |  | 
| 3605 |     // write some text to start editing | 
| 3606 |     QTest::keyClick(window: &window, key: Qt::Key_A); | 
| 3607 |  | 
| 3608 |     // click the first input. naturally, we are giving focus on press, but | 
| 3609 |     // second's editingFinished also attempts to assign focus. lastly, focus | 
| 3610 |     // should bounce back to second from first's editingFinished signal. | 
| 3611 |     // | 
| 3612 |     // this is a contrived example to be sure, but at the end of this, the | 
| 3613 |     // important thing is that only one thing should have activeFocus. | 
| 3614 |     Qt::KeyboardModifiers noModifiers = nullptr; | 
| 3615 |     QTest::mousePress(window: &window, button: Qt::LeftButton, stateKey: noModifiers, pos: QPoint(10, 10)); | 
| 3616 |  | 
| 3617 |     // make sure the press is processed. | 
| 3618 |     QGuiApplication::processEvents(); | 
| 3619 |  | 
| 3620 |     QVERIFY(second->hasActiveFocus()); // make sure it's still there | 
| 3621 |     QVERIFY(!third->hasActiveFocus()); // make sure it didn't end up anywhere else | 
| 3622 |     QVERIFY(!first->hasActiveFocus()); // make sure it didn't end up anywhere else | 
| 3623 |  | 
| 3624 |     // reset state | 
| 3625 |     QTest::mouseRelease(window: &window, button: Qt::LeftButton, stateKey: noModifiers, pos: QPoint(10, 10)); | 
| 3626 | } | 
| 3627 |  | 
| 3628 | void tst_qquicktextinput::openInputPanel() | 
| 3629 | { | 
| 3630 |     PlatformInputContext platformInputContext; | 
| 3631 |     QInputMethodPrivate *inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod()); | 
| 3632 |     inputMethodPrivate->testContext = &platformInputContext; | 
| 3633 |  | 
| 3634 |     QQuickView view(testFileUrl(fileName: "openInputPanel.qml" )); | 
| 3635 |     view.showNormal(); | 
| 3636 |     view.requestActivate(); | 
| 3637 |     QVERIFY(QTest::qWaitForWindowActive(&view)); | 
| 3638 |  | 
| 3639 |     QQuickTextInput *input = qobject_cast<QQuickTextInput *>(object: view.rootObject()); | 
| 3640 |     QVERIFY(input); | 
| 3641 |  | 
| 3642 |     // check default values | 
| 3643 |     QVERIFY(input->focusOnPress()); | 
| 3644 |     QVERIFY(!input->hasActiveFocus()); | 
| 3645 |     QVERIFY(qApp->focusObject() != input); | 
| 3646 |     QCOMPARE(qApp->inputMethod()->isVisible(), false); | 
| 3647 |  | 
| 3648 |     // input panel should open on focus | 
| 3649 |     Qt::KeyboardModifiers noModifiers = nullptr; | 
| 3650 |     QTest::mousePress(window: &view, button: Qt::LeftButton, stateKey: noModifiers); | 
| 3651 |     QGuiApplication::processEvents(); | 
| 3652 |     QVERIFY(input->hasActiveFocus()); | 
| 3653 |     QCOMPARE(qApp->focusObject(), input); | 
| 3654 |     QCOMPARE(qApp->inputMethod()->isVisible(), true); | 
| 3655 |     QTest::mouseRelease(window: &view, button: Qt::LeftButton, stateKey: noModifiers); | 
| 3656 |  | 
| 3657 |     // input panel should be re-opened when pressing already focused TextInput | 
| 3658 |     qApp->inputMethod()->hide(); | 
| 3659 |     QCOMPARE(qApp->inputMethod()->isVisible(), false); | 
| 3660 |     QVERIFY(input->hasActiveFocus()); | 
| 3661 |     QTest::mousePress(window: &view, button: Qt::LeftButton, stateKey: noModifiers); | 
| 3662 |     QGuiApplication::processEvents(); | 
| 3663 |     QCOMPARE(qApp->inputMethod()->isVisible(), true); | 
| 3664 |     QTest::mouseRelease(window: &view, button: Qt::LeftButton, stateKey: noModifiers); | 
| 3665 |  | 
| 3666 |     // input panel should stay visible if focus is lost to another text inputor | 
| 3667 |     QSignalSpy inputPanelVisibilitySpy(qApp->inputMethod(), SIGNAL(visibleChanged())); | 
| 3668 |     QQuickTextInput anotherInput; | 
| 3669 |     anotherInput.componentComplete(); | 
| 3670 |     anotherInput.setParentItem(view.rootObject()); | 
| 3671 |     anotherInput.setFocus(true); | 
| 3672 |     QCOMPARE(qApp->inputMethod()->isVisible(), true); | 
| 3673 |     QCOMPARE(qApp->focusObject(), qobject_cast<QObject*>(&anotherInput)); | 
| 3674 |     QCOMPARE(inputPanelVisibilitySpy.count(), 0); | 
| 3675 |  | 
| 3676 |     anotherInput.setFocus(false); | 
| 3677 |     QVERIFY(qApp->focusObject() != &anotherInput); | 
| 3678 |     QCOMPARE(view.activeFocusItem(), view.contentItem()); | 
| 3679 |     anotherInput.setFocus(true); | 
| 3680 |  | 
| 3681 |     qApp->inputMethod()->hide(); | 
| 3682 |  | 
| 3683 |     // input panel should not be opened if TextInput is read only | 
| 3684 |     input->setReadOnly(true); | 
| 3685 |     input->setFocus(true); | 
| 3686 |     QCOMPARE(qApp->inputMethod()->isVisible(), false); | 
| 3687 |     QTest::mousePress(window: &view, button: Qt::LeftButton, stateKey: noModifiers); | 
| 3688 |     QTest::mouseRelease(window: &view, button: Qt::LeftButton, stateKey: noModifiers); | 
| 3689 |     QGuiApplication::processEvents(); | 
| 3690 |     QCOMPARE(qApp->inputMethod()->isVisible(), false); | 
| 3691 |  | 
| 3692 |     // input panel should not be opened if focusOnPress is set to false | 
| 3693 |     input->setFocusOnPress(false); | 
| 3694 |     input->setFocus(false); | 
| 3695 |     input->setFocus(true); | 
| 3696 |     QCOMPARE(qApp->inputMethod()->isVisible(), false); | 
| 3697 |     QTest::mousePress(window: &view, button: Qt::LeftButton, stateKey: noModifiers); | 
| 3698 |     QTest::mouseRelease(window: &view, button: Qt::LeftButton, stateKey: noModifiers); | 
| 3699 |     QCOMPARE(qApp->inputMethod()->isVisible(), false); | 
| 3700 | } | 
| 3701 |  | 
| 3702 | class MyTextInput : public QQuickTextInput | 
| 3703 | { | 
| 3704 | public: | 
| 3705 |     MyTextInput(QQuickItem *parent = nullptr) : QQuickTextInput(parent) | 
| 3706 |     { | 
| 3707 |         nbPaint = 0; | 
| 3708 |     } | 
| 3709 |     virtual QSGNode *updatePaintNode(QSGNode *node, UpdatePaintNodeData *data) | 
| 3710 |     { | 
| 3711 |        nbPaint++; | 
| 3712 |        return QQuickTextInput::updatePaintNode(oldNode: node, data); | 
| 3713 |     } | 
| 3714 |     int nbPaint; | 
| 3715 | }; | 
| 3716 |  | 
| 3717 | void tst_qquicktextinput::setHAlignClearCache() | 
| 3718 | { | 
| 3719 |     QQuickView view; | 
| 3720 |     view.resize(w: 200, h: 200); | 
| 3721 |     MyTextInput input; | 
| 3722 |     input.setText("Hello world" ); | 
| 3723 |     input.setParentItem(view.contentItem()); | 
| 3724 |     view.show(); | 
| 3725 |     view.requestActivate(); | 
| 3726 |     QVERIFY(QTest::qWaitForWindowActive(&view)); | 
| 3727 |     QTRY_COMPARE(input.nbPaint, 1); | 
| 3728 |     input.setHAlign(QQuickTextInput::AlignRight); | 
| 3729 |     //Changing the alignment should trigger a repaint | 
| 3730 |     QTRY_COMPARE(input.nbPaint, 2); | 
| 3731 | } | 
| 3732 |  | 
| 3733 | void tst_qquicktextinput::focusOutClearSelection() | 
| 3734 | { | 
| 3735 |     QQuickView view; | 
| 3736 |     QQuickTextInput input; | 
| 3737 |     QQuickTextInput input2; | 
| 3738 |     input.setText(QLatin1String("Hello world" )); | 
| 3739 |     input.setFocus(true); | 
| 3740 |     input2.setParentItem(view.contentItem()); | 
| 3741 |     input.setParentItem(view.contentItem()); | 
| 3742 |     input.componentComplete(); | 
| 3743 |     input2.componentComplete(); | 
| 3744 |     view.show(); | 
| 3745 |     view.requestActivate(); | 
| 3746 |     QVERIFY(QTest::qWaitForWindowActive(&view)); | 
| 3747 |     QVERIFY(input.hasActiveFocus()); | 
| 3748 |     input.select(start: 2,end: 5); | 
| 3749 |     //The selection should work | 
| 3750 |     QTRY_COMPARE(input.selectedText(), QLatin1String("llo" )); | 
| 3751 |     input2.setFocus(true); | 
| 3752 |     QGuiApplication::processEvents(); | 
| 3753 |     //The input lost the focus selection should be cleared | 
| 3754 |     QTRY_COMPARE(input.selectedText(), QLatin1String("" )); | 
| 3755 | } | 
| 3756 |  | 
| 3757 | void tst_qquicktextinput::focusOutNotClearSelection() | 
| 3758 | { | 
| 3759 |     QQuickView view; | 
| 3760 |     QQuickTextInput input; | 
| 3761 |     input.setText(QLatin1String("Hello world" )); | 
| 3762 |     input.setFocus(true); | 
| 3763 |     input.setParentItem(view.contentItem()); | 
| 3764 |     input.componentComplete(); | 
| 3765 |     view.show(); | 
| 3766 |     view.requestActivate(); | 
| 3767 |     QVERIFY(QTest::qWaitForWindowActive(&view)); | 
| 3768 |  | 
| 3769 |     QVERIFY(input.hasActiveFocus()); | 
| 3770 |     input.select(start: 2,end: 5); | 
| 3771 |     QTRY_COMPARE(input.selectedText(), QLatin1String("llo" )); | 
| 3772 |  | 
| 3773 |     // The selection should not be cleared when the focus | 
| 3774 |     // out event has one of the following reason: | 
| 3775 |     // Qt::ActiveWindowFocusReason | 
| 3776 |     // Qt::PopupFocusReason | 
| 3777 |  | 
| 3778 |     input.setFocus(focus: false, reason: Qt::ActiveWindowFocusReason); | 
| 3779 |     QGuiApplication::processEvents(); | 
| 3780 |     QTRY_COMPARE(input.selectedText(), QLatin1String("llo" )); | 
| 3781 |     QTRY_COMPARE(input.hasActiveFocus(), false); | 
| 3782 |  | 
| 3783 |     input.setFocus(true); | 
| 3784 |     QTRY_COMPARE(input.hasActiveFocus(), true); | 
| 3785 |  | 
| 3786 |     input.setFocus(focus: false, reason: Qt::PopupFocusReason); | 
| 3787 |     QGuiApplication::processEvents(); | 
| 3788 |     QTRY_COMPARE(input.selectedText(), QLatin1String("llo" )); | 
| 3789 |     // QTBUG-36332 and 36292: a popup window does not take focus | 
| 3790 |     QTRY_COMPARE(input.hasActiveFocus(), true); | 
| 3791 |  | 
| 3792 |     input.setFocus(true); | 
| 3793 |     QTRY_COMPARE(input.hasActiveFocus(), true); | 
| 3794 |  | 
| 3795 |     input.setFocus(focus: false, reason: Qt::OtherFocusReason); | 
| 3796 |     QGuiApplication::processEvents(); | 
| 3797 |     QTRY_COMPARE(input.selectedText(), QLatin1String("" )); | 
| 3798 |     QTRY_COMPARE(input.hasActiveFocus(), false); | 
| 3799 | } | 
| 3800 |  | 
| 3801 | void tst_qquicktextinput::geometrySignals() | 
| 3802 | { | 
| 3803 |     QQmlComponent component(&engine, testFileUrl(fileName: "geometrySignals.qml" )); | 
| 3804 |     QObject *o = component.create(); | 
| 3805 |     QVERIFY(o); | 
| 3806 |     QCOMPARE(o->property("bindingWidth" ).toInt(), 400); | 
| 3807 |     QCOMPARE(o->property("bindingHeight" ).toInt(), 500); | 
| 3808 |     delete o; | 
| 3809 | } | 
| 3810 |  | 
| 3811 | void tst_qquicktextinput::contentSize() | 
| 3812 | { | 
| 3813 |     QString componentStr = "import QtQuick 2.0\nTextInput { width: 75; height: 16; font.pixelSize: 10 }" ; | 
| 3814 |     QQmlComponent textComponent(&engine); | 
| 3815 |     textComponent.setData(componentStr.toLatin1(), baseUrl: QUrl::fromLocalFile(localfile: "" )); | 
| 3816 |     QScopedPointer<QObject> object(textComponent.create()); | 
| 3817 |     QQuickTextInput *textObject = qobject_cast<QQuickTextInput *>(object: object.data()); | 
| 3818 |  | 
| 3819 |     QSignalSpy spy(textObject, SIGNAL(contentSizeChanged())); | 
| 3820 |  | 
| 3821 |     textObject->setText("The quick red fox jumped over the lazy brown dog" ); | 
| 3822 |  | 
| 3823 |     QVERIFY(textObject->contentWidth() > textObject->width()); | 
| 3824 |     QVERIFY(textObject->contentHeight() < textObject->height()); | 
| 3825 |     QCOMPARE(spy.count(), 1); | 
| 3826 |  | 
| 3827 |     textObject->setWrapMode(QQuickTextInput::WordWrap); | 
| 3828 |     QVERIFY(textObject->contentWidth() <= textObject->width()); | 
| 3829 |     QVERIFY(textObject->contentHeight() > textObject->height()); | 
| 3830 |     QCOMPARE(spy.count(), 2); | 
| 3831 |  | 
| 3832 |     textObject->setText("The quickredfoxjumpedoverthe lazy brown dog" ); | 
| 3833 |  | 
| 3834 |     QVERIFY(textObject->contentWidth() > textObject->width()); | 
| 3835 |     QVERIFY(textObject->contentHeight() > textObject->height()); | 
| 3836 |     QCOMPARE(spy.count(), 3); | 
| 3837 |  | 
| 3838 |     textObject->setText("The quick red fox jumped over the lazy brown dog" ); | 
| 3839 |     for (int w = 60; w < 120; ++w) { | 
| 3840 |         textObject->setWidth(w); | 
| 3841 |         QVERIFY(textObject->contentWidth() <= textObject->width()); | 
| 3842 |         QVERIFY(textObject->contentHeight() > textObject->height()); | 
| 3843 |     } | 
| 3844 | } | 
| 3845 |  | 
| 3846 | static void sendPreeditText(QQuickItem *item, const QString &text, int cursor) | 
| 3847 | { | 
| 3848 |     QInputMethodEvent event(text, QList<QInputMethodEvent::Attribute>() | 
| 3849 |             << QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, cursor, text.length(), QVariant())); | 
| 3850 |     QCoreApplication::sendEvent(receiver: item, event: &event); | 
| 3851 | } | 
| 3852 |  | 
| 3853 | void tst_qquicktextinput::preeditAutoScroll() | 
| 3854 | { | 
| 3855 |     QString preeditText = "califragisiticexpialidocious!" ; | 
| 3856 |  | 
| 3857 |     QQuickView view(testFileUrl(fileName: "preeditAutoScroll.qml" )); | 
| 3858 |     view.show(); | 
| 3859 |     view.requestActivate(); | 
| 3860 |     QVERIFY(QTest::qWaitForWindowActive(&view)); | 
| 3861 |     QQuickTextInput *input = qobject_cast<QQuickTextInput *>(object: view.rootObject()); | 
| 3862 |     QVERIFY(input); | 
| 3863 |     QVERIFY(input->hasActiveFocus()); | 
| 3864 |  | 
| 3865 |     input->setWidth(input->implicitWidth()); | 
| 3866 |  | 
| 3867 |     QSignalSpy cursorRectangleSpy(input, SIGNAL(cursorRectangleChanged())); | 
| 3868 |     int cursorRectangleChanges = 0; | 
| 3869 |  | 
| 3870 |     // test the text is scrolled so the preedit is visible. | 
| 3871 |     sendPreeditText(item: input, text: preeditText.mid(position: 0, n: 3), cursor: 1); | 
| 3872 |     QVERIFY(evaluate<int>(input, QString("positionAt(0)" )) != 0); | 
| 3873 |     QVERIFY(input->cursorRectangle().left() < input->boundingRect().width()); | 
| 3874 |     QCOMPARE(cursorRectangleSpy.count(), ++cursorRectangleChanges); | 
| 3875 |  | 
| 3876 |     // test the text is scrolled back when the preedit is removed. | 
| 3877 |     QInputMethodEvent imEvent; | 
| 3878 |     QCoreApplication::sendEvent(receiver: input, event: &imEvent); | 
| 3879 |     QCOMPARE(evaluate<int>(input, QString("positionAt(%1)" ).arg(0)), 0); | 
| 3880 |     QCOMPARE(evaluate<int>(input, QString("positionAt(%1)" ).arg(input->width())), 5); | 
| 3881 |     QCOMPARE(cursorRectangleSpy.count(), ++cursorRectangleChanges); | 
| 3882 |  | 
| 3883 |     QTextLayout layout(preeditText); | 
| 3884 |     layout.setFont(input->font()); | 
| 3885 |     if (!qmlDisableDistanceField()) { | 
| 3886 |         QTextOption option; | 
| 3887 |         option.setUseDesignMetrics(true); | 
| 3888 |         layout.setTextOption(option); | 
| 3889 |     } | 
| 3890 |     layout.beginLayout(); | 
| 3891 |     QTextLine line = layout.createLine(); | 
| 3892 |     layout.endLayout(); | 
| 3893 |  | 
| 3894 |     // test if the preedit is larger than the text input that the | 
| 3895 |     // character preceding the cursor is still visible. | 
| 3896 |     qreal x = input->positionToRectangle(pos: 0).x(); | 
| 3897 |     for (int i = 0; i < 3; ++i) { | 
| 3898 |         sendPreeditText(item: input, text: preeditText, cursor: i + 1); | 
| 3899 |         int width = ceil(x: line.cursorToX(cursorPos: i, edge: QTextLine::Trailing)) - floor(x: line.cursorToX(cursorPos: i)); | 
| 3900 |         QVERIFY(input->cursorRectangle().right() >= width - 3); | 
| 3901 |         QVERIFY(input->positionToRectangle(0).x() < x); | 
| 3902 |         QCOMPARE(cursorRectangleSpy.count(), ++cursorRectangleChanges); | 
| 3903 |         x = input->positionToRectangle(pos: 0).x(); | 
| 3904 |     } | 
| 3905 |     for (int i = 1; i >= 0; --i) { | 
| 3906 |         sendPreeditText(item: input, text: preeditText, cursor: i + 1); | 
| 3907 |         int width = ceil(x: line.cursorToX(cursorPos: i, edge: QTextLine::Trailing)) - floor(x: line.cursorToX(cursorPos: i)); | 
| 3908 |         QVERIFY(input->cursorRectangle().right() >= width - 3); | 
| 3909 |         QVERIFY(input->positionToRectangle(0).x() > x); | 
| 3910 |         QCOMPARE(cursorRectangleSpy.count(), ++cursorRectangleChanges); | 
| 3911 |         x = input->positionToRectangle(pos: 0).x(); | 
| 3912 |     } | 
| 3913 |  | 
| 3914 |     // Test incrementing the preedit cursor doesn't cause further | 
| 3915 |     // scrolling when right most text is visible. | 
| 3916 |     sendPreeditText(item: input, text: preeditText, cursor: preeditText.length() - 3); | 
| 3917 |     QCOMPARE(cursorRectangleSpy.count(), ++cursorRectangleChanges); | 
| 3918 |     x = input->positionToRectangle(pos: 0).x(); | 
| 3919 |     for (int i = 2; i >= 0; --i) { | 
| 3920 |         sendPreeditText(item: input, text: preeditText, cursor: preeditText.length() - i); | 
| 3921 |         QCOMPARE(input->positionToRectangle(0).x(), x); | 
| 3922 |         QCOMPARE(cursorRectangleSpy.count(), ++cursorRectangleChanges); | 
| 3923 |     } | 
| 3924 |     for (int i = 1; i <  3; ++i) { | 
| 3925 |         sendPreeditText(item: input, text: preeditText, cursor: preeditText.length() - i); | 
| 3926 |         QCOMPARE(input->positionToRectangle(0).x(), x); | 
| 3927 |         QCOMPARE(cursorRectangleSpy.count(), ++cursorRectangleChanges); | 
| 3928 |     } | 
| 3929 |  | 
| 3930 |     // Test disabling auto scroll. | 
| 3931 |     QCoreApplication::sendEvent(receiver: input, event: &imEvent); | 
| 3932 |  | 
| 3933 |     input->setAutoScroll(false); | 
| 3934 |     sendPreeditText(item: input, text: preeditText.mid(position: 0, n: 3), cursor: 1); | 
| 3935 |     QCOMPARE(evaluate<int>(input, QString("positionAt(%1)" ).arg(0)), 0); | 
| 3936 |     QCOMPARE(evaluate<int>(input, QString("positionAt(%1)" ).arg(input->width())), 5); | 
| 3937 | } | 
| 3938 |  | 
| 3939 | void tst_qquicktextinput::preeditCursorRectangle() | 
| 3940 | { | 
| 3941 |     QString preeditText = "super" ; | 
| 3942 |  | 
| 3943 |     QQuickView view(testFileUrl(fileName: "inputMethodEvent.qml" )); | 
| 3944 |     view.show(); | 
| 3945 |     view.requestActivate(); | 
| 3946 |     QVERIFY(QTest::qWaitForWindowActive(&view)); | 
| 3947 |     QQuickTextInput *input = qobject_cast<QQuickTextInput *>(object: view.rootObject()); | 
| 3948 |     QVERIFY(input); | 
| 3949 |     QVERIFY(input->hasActiveFocus()); | 
| 3950 |  | 
| 3951 |     QQuickItem *cursor = input->findChild<QQuickItem *>(aName: "cursor" ); | 
| 3952 |     QVERIFY(cursor); | 
| 3953 |  | 
| 3954 |     QRectF currentRect; | 
| 3955 |  | 
| 3956 |     QInputMethodQueryEvent query(Qt::ImCursorRectangle); | 
| 3957 |     QCoreApplication::sendEvent(receiver: input, event: &query); | 
| 3958 |     QRectF previousRect = query.value(query: Qt::ImCursorRectangle).toRectF(); | 
| 3959 |  | 
| 3960 |     // Verify that the micro focus rect is positioned the same for position 0 as | 
| 3961 |     // it would be if there was no preedit text. | 
| 3962 |     sendPreeditText(item: input, text: preeditText, cursor: 0); | 
| 3963 |     QCoreApplication::sendEvent(receiver: input, event: &query); | 
| 3964 |     currentRect = query.value(query: Qt::ImCursorRectangle).toRectF(); | 
| 3965 |     QCOMPARE(currentRect, previousRect); | 
| 3966 |     QCOMPARE(input->cursorRectangle(), currentRect); | 
| 3967 |     QCOMPARE(cursor->position(), currentRect.topLeft()); | 
| 3968 |  | 
| 3969 |     QSignalSpy inputSpy(input, SIGNAL(cursorRectangleChanged())); | 
| 3970 |     QSignalSpy panelSpy(qGuiApp->inputMethod(), SIGNAL(cursorRectangleChanged())); | 
| 3971 |  | 
| 3972 |     // Verify that the micro focus rect moves to the left as the cursor position | 
| 3973 |     // is incremented. | 
| 3974 |     for (int i = 1; i <= 5; ++i) { | 
| 3975 |         sendPreeditText(item: input, text: preeditText, cursor: i); | 
| 3976 |         QCoreApplication::sendEvent(receiver: input, event: &query); | 
| 3977 |         currentRect = query.value(query: Qt::ImCursorRectangle).toRectF(); | 
| 3978 |         QVERIFY(previousRect.left() < currentRect.left()); | 
| 3979 |         QCOMPARE(input->cursorRectangle(), currentRect); | 
| 3980 |         QCOMPARE(cursor->position(), currentRect.topLeft()); | 
| 3981 |         QVERIFY(inputSpy.count() > 0); inputSpy.clear(); | 
| 3982 |         QVERIFY(panelSpy.count() > 0); panelSpy.clear(); | 
| 3983 |         previousRect = currentRect; | 
| 3984 |     } | 
| 3985 |  | 
| 3986 |     // Verify that if the cursor rectangle is updated if the pre-edit text changes | 
| 3987 |     // but the (non-zero) cursor position is the same. | 
| 3988 |     inputSpy.clear(); | 
| 3989 |     panelSpy.clear(); | 
| 3990 |     sendPreeditText(item: input, text: "wwwww" , cursor: 5); | 
| 3991 |     QCoreApplication::sendEvent(receiver: input, event: &query); | 
| 3992 |     currentRect = query.value(query: Qt::ImCursorRectangle).toRectF(); | 
| 3993 |     QCOMPARE(input->cursorRectangle(), currentRect); | 
| 3994 |     QCOMPARE(cursor->position(), currentRect.topLeft()); | 
| 3995 |     QCOMPARE(inputSpy.count(), 1); | 
| 3996 |     QCOMPARE(panelSpy.count(), 1); | 
| 3997 |  | 
| 3998 |     // Verify that if there is no preedit cursor then the micro focus rect is the | 
| 3999 |     // same as it would be if it were positioned at the end of the preedit text. | 
| 4000 |     inputSpy.clear(); | 
| 4001 |     panelSpy.clear(); | 
| 4002 |     {   QInputMethodEvent imEvent(preeditText, QList<QInputMethodEvent::Attribute>()); | 
| 4003 |         QCoreApplication::sendEvent(receiver: input, event: &imEvent); } | 
| 4004 |     QCoreApplication::sendEvent(receiver: input, event: &query); | 
| 4005 |     currentRect = query.value(query: Qt::ImCursorRectangle).toRectF(); | 
| 4006 |     QCOMPARE(currentRect, previousRect); | 
| 4007 |     QCOMPARE(input->cursorRectangle(), currentRect); | 
| 4008 |     QCOMPARE(cursor->position(), currentRect.topLeft()); | 
| 4009 |     QCOMPARE(inputSpy.count(), 1); | 
| 4010 |     QCOMPARE(panelSpy.count(), 1); | 
| 4011 | } | 
| 4012 |  | 
| 4013 | void tst_qquicktextinput::inputContextMouseHandler() | 
| 4014 | { | 
| 4015 |     PlatformInputContext platformInputContext; | 
| 4016 |     QInputMethodPrivate *inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod()); | 
| 4017 |     inputMethodPrivate->testContext = &platformInputContext; | 
| 4018 |  | 
| 4019 |     QString text = "supercalifragisiticexpialidocious!" ; | 
| 4020 |     QQuickView view(testFileUrl(fileName: "inputContext.qml" )); | 
| 4021 |     QQuickTextInput *input = qobject_cast<QQuickTextInput *>(object: view.rootObject()); | 
| 4022 |     QVERIFY(input); | 
| 4023 |  | 
| 4024 |     input->setFocus(true); | 
| 4025 |     input->setText("" ); | 
| 4026 |  | 
| 4027 |     view.showNormal(); | 
| 4028 |     view.requestActivate(); | 
| 4029 |     QVERIFY(QTest::qWaitForWindowActive(&view)); | 
| 4030 |  | 
| 4031 |     QTextLayout layout(text); | 
| 4032 |     layout.setFont(input->font()); | 
| 4033 |     if (!qmlDisableDistanceField()) { | 
| 4034 |         QTextOption option; | 
| 4035 |         option.setUseDesignMetrics(true); | 
| 4036 |         layout.setTextOption(option); | 
| 4037 |     } | 
| 4038 |     layout.beginLayout(); | 
| 4039 |     QTextLine line = layout.createLine(); | 
| 4040 |     layout.endLayout(); | 
| 4041 |  | 
| 4042 |     const qreal x = line.cursorToX(cursorPos: 2, edge: QTextLine::Leading); | 
| 4043 |     const qreal y = line.height() / 2; | 
| 4044 |     QPoint position = QPointF(x, y).toPoint(); | 
| 4045 |  | 
| 4046 |     QInputMethodEvent inputEvent(text.mid(position: 0, n: 5), QList<QInputMethodEvent::Attribute>()); | 
| 4047 |     QGuiApplication::sendEvent(receiver: input, event: &inputEvent); | 
| 4048 |  | 
| 4049 |     QTest::mousePress(window: &view, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: position); | 
| 4050 |     QTest::mouseRelease(window: &view, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: position); | 
| 4051 |     QGuiApplication::processEvents(); | 
| 4052 |  | 
| 4053 |     QCOMPARE(platformInputContext.m_action, QInputMethod::Click); | 
| 4054 |     QCOMPARE(platformInputContext.m_invokeActionCallCount, 1); | 
| 4055 |     QCOMPARE(platformInputContext.m_cursorPosition, 2); | 
| 4056 | } | 
| 4057 |  | 
| 4058 | void tst_qquicktextinput::inputMethodComposing() | 
| 4059 | { | 
| 4060 |     QString text = "supercalifragisiticexpialidocious!" ; | 
| 4061 |  | 
| 4062 |     QQuickView view(testFileUrl(fileName: "inputContext.qml" )); | 
| 4063 |     view.show(); | 
| 4064 |     view.requestActivate(); | 
| 4065 |     QVERIFY(QTest::qWaitForWindowActive(&view)); | 
| 4066 |     QQuickTextInput *input = qobject_cast<QQuickTextInput *>(object: view.rootObject()); | 
| 4067 |     QVERIFY(input); | 
| 4068 |     QVERIFY(input->hasActiveFocus()); | 
| 4069 |     QSignalSpy spy(input, SIGNAL(inputMethodComposingChanged())); | 
| 4070 |  | 
| 4071 |     QCOMPARE(input->isInputMethodComposing(), false); | 
| 4072 |     { | 
| 4073 |         QInputMethodEvent event(text.mid(position: 3), QList<QInputMethodEvent::Attribute>()); | 
| 4074 |         QGuiApplication::sendEvent(receiver: input, event: &event); | 
| 4075 |     } | 
| 4076 |     QCOMPARE(input->isInputMethodComposing(), true); | 
| 4077 |     QCOMPARE(spy.count(), 1); | 
| 4078 |  | 
| 4079 |     { | 
| 4080 |         QInputMethodEvent event(text.mid(position: 12), QList<QInputMethodEvent::Attribute>()); | 
| 4081 |         QGuiApplication::sendEvent(receiver: input, event: &event); | 
| 4082 |     } | 
| 4083 |     QCOMPARE(spy.count(), 1); | 
| 4084 |  | 
| 4085 |     { | 
| 4086 |         QInputMethodEvent event; | 
| 4087 |         QGuiApplication::sendEvent(receiver: input, event: &event); | 
| 4088 |     } | 
| 4089 |     QCOMPARE(input->isInputMethodComposing(), false); | 
| 4090 |     QCOMPARE(spy.count(), 2); | 
| 4091 |  | 
| 4092 |     // Changing the text while not composing doesn't alter the composing state. | 
| 4093 |     input->setText(text.mid(position: 0, n: 16)); | 
| 4094 |     QCOMPARE(input->isInputMethodComposing(), false); | 
| 4095 |     QCOMPARE(spy.count(), 2); | 
| 4096 |  | 
| 4097 |     { | 
| 4098 |         QInputMethodEvent event(text.mid(position: 16), QList<QInputMethodEvent::Attribute>()); | 
| 4099 |         QGuiApplication::sendEvent(receiver: input, event: &event); | 
| 4100 |     } | 
| 4101 |     QCOMPARE(input->isInputMethodComposing(), true); | 
| 4102 |     QCOMPARE(spy.count(), 3); | 
| 4103 |  | 
| 4104 |     // Changing the text while composing cancels composition. | 
| 4105 |     input->setText(text.mid(position: 0, n: 12)); | 
| 4106 |     QCOMPARE(input->isInputMethodComposing(), false); | 
| 4107 |     QCOMPARE(spy.count(), 4); | 
| 4108 |  | 
| 4109 |     {   // Preedit cursor positioned outside (empty) preedit; composing. | 
| 4110 |         QInputMethodEvent event(QString(), QList<QInputMethodEvent::Attribute>() | 
| 4111 |                 << QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, -2, 1, QVariant())); | 
| 4112 |         QGuiApplication::sendEvent(receiver: input, event: &event); | 
| 4113 |     } | 
| 4114 |     QCOMPARE(input->isInputMethodComposing(), true); | 
| 4115 |     QCOMPARE(spy.count(), 5); | 
| 4116 |  | 
| 4117 |  | 
| 4118 |     {   // Cursor hidden; composing | 
| 4119 |         QInputMethodEvent event(QString(), QList<QInputMethodEvent::Attribute>() | 
| 4120 |                 << QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, 0, 0, QVariant())); | 
| 4121 |         QGuiApplication::sendEvent(receiver: input, event: &event); | 
| 4122 |     } | 
| 4123 |     QCOMPARE(input->isInputMethodComposing(), true); | 
| 4124 |     QCOMPARE(spy.count(), 5); | 
| 4125 |  | 
| 4126 |     {   // Default cursor attributes; composing. | 
| 4127 |         QInputMethodEvent event(QString(), QList<QInputMethodEvent::Attribute>() | 
| 4128 |                 << QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, 0, 1, QVariant())); | 
| 4129 |         QGuiApplication::sendEvent(receiver: input, event: &event); | 
| 4130 |     } | 
| 4131 |     QCOMPARE(input->isInputMethodComposing(), true); | 
| 4132 |     QCOMPARE(spy.count(), 5); | 
| 4133 |  | 
| 4134 |     {   // Selections are persisted: not composing | 
| 4135 |         QInputMethodEvent event(QString(), QList<QInputMethodEvent::Attribute>() | 
| 4136 |                 << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, -5, 4, QVariant())); | 
| 4137 |         QGuiApplication::sendEvent(receiver: input, event: &event); | 
| 4138 |     } | 
| 4139 |     QCOMPARE(input->isInputMethodComposing(), false); | 
| 4140 |     QCOMPARE(spy.count(), 6); | 
| 4141 |  | 
| 4142 |     input->setCursorPosition(12); | 
| 4143 |  | 
| 4144 |     {   // Formatting applied; composing. | 
| 4145 |         QTextCharFormat format; | 
| 4146 |         format.setUnderlineStyle(QTextCharFormat::SingleUnderline); | 
| 4147 |         QInputMethodEvent event(QString(), QList<QInputMethodEvent::Attribute>() | 
| 4148 |                 << QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, -5, 4, format)); | 
| 4149 |         QGuiApplication::sendEvent(receiver: input, event: &event); | 
| 4150 |     } | 
| 4151 |     QCOMPARE(input->isInputMethodComposing(), true); | 
| 4152 |     QCOMPARE(spy.count(), 7); | 
| 4153 |  | 
| 4154 |     { | 
| 4155 |         QInputMethodEvent event; | 
| 4156 |         QGuiApplication::sendEvent(receiver: input, event: &event); | 
| 4157 |     } | 
| 4158 |     QCOMPARE(input->isInputMethodComposing(), false); | 
| 4159 |     QCOMPARE(spy.count(), 8); | 
| 4160 | } | 
| 4161 |  | 
| 4162 | void tst_qquicktextinput::inputMethodUpdate() | 
| 4163 | { | 
| 4164 |     PlatformInputContext platformInputContext; | 
| 4165 |     QInputMethodPrivate *inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod()); | 
| 4166 |     inputMethodPrivate->testContext = &platformInputContext; | 
| 4167 |  | 
| 4168 |     QQuickView view(testFileUrl(fileName: "inputContext.qml" )); | 
| 4169 |     view.show(); | 
| 4170 |     view.requestActivate(); | 
| 4171 |     QVERIFY(QTest::qWaitForWindowActive(&view)); | 
| 4172 |     QQuickTextInput *input = qobject_cast<QQuickTextInput *>(object: view.rootObject()); | 
| 4173 |     QVERIFY(input); | 
| 4174 |     QVERIFY(input->hasActiveFocus()); | 
| 4175 |  | 
| 4176 |     // text change even without cursor position change needs to trigger update | 
| 4177 |     input->setText("test" ); | 
| 4178 |     platformInputContext.clear(); | 
| 4179 |     input->setText("xxxx" ); | 
| 4180 |     QVERIFY(platformInputContext.m_updateCallCount > 0); | 
| 4181 |  | 
| 4182 |     // input method event replacing text | 
| 4183 |     platformInputContext.clear(); | 
| 4184 |     { | 
| 4185 |         QInputMethodEvent inputMethodEvent; | 
| 4186 |         inputMethodEvent.setCommitString(commitString: "y" , replaceFrom: -1, replaceLength: 1); | 
| 4187 |         QGuiApplication::sendEvent(receiver: input, event: &inputMethodEvent); | 
| 4188 |     } | 
| 4189 |     QVERIFY(platformInputContext.m_updateCallCount > 0); | 
| 4190 |  | 
| 4191 |     // input method changing selection | 
| 4192 |     platformInputContext.clear(); | 
| 4193 |     { | 
| 4194 |         QList<QInputMethodEvent::Attribute> attributes; | 
| 4195 |         attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 0, 2, QVariant()); | 
| 4196 |         QInputMethodEvent inputMethodEvent("" , attributes); | 
| 4197 |         QGuiApplication::sendEvent(receiver: input, event: &inputMethodEvent); | 
| 4198 |     } | 
| 4199 |     QVERIFY(input->selectionStart() != input->selectionEnd()); | 
| 4200 |     QVERIFY(platformInputContext.m_updateCallCount > 0); | 
| 4201 |  | 
| 4202 |     // programmatical selections trigger update | 
| 4203 |     platformInputContext.clear(); | 
| 4204 |     input->selectAll(); | 
| 4205 |     QVERIFY(platformInputContext.m_updateCallCount > 0); | 
| 4206 |  | 
| 4207 |     // font changes | 
| 4208 |     platformInputContext.clear(); | 
| 4209 |     QFont font = input->font(); | 
| 4210 |     font.setBold(!font.bold()); | 
| 4211 |     input->setFont(font); | 
| 4212 |     QVERIFY(platformInputContext.m_updateCallCount > 0); | 
| 4213 |  | 
| 4214 |     // normal input | 
| 4215 |     platformInputContext.clear(); | 
| 4216 |     { | 
| 4217 |         QInputMethodEvent inputMethodEvent; | 
| 4218 |         inputMethodEvent.setCommitString(commitString: "y" ); | 
| 4219 |         QGuiApplication::sendEvent(receiver: input, event: &inputMethodEvent); | 
| 4220 |     } | 
| 4221 |     QVERIFY(platformInputContext.m_updateCallCount > 0); | 
| 4222 |  | 
| 4223 |     // changing cursor position | 
| 4224 |     platformInputContext.clear(); | 
| 4225 |     input->setCursorPosition(0); | 
| 4226 |     QVERIFY(platformInputContext.m_updateCallCount > 0); | 
| 4227 |  | 
| 4228 |     // read only disabled input method | 
| 4229 |     platformInputContext.clear(); | 
| 4230 |     input->setReadOnly(true); | 
| 4231 |     QVERIFY(platformInputContext.m_updateCallCount > 0); | 
| 4232 |     input->setReadOnly(false); | 
| 4233 |  | 
| 4234 |     // no updates while no focus | 
| 4235 |     input->setFocus(false); | 
| 4236 |     platformInputContext.clear(); | 
| 4237 |     input->setText("Foo" ); | 
| 4238 |     QCOMPARE(platformInputContext.m_updateCallCount, 0); | 
| 4239 |     input->setCursorPosition(1); | 
| 4240 |     QCOMPARE(platformInputContext.m_updateCallCount, 0); | 
| 4241 |     input->selectAll(); | 
| 4242 |     QCOMPARE(platformInputContext.m_updateCallCount, 0); | 
| 4243 |     input->setReadOnly(true); | 
| 4244 |     QCOMPARE(platformInputContext.m_updateCallCount, 0); | 
| 4245 | } | 
| 4246 |  | 
| 4247 | void tst_qquicktextinput::cursorRectangleSize() | 
| 4248 | { | 
| 4249 |     QQuickView *window = new QQuickView(testFileUrl(fileName: "positionAt.qml" )); | 
| 4250 |     QVERIFY(window->rootObject() != nullptr); | 
| 4251 |     QQuickTextInput *textInput = qobject_cast<QQuickTextInput *>(object: window->rootObject()); | 
| 4252 |  | 
| 4253 |     // make sure cursor rectangle is not at (0,0) | 
| 4254 |     textInput->setX(10); | 
| 4255 |     textInput->setY(10); | 
| 4256 |     textInput->setCursorPosition(3); | 
| 4257 |     QVERIFY(textInput != nullptr); | 
| 4258 |     textInput->setFocus(true); | 
| 4259 |     window->show(); | 
| 4260 |     window->requestActivate(); | 
| 4261 |     QVERIFY(QTest::qWaitForWindowActive(window)); | 
| 4262 |     QVERIFY(textInput->hasActiveFocus()); | 
| 4263 |  | 
| 4264 |     QInputMethodQueryEvent event(Qt::ImCursorRectangle); | 
| 4265 |     qApp->sendEvent(receiver: textInput, event: &event); | 
| 4266 |     QRectF cursorRectFromQuery = event.value(query: Qt::ImCursorRectangle).toRectF(); | 
| 4267 |  | 
| 4268 |     QRectF cursorRectFromItem = textInput->cursorRectangle(); | 
| 4269 |     QRectF cursorRectFromPositionToRectangle = textInput->positionToRectangle(pos: textInput->cursorPosition()); | 
| 4270 |  | 
| 4271 |     // item and input query cursor rectangles match | 
| 4272 |     QCOMPARE(cursorRectFromItem, cursorRectFromQuery); | 
| 4273 |  | 
| 4274 |     // item cursor rectangle and positionToRectangle calculations match | 
| 4275 |     QCOMPARE(cursorRectFromItem, cursorRectFromPositionToRectangle); | 
| 4276 |  | 
| 4277 |     // item-window transform and input item transform match | 
| 4278 |     QCOMPARE(QQuickItemPrivate::get(textInput)->itemToWindowTransform(), qApp->inputMethod()->inputItemTransform()); | 
| 4279 |  | 
| 4280 |     // input panel cursorRectangle property and tranformed item cursor rectangle match | 
| 4281 |     QRectF sceneCursorRect = QQuickItemPrivate::get(item: textInput)->itemToWindowTransform().mapRect(cursorRectFromItem); | 
| 4282 |     QCOMPARE(sceneCursorRect, qApp->inputMethod()->cursorRectangle()); | 
| 4283 |  | 
| 4284 |     delete window; | 
| 4285 | } | 
| 4286 |  | 
| 4287 | void tst_qquicktextinput::tripleClickSelectsAll() | 
| 4288 | { | 
| 4289 |     QString qmlfile = testFile(fileName: "positionAt.qml" ); | 
| 4290 |     QQuickView view(QUrl::fromLocalFile(localfile: qmlfile)); | 
| 4291 |     view.show(); | 
| 4292 |     view.requestActivate(); | 
| 4293 |     QVERIFY(QTest::qWaitForWindowActive(&view)); | 
| 4294 |  | 
| 4295 |     QQuickTextInput* input = qobject_cast<QQuickTextInput*>(object: view.rootObject()); | 
| 4296 |     QVERIFY(input); | 
| 4297 |  | 
| 4298 |     QLatin1String hello("Hello world!" ); | 
| 4299 |     input->setSelectByMouse(true); | 
| 4300 |     input->setText(hello); | 
| 4301 |  | 
| 4302 |     // Clicking on the same point inside TextInput three times in a row | 
| 4303 |     // should trigger a triple click, thus selecting all the text. | 
| 4304 |     QPoint pointInside = input->position().toPoint() + QPoint(2,2); | 
| 4305 |     QTest::mouseDClick(window: &view, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: pointInside); | 
| 4306 |     QTest::mouseClick(window: &view, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: pointInside); | 
| 4307 |     QGuiApplication::processEvents(); | 
| 4308 |     QCOMPARE(input->selectedText(), hello); | 
| 4309 |  | 
| 4310 |     // Now it simulates user moving the mouse between the second and the third click. | 
| 4311 |     // In this situation, we don't expect a triple click. | 
| 4312 |     QPoint pointInsideButFar = QPoint(input->width(),input->height()) - QPoint(2,2); | 
| 4313 |     QTest::mouseDClick(window: &view, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: pointInside); | 
| 4314 |     QTest::mouseClick(window: &view, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: pointInsideButFar); | 
| 4315 |     QGuiApplication::processEvents(); | 
| 4316 |     QVERIFY(input->selectedText().isEmpty()); | 
| 4317 |  | 
| 4318 |     // And now we press the third click too late, so no triple click event is triggered. | 
| 4319 |     QTest::mouseDClick(window: &view, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: pointInside); | 
| 4320 |     QGuiApplication::processEvents(); | 
| 4321 |     QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 1); | 
| 4322 |     QTest::mouseClick(window: &view, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: pointInside); | 
| 4323 |     QGuiApplication::processEvents(); | 
| 4324 |     QVERIFY(input->selectedText().isEmpty()); | 
| 4325 | } | 
| 4326 |  | 
| 4327 | void tst_qquicktextinput::QTBUG_19956_data() | 
| 4328 | { | 
| 4329 |     QTest::addColumn<QString>(name: "url" ); | 
| 4330 |     QTest::newRow(dataTag: "intvalidator" ) << "qtbug-19956int.qml" ; | 
| 4331 |     QTest::newRow(dataTag: "doublevalidator" ) << "qtbug-19956double.qml" ; | 
| 4332 | } | 
| 4333 |  | 
| 4334 |  | 
| 4335 | void tst_qquicktextinput::getText_data() | 
| 4336 | { | 
| 4337 |     QTest::addColumn<QString>(name: "text" ); | 
| 4338 |     QTest::addColumn<QString>(name: "inputMask" ); | 
| 4339 |     QTest::addColumn<int>(name: "start" ); | 
| 4340 |     QTest::addColumn<int>(name: "end" ); | 
| 4341 |     QTest::addColumn<QString>(name: "expectedText" ); | 
| 4342 |  | 
| 4343 |     QTest::newRow(dataTag: "all plain text" ) | 
| 4344 |             << standard.at(i: 0) | 
| 4345 |             << QString() | 
| 4346 |             << 0 << standard.at(i: 0).length() | 
| 4347 |             << standard.at(i: 0); | 
| 4348 |  | 
| 4349 |     QTest::newRow(dataTag: "plain text sub string" ) | 
| 4350 |             << standard.at(i: 0) | 
| 4351 |             << QString() | 
| 4352 |             << 0 << 12 | 
| 4353 |             << standard.at(i: 0).mid(position: 0, n: 12); | 
| 4354 |  | 
| 4355 |     QTest::newRow(dataTag: "plain text sub string reversed" ) | 
| 4356 |             << standard.at(i: 0) | 
| 4357 |             << QString() | 
| 4358 |             << 12 << 0 | 
| 4359 |             << standard.at(i: 0).mid(position: 0, n: 12); | 
| 4360 |  | 
| 4361 |     QTest::newRow(dataTag: "plain text cropped beginning" ) | 
| 4362 |             << standard.at(i: 0) | 
| 4363 |             << QString() | 
| 4364 |             << -3 << 4 | 
| 4365 |             << standard.at(i: 0).mid(position: 0, n: 4); | 
| 4366 |  | 
| 4367 |     QTest::newRow(dataTag: "plain text cropped end" ) | 
| 4368 |             << standard.at(i: 0) | 
| 4369 |             << QString() | 
| 4370 |             << 23 << standard.at(i: 0).length() + 8 | 
| 4371 |             << standard.at(i: 0).mid(position: 23); | 
| 4372 |  | 
| 4373 |     QTest::newRow(dataTag: "plain text cropped beginning and end" ) | 
| 4374 |             << standard.at(i: 0) | 
| 4375 |             << QString() | 
| 4376 |             << -9 << standard.at(i: 0).length() + 4 | 
| 4377 |             << standard.at(i: 0); | 
| 4378 | } | 
| 4379 |  | 
| 4380 | void tst_qquicktextinput::getText() | 
| 4381 | { | 
| 4382 |     QFETCH(QString, text); | 
| 4383 |     QFETCH(QString, inputMask); | 
| 4384 |     QFETCH(int, start); | 
| 4385 |     QFETCH(int, end); | 
| 4386 |     QFETCH(QString, expectedText); | 
| 4387 |  | 
| 4388 |     QString componentStr = "import QtQuick 2.0\nTextInput { text: \""  + text + "\"; inputMask: \""  + inputMask + "\" }" ; | 
| 4389 |     QQmlComponent textInputComponent(&engine); | 
| 4390 |     textInputComponent.setData(componentStr.toLatin1(), baseUrl: QUrl()); | 
| 4391 |     QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(object: textInputComponent.create()); | 
| 4392 |     QVERIFY(textInput != nullptr); | 
| 4393 |  | 
| 4394 |     QCOMPARE(textInput->getText(start, end), expectedText); | 
| 4395 | } | 
| 4396 |  | 
| 4397 | void tst_qquicktextinput::insert_data() | 
| 4398 | { | 
| 4399 |     QTest::addColumn<QString>(name: "text" ); | 
| 4400 |     QTest::addColumn<QString>(name: "inputMask" ); | 
| 4401 |     QTest::addColumn<int>(name: "selectionStart" ); | 
| 4402 |     QTest::addColumn<int>(name: "selectionEnd" ); | 
| 4403 |     QTest::addColumn<int>(name: "insertPosition" ); | 
| 4404 |     QTest::addColumn<QString>(name: "insertText" ); | 
| 4405 |     QTest::addColumn<QString>(name: "expectedText" ); | 
| 4406 |     QTest::addColumn<int>(name: "expectedSelectionStart" ); | 
| 4407 |     QTest::addColumn<int>(name: "expectedSelectionEnd" ); | 
| 4408 |     QTest::addColumn<int>(name: "expectedCursorPosition" ); | 
| 4409 |     QTest::addColumn<bool>(name: "selectionChanged" ); | 
| 4410 |     QTest::addColumn<bool>(name: "cursorPositionChanged" ); | 
| 4411 |  | 
| 4412 |     QTest::newRow(dataTag: "at cursor position (beginning)" ) | 
| 4413 |             << standard.at(i: 0) | 
| 4414 |             << QString() | 
| 4415 |             << 0 << 0 << 0 | 
| 4416 |             << QString("Hello" ) | 
| 4417 |             << QString("Hello" ) + standard.at(i: 0) | 
| 4418 |             << 5 << 5 << 5 | 
| 4419 |             << false << true; | 
| 4420 |  | 
| 4421 |     QTest::newRow(dataTag: "at cursor position (end)" ) | 
| 4422 |             << standard.at(i: 0) | 
| 4423 |             << QString() | 
| 4424 |             << standard.at(i: 0).length() << standard.at(i: 0).length() << standard.at(i: 0).length() | 
| 4425 |             << QString("Hello" ) | 
| 4426 |             << standard.at(i: 0) + QString("Hello" ) | 
| 4427 |             << standard.at(i: 0).length() + 5 << standard.at(i: 0).length() + 5 << standard.at(i: 0).length() + 5 | 
| 4428 |             << false << true; | 
| 4429 |  | 
| 4430 |     QTest::newRow(dataTag: "at cursor position (middle)" ) | 
| 4431 |             << standard.at(i: 0) | 
| 4432 |             << QString() | 
| 4433 |             << 18 << 18 << 18 | 
| 4434 |             << QString("Hello" ) | 
| 4435 |             << standard.at(i: 0).mid(position: 0, n: 18) + QString("Hello" ) + standard.at(i: 0).mid(position: 18) | 
| 4436 |             << 23 << 23 << 23 | 
| 4437 |             << false << true; | 
| 4438 |  | 
| 4439 |     QTest::newRow(dataTag: "after cursor position (beginning)" ) | 
| 4440 |             << standard.at(i: 0) | 
| 4441 |             << QString() | 
| 4442 |             << 0 << 0 << 18 | 
| 4443 |             << QString("Hello" ) | 
| 4444 |             << standard.at(i: 0).mid(position: 0, n: 18) + QString("Hello" ) + standard.at(i: 0).mid(position: 18) | 
| 4445 |             << 0 << 0 << 0 | 
| 4446 |             << false << false; | 
| 4447 |  | 
| 4448 |     QTest::newRow(dataTag: "before cursor position (end)" ) | 
| 4449 |             << standard.at(i: 0) | 
| 4450 |             << QString() | 
| 4451 |             << standard.at(i: 0).length() << standard.at(i: 0).length() << 18 | 
| 4452 |             << QString("Hello" ) | 
| 4453 |             << standard.at(i: 0).mid(position: 0, n: 18) + QString("Hello" ) + standard.at(i: 0).mid(position: 18) | 
| 4454 |             << standard.at(i: 0).length() + 5 << standard.at(i: 0).length() + 5 << standard.at(i: 0).length() + 5 | 
| 4455 |             << false << true; | 
| 4456 |  | 
| 4457 |     QTest::newRow(dataTag: "before cursor position (middle)" ) | 
| 4458 |             << standard.at(i: 0) | 
| 4459 |             << QString() | 
| 4460 |             << 18 << 18 << 0 | 
| 4461 |             << QString("Hello" ) | 
| 4462 |             << QString("Hello" ) + standard.at(i: 0) | 
| 4463 |             << 23 << 23 << 23 | 
| 4464 |             << false << true; | 
| 4465 |  | 
| 4466 |     QTest::newRow(dataTag: "after cursor position (middle)" ) | 
| 4467 |             << standard.at(i: 0) | 
| 4468 |             << QString() | 
| 4469 |             << 18 << 18 << standard.at(i: 0).length() | 
| 4470 |             << QString("Hello" ) | 
| 4471 |             << standard.at(i: 0) + QString("Hello" ) | 
| 4472 |             << 18 << 18 << 18 | 
| 4473 |             << false << false; | 
| 4474 |  | 
| 4475 |     QTest::newRow(dataTag: "before selection" ) | 
| 4476 |             << standard.at(i: 0) | 
| 4477 |             << QString() | 
| 4478 |             << 14 << 19 << 0 | 
| 4479 |             << QString("Hello" ) | 
| 4480 |             << QString("Hello" ) + standard.at(i: 0) | 
| 4481 |             << 19 << 24 << 24 | 
| 4482 |             << false << true; | 
| 4483 |  | 
| 4484 |     QTest::newRow(dataTag: "before reversed selection" ) | 
| 4485 |             << standard.at(i: 0) | 
| 4486 |             << QString() | 
| 4487 |             << 19 << 14 << 0 | 
| 4488 |             << QString("Hello" ) | 
| 4489 |             << QString("Hello" ) + standard.at(i: 0) | 
| 4490 |             << 19 << 24 << 19 | 
| 4491 |             << false << true; | 
| 4492 |  | 
| 4493 |     QTest::newRow(dataTag: "after selection" ) | 
| 4494 |             << standard.at(i: 0) | 
| 4495 |             << QString() | 
| 4496 |             << 14 << 19 << standard.at(i: 0).length() | 
| 4497 |             << QString("Hello" ) | 
| 4498 |             << standard.at(i: 0) + QString("Hello" ) | 
| 4499 |             << 14 << 19 << 19 | 
| 4500 |             << false << false; | 
| 4501 |  | 
| 4502 |     QTest::newRow(dataTag: "after reversed selection" ) | 
| 4503 |             << standard.at(i: 0) | 
| 4504 |             << QString() | 
| 4505 |             << 19 << 14 << standard.at(i: 0).length() | 
| 4506 |             << QString("Hello" ) | 
| 4507 |             << standard.at(i: 0) + QString("Hello" ) | 
| 4508 |             << 14 << 19 << 14 | 
| 4509 |             << false << false; | 
| 4510 |  | 
| 4511 |     QTest::newRow(dataTag: "into selection" ) | 
| 4512 |             << standard.at(i: 0) | 
| 4513 |             << QString() | 
| 4514 |             << 14 << 19 << 18 | 
| 4515 |             << QString("Hello" ) | 
| 4516 |             << standard.at(i: 0).mid(position: 0, n: 18) + QString("Hello" ) + standard.at(i: 0).mid(position: 18) | 
| 4517 |             << 14 << 24 << 24 | 
| 4518 |             << true << true; | 
| 4519 |  | 
| 4520 |     QTest::newRow(dataTag: "into reversed selection" ) | 
| 4521 |             << standard.at(i: 0) | 
| 4522 |             << QString() | 
| 4523 |             << 19 << 14 << 18 | 
| 4524 |             << QString("Hello" ) | 
| 4525 |             << standard.at(i: 0).mid(position: 0, n: 18) + QString("Hello" ) + standard.at(i: 0).mid(position: 18) | 
| 4526 |             << 14 << 24 << 14 | 
| 4527 |             << true << false; | 
| 4528 |  | 
| 4529 |     QTest::newRow(dataTag: "rich text into plain text" ) | 
| 4530 |             << standard.at(i: 0) | 
| 4531 |             << QString() | 
| 4532 |             << 0 << 0 << 0 | 
| 4533 |             << QString("<b>Hello</b>" ) | 
| 4534 |             << QString("<b>Hello</b>" ) + standard.at(i: 0) | 
| 4535 |             << 12 << 12 << 12 | 
| 4536 |             << false << true; | 
| 4537 |  | 
| 4538 |     QTest::newRow(dataTag: "before start" ) | 
| 4539 |             << standard.at(i: 0) | 
| 4540 |             << QString() | 
| 4541 |             << 0 << 0 << -3 | 
| 4542 |             << QString("Hello" ) | 
| 4543 |             << standard.at(i: 0) | 
| 4544 |             << 0 << 0 << 0 | 
| 4545 |             << false << false; | 
| 4546 |  | 
| 4547 |     QTest::newRow(dataTag: "past end" ) | 
| 4548 |             << standard.at(i: 0) | 
| 4549 |             << QString() | 
| 4550 |             << 0 << 0 << standard.at(i: 0).length() + 3 | 
| 4551 |             << QString("Hello" ) | 
| 4552 |             << standard.at(i: 0) | 
| 4553 |             << 0 << 0 << 0 | 
| 4554 |             << false << false; | 
| 4555 |  | 
| 4556 |     const QString inputMask = "009.009.009.009" ; | 
| 4557 |     const QString ip = "192.168.2.14" ; | 
| 4558 |  | 
| 4559 |     QTest::newRow(dataTag: "mask: at cursor position (beginning)" ) | 
| 4560 |             << ip | 
| 4561 |             << inputMask | 
| 4562 |             << 0 << 0 << 0 | 
| 4563 |             << QString("125" ) | 
| 4564 |             << QString("125.168.2.14" ) | 
| 4565 |             << 0 << 0 << 0 | 
| 4566 |             << false << false; | 
| 4567 |  | 
| 4568 |     QTest::newRow(dataTag: "mask: at cursor position (end)" ) | 
| 4569 |             << ip | 
| 4570 |             << inputMask | 
| 4571 |             << inputMask.length() << inputMask.length() << inputMask.length() | 
| 4572 |             << QString("8" ) | 
| 4573 |             << ip | 
| 4574 |             << inputMask.length() << inputMask.length() << inputMask.length() | 
| 4575 |             << false << false; | 
| 4576 |  | 
| 4577 |     QTest::newRow(dataTag: "mask: at cursor position (middle)" ) | 
| 4578 |             << ip | 
| 4579 |             << inputMask | 
| 4580 |             << 6 << 6 << 6 | 
| 4581 |             << QString("75.2" ) | 
| 4582 |             << QString("192.167.5.24" ) | 
| 4583 |             << 6 << 6 << 6 | 
| 4584 |             << false << false; | 
| 4585 |  | 
| 4586 |     QTest::newRow(dataTag: "mask: after cursor position (beginning)" ) | 
| 4587 |             << ip | 
| 4588 |             << inputMask | 
| 4589 |             << 0 << 0 << 6 | 
| 4590 |             << QString("75.2" ) | 
| 4591 |             << QString("192.167.5.24" ) | 
| 4592 |             << 0 << 0 << 0 | 
| 4593 |             << false << false; | 
| 4594 |  | 
| 4595 |     QTest::newRow(dataTag: "mask: before cursor position (end)" ) | 
| 4596 |             << ip | 
| 4597 |             << inputMask | 
| 4598 |             << inputMask.length() << inputMask.length() << 6 | 
| 4599 |             << QString("75.2" ) | 
| 4600 |             << QString("192.167.5.24" ) | 
| 4601 |             << inputMask.length() << inputMask.length() << inputMask.length() | 
| 4602 |             << false << false; | 
| 4603 |  | 
| 4604 |     QTest::newRow(dataTag: "mask: before cursor position (middle)" ) | 
| 4605 |             << ip | 
| 4606 |             << inputMask | 
| 4607 |             << 6 << 6 << 0 | 
| 4608 |             << QString("125" ) | 
| 4609 |             << QString("125.168.2.14" ) | 
| 4610 |             << 6 << 6 << 6 | 
| 4611 |             << false << false; | 
| 4612 |  | 
| 4613 |     QTest::newRow(dataTag: "mask: after cursor position (middle)" ) | 
| 4614 |             << ip | 
| 4615 |             << inputMask | 
| 4616 |             << 6 << 6 << 13 | 
| 4617 |             << QString("8" ) | 
| 4618 |             << "192.168.2.18"  | 
| 4619 |             << 6 << 6 << 6 | 
| 4620 |             << false << false; | 
| 4621 |  | 
| 4622 |     QTest::newRow(dataTag: "mask: before selection" ) | 
| 4623 |             << ip | 
| 4624 |             << inputMask | 
| 4625 |             << 6 << 8 << 0 | 
| 4626 |             << QString("125" ) | 
| 4627 |             << QString("125.168.2.14" ) | 
| 4628 |             << 6 << 8 << 8 | 
| 4629 |             << false << false; | 
| 4630 |  | 
| 4631 |     QTest::newRow(dataTag: "mask: before reversed selection" ) | 
| 4632 |             << ip | 
| 4633 |             << inputMask | 
| 4634 |             << 8 << 6 << 0 | 
| 4635 |             << QString("125" ) | 
| 4636 |             << QString("125.168.2.14" ) | 
| 4637 |             << 6 << 8 << 6 | 
| 4638 |             << false << false; | 
| 4639 |  | 
| 4640 |     QTest::newRow(dataTag: "mask: after selection" ) | 
| 4641 |             << ip | 
| 4642 |             << inputMask | 
| 4643 |             << 6 << 8 << 13 | 
| 4644 |             << QString("8" ) | 
| 4645 |             << "192.168.2.18"  | 
| 4646 |             << 6 << 8 << 8 | 
| 4647 |             << false << false; | 
| 4648 |  | 
| 4649 |     QTest::newRow(dataTag: "mask: after reversed selection" ) | 
| 4650 |             << ip | 
| 4651 |             << inputMask | 
| 4652 |             << 8 << 6 << 13 | 
| 4653 |             << QString("8" ) | 
| 4654 |             << "192.168.2.18"  | 
| 4655 |             << 6 << 8 << 6 | 
| 4656 |             << false << false; | 
| 4657 |  | 
| 4658 |     QTest::newRow(dataTag: "mask: into selection" ) | 
| 4659 |             << ip | 
| 4660 |             << inputMask | 
| 4661 |             << 5 << 8 << 6 | 
| 4662 |             << QString("75.2" ) | 
| 4663 |             << QString("192.167.5.24" ) | 
| 4664 |             << 5 << 8 << 8 | 
| 4665 |             << true << false; | 
| 4666 |  | 
| 4667 |     QTest::newRow(dataTag: "mask: into reversed selection" ) | 
| 4668 |             << ip | 
| 4669 |             << inputMask | 
| 4670 |             << 8 << 5 << 6 | 
| 4671 |             << QString("75.2" ) | 
| 4672 |             << QString("192.167.5.24" ) | 
| 4673 |             << 5 << 8 << 5 | 
| 4674 |             << true << false; | 
| 4675 |  | 
| 4676 |     QTest::newRow(dataTag: "mask: before start" ) | 
| 4677 |             << ip | 
| 4678 |             << inputMask | 
| 4679 |             << 0 << 0 << -3 | 
| 4680 |             << QString("4" ) | 
| 4681 |             << ip | 
| 4682 |             << 0 << 0 << 0 | 
| 4683 |             << false << false; | 
| 4684 |  | 
| 4685 |     QTest::newRow(dataTag: "mask: past end" ) | 
| 4686 |             << ip | 
| 4687 |             << inputMask | 
| 4688 |             << 0 << 0 << ip.length() + 3 | 
| 4689 |             << QString("4" ) | 
| 4690 |             << ip | 
| 4691 |             << 0 << 0 << 0 | 
| 4692 |             << false << false; | 
| 4693 |  | 
| 4694 |     QTest::newRow(dataTag: "mask: invalid characters" ) | 
| 4695 |             << ip | 
| 4696 |             << inputMask | 
| 4697 |             << 0 << 0 << 0 | 
| 4698 |             << QString("abc" ) | 
| 4699 |             << QString("192.168.2.14" ) | 
| 4700 |             << 0 << 0 << 0 | 
| 4701 |             << false << false; | 
| 4702 |  | 
| 4703 |     QTest::newRow(dataTag: "mask: mixed validity" ) | 
| 4704 |             << ip | 
| 4705 |             << inputMask | 
| 4706 |             << 0 << 0 << 0 | 
| 4707 |             << QString("a1b2c5" ) | 
| 4708 |             << QString("125.168.2.14" ) | 
| 4709 |             << 0 << 0 << 0 | 
| 4710 |             << false << false; | 
| 4711 | } | 
| 4712 |  | 
| 4713 | void tst_qquicktextinput::insert() | 
| 4714 | { | 
| 4715 |     QFETCH(QString, text); | 
| 4716 |     QFETCH(QString, inputMask); | 
| 4717 |     QFETCH(int, selectionStart); | 
| 4718 |     QFETCH(int, selectionEnd); | 
| 4719 |     QFETCH(int, insertPosition); | 
| 4720 |     QFETCH(QString, insertText); | 
| 4721 |     QFETCH(QString, expectedText); | 
| 4722 |     QFETCH(int, expectedSelectionStart); | 
| 4723 |     QFETCH(int, expectedSelectionEnd); | 
| 4724 |     QFETCH(int, expectedCursorPosition); | 
| 4725 |     QFETCH(bool, selectionChanged); | 
| 4726 |     QFETCH(bool, cursorPositionChanged); | 
| 4727 |  | 
| 4728 |     QString componentStr = "import QtQuick 2.0\nTextInput { text: \""  + text + "\"; inputMask: \""  + inputMask + "\" }" ; | 
| 4729 |     QQmlComponent textInputComponent(&engine); | 
| 4730 |     textInputComponent.setData(componentStr.toLatin1(), baseUrl: QUrl()); | 
| 4731 |     QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(object: textInputComponent.create()); | 
| 4732 |     QVERIFY(textInput != nullptr); | 
| 4733 |  | 
| 4734 |     textInput->select(start: selectionStart, end: selectionEnd); | 
| 4735 |  | 
| 4736 |     QSignalSpy selectionSpy(textInput, SIGNAL(selectedTextChanged())); | 
| 4737 |     QSignalSpy selectionStartSpy(textInput, SIGNAL(selectionStartChanged())); | 
| 4738 |     QSignalSpy selectionEndSpy(textInput, SIGNAL(selectionEndChanged())); | 
| 4739 |     QSignalSpy textSpy(textInput, SIGNAL(textChanged())); | 
| 4740 |     QSignalSpy cursorPositionSpy(textInput, SIGNAL(cursorPositionChanged())); | 
| 4741 |  | 
| 4742 |     textInput->insert(position: insertPosition, text: insertText); | 
| 4743 |  | 
| 4744 |     QCOMPARE(textInput->text(), expectedText); | 
| 4745 |     QCOMPARE(textInput->length(), inputMask.isEmpty() ? expectedText.length() : inputMask.length()); | 
| 4746 |  | 
| 4747 |     QCOMPARE(textInput->selectionStart(), expectedSelectionStart); | 
| 4748 |     QCOMPARE(textInput->selectionEnd(), expectedSelectionEnd); | 
| 4749 |     QCOMPARE(textInput->cursorPosition(), expectedCursorPosition); | 
| 4750 |  | 
| 4751 |     if (selectionStart > selectionEnd) | 
| 4752 |         qSwap(value1&: selectionStart, value2&: selectionEnd); | 
| 4753 |  | 
| 4754 |     QCOMPARE(selectionSpy.count() > 0, selectionChanged); | 
| 4755 |     QCOMPARE(selectionStartSpy.count() > 0, selectionStart != expectedSelectionStart); | 
| 4756 |     QCOMPARE(selectionEndSpy.count() > 0, selectionEnd != expectedSelectionEnd); | 
| 4757 |     QCOMPARE(textSpy.count() > 0, text != expectedText); | 
| 4758 |     QCOMPARE(cursorPositionSpy.count() > 0, cursorPositionChanged); | 
| 4759 | } | 
| 4760 |  | 
| 4761 | void tst_qquicktextinput::remove_data() | 
| 4762 | { | 
| 4763 |     QTest::addColumn<QString>(name: "text" ); | 
| 4764 |     QTest::addColumn<QString>(name: "inputMask" ); | 
| 4765 |     QTest::addColumn<int>(name: "selectionStart" ); | 
| 4766 |     QTest::addColumn<int>(name: "selectionEnd" ); | 
| 4767 |     QTest::addColumn<int>(name: "removeStart" ); | 
| 4768 |     QTest::addColumn<int>(name: "removeEnd" ); | 
| 4769 |     QTest::addColumn<QString>(name: "expectedText" ); | 
| 4770 |     QTest::addColumn<int>(name: "expectedSelectionStart" ); | 
| 4771 |     QTest::addColumn<int>(name: "expectedSelectionEnd" ); | 
| 4772 |     QTest::addColumn<int>(name: "expectedCursorPosition" ); | 
| 4773 |     QTest::addColumn<bool>(name: "selectionChanged" ); | 
| 4774 |     QTest::addColumn<bool>(name: "cursorPositionChanged" ); | 
| 4775 |  | 
| 4776 |     QTest::newRow(dataTag: "from cursor position (beginning)" ) | 
| 4777 |             << standard.at(i: 0) | 
| 4778 |             << QString() | 
| 4779 |             << 0 << 0 | 
| 4780 |             << 0 << 5 | 
| 4781 |             << standard.at(i: 0).mid(position: 5) | 
| 4782 |             << 0 << 0 << 0 | 
| 4783 |             << false << false; | 
| 4784 |  | 
| 4785 |     QTest::newRow(dataTag: "to cursor position (beginning)" ) | 
| 4786 |             << standard.at(i: 0) | 
| 4787 |             << QString() | 
| 4788 |             << 0 << 0 | 
| 4789 |             << 5 << 0 | 
| 4790 |             << standard.at(i: 0).mid(position: 5) | 
| 4791 |             << 0 << 0 << 0 | 
| 4792 |             << false << false; | 
| 4793 |  | 
| 4794 |     QTest::newRow(dataTag: "to cursor position (end)" ) | 
| 4795 |             << standard.at(i: 0) | 
| 4796 |             << QString() | 
| 4797 |             << standard.at(i: 0).length() << standard.at(i: 0).length() | 
| 4798 |             << standard.at(i: 0).length() << standard.at(i: 0).length() - 5 | 
| 4799 |             << standard.at(i: 0).mid(position: 0, n: standard.at(i: 0).length() - 5) | 
| 4800 |             << standard.at(i: 0).length() - 5 << standard.at(i: 0).length() - 5 << standard.at(i: 0).length() - 5 | 
| 4801 |             << false << true; | 
| 4802 |  | 
| 4803 |     QTest::newRow(dataTag: "to cursor position (end)" ) | 
| 4804 |             << standard.at(i: 0) | 
| 4805 |             << QString() | 
| 4806 |             << standard.at(i: 0).length() << standard.at(i: 0).length() | 
| 4807 |             << standard.at(i: 0).length() - 5 << standard.at(i: 0).length() | 
| 4808 |             << standard.at(i: 0).mid(position: 0, n: standard.at(i: 0).length() - 5) | 
| 4809 |             << standard.at(i: 0).length() - 5 << standard.at(i: 0).length() - 5 << standard.at(i: 0).length() - 5 | 
| 4810 |             << false << true; | 
| 4811 |  | 
| 4812 |     QTest::newRow(dataTag: "from cursor position (middle)" ) | 
| 4813 |             << standard.at(i: 0) | 
| 4814 |             << QString() | 
| 4815 |             << 18 << 18 | 
| 4816 |             << 18 << 23 | 
| 4817 |             << standard.at(i: 0).mid(position: 0, n: 18) + standard.at(i: 0).mid(position: 23) | 
| 4818 |             << 18 << 18 << 18 | 
| 4819 |             << false << false; | 
| 4820 |  | 
| 4821 |     QTest::newRow(dataTag: "to cursor position (middle)" ) | 
| 4822 |             << standard.at(i: 0) | 
| 4823 |             << QString() | 
| 4824 |             << 23 << 23 | 
| 4825 |             << 18 << 23 | 
| 4826 |             << standard.at(i: 0).mid(position: 0, n: 18) + standard.at(i: 0).mid(position: 23) | 
| 4827 |             << 18 << 18 << 18 | 
| 4828 |             << false << true; | 
| 4829 |  | 
| 4830 |     QTest::newRow(dataTag: "after cursor position (beginning)" ) | 
| 4831 |             << standard.at(i: 0) | 
| 4832 |             << QString() | 
| 4833 |             << 0 << 0 | 
| 4834 |             << 18 << 23 | 
| 4835 |             << standard.at(i: 0).mid(position: 0, n: 18) + standard.at(i: 0).mid(position: 23) | 
| 4836 |             << 0 << 0 << 0 | 
| 4837 |             << false << false; | 
| 4838 |  | 
| 4839 |     QTest::newRow(dataTag: "before cursor position (end)" ) | 
| 4840 |             << standard.at(i: 0) | 
| 4841 |             << QString() | 
| 4842 |             << standard.at(i: 0).length() << standard.at(i: 0).length() | 
| 4843 |             << 18 << 23 | 
| 4844 |             << standard.at(i: 0).mid(position: 0, n: 18) + standard.at(i: 0).mid(position: 23) | 
| 4845 |             << standard.at(i: 0).length() - 5 << standard.at(i: 0).length() - 5 << standard.at(i: 0).length() - 5 | 
| 4846 |             << false << true; | 
| 4847 |  | 
| 4848 |     QTest::newRow(dataTag: "before cursor position (middle)" ) | 
| 4849 |             << standard.at(i: 0) | 
| 4850 |             << QString() | 
| 4851 |             << 23 << 23 | 
| 4852 |             << 0 << 5 | 
| 4853 |             << standard.at(i: 0).mid(position: 5) | 
| 4854 |             << 18 << 18 << 18 | 
| 4855 |             << false << true; | 
| 4856 |  | 
| 4857 |     QTest::newRow(dataTag: "after cursor position (middle)" ) | 
| 4858 |             << standard.at(i: 0) | 
| 4859 |             << QString() | 
| 4860 |             << 18 << 18 | 
| 4861 |             << 18 << 23 | 
| 4862 |             << standard.at(i: 0).mid(position: 0, n: 18) + standard.at(i: 0).mid(position: 23) | 
| 4863 |             << 18 << 18 << 18 | 
| 4864 |             << false << false; | 
| 4865 |  | 
| 4866 |     QTest::newRow(dataTag: "before selection" ) | 
| 4867 |             << standard.at(i: 0) | 
| 4868 |             << QString() | 
| 4869 |             << 14 << 19 | 
| 4870 |             << 0 << 5 | 
| 4871 |             << standard.at(i: 0).mid(position: 5) | 
| 4872 |             << 9 << 14 << 14 | 
| 4873 |             << false << true; | 
| 4874 |  | 
| 4875 |     QTest::newRow(dataTag: "before reversed selection" ) | 
| 4876 |             << standard.at(i: 0) | 
| 4877 |             << QString() | 
| 4878 |             << 19 << 14 | 
| 4879 |             << 0 << 5 | 
| 4880 |             << standard.at(i: 0).mid(position: 5) | 
| 4881 |             << 9 << 14 << 9 | 
| 4882 |             << false << true; | 
| 4883 |  | 
| 4884 |     QTest::newRow(dataTag: "after selection" ) | 
| 4885 |             << standard.at(i: 0) | 
| 4886 |             << QString() | 
| 4887 |             << 14 << 19 | 
| 4888 |             << standard.at(i: 0).length() - 5 << standard.at(i: 0).length() | 
| 4889 |             << standard.at(i: 0).mid(position: 0, n: standard.at(i: 0).length() - 5) | 
| 4890 |             << 14 << 19 << 19 | 
| 4891 |             << false << false; | 
| 4892 |  | 
| 4893 |     QTest::newRow(dataTag: "after reversed selection" ) | 
| 4894 |             << standard.at(i: 0) | 
| 4895 |             << QString() | 
| 4896 |             << 19 << 14 | 
| 4897 |             << standard.at(i: 0).length() - 5 << standard.at(i: 0).length() | 
| 4898 |             << standard.at(i: 0).mid(position: 0, n: standard.at(i: 0).length() - 5) | 
| 4899 |             << 14 << 19 << 14 | 
| 4900 |             << false << false; | 
| 4901 |  | 
| 4902 |     QTest::newRow(dataTag: "from selection" ) | 
| 4903 |             << standard.at(i: 0) | 
| 4904 |             << QString() | 
| 4905 |             << 14 << 24 | 
| 4906 |             << 18 << 23 | 
| 4907 |             << standard.at(i: 0).mid(position: 0, n: 18) + standard.at(i: 0).mid(position: 23) | 
| 4908 |             << 14 << 19 << 19 | 
| 4909 |             << true << true; | 
| 4910 |  | 
| 4911 |     QTest::newRow(dataTag: "from reversed selection" ) | 
| 4912 |             << standard.at(i: 0) | 
| 4913 |             << QString() | 
| 4914 |             << 24 << 14 | 
| 4915 |             << 18 << 23 | 
| 4916 |             << standard.at(i: 0).mid(position: 0, n: 18) + standard.at(i: 0).mid(position: 23) | 
| 4917 |             << 14 << 19 << 14 | 
| 4918 |             << true << false; | 
| 4919 |  | 
| 4920 |     QTest::newRow(dataTag: "cropped beginning" ) | 
| 4921 |             << standard.at(i: 0) | 
| 4922 |             << QString() | 
| 4923 |             << 0 << 0 | 
| 4924 |             << -3 << 4 | 
| 4925 |             << standard.at(i: 0).mid(position: 4) | 
| 4926 |             << 0 << 0 << 0 | 
| 4927 |             << false << false; | 
| 4928 |  | 
| 4929 |     QTest::newRow(dataTag: "cropped end" ) | 
| 4930 |             << standard.at(i: 0) | 
| 4931 |             << QString() | 
| 4932 |             << 0 << 0 | 
| 4933 |             << 23 << standard.at(i: 0).length() + 8 | 
| 4934 |             << standard.at(i: 0).mid(position: 0, n: 23) | 
| 4935 |             << 0 << 0 << 0 | 
| 4936 |             << false << false; | 
| 4937 |  | 
| 4938 |     QTest::newRow(dataTag: "cropped beginning and end" ) | 
| 4939 |             << standard.at(i: 0) | 
| 4940 |             << QString() | 
| 4941 |             << 0 << 0 | 
| 4942 |             << -9 << standard.at(i: 0).length() + 4 | 
| 4943 |             << QString() | 
| 4944 |             << 0 << 0 << 0 | 
| 4945 |             << false << false; | 
| 4946 |  | 
| 4947 |     const QString inputMask = "009.009.009.009" ; | 
| 4948 |     const QString ip = "192.168.2.14" ; | 
| 4949 |  | 
| 4950 |     QTest::newRow(dataTag: "mask: from cursor position" ) | 
| 4951 |             << ip | 
| 4952 |             << inputMask | 
| 4953 |             << 6 << 6 | 
| 4954 |             << 6 << 9 | 
| 4955 |             << QString("192.16..14" ) | 
| 4956 |             << 6 << 6 << 6 | 
| 4957 |             << false << false; | 
| 4958 |  | 
| 4959 |     QTest::newRow(dataTag: "mask: to cursor position" ) | 
| 4960 |             << ip | 
| 4961 |             << inputMask | 
| 4962 |             << 6 << 6 | 
| 4963 |             << 2 << 6 | 
| 4964 |             << QString("19.8.2.14" ) | 
| 4965 |             << 6 << 6 << 6 | 
| 4966 |             << false << false; | 
| 4967 |  | 
| 4968 |     QTest::newRow(dataTag: "mask: before cursor position" ) | 
| 4969 |             << ip | 
| 4970 |             << inputMask | 
| 4971 |             << 6 << 6 | 
| 4972 |             << 0 << 2 | 
| 4973 |             << QString("2.168.2.14" ) | 
| 4974 |             << 6 << 6 << 6 | 
| 4975 |             << false << false; | 
| 4976 |  | 
| 4977 |     QTest::newRow(dataTag: "mask: after cursor position" ) | 
| 4978 |             << ip | 
| 4979 |             << inputMask | 
| 4980 |             << 6 << 6 | 
| 4981 |             << 12 << 16 | 
| 4982 |             << QString("192.168.2." ) | 
| 4983 |             << 6 << 6 << 6 | 
| 4984 |             << false << false; | 
| 4985 |  | 
| 4986 |     QTest::newRow(dataTag: "mask: before selection" ) | 
| 4987 |             << ip | 
| 4988 |             << inputMask | 
| 4989 |             << 6 << 8 | 
| 4990 |             << 0 << 2 | 
| 4991 |             << QString("2.168.2.14" ) | 
| 4992 |             << 6 << 8 << 8 | 
| 4993 |             << false << false; | 
| 4994 |  | 
| 4995 |     QTest::newRow(dataTag: "mask: before reversed selection" ) | 
| 4996 |             << ip | 
| 4997 |             << inputMask | 
| 4998 |             << 8 << 6 | 
| 4999 |             << 0 << 2 | 
| 5000 |             << QString("2.168.2.14" ) | 
| 5001 |             << 6 << 8 << 6 | 
| 5002 |             << false << false; | 
| 5003 |  | 
| 5004 |     QTest::newRow(dataTag: "mask: after selection" ) | 
| 5005 |             << ip | 
| 5006 |             << inputMask | 
| 5007 |             << 6 << 8 | 
| 5008 |             << 12 << 16 | 
| 5009 |             << QString("192.168.2." ) | 
| 5010 |             << 6 << 8 << 8 | 
| 5011 |             << false << false; | 
| 5012 |  | 
| 5013 |     QTest::newRow(dataTag: "mask: after reversed selection" ) | 
| 5014 |             << ip | 
| 5015 |             << inputMask | 
| 5016 |             << 8 << 6 | 
| 5017 |             << 12 << 16 | 
| 5018 |             << QString("192.168.2." ) | 
| 5019 |             << 6 << 8 << 6 | 
| 5020 |             << false << false; | 
| 5021 |  | 
| 5022 |     QTest::newRow(dataTag: "mask: from selection" ) | 
| 5023 |             << ip | 
| 5024 |             << inputMask | 
| 5025 |             << 6 << 13 | 
| 5026 |             << 8 << 10 | 
| 5027 |             << QString("192.168..14" ) | 
| 5028 |             << 6 << 13 << 13 | 
| 5029 |             << true << false; | 
| 5030 |  | 
| 5031 |     QTest::newRow(dataTag: "mask: from reversed selection" ) | 
| 5032 |             << ip | 
| 5033 |             << inputMask | 
| 5034 |             << 13 << 6 | 
| 5035 |             << 8 << 10 | 
| 5036 |             << QString("192.168..14" ) | 
| 5037 |             << 6 << 13 << 6 | 
| 5038 |             << true << false; | 
| 5039 |  | 
| 5040 |     QTest::newRow(dataTag: "mask: cropped beginning" ) | 
| 5041 |             << ip | 
| 5042 |             << inputMask | 
| 5043 |             << 0 << 0 | 
| 5044 |             << -3 << 4 | 
| 5045 |             << QString(".168.2.14" ) | 
| 5046 |             << 0 << 0 << 0 | 
| 5047 |             << false << false; | 
| 5048 |  | 
| 5049 |     QTest::newRow(dataTag: "mask: cropped end" ) | 
| 5050 |             << ip | 
| 5051 |             << inputMask | 
| 5052 |             << 0 << 0 | 
| 5053 |             << 13 << 28 | 
| 5054 |             << QString("192.168.2.1" ) | 
| 5055 |             << 0 << 0 << 0 | 
| 5056 |             << false << false; | 
| 5057 |  | 
| 5058 |     QTest::newRow(dataTag: "mask: cropped beginning and end" ) | 
| 5059 |             << ip | 
| 5060 |             << inputMask | 
| 5061 |             << 0 << 0 | 
| 5062 |             << -9 << 28 | 
| 5063 |             << QString("..." ) | 
| 5064 |             << 0 << 0 << 0 | 
| 5065 |             << false << false; | 
| 5066 | } | 
| 5067 |  | 
| 5068 | void tst_qquicktextinput::remove() | 
| 5069 | { | 
| 5070 |     QFETCH(QString, text); | 
| 5071 |     QFETCH(QString, inputMask); | 
| 5072 |     QFETCH(int, selectionStart); | 
| 5073 |     QFETCH(int, selectionEnd); | 
| 5074 |     QFETCH(int, removeStart); | 
| 5075 |     QFETCH(int, removeEnd); | 
| 5076 |     QFETCH(QString, expectedText); | 
| 5077 |     QFETCH(int, expectedSelectionStart); | 
| 5078 |     QFETCH(int, expectedSelectionEnd); | 
| 5079 |     QFETCH(int, expectedCursorPosition); | 
| 5080 |     QFETCH(bool, selectionChanged); | 
| 5081 |     QFETCH(bool, cursorPositionChanged); | 
| 5082 |  | 
| 5083 |     QString componentStr = "import QtQuick 2.0\nTextInput { text: \""  + text + "\"; inputMask: \""  + inputMask + "\" }" ; | 
| 5084 |     QQmlComponent textInputComponent(&engine); | 
| 5085 |     textInputComponent.setData(componentStr.toLatin1(), baseUrl: QUrl()); | 
| 5086 |     QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(object: textInputComponent.create()); | 
| 5087 |     QVERIFY(textInput != nullptr); | 
| 5088 |  | 
| 5089 |     textInput->select(start: selectionStart, end: selectionEnd); | 
| 5090 |  | 
| 5091 |     QSignalSpy selectionSpy(textInput, SIGNAL(selectedTextChanged())); | 
| 5092 |     QSignalSpy selectionStartSpy(textInput, SIGNAL(selectionStartChanged())); | 
| 5093 |     QSignalSpy selectionEndSpy(textInput, SIGNAL(selectionEndChanged())); | 
| 5094 |     QSignalSpy textSpy(textInput, SIGNAL(textChanged())); | 
| 5095 |     QSignalSpy cursorPositionSpy(textInput, SIGNAL(cursorPositionChanged())); | 
| 5096 |  | 
| 5097 |     textInput->remove(start: removeStart, end: removeEnd); | 
| 5098 |  | 
| 5099 |     QCOMPARE(textInput->text(), expectedText); | 
| 5100 |     QCOMPARE(textInput->length(), inputMask.isEmpty() ? expectedText.length() : inputMask.length()); | 
| 5101 |  | 
| 5102 |     if (selectionStart > selectionEnd)  // | 
| 5103 |         qSwap(value1&: selectionStart, value2&: selectionEnd); | 
| 5104 |  | 
| 5105 |     QCOMPARE(textInput->selectionStart(), expectedSelectionStart); | 
| 5106 |     QCOMPARE(textInput->selectionEnd(), expectedSelectionEnd); | 
| 5107 |     QCOMPARE(textInput->cursorPosition(), expectedCursorPosition); | 
| 5108 |  | 
| 5109 |     QCOMPARE(selectionSpy.count() > 0, selectionChanged); | 
| 5110 |     QCOMPARE(selectionStartSpy.count() > 0, selectionStart != expectedSelectionStart); | 
| 5111 |     QCOMPARE(selectionEndSpy.count() > 0, selectionEnd != expectedSelectionEnd); | 
| 5112 |     QCOMPARE(textSpy.count() > 0, text != expectedText); | 
| 5113 |  | 
| 5114 |     if (cursorPositionChanged)  // | 
| 5115 |         QVERIFY(cursorPositionSpy.count() > 0); | 
| 5116 | } | 
| 5117 |  | 
| 5118 | #if QT_CONFIG(shortcut) | 
| 5119 | void tst_qquicktextinput::keySequence_data() | 
| 5120 | { | 
| 5121 |     QTest::addColumn<QString>(name: "text" ); | 
| 5122 |     QTest::addColumn<QKeySequence>(name: "sequence" ); | 
| 5123 |     QTest::addColumn<int>(name: "selectionStart" ); | 
| 5124 |     QTest::addColumn<int>(name: "selectionEnd" ); | 
| 5125 |     QTest::addColumn<int>(name: "cursorPosition" ); | 
| 5126 |     QTest::addColumn<QString>(name: "expectedText" ); | 
| 5127 |     QTest::addColumn<QString>(name: "selectedText" ); | 
| 5128 |     QTest::addColumn<QQuickTextInput::EchoMode>(name: "echoMode" ); | 
| 5129 |     QTest::addColumn<Qt::Key>(name: "layoutDirection" ); | 
| 5130 |  | 
| 5131 |     // standard[0] == "the [4]quick [10]brown [16]fox [20]jumped [27]over [32]the [36]lazy [41]dog" | 
| 5132 |  | 
| 5133 |     QTest::newRow(dataTag: "select all" ) | 
| 5134 |             << standard.at(i: 0) << QKeySequence(QKeySequence::SelectAll) << 0 << 0 | 
| 5135 |             << 44 << standard.at(i: 0) << standard.at(i: 0) | 
| 5136 |             << QQuickTextInput::Normal << Qt::Key_Direction_L; | 
| 5137 |     QTest::newRow(dataTag: "select start of line" ) | 
| 5138 |             << standard.at(i: 0) << QKeySequence(QKeySequence::SelectStartOfLine) << 5 << 5 | 
| 5139 |             << 0 << standard.at(i: 0) << standard.at(i: 0).mid(position: 0, n: 5) | 
| 5140 |             << QQuickTextInput::Normal << Qt::Key_Direction_L; | 
| 5141 |     QTest::newRow(dataTag: "select start of block" ) | 
| 5142 |             << standard.at(i: 0) << QKeySequence(QKeySequence::SelectStartOfBlock) << 5 << 5 | 
| 5143 |             << 0 << standard.at(i: 0) << standard.at(i: 0).mid(position: 0, n: 5) | 
| 5144 |             << QQuickTextInput::Normal << Qt::Key_Direction_L; | 
| 5145 |     QTest::newRow(dataTag: "select end of line" ) | 
| 5146 |             << standard.at(i: 0) << QKeySequence(QKeySequence::SelectEndOfLine) << 5 << 5 | 
| 5147 |             << 44 << standard.at(i: 0) << standard.at(i: 0).mid(position: 5) | 
| 5148 |             << QQuickTextInput::Normal << Qt::Key_Direction_L; | 
| 5149 |     QTest::newRow(dataTag: "select end of document" ) // ### Not handled. | 
| 5150 |             << standard.at(i: 0) << QKeySequence(QKeySequence::SelectEndOfDocument) << 3 << 3 | 
| 5151 |             << 3 << standard.at(i: 0) << QString() | 
| 5152 |             << QQuickTextInput::Normal << Qt::Key_Direction_L; | 
| 5153 |     QTest::newRow(dataTag: "select end of block" ) | 
| 5154 |             << standard.at(i: 0) << QKeySequence(QKeySequence::SelectEndOfBlock) << 18 << 18 | 
| 5155 |             << 44 << standard.at(i: 0) << standard.at(i: 0).mid(position: 18) | 
| 5156 |             << QQuickTextInput::Normal << Qt::Key_Direction_L; | 
| 5157 |     QTest::newRow(dataTag: "delete end of line" ) | 
| 5158 |             << standard.at(i: 0) << QKeySequence(QKeySequence::DeleteEndOfLine) << 24 << 24 | 
| 5159 |             << 24 << standard.at(i: 0).mid(position: 0, n: 24) << QString() | 
| 5160 |             << QQuickTextInput::Normal << Qt::Key_Direction_L; | 
| 5161 |     QTest::newRow(dataTag: "move to start of line" ) | 
| 5162 |             << standard.at(i: 0) << QKeySequence(QKeySequence::MoveToStartOfLine) << 31 << 31 | 
| 5163 |             << 0 << standard.at(i: 0) << QString() | 
| 5164 |             << QQuickTextInput::Normal << Qt::Key_Direction_L; | 
| 5165 |     QTest::newRow(dataTag: "move to start of block" ) | 
| 5166 |             << standard.at(i: 0) << QKeySequence(QKeySequence::MoveToStartOfBlock) << 25 << 25 | 
| 5167 |             << 0 << standard.at(i: 0) << QString() | 
| 5168 |             << QQuickTextInput::Normal << Qt::Key_Direction_L; | 
| 5169 |     QTest::newRow(dataTag: "move to next char" ) | 
| 5170 |             << standard.at(i: 0) << QKeySequence(QKeySequence::MoveToNextChar) << 12 << 12 | 
| 5171 |             << 13 << standard.at(i: 0) << QString() | 
| 5172 |             << QQuickTextInput::Normal << Qt::Key_Direction_L; | 
| 5173 |     QTest::newRow(dataTag: "move to previous char (ltr)" ) | 
| 5174 |             << standard.at(i: 0) << QKeySequence(QKeySequence::MoveToPreviousChar) << 3 << 3 | 
| 5175 |             << 2 << standard.at(i: 0) << QString() | 
| 5176 |             << QQuickTextInput::Normal << Qt::Key_Direction_L; | 
| 5177 |     QTest::newRow(dataTag: "move to previous char (rtl)" ) | 
| 5178 |             << standard.at(i: 0) << QKeySequence(QKeySequence::MoveToPreviousChar) << 3 << 3 | 
| 5179 |             << 4 << standard.at(i: 0) << QString() | 
| 5180 |             << QQuickTextInput::Normal << Qt::Key_Direction_R; | 
| 5181 |     QTest::newRow(dataTag: "move to previous char with selection" ) | 
| 5182 |             << standard.at(i: 0) << QKeySequence(QKeySequence::MoveToPreviousChar) << 3 << 7 | 
| 5183 |             << 3 << standard.at(i: 0) << QString() | 
| 5184 |             << QQuickTextInput::Normal << Qt::Key_Direction_L; | 
| 5185 |     QTest::newRow(dataTag: "select next char (ltr)" ) | 
| 5186 |             << standard.at(i: 0) << QKeySequence(QKeySequence::SelectNextChar) << 23 << 23 | 
| 5187 |             << 24 << standard.at(i: 0) << standard.at(i: 0).mid(position: 23, n: 1) | 
| 5188 |             << QQuickTextInput::Normal << Qt::Key_Direction_L; | 
| 5189 |     QTest::newRow(dataTag: "select next char (rtl)" ) | 
| 5190 |             << standard.at(i: 0) << QKeySequence(QKeySequence::SelectNextChar) << 23 << 23 | 
| 5191 |             << 22 << standard.at(i: 0) << standard.at(i: 0).mid(position: 22, n: 1) | 
| 5192 |             << QQuickTextInput::Normal << Qt::Key_Direction_R; | 
| 5193 |     QTest::newRow(dataTag: "select previous char (ltr)" ) | 
| 5194 |             << standard.at(i: 0) << QKeySequence(QKeySequence::SelectPreviousChar) << 19 << 19 | 
| 5195 |             << 18 << standard.at(i: 0) << standard.at(i: 0).mid(position: 18, n: 1) | 
| 5196 |             << QQuickTextInput::Normal << Qt::Key_Direction_L; | 
| 5197 |     QTest::newRow(dataTag: "select previous char (rtl)" ) | 
| 5198 |             << standard.at(i: 0) << QKeySequence(QKeySequence::SelectPreviousChar) << 19 << 19 | 
| 5199 |             << 20 << standard.at(i: 0) << standard.at(i: 0).mid(position: 19, n: 1) | 
| 5200 |             << QQuickTextInput::Normal << Qt::Key_Direction_R; | 
| 5201 |     QTest::newRow(dataTag: "move to next word (ltr)" ) | 
| 5202 |             << standard.at(i: 0) << QKeySequence(QKeySequence::MoveToNextWord) << 7 << 7 | 
| 5203 |             << 10 << standard.at(i: 0) << QString() | 
| 5204 |             << QQuickTextInput::Normal << Qt::Key_Direction_L; | 
| 5205 |     QTest::newRow(dataTag: "move to next word (rtl)" ) | 
| 5206 |             << standard.at(i: 0) << QKeySequence(QKeySequence::MoveToNextWord) << 7 << 7 | 
| 5207 |             << 4 << standard.at(i: 0) << QString() | 
| 5208 |             << QQuickTextInput::Normal << Qt::Key_Direction_R; | 
| 5209 |     QTest::newRow(dataTag: "move to next word (password,ltr)" ) | 
| 5210 |             << standard.at(i: 0) << QKeySequence(QKeySequence::MoveToNextWord) << 7 << 7 | 
| 5211 |             << 44 << standard.at(i: 0) << QString() | 
| 5212 |             << QQuickTextInput::Password << Qt::Key_Direction_L; | 
| 5213 |     QTest::newRow(dataTag: "move to next word (password,rtl)" ) | 
| 5214 |             << standard.at(i: 0) << QKeySequence(QKeySequence::MoveToNextWord) << 7 << 7 | 
| 5215 |             << 0 << standard.at(i: 0) << QString() | 
| 5216 |             << QQuickTextInput::Password << Qt::Key_Direction_R; | 
| 5217 |     QTest::newRow(dataTag: "move to previous word (ltr)" ) | 
| 5218 |             << standard.at(i: 0) << QKeySequence(QKeySequence::MoveToPreviousWord) << 7 << 7 | 
| 5219 |             << 4 << standard.at(i: 0) << QString() | 
| 5220 |             << QQuickTextInput::Normal << Qt::Key_Direction_L; | 
| 5221 |     QTest::newRow(dataTag: "move to previous word (rlt)" ) | 
| 5222 |             << standard.at(i: 0) << QKeySequence(QKeySequence::MoveToPreviousWord) << 7 << 7 | 
| 5223 |             << 10 << standard.at(i: 0) << QString() | 
| 5224 |             << QQuickTextInput::Normal << Qt::Key_Direction_R; | 
| 5225 |     QTest::newRow(dataTag: "move to previous word (password,ltr)" ) | 
| 5226 |             << standard.at(i: 0) << QKeySequence(QKeySequence::MoveToPreviousWord) << 7 << 7 | 
| 5227 |             << 0 << standard.at(i: 0) << QString() | 
| 5228 |             << QQuickTextInput::Password << Qt::Key_Direction_L; | 
| 5229 |     QTest::newRow(dataTag: "move to previous word (password,rtl)" ) | 
| 5230 |             << standard.at(i: 0) << QKeySequence(QKeySequence::MoveToPreviousWord) << 7 << 7 | 
| 5231 |             << 44 << standard.at(i: 0) << QString() | 
| 5232 |             << QQuickTextInput::Password << Qt::Key_Direction_R; | 
| 5233 |     QTest::newRow(dataTag: "select next word" ) | 
| 5234 |             << standard.at(i: 0) << QKeySequence(QKeySequence::SelectNextWord) << 11 << 11 | 
| 5235 |             << 16 << standard.at(i: 0) << standard.at(i: 0).mid(position: 11, n: 5) | 
| 5236 |             << QQuickTextInput::Normal << Qt::Key_Direction_L; | 
| 5237 |     QTest::newRow(dataTag: "select previous word" ) | 
| 5238 |             << standard.at(i: 0) << QKeySequence(QKeySequence::SelectPreviousWord) << 11 << 11 | 
| 5239 |             << 10 << standard.at(i: 0) << standard.at(i: 0).mid(position: 10, n: 1) | 
| 5240 |             << QQuickTextInput::Normal << Qt::Key_Direction_L; | 
| 5241 |     QTest::newRow(dataTag: "delete (selection)" ) | 
| 5242 |             << standard.at(i: 0) << QKeySequence(QKeySequence::Delete) << 12 << 15 | 
| 5243 |             << 12 << (standard.at(i: 0).mid(position: 0, n: 12) + standard.at(i: 0).mid(position: 15)) << QString() | 
| 5244 |             << QQuickTextInput::Normal << Qt::Key_Direction_L; | 
| 5245 |     QTest::newRow(dataTag: "delete (no selection)" ) | 
| 5246 |             << standard.at(i: 0) << QKeySequence(QKeySequence::Delete) << 15 << 15 | 
| 5247 |             << 15 << (standard.at(i: 0).mid(position: 0, n: 15) + standard.at(i: 0).mid(position: 16)) << QString() | 
| 5248 |             << QQuickTextInput::Normal << Qt::Key_Direction_L; | 
| 5249 |     QTest::newRow(dataTag: "delete end of word" ) | 
| 5250 |             << standard.at(i: 0) << QKeySequence(QKeySequence::DeleteEndOfWord) << 24 << 24 | 
| 5251 |             << 24 << (standard.at(i: 0).mid(position: 0, n: 24) + standard.at(i: 0).mid(position: 27)) << QString() | 
| 5252 |             << QQuickTextInput::Normal << Qt::Key_Direction_L; | 
| 5253 |     QTest::newRow(dataTag: "delete start of word" ) | 
| 5254 |             << standard.at(i: 0) << QKeySequence(QKeySequence::DeleteStartOfWord) << 7 << 7 | 
| 5255 |             << 4 << (standard.at(i: 0).mid(position: 0, n: 4) + standard.at(i: 0).mid(position: 7)) << QString() | 
| 5256 |             << QQuickTextInput::Normal << Qt::Key_Direction_L; | 
| 5257 |     QTest::newRow(dataTag: "delete complete line" ) | 
| 5258 |             << standard.at(i: 0) << QKeySequence(QKeySequence::DeleteCompleteLine) << 0 << 0 | 
| 5259 |             << 0 << QString() << QString() | 
| 5260 |             << QQuickTextInput::Normal << Qt::Key_Direction_L; | 
| 5261 | } | 
| 5262 |  | 
| 5263 | void tst_qquicktextinput::keySequence() | 
| 5264 | { | 
| 5265 |     QFETCH(QString, text); | 
| 5266 |     QFETCH(QKeySequence, sequence); | 
| 5267 |     QFETCH(int, selectionStart); | 
| 5268 |     QFETCH(int, selectionEnd); | 
| 5269 |     QFETCH(int, cursorPosition); | 
| 5270 |     QFETCH(QString, expectedText); | 
| 5271 |     QFETCH(QString, selectedText); | 
| 5272 |     QFETCH(QQuickTextInput::EchoMode, echoMode); | 
| 5273 |     QFETCH(Qt::Key, layoutDirection); | 
| 5274 |  | 
| 5275 |     if (sequence.isEmpty()) { | 
| 5276 |         QSKIP("Key sequence is undefined" ); | 
| 5277 |     } | 
| 5278 |  | 
| 5279 |     QString componentStr = "import QtQuick 2.0\nTextInput { focus: true; text: \""  + text + "\" }" ; | 
| 5280 |     QQmlComponent textInputComponent(&engine); | 
| 5281 |     textInputComponent.setData(componentStr.toLatin1(), baseUrl: QUrl()); | 
| 5282 |     QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(object: textInputComponent.create()); | 
| 5283 |     QVERIFY(textInput != nullptr); | 
| 5284 |     textInput->setEchoMode(echoMode); | 
| 5285 |  | 
| 5286 |     QQuickWindow window; | 
| 5287 |     textInput->setParentItem(window.contentItem()); | 
| 5288 |     window.show(); | 
| 5289 |     window.requestActivate(); | 
| 5290 |     QVERIFY(QTest::qWaitForWindowActive(&window)); | 
| 5291 |     QVERIFY(textInput->hasActiveFocus()); | 
| 5292 |  | 
| 5293 |     simulateKey(view: &window, key: layoutDirection); | 
| 5294 |  | 
| 5295 |     textInput->select(start: selectionStart, end: selectionEnd); | 
| 5296 |  | 
| 5297 |     simulateKeys(window: &window, sequence); | 
| 5298 |  | 
| 5299 |     QCOMPARE(textInput->cursorPosition(), cursorPosition); | 
| 5300 |     QCOMPARE(textInput->text(), expectedText); | 
| 5301 |     QCOMPARE(textInput->selectedText(), selectedText); | 
| 5302 | } | 
| 5303 |  | 
| 5304 | #endif // QT_CONFIG(shortcut) | 
| 5305 |  | 
| 5306 | #define NORMAL 0 | 
| 5307 | #define REPLACE_UNTIL_END 1 | 
| 5308 |  | 
| 5309 | void tst_qquicktextinput::undo_data() | 
| 5310 | { | 
| 5311 |     QTest::addColumn<QStringList>(name: "insertString" ); | 
| 5312 |     QTest::addColumn<IntList>(name: "insertIndex" ); | 
| 5313 |     QTest::addColumn<IntList>(name: "insertMode" ); | 
| 5314 |     QTest::addColumn<QStringList>(name: "expectedString" ); | 
| 5315 |     QTest::addColumn<bool>(name: "use_keys" ); | 
| 5316 |  | 
| 5317 |     for (int i=0; i<2; i++) { | 
| 5318 |         QString keys_str = "keyboard" ; | 
| 5319 |         bool use_keys = true; | 
| 5320 |         if (i==0) { | 
| 5321 |             keys_str = "insert" ; | 
| 5322 |             use_keys = false; | 
| 5323 |         } | 
| 5324 |  | 
| 5325 |         { | 
| 5326 |             IntList insertIndex; | 
| 5327 |             IntList insertMode; | 
| 5328 |             QStringList insertString; | 
| 5329 |             QStringList expectedString; | 
| 5330 |  | 
| 5331 |             insertIndex << -1; | 
| 5332 |             insertMode << NORMAL; | 
| 5333 |             insertString << "1" ; | 
| 5334 |  | 
| 5335 |             insertIndex << -1; | 
| 5336 |             insertMode << NORMAL; | 
| 5337 |             insertString << "5" ; | 
| 5338 |  | 
| 5339 |             insertIndex << 1; | 
| 5340 |             insertMode << NORMAL; | 
| 5341 |             insertString << "3" ; | 
| 5342 |  | 
| 5343 |             insertIndex << 1; | 
| 5344 |             insertMode << NORMAL; | 
| 5345 |             insertString << "2" ; | 
| 5346 |  | 
| 5347 |             insertIndex << 3; | 
| 5348 |             insertMode << NORMAL; | 
| 5349 |             insertString << "4" ; | 
| 5350 |  | 
| 5351 |             expectedString << "12345" ; | 
| 5352 |             expectedString << "1235" ; | 
| 5353 |             expectedString << "135" ; | 
| 5354 |             expectedString << "15" ; | 
| 5355 |             expectedString << "" ; | 
| 5356 |  | 
| 5357 |             QTest::newRow(dataTag: QString(keys_str + "_numbers" ).toLatin1()) << | 
| 5358 |                 insertString << | 
| 5359 |                 insertIndex << | 
| 5360 |                 insertMode << | 
| 5361 |                 expectedString << | 
| 5362 |                 bool(use_keys); | 
| 5363 |         } | 
| 5364 |         { | 
| 5365 |             IntList insertIndex; | 
| 5366 |             IntList insertMode; | 
| 5367 |             QStringList insertString; | 
| 5368 |             QStringList expectedString; | 
| 5369 |  | 
| 5370 |             insertIndex << -1; | 
| 5371 |             insertMode << NORMAL; | 
| 5372 |             insertString << "World" ; // World | 
| 5373 |  | 
| 5374 |             insertIndex << 0; | 
| 5375 |             insertMode << NORMAL; | 
| 5376 |             insertString << "Hello" ; // HelloWorld | 
| 5377 |  | 
| 5378 |             insertIndex << 0; | 
| 5379 |             insertMode << NORMAL; | 
| 5380 |             insertString << "Well" ; // WellHelloWorld | 
| 5381 |  | 
| 5382 |             insertIndex << 9; | 
| 5383 |             insertMode << NORMAL; | 
| 5384 |             insertString << "There" ; // WellHelloThereWorld; | 
| 5385 |  | 
| 5386 |             expectedString << "WellHelloThereWorld" ; | 
| 5387 |             expectedString << "WellHelloWorld" ; | 
| 5388 |             expectedString << "HelloWorld" ; | 
| 5389 |             expectedString << "World" ; | 
| 5390 |             expectedString << "" ; | 
| 5391 |  | 
| 5392 |             QTest::newRow(dataTag: QString(keys_str + "_helloworld" ).toLatin1()) << | 
| 5393 |                 insertString << | 
| 5394 |                 insertIndex << | 
| 5395 |                 insertMode << | 
| 5396 |                 expectedString << | 
| 5397 |                 bool(use_keys); | 
| 5398 |         } | 
| 5399 |         { | 
| 5400 |             IntList insertIndex; | 
| 5401 |             IntList insertMode; | 
| 5402 |             QStringList insertString; | 
| 5403 |             QStringList expectedString; | 
| 5404 |  | 
| 5405 |             insertIndex << -1; | 
| 5406 |             insertMode << NORMAL; | 
| 5407 |             insertString << "Ensuring" ; | 
| 5408 |  | 
| 5409 |             insertIndex << -1; | 
| 5410 |             insertMode << NORMAL; | 
| 5411 |             insertString << " instan" ; | 
| 5412 |  | 
| 5413 |             insertIndex << 9; | 
| 5414 |             insertMode << NORMAL; | 
| 5415 |             insertString << "an " ; | 
| 5416 |  | 
| 5417 |             insertIndex << 10; | 
| 5418 |             insertMode << REPLACE_UNTIL_END; | 
| 5419 |             insertString << " unique instance." ; | 
| 5420 |  | 
| 5421 |             expectedString << "Ensuring a unique instance." ; | 
| 5422 |             expectedString << "Ensuring an instan" ; | 
| 5423 |             expectedString << "Ensuring instan" ; | 
| 5424 |             expectedString << "" ; | 
| 5425 |  | 
| 5426 |             QTest::newRow(dataTag: QString(keys_str + "_patterns" ).toLatin1()) << | 
| 5427 |                 insertString << | 
| 5428 |                 insertIndex << | 
| 5429 |                 insertMode << | 
| 5430 |                 expectedString << | 
| 5431 |                 bool(use_keys); | 
| 5432 |         } | 
| 5433 |     } | 
| 5434 | } | 
| 5435 |  | 
| 5436 | void tst_qquicktextinput::undo() | 
| 5437 | { | 
| 5438 |     QFETCH(QStringList, insertString); | 
| 5439 |     QFETCH(IntList, insertIndex); | 
| 5440 |     QFETCH(IntList, insertMode); | 
| 5441 |     QFETCH(QStringList, expectedString); | 
| 5442 |  | 
| 5443 |     QString componentStr = "import QtQuick 2.0\nTextInput { focus: true }" ; | 
| 5444 |     QQmlComponent textInputComponent(&engine); | 
| 5445 |     textInputComponent.setData(componentStr.toLatin1(), baseUrl: QUrl()); | 
| 5446 |     QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(object: textInputComponent.create()); | 
| 5447 |     QVERIFY(textInput != nullptr); | 
| 5448 |  | 
| 5449 |     QQuickWindow window; | 
| 5450 |     textInput->setParentItem(window.contentItem()); | 
| 5451 |     window.show(); | 
| 5452 |     window.requestActivate(); | 
| 5453 |     QVERIFY(QTest::qWaitForWindowActive(&window)); | 
| 5454 |     QVERIFY(textInput->hasActiveFocus()); | 
| 5455 |  | 
| 5456 |     QVERIFY(!textInput->canUndo()); | 
| 5457 |  | 
| 5458 |     QSignalSpy spy(textInput, SIGNAL(canUndoChanged())); | 
| 5459 |  | 
| 5460 |     int i; | 
| 5461 |  | 
| 5462 | // STEP 1: First build up an undo history by inserting or typing some strings... | 
| 5463 |     for (i = 0; i < insertString.size(); ++i) { | 
| 5464 |         if (insertIndex[i] > -1) | 
| 5465 |             textInput->setCursorPosition(insertIndex[i]); | 
| 5466 |  | 
| 5467 |  // experimental stuff | 
| 5468 |         if (insertMode[i] == REPLACE_UNTIL_END) { | 
| 5469 |             textInput->select(start: insertIndex[i], end: insertIndex[i] + 8); | 
| 5470 |  | 
| 5471 |             // This is what I actually want... | 
| 5472 |             // QTest::keyClick(testWidget, Qt::Key_End, Qt::ShiftModifier); | 
| 5473 |         } | 
| 5474 |  | 
| 5475 |         for (int j = 0; j < insertString.at(i).length(); j++) | 
| 5476 |             QTest::keyClick(window: &window, key: insertString.at(i).at(i: j).toLatin1()); | 
| 5477 |     } | 
| 5478 |  | 
| 5479 |     QCOMPARE(spy.count(), 1); | 
| 5480 |  | 
| 5481 | // STEP 2: Next call undo several times and see if we can restore to the previous state | 
| 5482 |     for (i = 0; i < expectedString.size() - 1; ++i) { | 
| 5483 |         QCOMPARE(textInput->text(), expectedString[i]); | 
| 5484 |         QVERIFY(textInput->canUndo()); | 
| 5485 |         textInput->undo(); | 
| 5486 |     } | 
| 5487 |  | 
| 5488 | // STEP 3: Verify that we have undone everything | 
| 5489 |     QVERIFY(textInput->text().isEmpty()); | 
| 5490 |     QVERIFY(!textInput->canUndo()); | 
| 5491 |     QCOMPARE(spy.count(), 2); | 
| 5492 | } | 
| 5493 |  | 
| 5494 | void tst_qquicktextinput::redo_data() | 
| 5495 | { | 
| 5496 |     QTest::addColumn<QStringList>(name: "insertString" ); | 
| 5497 |     QTest::addColumn<IntList>(name: "insertIndex" ); | 
| 5498 |     QTest::addColumn<QStringList>(name: "expectedString" ); | 
| 5499 |  | 
| 5500 |     { | 
| 5501 |         IntList insertIndex; | 
| 5502 |         QStringList insertString; | 
| 5503 |         QStringList expectedString; | 
| 5504 |  | 
| 5505 |         insertIndex << -1; | 
| 5506 |         insertString << "World" ; // World | 
| 5507 |         insertIndex << 0; | 
| 5508 |         insertString << "Hello" ; // HelloWorld | 
| 5509 |         insertIndex << 0; | 
| 5510 |         insertString << "Well" ; // WellHelloWorld | 
| 5511 |         insertIndex << 9; | 
| 5512 |         insertString << "There" ; // WellHelloThereWorld; | 
| 5513 |  | 
| 5514 |         expectedString << "World" ; | 
| 5515 |         expectedString << "HelloWorld" ; | 
| 5516 |         expectedString << "WellHelloWorld" ; | 
| 5517 |         expectedString << "WellHelloThereWorld" ; | 
| 5518 |  | 
| 5519 |         QTest::newRow(dataTag: "Inserts and setting cursor" ) << insertString << insertIndex << expectedString; | 
| 5520 |     } | 
| 5521 | } | 
| 5522 |  | 
| 5523 | void tst_qquicktextinput::redo() | 
| 5524 | { | 
| 5525 |     QFETCH(QStringList, insertString); | 
| 5526 |     QFETCH(IntList, insertIndex); | 
| 5527 |     QFETCH(QStringList, expectedString); | 
| 5528 |  | 
| 5529 |     QString componentStr = "import QtQuick 2.0\nTextInput { focus: true }" ; | 
| 5530 |     QQmlComponent textInputComponent(&engine); | 
| 5531 |     textInputComponent.setData(componentStr.toLatin1(), baseUrl: QUrl()); | 
| 5532 |     QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(object: textInputComponent.create()); | 
| 5533 |     QVERIFY(textInput != nullptr); | 
| 5534 |  | 
| 5535 |     QQuickWindow window; | 
| 5536 |     textInput->setParentItem(window.contentItem()); | 
| 5537 |     window.show(); | 
| 5538 |     window.requestActivate(); | 
| 5539 |     QVERIFY(QTest::qWaitForWindowActive(&window)); | 
| 5540 |  | 
| 5541 |     QVERIFY(textInput->hasActiveFocus()); | 
| 5542 |     QVERIFY(!textInput->canUndo()); | 
| 5543 |     QVERIFY(!textInput->canRedo()); | 
| 5544 |  | 
| 5545 |     QSignalSpy spy(textInput, SIGNAL(canRedoChanged())); | 
| 5546 |  | 
| 5547 |     int i; | 
| 5548 |     // inserts the diff strings at diff positions | 
| 5549 |     for (i = 0; i < insertString.size(); ++i) { | 
| 5550 |         if (insertIndex[i] > -1) | 
| 5551 |             textInput->setCursorPosition(insertIndex[i]); | 
| 5552 |         for (int j = 0; j < insertString.at(i).length(); j++) | 
| 5553 |             QTest::keyClick(window: &window, key: insertString.at(i).at(i: j).toLatin1()); | 
| 5554 |         QVERIFY(textInput->canUndo()); | 
| 5555 |         QVERIFY(!textInput->canRedo()); | 
| 5556 |     } | 
| 5557 |  | 
| 5558 |     QCOMPARE(spy.count(), 0); | 
| 5559 |  | 
| 5560 |     // undo everything | 
| 5561 |     while (!textInput->text().isEmpty()) { | 
| 5562 |         QVERIFY(textInput->canUndo()); | 
| 5563 |         textInput->undo(); | 
| 5564 |         QVERIFY(textInput->canRedo()); | 
| 5565 |     } | 
| 5566 |  | 
| 5567 |     QCOMPARE(spy.count(), 1); | 
| 5568 |  | 
| 5569 |     for (i = 0; i < expectedString.size(); ++i) { | 
| 5570 |         QVERIFY(textInput->canRedo()); | 
| 5571 |         textInput->redo(); | 
| 5572 |         QCOMPARE(textInput->text() , expectedString[i]); | 
| 5573 |         QVERIFY(textInput->canUndo()); | 
| 5574 |     } | 
| 5575 |     QVERIFY(!textInput->canRedo()); | 
| 5576 |     QCOMPARE(spy.count(), 2); | 
| 5577 | } | 
| 5578 |  | 
| 5579 | #if QT_CONFIG(shortcut) | 
| 5580 |  | 
| 5581 | void tst_qquicktextinput::undo_keypressevents_data() | 
| 5582 | { | 
| 5583 |     QTest::addColumn<KeyList>(name: "keys" ); | 
| 5584 |     QTest::addColumn<QStringList>(name: "expectedString" ); | 
| 5585 |  | 
| 5586 |     { | 
| 5587 |         KeyList keys; | 
| 5588 |         QStringList expectedString; | 
| 5589 |  | 
| 5590 |         keys << "AFRAID"  | 
| 5591 |                 << QKeySequence::MoveToStartOfLine | 
| 5592 |                 << "VERY"  | 
| 5593 |                 << Qt::Key_Left | 
| 5594 |                 << Qt::Key_Left | 
| 5595 |                 << Qt::Key_Left | 
| 5596 |                 << Qt::Key_Left | 
| 5597 |                 << "BE"  | 
| 5598 |                 << QKeySequence::MoveToEndOfLine | 
| 5599 |                 << "!" ; | 
| 5600 |  | 
| 5601 |         expectedString << "BEVERYAFRAID!" ; | 
| 5602 |         expectedString << "BEVERYAFRAID" ; | 
| 5603 |         expectedString << "VERYAFRAID" ; | 
| 5604 |         expectedString << "AFRAID" ; | 
| 5605 |  | 
| 5606 |         QTest::newRow(dataTag: "Inserts and moving cursor" ) << keys << expectedString; | 
| 5607 |     } { | 
| 5608 |         KeyList keys; | 
| 5609 |         QStringList expectedString; | 
| 5610 |  | 
| 5611 |         // inserting '1234' | 
| 5612 |         keys << "1234"  << QKeySequence::MoveToStartOfLine | 
| 5613 |                 // skipping '12' | 
| 5614 |                 << Qt::Key_Right << Qt::Key_Right | 
| 5615 |                 // selecting '34' | 
| 5616 |                 << (Qt::Key_Right | Qt::ShiftModifier) << (Qt::Key_Right | Qt::ShiftModifier) | 
| 5617 |                 // deleting '34' | 
| 5618 |                 << Qt::Key_Delete; | 
| 5619 |  | 
| 5620 |         expectedString << "12" ; | 
| 5621 |         expectedString << "1234" ; | 
| 5622 |  | 
| 5623 |         QTest::newRow(dataTag: "Inserts,moving,selection and delete" ) << keys << expectedString; | 
| 5624 |     } { | 
| 5625 |         KeyList keys; | 
| 5626 |         QStringList expectedString; | 
| 5627 |  | 
| 5628 |         // inserting 'AB12' | 
| 5629 |         keys << "AB12"  | 
| 5630 |                 << QKeySequence::MoveToStartOfLine | 
| 5631 |                 // selecting 'AB' | 
| 5632 |                 << (Qt::Key_Right | Qt::ShiftModifier) << (Qt::Key_Right | Qt::ShiftModifier) | 
| 5633 |                 << Qt::Key_Backspace | 
| 5634 |                 << QKeySequence::Undo | 
| 5635 |                 << Qt::Key_Right | 
| 5636 |                 << (Qt::Key_Right | Qt::ShiftModifier) << (Qt::Key_Right | Qt::ShiftModifier) | 
| 5637 |                 << Qt::Key_Delete; | 
| 5638 |  | 
| 5639 |         expectedString << "AB" ; | 
| 5640 |         expectedString << "AB12" ; | 
| 5641 |  | 
| 5642 |         QTest::newRow(dataTag: "Inserts,moving,selection, delete and undo" ) << keys << expectedString; | 
| 5643 |     } { | 
| 5644 |         KeyList keys; | 
| 5645 |         QStringList expectedString; | 
| 5646 |  | 
| 5647 |         // inserting 'ABCD' | 
| 5648 |         keys << "abcd"  | 
| 5649 |                 //move left two | 
| 5650 |                 << Qt::Key_Left << Qt::Key_Left | 
| 5651 |                 // inserting '1234' | 
| 5652 |                 << "1234"  | 
| 5653 |                 // selecting '1234' | 
| 5654 |                 << (Qt::Key_Left | Qt::ShiftModifier) << (Qt::Key_Left | Qt::ShiftModifier) << (Qt::Key_Left | Qt::ShiftModifier) << (Qt::Key_Left | Qt::ShiftModifier) | 
| 5655 |                 // overwriting '1234' with '5' | 
| 5656 |                 << "5"  | 
| 5657 |                 // undoing deletion of 'AB' | 
| 5658 |                 << QKeySequence::Undo | 
| 5659 |                 // overwriting '1234' with '6' | 
| 5660 |                 << "6" ; | 
| 5661 |  | 
| 5662 |         expectedString << "ab6cd" ; | 
| 5663 |         // for versions previous to 3.2 we overwrite needed two undo operations | 
| 5664 |         expectedString << "ab1234cd" ; | 
| 5665 |         expectedString << "abcd" ; | 
| 5666 |  | 
| 5667 |         QTest::newRow(dataTag: "Inserts,moving,selection and undo, removing selection" ) << keys << expectedString; | 
| 5668 |     } { | 
| 5669 |         KeyList keys; | 
| 5670 |         QStringList expectedString; | 
| 5671 |  | 
| 5672 |         // inserting 'ABC' | 
| 5673 |         keys << "ABC"  | 
| 5674 |                 // removes 'C' | 
| 5675 |                 << Qt::Key_Backspace; | 
| 5676 |  | 
| 5677 |         expectedString << "AB" ; | 
| 5678 |         expectedString << "ABC" ; | 
| 5679 |  | 
| 5680 |         QTest::newRow(dataTag: "Inserts,backspace" ) << keys << expectedString; | 
| 5681 |     } { | 
| 5682 |         KeyList keys; | 
| 5683 |         QStringList expectedString; | 
| 5684 |  | 
| 5685 |         keys << "ABC"  | 
| 5686 |                 // removes 'C' | 
| 5687 |                 << Qt::Key_Backspace | 
| 5688 |                 // inserting 'Z' | 
| 5689 |                 << "Z" ; | 
| 5690 |  | 
| 5691 |         expectedString << "ABZ" ; | 
| 5692 |         expectedString << "AB" ; | 
| 5693 |         expectedString << "ABC" ; | 
| 5694 |  | 
| 5695 |         QTest::newRow(dataTag: "Inserts,backspace,inserts" ) << keys << expectedString; | 
| 5696 |     } { | 
| 5697 |         KeyList keys; | 
| 5698 |         QStringList expectedString; | 
| 5699 |  | 
| 5700 |         // inserting '123' | 
| 5701 |         keys << "123"  << QKeySequence::MoveToStartOfLine | 
| 5702 |             // selecting '123' | 
| 5703 |              << QKeySequence::SelectEndOfLine | 
| 5704 |             // overwriting '123' with 'ABC' | 
| 5705 |              << "ABC" ; | 
| 5706 |  | 
| 5707 |         expectedString << "ABC" ; | 
| 5708 |         expectedString << "123" ; | 
| 5709 |  | 
| 5710 |         QTest::newRow(dataTag: "Inserts,moving,selection and overwriting" ) << keys << expectedString; | 
| 5711 |     } { | 
| 5712 |         KeyList keys; | 
| 5713 |         QStringList expectedString; | 
| 5714 |  | 
| 5715 |         // inserting '123' | 
| 5716 |         keys << "123"  | 
| 5717 |                 << QKeySequence::Undo | 
| 5718 |                 << QKeySequence::Redo; | 
| 5719 |  | 
| 5720 |         expectedString << "123" ; | 
| 5721 |         expectedString << QString(); | 
| 5722 |  | 
| 5723 |         QTest::newRow(dataTag: "Insert,undo,redo" ) << keys << expectedString; | 
| 5724 |     } { | 
| 5725 |         KeyList keys; | 
| 5726 |         QStringList expectedString; | 
| 5727 |  | 
| 5728 |         keys << "hello world"  | 
| 5729 |              << (Qt::Key_Backspace | Qt::ControlModifier) | 
| 5730 |              << QKeySequence::Undo | 
| 5731 |              << QKeySequence::Redo | 
| 5732 |              << "hello" ; | 
| 5733 |  | 
| 5734 |         expectedString | 
| 5735 |                 << "hello hello"  | 
| 5736 |                 << "hello "  | 
| 5737 |                 << "hello world"  | 
| 5738 |                 << QString(); | 
| 5739 |  | 
| 5740 |         QTest::newRow(dataTag: "Insert,delete previous word,undo,redo,insert" ) << keys << expectedString; | 
| 5741 |     } { | 
| 5742 |         KeyList keys; | 
| 5743 |         QStringList expectedString; | 
| 5744 |  | 
| 5745 |         keys << "hello world"  | 
| 5746 |              << QKeySequence::SelectPreviousWord | 
| 5747 |              << (Qt::Key_Backspace) | 
| 5748 |              << QKeySequence::Undo | 
| 5749 |              << "hello" ; | 
| 5750 |  | 
| 5751 |         expectedString | 
| 5752 |                 << "hello hello"  | 
| 5753 |                 << "hello world"  | 
| 5754 |                 << QString(); | 
| 5755 |  | 
| 5756 |         QTest::newRow(dataTag: "Insert,select previous word,remove,undo,insert" ) << keys << expectedString; | 
| 5757 |     } { | 
| 5758 |         KeyList keys; | 
| 5759 |         QStringList expectedString; | 
| 5760 |  | 
| 5761 |         keys << "hello world"  | 
| 5762 |              << QKeySequence::DeleteStartOfWord | 
| 5763 |              << QKeySequence::Undo | 
| 5764 |              << "hello" ; | 
| 5765 |  | 
| 5766 |         expectedString | 
| 5767 |                 << "hello worldhello"  | 
| 5768 |                 << "hello world"  | 
| 5769 |                 << QString(); | 
| 5770 |  | 
| 5771 |         QTest::newRow(dataTag: "Insert,delete previous word,undo,insert" ) << keys << expectedString; | 
| 5772 |     } { | 
| 5773 |         KeyList keys; | 
| 5774 |         QStringList expectedString; | 
| 5775 |  | 
| 5776 |         keys << "hello world"  | 
| 5777 |              << QKeySequence::MoveToPreviousWord | 
| 5778 |              << QKeySequence::DeleteEndOfWord | 
| 5779 |              << QKeySequence::Undo | 
| 5780 |              << "hello" ; | 
| 5781 |  | 
| 5782 |         expectedString | 
| 5783 |                 << "hello helloworld"  | 
| 5784 |                 << "hello world"  | 
| 5785 |                 << QString(); | 
| 5786 |  | 
| 5787 |         QTest::newRow(dataTag: "Insert,move,delete next word,undo,insert" ) << keys << expectedString; | 
| 5788 |     } | 
| 5789 |     if (!QKeySequence(QKeySequence::DeleteEndOfLine).isEmpty()) {   // X11 only. | 
| 5790 |         KeyList keys; | 
| 5791 |         QStringList expectedString; | 
| 5792 |  | 
| 5793 |         keys << "hello world"  | 
| 5794 |              << QKeySequence::MoveToStartOfLine | 
| 5795 |              << Qt::Key_Right | 
| 5796 |              << QKeySequence::DeleteEndOfLine | 
| 5797 |              << QKeySequence::Undo | 
| 5798 |              << "hello" ; | 
| 5799 |  | 
| 5800 |         expectedString | 
| 5801 |                 << "hhelloello world"  | 
| 5802 |                 << "hello world"  | 
| 5803 |                 << QString(); | 
| 5804 |  | 
| 5805 |         QTest::newRow(dataTag: "Insert,move,delete end of line,undo,insert" ) << keys << expectedString; | 
| 5806 |     } { | 
| 5807 |         KeyList keys; | 
| 5808 |         QStringList expectedString; | 
| 5809 |  | 
| 5810 |         keys << "hello world"  | 
| 5811 |              << QKeySequence::MoveToPreviousWord | 
| 5812 |              << (Qt::Key_Left | Qt::ShiftModifier) | 
| 5813 |              << (Qt::Key_Left | Qt::ShiftModifier) | 
| 5814 |              << QKeySequence::DeleteEndOfWord | 
| 5815 |              << QKeySequence::Undo | 
| 5816 |              << "hello" ; | 
| 5817 |  | 
| 5818 |         expectedString | 
| 5819 |                 << "hellhelloworld"  | 
| 5820 |                 << "hello world"  | 
| 5821 |                 << QString(); | 
| 5822 |  | 
| 5823 |         QTest::newRow(dataTag: "Insert,move,select,delete next word,undo,insert" ) << keys << expectedString; | 
| 5824 |     } | 
| 5825 |  | 
| 5826 |     bool canCopyPaste = PlatformQuirks::isClipboardAvailable(); | 
| 5827 |  | 
| 5828 |     if (canCopyPaste) { | 
| 5829 |         KeyList keys; | 
| 5830 |         keys    << "123"  | 
| 5831 |                 << QKeySequence(QKeySequence::SelectStartOfLine) | 
| 5832 |                 << QKeySequence(QKeySequence::Cut) | 
| 5833 |                 << "ABC"  | 
| 5834 |                 << QKeySequence(QKeySequence::Paste); | 
| 5835 |         QStringList expectedString = QStringList() | 
| 5836 |                 << "ABC123"  | 
| 5837 |                 << "ABC"  | 
| 5838 |                 // TextEdit: "" | 
| 5839 |                 << "123" ; | 
| 5840 |         QTest::newRow(dataTag: "Cut,paste" ) << keys << expectedString; | 
| 5841 |     } | 
| 5842 |     if (canCopyPaste) { | 
| 5843 |         KeyList keys; | 
| 5844 |         keys    << "123"  | 
| 5845 |                 << QKeySequence(QKeySequence::SelectStartOfLine) | 
| 5846 |                 << QKeySequence(QKeySequence::Copy) | 
| 5847 |                 << "ABC"  | 
| 5848 |                 << QKeySequence(QKeySequence::Paste); | 
| 5849 |         QStringList expectedString = QStringList() | 
| 5850 |                 << "ABC123"  | 
| 5851 |                 << "ABC"  | 
| 5852 |                 // TextEdit: "A" | 
| 5853 |                 << "123" ; | 
| 5854 |         QTest::newRow(dataTag: "Copy,paste" ) << keys << expectedString; | 
| 5855 |     } | 
| 5856 | } | 
| 5857 |  | 
| 5858 | void tst_qquicktextinput::undo_keypressevents() | 
| 5859 | { | 
| 5860 |     QFETCH(KeyList, keys); | 
| 5861 |     QFETCH(QStringList, expectedString); | 
| 5862 |  | 
| 5863 |     QString componentStr = "import QtQuick 2.0\nTextInput { focus: true }" ; | 
| 5864 |     QQmlComponent textInputComponent(&engine); | 
| 5865 |     textInputComponent.setData(componentStr.toLatin1(), baseUrl: QUrl()); | 
| 5866 |     QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(object: textInputComponent.create()); | 
| 5867 |     QVERIFY(textInput != nullptr); | 
| 5868 |  | 
| 5869 |     QQuickWindow window; | 
| 5870 |     textInput->setParentItem(window.contentItem()); | 
| 5871 |     window.show(); | 
| 5872 |     window.requestActivate(); | 
| 5873 |     QVERIFY(QTest::qWaitForWindowActive(&window)); | 
| 5874 |     QVERIFY(textInput->hasActiveFocus()); | 
| 5875 |  | 
| 5876 |     simulateKeys(window: &window, keys); | 
| 5877 |  | 
| 5878 |     for (int i = 0; i < expectedString.size(); ++i) { | 
| 5879 |         QCOMPARE(textInput->text() , expectedString[i]); | 
| 5880 |         textInput->undo(); | 
| 5881 |     } | 
| 5882 |     QVERIFY(textInput->text().isEmpty()); | 
| 5883 | } | 
| 5884 |  | 
| 5885 | #endif // QT_CONFIG(shortcut) | 
| 5886 |  | 
| 5887 | void tst_qquicktextinput::clear() | 
| 5888 | { | 
| 5889 |     QString componentStr = "import QtQuick 2.0\nTextInput { focus: true }" ; | 
| 5890 |     QQmlComponent textInputComponent(&engine); | 
| 5891 |     textInputComponent.setData(componentStr.toLatin1(), baseUrl: QUrl()); | 
| 5892 |     QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(object: textInputComponent.create()); | 
| 5893 |     QVERIFY(textInput != nullptr); | 
| 5894 |  | 
| 5895 |     QQuickWindow window; | 
| 5896 |     textInput->setParentItem(window.contentItem()); | 
| 5897 |     window.show(); | 
| 5898 |     window.requestActivate(); | 
| 5899 |     QVERIFY(QTest::qWaitForWindowActive(&window)); | 
| 5900 |     QVERIFY(textInput->hasActiveFocus()); | 
| 5901 |     QVERIFY(!textInput->canUndo()); | 
| 5902 |  | 
| 5903 |     QSignalSpy spy(textInput, SIGNAL(canUndoChanged())); | 
| 5904 |  | 
| 5905 |     textInput->setText("I am Legend" ); | 
| 5906 |     QCOMPARE(textInput->text(), QString("I am Legend" )); | 
| 5907 |     textInput->clear(); | 
| 5908 |     QVERIFY(textInput->text().isEmpty()); | 
| 5909 |  | 
| 5910 |     QCOMPARE(spy.count(), 1); | 
| 5911 |  | 
| 5912 |     // checks that clears can be undone | 
| 5913 |     textInput->undo(); | 
| 5914 |     QVERIFY(!textInput->canUndo()); | 
| 5915 |     QCOMPARE(spy.count(), 2); | 
| 5916 |     QCOMPARE(textInput->text(), QString("I am Legend" )); | 
| 5917 |  | 
| 5918 |     textInput->setCursorPosition(4); | 
| 5919 |     QInputMethodEvent preeditEvent("PREEDIT" , QList<QInputMethodEvent::Attribute>()); | 
| 5920 |     QGuiApplication::sendEvent(receiver: textInput, event: &preeditEvent); | 
| 5921 |     QCOMPARE(textInput->text(), QString("I am Legend" )); | 
| 5922 |     QCOMPARE(textInput->displayText(), QString("I amPREEDIT Legend" )); | 
| 5923 |     QCOMPARE(textInput->preeditText(), QString("PREEDIT" )); | 
| 5924 |  | 
| 5925 |     textInput->clear(); | 
| 5926 |     QVERIFY(textInput->text().isEmpty()); | 
| 5927 |     QVERIFY2(textInput->preeditText().isEmpty(), "Pre-edit text must be empty after clear" ); | 
| 5928 |  | 
| 5929 |     QCOMPARE(spy.count(), 3); | 
| 5930 |  | 
| 5931 |     // checks that clears can be undone | 
| 5932 |     textInput->undo(); | 
| 5933 |     QVERIFY(!textInput->canUndo()); | 
| 5934 |     QCOMPARE(spy.count(), 4); | 
| 5935 |     QCOMPARE(textInput->text(), QString("I am Legend" )); | 
| 5936 |     QVERIFY2(textInput->preeditText().isEmpty(), "Pre-edit text must be empty after undo" ); | 
| 5937 | } | 
| 5938 |  | 
| 5939 | void tst_qquicktextinput::backspaceSurrogatePairs() | 
| 5940 | { | 
| 5941 |     // Test backspace, and delete remove both characters in a surrogate pair. | 
| 5942 |     static const quint16 textData[] = { 0xd800, 0xdf00, 0xd800, 0xdf01, 0xd800, 0xdf02, 0xd800, 0xdf03, 0xd800, 0xdf04 }; | 
| 5943 |     const QString text = QString::fromUtf16(textData, size: lengthOf(textData)); | 
| 5944 |  | 
| 5945 |     QString componentStr = "import QtQuick 2.0\nTextInput { focus: true }" ; | 
| 5946 |     QQmlComponent textInputComponent(&engine); | 
| 5947 |     textInputComponent.setData(componentStr.toLatin1(), baseUrl: QUrl()); | 
| 5948 |     QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(object: textInputComponent.create()); | 
| 5949 |     QVERIFY(textInput != nullptr); | 
| 5950 |     textInput->setText(text); | 
| 5951 |     textInput->setCursorPosition(text.length()); | 
| 5952 |  | 
| 5953 |     QQuickWindow window; | 
| 5954 |     textInput->setParentItem(window.contentItem()); | 
| 5955 |     window.show(); | 
| 5956 |     window.requestActivate(); | 
| 5957 |     QVERIFY(QTest::qWaitForWindowActive(&window)); | 
| 5958 |     QCOMPARE(QGuiApplication::focusWindow(), &window); | 
| 5959 |  | 
| 5960 |     for (int i = text.length(); i >= 0; i -= 2) { | 
| 5961 |         QCOMPARE(textInput->text(), text.mid(0, i)); | 
| 5962 |         QTest::keyClick(window: &window, key: Qt::Key_Backspace, modifier: Qt::NoModifier); | 
| 5963 |     } | 
| 5964 |     QCOMPARE(textInput->text(), QString()); | 
| 5965 |  | 
| 5966 |     textInput->setText(text); | 
| 5967 |     textInput->setCursorPosition(0); | 
| 5968 |  | 
| 5969 |     for (int i = 0; i < text.length(); i += 2) { | 
| 5970 |         QCOMPARE(textInput->text(), text.mid(i)); | 
| 5971 |         QTest::keyClick(window: &window, key: Qt::Key_Delete, modifier: Qt::NoModifier); | 
| 5972 |     } | 
| 5973 |     QCOMPARE(textInput->text(), QString()); | 
| 5974 | } | 
| 5975 |  | 
| 5976 | void tst_qquicktextinput::QTBUG_19956() | 
| 5977 | { | 
| 5978 |     QFETCH(QString, url); | 
| 5979 |  | 
| 5980 |     QQuickView window(testFileUrl(fileName: url)); | 
| 5981 |     window.show(); | 
| 5982 |     window.requestActivate(); | 
| 5983 |     QVERIFY(QTest::qWaitForWindowActive(&window)); | 
| 5984 |     QVERIFY(window.rootObject() != nullptr); | 
| 5985 |     QQuickTextInput *input = qobject_cast<QQuickTextInput*>(object: window.rootObject()); | 
| 5986 |     QVERIFY(input); | 
| 5987 |     input->setFocus(true); | 
| 5988 |     QVERIFY(input->hasActiveFocus()); | 
| 5989 |  | 
| 5990 |     QCOMPARE(window.rootObject()->property("topvalue" ).toInt(), 30); | 
| 5991 |     QCOMPARE(window.rootObject()->property("bottomvalue" ).toInt(), 10); | 
| 5992 |     QCOMPARE(window.rootObject()->property("text" ).toString(), QString("20" )); | 
| 5993 |     QVERIFY(window.rootObject()->property("acceptableInput" ).toBool()); | 
| 5994 |  | 
| 5995 |     window.rootObject()->setProperty(name: "topvalue" , value: 15); | 
| 5996 |     QCOMPARE(window.rootObject()->property("topvalue" ).toInt(), 15); | 
| 5997 |     QVERIFY(!window.rootObject()->property("acceptableInput" ).toBool()); | 
| 5998 |  | 
| 5999 |     window.rootObject()->setProperty(name: "topvalue" , value: 25); | 
| 6000 |     QCOMPARE(window.rootObject()->property("topvalue" ).toInt(), 25); | 
| 6001 |     QVERIFY(window.rootObject()->property("acceptableInput" ).toBool()); | 
| 6002 |  | 
| 6003 |     window.rootObject()->setProperty(name: "bottomvalue" , value: 21); | 
| 6004 |     QCOMPARE(window.rootObject()->property("bottomvalue" ).toInt(), 21); | 
| 6005 |     QVERIFY(!window.rootObject()->property("acceptableInput" ).toBool()); | 
| 6006 |  | 
| 6007 |     window.rootObject()->setProperty(name: "bottomvalue" , value: 10); | 
| 6008 |     QCOMPARE(window.rootObject()->property("bottomvalue" ).toInt(), 10); | 
| 6009 |     QVERIFY(window.rootObject()->property("acceptableInput" ).toBool()); | 
| 6010 | } | 
| 6011 |  | 
| 6012 | void tst_qquicktextinput::QTBUG_19956_regexp() | 
| 6013 | { | 
| 6014 |     QUrl url = testFileUrl(fileName: "qtbug-19956regexp.qml" ); | 
| 6015 |  | 
| 6016 |     QString warning = url.toString() + ":11:9: Unable to assign [undefined] to QRegExp" ; | 
| 6017 |     QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning)); | 
| 6018 |  | 
| 6019 |     QQuickView window(url); | 
| 6020 |     window.show(); | 
| 6021 |     window.requestActivate(); | 
| 6022 |     QVERIFY(QTest::qWaitForWindowActive(&window)); | 
| 6023 |     QVERIFY(window.rootObject() != nullptr); | 
| 6024 |     QQuickTextInput *input = qobject_cast<QQuickTextInput*>(object: window.rootObject()); | 
| 6025 |     QVERIFY(input); | 
| 6026 |     input->setFocus(true); | 
| 6027 |     QVERIFY(input->hasActiveFocus()); | 
| 6028 |  | 
| 6029 |     window.rootObject()->setProperty(name: "regexvalue" , value: QRegExp("abc" )); | 
| 6030 |     QCOMPARE(window.rootObject()->property("regexvalue" ).toRegExp(), QRegExp("abc" )); | 
| 6031 |     QCOMPARE(window.rootObject()->property("text" ).toString(), QString("abc" )); | 
| 6032 |     QVERIFY(window.rootObject()->property("acceptableInput" ).toBool()); | 
| 6033 |  | 
| 6034 |     window.rootObject()->setProperty(name: "regexvalue" , value: QRegExp("abcd" )); | 
| 6035 |     QCOMPARE(window.rootObject()->property("regexvalue" ).toRegExp(), QRegExp("abcd" )); | 
| 6036 |     QVERIFY(!window.rootObject()->property("acceptableInput" ).toBool()); | 
| 6037 |  | 
| 6038 |     window.rootObject()->setProperty(name: "regexvalue" , value: QRegExp("abc" )); | 
| 6039 |     QCOMPARE(window.rootObject()->property("regexvalue" ).toRegExp(), QRegExp("abc" )); | 
| 6040 |     QVERIFY(window.rootObject()->property("acceptableInput" ).toBool()); | 
| 6041 | } | 
| 6042 |  | 
| 6043 | void tst_qquicktextinput::implicitSize_data() | 
| 6044 | { | 
| 6045 |     QTest::addColumn<QString>(name: "text" ); | 
| 6046 |     QTest::addColumn<QString>(name: "wrap" ); | 
| 6047 |     QTest::newRow(dataTag: "plain" ) << "The quick red fox jumped over the lazy brown dog"  << "TextInput.NoWrap" ; | 
| 6048 |     QTest::newRow(dataTag: "plain_wrap" ) << "The quick red fox jumped over the lazy brown dog"  << "TextInput.Wrap" ; | 
| 6049 | } | 
| 6050 |  | 
| 6051 | void tst_qquicktextinput::implicitSize() | 
| 6052 | { | 
| 6053 |     QFETCH(QString, text); | 
| 6054 |     QFETCH(QString, wrap); | 
| 6055 |     QString componentStr = "import QtQuick 2.0\nTextInput { text: \""  + text + "\"; width: 50; wrapMode: "  + wrap + " }" ; | 
| 6056 |     QQmlComponent textComponent(&engine); | 
| 6057 |     textComponent.setData(componentStr.toLatin1(), baseUrl: QUrl::fromLocalFile(localfile: "" )); | 
| 6058 |     QQuickTextInput *textObject = qobject_cast<QQuickTextInput*>(object: textComponent.create()); | 
| 6059 |  | 
| 6060 |     QVERIFY(textObject->width() < textObject->implicitWidth()); | 
| 6061 |     QCOMPARE(textObject->height(), textObject->implicitHeight()); | 
| 6062 |  | 
| 6063 |     textObject->resetWidth(); | 
| 6064 |     QCOMPARE(textObject->width(), textObject->implicitWidth()); | 
| 6065 |     QCOMPARE(textObject->height(), textObject->implicitHeight()); | 
| 6066 | } | 
| 6067 |  | 
| 6068 | void tst_qquicktextinput::implicitSizeBinding_data() | 
| 6069 | { | 
| 6070 |     implicitSize_data(); | 
| 6071 | } | 
| 6072 |  | 
| 6073 | void tst_qquicktextinput::implicitSizeBinding() | 
| 6074 | { | 
| 6075 |     QFETCH(QString, text); | 
| 6076 |     QFETCH(QString, wrap); | 
| 6077 |     QString componentStr = "import QtQuick 2.0\nTextInput { text: \""  + text + "\"; width: implicitWidth; height: implicitHeight; wrapMode: "  + wrap + " }" ; | 
| 6078 |     QQmlComponent textComponent(&engine); | 
| 6079 |     textComponent.setData(componentStr.toLatin1(), baseUrl: QUrl::fromLocalFile(localfile: "" )); | 
| 6080 |     QScopedPointer<QObject> object(textComponent.create()); | 
| 6081 |     QQuickTextInput *textObject = qobject_cast<QQuickTextInput *>(object: object.data()); | 
| 6082 |  | 
| 6083 |     QCOMPARE(textObject->width(), textObject->implicitWidth()); | 
| 6084 |     QCOMPARE(textObject->height(), textObject->implicitHeight()); | 
| 6085 |  | 
| 6086 |     textObject->resetWidth(); | 
| 6087 |     QCOMPARE(textObject->width(), textObject->implicitWidth()); | 
| 6088 |     QCOMPARE(textObject->height(), textObject->implicitHeight()); | 
| 6089 |  | 
| 6090 |     textObject->resetHeight(); | 
| 6091 |     QCOMPARE(textObject->width(), textObject->implicitWidth()); | 
| 6092 |     QCOMPARE(textObject->height(), textObject->implicitHeight()); | 
| 6093 | } | 
| 6094 |  | 
| 6095 | void tst_qquicktextinput::implicitResize_data() | 
| 6096 | { | 
| 6097 |     QTest::addColumn<int>(name: "alignment" ); | 
| 6098 |     QTest::newRow(dataTag: "left" ) << int(Qt::AlignLeft); | 
| 6099 |     QTest::newRow(dataTag: "center" ) << int(Qt::AlignHCenter); | 
| 6100 |     QTest::newRow(dataTag: "right" ) << int(Qt::AlignRight); | 
| 6101 | } | 
| 6102 |  | 
| 6103 | void tst_qquicktextinput::implicitResize() | 
| 6104 | { | 
| 6105 |     QFETCH(int, alignment); | 
| 6106 |  | 
| 6107 |     QQmlComponent component(&engine); | 
| 6108 |     component.setData("import QtQuick 2.0\nTextInput { }" , baseUrl: QUrl::fromLocalFile(localfile: "" )); | 
| 6109 |  | 
| 6110 |     QScopedPointer<QQuickTextInput> textInput(qobject_cast<QQuickTextInput *>(object: component.create())); | 
| 6111 |     QVERIFY(!textInput.isNull()); | 
| 6112 |  | 
| 6113 |     QScopedPointer<QQuickTextInput> textField(qobject_cast<QQuickTextInput *>(object: component.create())); | 
| 6114 |     QVERIFY(!textField.isNull()); | 
| 6115 |     QQuickTextInputPrivate::get(t: textField.data())->setImplicitResizeEnabled(false); | 
| 6116 |  | 
| 6117 |     textInput->setWidth(200); | 
| 6118 |     textField->setImplicitWidth(200); | 
| 6119 |  | 
| 6120 |     textInput->setHAlign(QQuickTextInput::HAlignment(alignment)); | 
| 6121 |     textField->setHAlign(QQuickTextInput::HAlignment(alignment)); | 
| 6122 |  | 
| 6123 |     textInput->setText("Qt" ); | 
| 6124 |     textField->setText("Qt" ); | 
| 6125 |  | 
| 6126 |     QCOMPARE(textField->positionToRectangle(0), textInput->positionToRectangle(0)); | 
| 6127 | } | 
| 6128 |  | 
| 6129 | void tst_qquicktextinput::negativeDimensions() | 
| 6130 | { | 
| 6131 |     // Verify this doesn't assert during initialization. | 
| 6132 |     QQmlComponent component(&engine, testFileUrl(fileName: "negativeDimensions.qml" )); | 
| 6133 |     QScopedPointer<QObject> o(component.create()); | 
| 6134 |     QVERIFY(o); | 
| 6135 |     QQuickTextInput *input = o->findChild<QQuickTextInput *>(aName: "input" ); | 
| 6136 |     QVERIFY(input); | 
| 6137 |     QCOMPARE(input->width(), qreal(-1)); | 
| 6138 |     QCOMPARE(input->height(), qreal(-1)); | 
| 6139 | } | 
| 6140 |  | 
| 6141 | void tst_qquicktextinput::keypress_inputMask_withValidator_data() | 
| 6142 | { | 
| 6143 |     QTest::addColumn<QString>(name: "mask" ); | 
| 6144 |     QTest::addColumn<qreal>(name: "validatorMinimum" ); | 
| 6145 |     QTest::addColumn<qreal>(name: "validatorMaximum" ); | 
| 6146 |     QTest::addColumn<int>(name: "decimals" ); | 
| 6147 |     QTest::addColumn<QString>(name: "validatorRegExp" ); | 
| 6148 |     QTest::addColumn<KeyList>(name: "keys" ); | 
| 6149 |     QTest::addColumn<QString>(name: "expectedText" ); | 
| 6150 |     QTest::addColumn<QString>(name: "expectedDisplayText" ); | 
| 6151 |  | 
| 6152 |     { | 
| 6153 |         KeyList keys; | 
| 6154 |         // inserting '1212' then two backspaces | 
| 6155 |         keys << Qt::Key_Home << "1212"  << Qt::Key_Backspace << Qt::Key_Backspace; | 
| 6156 |         QTest::newRow(dataTag: "backspaceWithInt" ) << QString("9999;_" ) << 1.0 << 9999.00 << 0 << QString() | 
| 6157 |                                              << keys << QString("12" ) << QString("12__" ); | 
| 6158 |     } | 
| 6159 |     { | 
| 6160 |         KeyList keys; | 
| 6161 |         // inserting '12.12' then two backspaces | 
| 6162 |         keys << Qt::Key_Home << "12.12"  << Qt::Key_Backspace << Qt::Key_Backspace; | 
| 6163 |         QTest::newRow(dataTag: "backspaceWithDouble" ) << QString("99.99;_" ) << 1.0 << 99.99 << 2 << QString() | 
| 6164 |                                              << keys << QString("12." ) << QString("12.__" ); | 
| 6165 |     } | 
| 6166 |     { | 
| 6167 |         KeyList keys; | 
| 6168 |         // inserting '1111.11' then two backspaces | 
| 6169 |         keys << Qt::Key_Home << "1111.11"  << Qt::Key_Backspace << Qt::Key_Backspace; | 
| 6170 |         QTest::newRow(dataTag: "backspaceWithRegExp" ) << QString("9999;_" ) << 0.0 << 0.0 << 0 | 
| 6171 |                                              << QString("/^[-]?((\\.\\d+)|(\\d+(\\.\\d+)?))$/" ) | 
| 6172 |                                              << keys << QString("11" ) << QString("11__" ); | 
| 6173 |     } | 
| 6174 |     { | 
| 6175 |         KeyList keys; | 
| 6176 |         // inserting '99' - QTBUG-64616 | 
| 6177 |         keys << Qt::Key_Home << "99" ; | 
| 6178 |         QTest::newRow(dataTag: "invalidTextWithRegExp" ) << QString("X9;_" ) << 0.0 << 0.0 << 0 | 
| 6179 |                                                << QString("/[+-][0+9]/" ) | 
| 6180 |                                                << keys << QString("" ) << QString("__" ); | 
| 6181 |     } | 
| 6182 | } | 
| 6183 |  | 
| 6184 | void tst_qquicktextinput::keypress_inputMask_withValidator() | 
| 6185 | { | 
| 6186 |     QFETCH(QString, mask); | 
| 6187 |     QFETCH(qreal, validatorMinimum); | 
| 6188 |     QFETCH(qreal, validatorMaximum); | 
| 6189 |     QFETCH(int, decimals); | 
| 6190 |     QFETCH(QString, validatorRegExp); | 
| 6191 |     QFETCH(KeyList, keys); | 
| 6192 |     QFETCH(QString, expectedText); | 
| 6193 |     QFETCH(QString, expectedDisplayText); | 
| 6194 |  | 
| 6195 |     QString componentStr = "import QtQuick 2.0\nTextInput { focus: true; inputMask: \""  + mask + "\"\n" ; | 
| 6196 |     if (!validatorRegExp.isEmpty()) | 
| 6197 |         componentStr += "validator: RegExpValidator { regExp: "  + validatorRegExp + " }\n}" ; | 
| 6198 |     else if (decimals > 0) | 
| 6199 |         componentStr += QString("validator: DoubleValidator { bottom: %1; decimals: %2; top: %3 }\n}" ). | 
| 6200 |                             arg(a: validatorMinimum).arg(a: decimals).arg(a: validatorMaximum); | 
| 6201 |     else | 
| 6202 |         componentStr += QString("validator: IntValidator { bottom: %1; top: %2 }\n}" ). | 
| 6203 |                             arg(a: (int)validatorMinimum).arg(a: (int)validatorMaximum); | 
| 6204 |  | 
| 6205 |     QQmlComponent textInputComponent(&engine); | 
| 6206 |     textInputComponent.setData(componentStr.toLatin1(), baseUrl: QUrl()); | 
| 6207 |     QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(object: textInputComponent.create()); | 
| 6208 |     QVERIFY(textInput != nullptr); | 
| 6209 |  | 
| 6210 |     QQuickWindow window; | 
| 6211 |     textInput->setParentItem(window.contentItem()); | 
| 6212 |     window.show(); | 
| 6213 |     window.requestActivate(); | 
| 6214 |     QVERIFY(QTest::qWaitForWindowActive(&window)); | 
| 6215 |     QVERIFY(textInput->hasActiveFocus()); | 
| 6216 |  | 
| 6217 |     simulateKeys(window: &window, keys); | 
| 6218 |  | 
| 6219 |     QCOMPARE(textInput->text(), expectedText); | 
| 6220 |     QCOMPARE(textInput->displayText(), expectedDisplayText); | 
| 6221 | } | 
| 6222 |  | 
| 6223 | void tst_qquicktextinput::setInputMask_data() | 
| 6224 | { | 
| 6225 |     QTest::addColumn<QString>(name: "mask" ); | 
| 6226 |     QTest::addColumn<QString>(name: "input" ); | 
| 6227 |     QTest::addColumn<QString>(name: "expectedText" ); | 
| 6228 |     QTest::addColumn<QString>(name: "expectedDisplay" ); | 
| 6229 |     QTest::addColumn<bool>(name: "insert_text" ); | 
| 6230 |  | 
| 6231 |     // both keyboard and insert() | 
| 6232 |     for (int i=0; i<2; i++) { | 
| 6233 |         bool insert_text = i==0 ? false : true; | 
| 6234 |         QString insert_mode = "keys " ; | 
| 6235 |         if (insert_text) | 
| 6236 |             insert_mode = "insert " ; | 
| 6237 |  | 
| 6238 |         QTest::newRow(dataTag: QString(insert_mode + "ip_localhost" ).toLatin1()) | 
| 6239 |             << QString("000.000.000.000" ) | 
| 6240 |             << QString("127.0.0.1" ) | 
| 6241 |             << QString("127.0.0.1" ) | 
| 6242 |             << QString("127.0  .0  .1  " ) | 
| 6243 |             << bool(insert_text); | 
| 6244 |         QTest::newRow(dataTag: QString(insert_mode + "mac" ).toLatin1()) | 
| 6245 |             << QString("HH:HH:HH:HH:HH:HH;#" ) | 
| 6246 |             << QString("00:E0:81:21:9E:8E" ) | 
| 6247 |             << QString("00:E0:81:21:9E:8E" ) | 
| 6248 |             << QString("00:E0:81:21:9E:8E" ) | 
| 6249 |             << bool(insert_text); | 
| 6250 |         QTest::newRow(dataTag: QString(insert_mode + "mac2" ).toLatin1()) | 
| 6251 |             << QString("<HH:>HH:!HH:HH:HH:HH;#" ) | 
| 6252 |             << QString("AAe081219E8E" ) | 
| 6253 |             << QString("aa:E0:81:21:9E:8E" ) | 
| 6254 |             << QString("aa:E0:81:21:9E:8E" ) | 
| 6255 |             << bool(insert_text); | 
| 6256 |         QTest::newRow(dataTag: QString(insert_mode + "byte" ).toLatin1()) | 
| 6257 |             << QString("BBBBBBBB;0" ) | 
| 6258 |             << QString("11011001" ) | 
| 6259 |             << QString("11111" ) | 
| 6260 |             << QString("11011001" ) | 
| 6261 |             << bool(insert_text); | 
| 6262 |         QTest::newRow(dataTag: QString(insert_mode + "halfbytes" ).toLatin1()) | 
| 6263 |             << QString("bbbb.bbbb;-" ) | 
| 6264 |             << QString("110. 0001" ) | 
| 6265 |             << QString("110.0001" ) | 
| 6266 |             << QString("110-.0001" ) | 
| 6267 |             << bool(insert_text); | 
| 6268 |         QTest::newRow(dataTag: QString(insert_mode + "blank char same type as content" ).toLatin1()) | 
| 6269 |             << QString("000.000.000.000;0" ) | 
| 6270 |             << QString("127.0.0.1" ) | 
| 6271 |             << QString("127...1" ) | 
| 6272 |             << QString("127.000.000.100" ) | 
| 6273 |             << bool(insert_text); | 
| 6274 |         QTest::newRow(dataTag: QString(insert_mode + "parts of ip_localhost" ).toLatin1()) | 
| 6275 |             << QString("000.000.000.000" ) | 
| 6276 |             << QString(".0.0.1" ) | 
| 6277 |             << QString(".0.0.1" ) | 
| 6278 |             << QString("   .0  .0  .1  " ) | 
| 6279 |             << bool(insert_text); | 
| 6280 |         QTest::newRow(dataTag: QString(insert_mode + "ip_null" ).toLatin1()) | 
| 6281 |             << QString("000.000.000.000" ) | 
| 6282 |             << QString() | 
| 6283 |             << QString("..." ) | 
| 6284 |             << QString("   .   .   .   " ) | 
| 6285 |             << bool(insert_text); | 
| 6286 |         QTest::newRow(dataTag: QString(insert_mode + "ip_null_hash" ).toLatin1()) | 
| 6287 |             << QString("000.000.000.000;#" ) | 
| 6288 |             << QString() | 
| 6289 |             << QString("..." ) | 
| 6290 |             << QString("###.###.###.###" ) | 
| 6291 |             << bool(insert_text); | 
| 6292 |         QTest::newRow(dataTag: QString(insert_mode + "ip_overflow" ).toLatin1()) | 
| 6293 |             << QString("000.000.000.000" ) | 
| 6294 |             << QString("1234123412341234" ) | 
| 6295 |             << QString("123.412.341.234" ) | 
| 6296 |             << QString("123.412.341.234" ) | 
| 6297 |             << bool(insert_text); | 
| 6298 |         QTest::newRow(dataTag: QString(insert_mode + "uppercase" ).toLatin1()) | 
| 6299 |             << QString(">AAAA" ) | 
| 6300 |             << QString("AbCd" ) | 
| 6301 |             << QString("ABCD" ) | 
| 6302 |             << QString("ABCD" ) | 
| 6303 |             << bool(insert_text); | 
| 6304 |         QTest::newRow(dataTag: QString(insert_mode + "lowercase" ).toLatin1()) | 
| 6305 |             << QString("<AAAA" ) | 
| 6306 |             << QString("AbCd" ) | 
| 6307 |             << QString("abcd" ) | 
| 6308 |             << QString("abcd" ) | 
| 6309 |             << bool(insert_text); | 
| 6310 |  | 
| 6311 |         QTest::newRow(dataTag: QString(insert_mode + "nocase" ).toLatin1()) | 
| 6312 |             << QString("!AAAA" ) | 
| 6313 |             << QString("AbCd" ) | 
| 6314 |             << QString("AbCd" ) | 
| 6315 |             << QString("AbCd" ) | 
| 6316 |             << bool(insert_text); | 
| 6317 |         QTest::newRow(dataTag: QString(insert_mode + "nocase1" ).toLatin1()) | 
| 6318 |             << QString("!A!A!A!A" ) | 
| 6319 |             << QString("AbCd" ) | 
| 6320 |             << QString("AbCd" ) | 
| 6321 |             << QString("AbCd" ) | 
| 6322 |             << bool(insert_text); | 
| 6323 |         QTest::newRow(dataTag: QString(insert_mode + "nocase2" ).toLatin1()) | 
| 6324 |             << QString("AAAA" ) | 
| 6325 |             << QString("AbCd" ) | 
| 6326 |             << QString("AbCd" ) | 
| 6327 |             << QString("AbCd" ) | 
| 6328 |             << bool(insert_text); | 
| 6329 |  | 
| 6330 |         QTest::newRow(dataTag: QString(insert_mode + "reserved" ).toLatin1()) | 
| 6331 |             << QString("{n}[0]" ) | 
| 6332 |             << QString("A9" ) | 
| 6333 |             << QString("A9" ) | 
| 6334 |             << QString("A9" ) | 
| 6335 |             << bool(insert_text); | 
| 6336 |         QTest::newRow(dataTag: QString(insert_mode + "escape01" ).toLatin1()) | 
| 6337 |             << QString("\\\\N\\\\n00" ) | 
| 6338 |             << QString("9" ) | 
| 6339 |             << QString("Nn9" ) | 
| 6340 |             << QString("Nn9 " ) | 
| 6341 |             << bool(insert_text); | 
| 6342 |         QTest::newRow(dataTag: QString(insert_mode + "escape02" ).toLatin1()) | 
| 6343 |             << QString("\\\\\\\\00" ) | 
| 6344 |             << QString("0" ) | 
| 6345 |             << QString("\\0" ) | 
| 6346 |             << QString("\\0 " ) | 
| 6347 |             << bool(insert_text); | 
| 6348 |         QTest::newRow(dataTag: QString(insert_mode + "escape03" ).toLatin1()) | 
| 6349 |             << QString("\\\\(00\\\\)" ) | 
| 6350 |             << QString("0" ) | 
| 6351 |             << QString("(0)" ) | 
| 6352 |             << QString("(0 )" ) | 
| 6353 |             << bool(insert_text); | 
| 6354 |  | 
| 6355 |         QTest::newRow(dataTag: QString(insert_mode + "upper_lower_nocase1" ).toLatin1()) | 
| 6356 |             << QString(">AAAA<AAAA!AAAA" ) | 
| 6357 |             << QString("AbCdEfGhIjKl" ) | 
| 6358 |             << QString("ABCDefghIjKl" ) | 
| 6359 |             << QString("ABCDefghIjKl" ) | 
| 6360 |             << bool(insert_text); | 
| 6361 |         QTest::newRow(dataTag: QString(insert_mode + "upper_lower_nocase2" ).toLatin1()) | 
| 6362 |             << QString(">aaaa<aaaa!aaaa" ) | 
| 6363 |             << QString("AbCdEfGhIjKl" ) | 
| 6364 |             << QString("ABCDefghIjKl" ) | 
| 6365 |             << QString("ABCDefghIjKl" ) | 
| 6366 |             << bool(insert_text); | 
| 6367 |  | 
| 6368 |         QTest::newRow(dataTag: QString(insert_mode + "exact_case1" ).toLatin1()) | 
| 6369 |             << QString(">A<A<A>A>A<A!A!A" ) | 
| 6370 |             << QString("AbCdEFGH" ) | 
| 6371 |             << QString("AbcDEfGH" ) | 
| 6372 |             << QString("AbcDEfGH" ) | 
| 6373 |             << bool(insert_text); | 
| 6374 |         QTest::newRow(dataTag: QString(insert_mode + "exact_case2" ).toLatin1()) | 
| 6375 |             << QString(">A<A<A>A>A<A!A!A" ) | 
| 6376 |             << QString("aBcDefgh" ) | 
| 6377 |             << QString("AbcDEfgh" ) | 
| 6378 |             << QString("AbcDEfgh" ) | 
| 6379 |             << bool(insert_text); | 
| 6380 |         QTest::newRow(dataTag: QString(insert_mode + "exact_case3" ).toLatin1()) | 
| 6381 |             << QString(">a<a<a>a>a<a!a!a" ) | 
| 6382 |             << QString("AbCdEFGH" ) | 
| 6383 |             << QString("AbcDEfGH" ) | 
| 6384 |             << QString("AbcDEfGH" ) | 
| 6385 |             << bool(insert_text); | 
| 6386 |         QTest::newRow(dataTag: QString(insert_mode + "exact_case4" ).toLatin1()) | 
| 6387 |             << QString(">a<a<a>a>a<a!a!a" ) | 
| 6388 |             << QString("aBcDefgh" ) | 
| 6389 |             << QString("AbcDEfgh" ) | 
| 6390 |             << QString("AbcDEfgh" ) | 
| 6391 |             << bool(insert_text); | 
| 6392 |         QTest::newRow(dataTag: QString(insert_mode + "exact_case5" ).toLatin1()) | 
| 6393 |             << QString(">H<H<H>H>H<H!H!H" ) | 
| 6394 |             << QString("aBcDef01" ) | 
| 6395 |             << QString("AbcDEf01" ) | 
| 6396 |             << QString("AbcDEf01" ) | 
| 6397 |             << bool(insert_text); | 
| 6398 |         QTest::newRow(dataTag: QString(insert_mode + "exact_case6" ).toLatin1()) | 
| 6399 |             << QString(">h<h<h>h>h<h!h!h" ) | 
| 6400 |             << QString("aBcDef92" ) | 
| 6401 |             << QString("AbcDEf92" ) | 
| 6402 |             << QString("AbcDEf92" ) | 
| 6403 |             << bool(insert_text); | 
| 6404 |  | 
| 6405 |         QTest::newRow(dataTag: QString(insert_mode + "illegal_keys1" ).toLatin1()) | 
| 6406 |             << QString("AAAAAAAA" ) | 
| 6407 |             << QString("A2#a;.0!" ) | 
| 6408 |             << QString("Aa" ) | 
| 6409 |             << QString("Aa      " ) | 
| 6410 |             << bool(insert_text); | 
| 6411 |         QTest::newRow(dataTag: QString(insert_mode + "illegal_keys2" ).toLatin1()) | 
| 6412 |             << QString("AAAA" ) | 
| 6413 |             << QString("f4f4f4f4" ) | 
| 6414 |             << QString("ffff" ) | 
| 6415 |             << QString("ffff" ) | 
| 6416 |             << bool(insert_text); | 
| 6417 |         QTest::newRow(dataTag: QString(insert_mode + "blank=input" ).toLatin1()) | 
| 6418 |             << QString("9999;0" ) | 
| 6419 |             << QString("2004" ) | 
| 6420 |             << QString("24" ) | 
| 6421 |             << QString("2004" ) | 
| 6422 |             << bool(insert_text); | 
| 6423 |         QTest::newRow(dataTag: QString(insert_mode + "any_opt" ).toLatin1()) | 
| 6424 |             << QString("@xxx@" ) | 
| 6425 |             << QString("@A C@" ) | 
| 6426 |             << QString("@AC@" ) | 
| 6427 |             << QString("@A C@" ) | 
| 6428 |             << bool(insert_text); | 
| 6429 |         QTest::newRow(dataTag: QString(insert_mode + "any_req" ).toLatin1()) | 
| 6430 |             << QString("@XXX@" ) | 
| 6431 |             << QString("@A C@" ) | 
| 6432 |             << QString("@AC@@" ) | 
| 6433 |             << QString("@AC@@" ) | 
| 6434 |             << bool(insert_text); | 
| 6435 |     } | 
| 6436 | } | 
| 6437 |  | 
| 6438 | void tst_qquicktextinput::setInputMask() | 
| 6439 | { | 
| 6440 |     QFETCH(QString, mask); | 
| 6441 |     QFETCH(QString, input); | 
| 6442 |     QFETCH(QString, expectedText); | 
| 6443 |     QFETCH(QString, expectedDisplay); | 
| 6444 |     QFETCH(bool, insert_text); | 
| 6445 |  | 
| 6446 |     QString componentStr = "import QtQuick 2.0\nTextInput { focus: true; inputMask: \""  + mask + "\" }" ; | 
| 6447 |     QQmlComponent textInputComponent(&engine); | 
| 6448 |     textInputComponent.setData(componentStr.toLatin1(), baseUrl: QUrl()); | 
| 6449 |     QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(object: textInputComponent.create()); | 
| 6450 |     QVERIFY(textInput != nullptr); | 
| 6451 |  | 
| 6452 |     // [QTBUG-80190] check if setting the same property value again doesn't emit an | 
| 6453 |     // inputMaskChanged signal | 
| 6454 |     QString unescapedMask = mask;   // mask is escaped, because '\' is also escape in a JS string | 
| 6455 |     unescapedMask.replace(before: QLatin1String("\\\\" ), after: QLatin1String("\\" ));  // simple unescape | 
| 6456 |     QSignalSpy spy(textInput, SIGNAL(inputMaskChanged(const QString &))); | 
| 6457 |     textInput->setInputMask(unescapedMask); | 
| 6458 |     QCOMPARE(spy.count(), 0); | 
| 6459 |  | 
| 6460 |     // then either insert using insert() or keyboard | 
| 6461 |     if (insert_text) { | 
| 6462 |         textInput->insert(position: 0, text: input); | 
| 6463 |     } else { | 
| 6464 |         QQuickWindow window; | 
| 6465 |         textInput->setParentItem(window.contentItem()); | 
| 6466 |         window.show(); | 
| 6467 |         window.requestActivate(); | 
| 6468 |         QVERIFY(QTest::qWaitForWindowActive(&window)); | 
| 6469 |         QVERIFY(textInput->hasActiveFocus()); | 
| 6470 |  | 
| 6471 |         simulateKey(view: &window, key: Qt::Key_Home); | 
| 6472 |         for (int i = 0; i < input.length(); i++) | 
| 6473 |             QTest::keyClick(window: &window, key: input.at(i).toLatin1()); | 
| 6474 |     } | 
| 6475 |  | 
| 6476 |     QCOMPARE(textInput->text(), expectedText); | 
| 6477 |     QCOMPARE(textInput->displayText(), expectedDisplay); | 
| 6478 | } | 
| 6479 |  | 
| 6480 | void tst_qquicktextinput::inputMask_data() | 
| 6481 | { | 
| 6482 |     QTest::addColumn<QString>(name: "mask" ); | 
| 6483 |     QTest::addColumn<QString>(name: "expectedMask" ); | 
| 6484 |  | 
| 6485 |     // if no mask is set a nul string should be returned | 
| 6486 |     QTest::newRow(dataTag: "nul 1" ) << QString("" ) << QString(); | 
| 6487 |     QTest::newRow(dataTag: "nul 2" ) << QString() << QString(); | 
| 6488 |  | 
| 6489 |     // try different masks | 
| 6490 |     QTest::newRow(dataTag: "mask 1" ) << QString("000.000.000.000" ) << QString("000.000.000.000; " ); | 
| 6491 |     QTest::newRow(dataTag: "mask 2" ) << QString("000.000.000.000;#" ) << QString("000.000.000.000;#" ); | 
| 6492 |     QTest::newRow(dataTag: "mask 3" ) << QString("AAA.aa.999.###;" ) << QString("AAA.aa.999.###; " ); | 
| 6493 |     QTest::newRow(dataTag: "mask 4" ) << QString(">abcdef<GHIJK" ) << QString(">abcdef<GHIJK; " ); | 
| 6494 |  | 
| 6495 |     // set an invalid input mask... | 
| 6496 |     // the current behaviour is that this exact (faulty) string is returned. | 
| 6497 |     QTest::newRow(dataTag: "invalid" ) << QString("ABCDEFGHIKLMNOP;" ) << QString("ABCDEFGHIKLMNOP; " ); | 
| 6498 |  | 
| 6499 |     // verify that we can unset the mask again | 
| 6500 |     QTest::newRow(dataTag: "unset" ) << QString("" ) << QString(); | 
| 6501 | } | 
| 6502 |  | 
| 6503 | void tst_qquicktextinput::inputMask() | 
| 6504 | { | 
| 6505 |     QFETCH(QString, mask); | 
| 6506 |     QFETCH(QString, expectedMask); | 
| 6507 |  | 
| 6508 |     QString componentStr = "import QtQuick 2.0\nTextInput { focus: true; inputMask: \""  + mask + "\" }" ; | 
| 6509 |     QQmlComponent textInputComponent(&engine); | 
| 6510 |     textInputComponent.setData(componentStr.toLatin1(), baseUrl: QUrl()); | 
| 6511 |     QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(object: textInputComponent.create()); | 
| 6512 |     QVERIFY(textInput != nullptr); | 
| 6513 |  | 
| 6514 |     QCOMPARE(textInput->inputMask(), expectedMask); | 
| 6515 | } | 
| 6516 |  | 
| 6517 | void tst_qquicktextinput::clearInputMask() | 
| 6518 | { | 
| 6519 |     QString componentStr = "import QtQuick 2.0\nTextInput { focus: true; inputMask: \"000.000.000.000\" }" ; | 
| 6520 |     QQmlComponent textInputComponent(&engine); | 
| 6521 |     textInputComponent.setData(componentStr.toLatin1(), baseUrl: QUrl()); | 
| 6522 |     QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(object: textInputComponent.create()); | 
| 6523 |     QVERIFY(textInput != nullptr); | 
| 6524 |  | 
| 6525 |     QVERIFY(!textInput->inputMask().isEmpty()); | 
| 6526 |     textInput->setInputMask(QString()); | 
| 6527 |     QCOMPARE(textInput->inputMask(), QString()); | 
| 6528 | } | 
| 6529 |  | 
| 6530 | void tst_qquicktextinput::keypress_inputMask_data() | 
| 6531 | { | 
| 6532 |     QTest::addColumn<QString>(name: "mask" ); | 
| 6533 |     QTest::addColumn<KeyList>(name: "keys" ); | 
| 6534 |     QTest::addColumn<QString>(name: "expectedText" ); | 
| 6535 |     QTest::addColumn<QString>(name: "expectedDisplayText" ); | 
| 6536 |  | 
| 6537 |     { | 
| 6538 |         KeyList keys; | 
| 6539 |         // inserting 'A1.2B' | 
| 6540 |         keys << Qt::Key_Home << "A1.2B" ; | 
| 6541 |         QTest::newRow(dataTag: "jumping on period(separator)" ) << QString("000.000;_" ) << keys << QString("1.2" ) << QString("1__.2__" ); | 
| 6542 |     } | 
| 6543 |     { | 
| 6544 |         KeyList keys; | 
| 6545 |         // inserting '0!P3' | 
| 6546 |         keys << Qt::Key_Home << "0!P3" ; | 
| 6547 |         QTest::newRow(dataTag: "jumping on input" ) << QString("D0.AA.XX.AA.00;_" ) << keys << QString("0..!P..3" ) << QString("_0.__.!P.__.3_" ); | 
| 6548 |     } | 
| 6549 |     { | 
| 6550 |         KeyList keys; | 
| 6551 |         // pressing delete | 
| 6552 |         keys << Qt::Key_Home | 
| 6553 |              << Qt::Key_Delete; | 
| 6554 |         QTest::newRow(dataTag: "delete" ) << QString("000.000;_" ) << keys << QString("." ) << QString("___.___" ); | 
| 6555 |     } | 
| 6556 |     { | 
| 6557 |         KeyList keys; | 
| 6558 |         // selecting all and delete | 
| 6559 |         keys << Qt::Key_Home | 
| 6560 |              << Key(Qt::ShiftModifier, Qt::Key_End) | 
| 6561 |              << Qt::Key_Delete; | 
| 6562 |         QTest::newRow(dataTag: "deleting all" ) << QString("000.000;_" ) << keys << QString("." ) << QString("___.___" ); | 
| 6563 |     } | 
| 6564 |     { | 
| 6565 |         KeyList keys; | 
| 6566 |         // inserting '12.12' then two backspaces | 
| 6567 |         keys << Qt::Key_Home << "12.12"  << Qt::Key_Backspace << Qt::Key_Backspace; | 
| 6568 |         QTest::newRow(dataTag: "backspace" ) << QString("000.000;_" ) << keys << QString("12." ) << QString("12_.___" ); | 
| 6569 |     } | 
| 6570 |     { | 
| 6571 |         KeyList keys; | 
| 6572 |         // inserting '12ab' | 
| 6573 |         keys << Qt::Key_Home << "12ab" ; | 
| 6574 |         QTest::newRow(dataTag: "uppercase" ) << QString("9999 >AA;_" ) << keys << QString("12 AB" ) << QString("12__ AB" ); | 
| 6575 |     } | 
| 6576 |     { | 
| 6577 |         KeyList keys; | 
| 6578 |         // inserting '12ab' | 
| 6579 |         keys << Qt::Key_Right << Qt::Key_Right << "1" ; | 
| 6580 |         QTest::newRow(dataTag: "Move in mask" ) << QString("#0:00;*" ) << keys << QString(":1" ) << QString("**:1*" ); | 
| 6581 |     } | 
| 6582 | } | 
| 6583 |  | 
| 6584 | void tst_qquicktextinput::keypress_inputMask() | 
| 6585 | { | 
| 6586 |     QFETCH(QString, mask); | 
| 6587 |     QFETCH(KeyList, keys); | 
| 6588 |     QFETCH(QString, expectedText); | 
| 6589 |     QFETCH(QString, expectedDisplayText); | 
| 6590 |  | 
| 6591 |     QString componentStr = "import QtQuick 2.0\nTextInput { focus: true; inputMask: \""  + mask + "\" }" ; | 
| 6592 |     QQmlComponent textInputComponent(&engine); | 
| 6593 |     textInputComponent.setData(componentStr.toLatin1(), baseUrl: QUrl()); | 
| 6594 |     QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(object: textInputComponent.create()); | 
| 6595 |     QVERIFY(textInput != nullptr); | 
| 6596 |  | 
| 6597 |     QQuickWindow window; | 
| 6598 |     textInput->setParentItem(window.contentItem()); | 
| 6599 |     window.show(); | 
| 6600 |     window.requestActivate(); | 
| 6601 |     QVERIFY(QTest::qWaitForWindowActive(&window)); | 
| 6602 |     QVERIFY(textInput->hasActiveFocus()); | 
| 6603 |  | 
| 6604 |     simulateKeys(window: &window, keys); | 
| 6605 |  | 
| 6606 |     QCOMPARE(textInput->text(), expectedText); | 
| 6607 |     QCOMPARE(textInput->displayText(), expectedDisplayText); | 
| 6608 | } | 
| 6609 |  | 
| 6610 | void tst_qquicktextinput::keypress_inputMethod_inputMask() | 
| 6611 | { | 
| 6612 |     // Similar to the keypress_inputMask test, but this is done solely via | 
| 6613 |     // input methods | 
| 6614 |     QString componentStr = "import QtQuick 2.0\nTextInput { focus: true; inputMask: \"AA.AA.AA\" }" ; | 
| 6615 |     QQmlComponent textInputComponent(&engine); | 
| 6616 |     textInputComponent.setData(componentStr.toLatin1(), baseUrl: QUrl()); | 
| 6617 |     QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(object: textInputComponent.create()); | 
| 6618 |     QVERIFY(textInput != nullptr); | 
| 6619 |  | 
| 6620 |     QQuickWindow window; | 
| 6621 |     textInput->setParentItem(window.contentItem()); | 
| 6622 |     window.show(); | 
| 6623 |     window.requestActivate(); | 
| 6624 |     QVERIFY(QTest::qWaitForWindowActive(&window)); | 
| 6625 |     QVERIFY(textInput->hasActiveFocus()); | 
| 6626 |  | 
| 6627 |     { | 
| 6628 |         QList<QInputMethodEvent::Attribute> attributes; | 
| 6629 |         QInputMethodEvent event("" , attributes); | 
| 6630 |         event.setCommitString(commitString: "EE" ); | 
| 6631 |         QGuiApplication::sendEvent(receiver: textInput, event: &event); | 
| 6632 |     } | 
| 6633 |     QCOMPARE(textInput->cursorPosition(), 3); | 
| 6634 |     QCOMPARE(textInput->text(), QStringLiteral("EE.." )); | 
| 6635 |     { | 
| 6636 |         QList<QInputMethodEvent::Attribute> attributes; | 
| 6637 |         QInputMethodEvent event("" , attributes); | 
| 6638 |         event.setCommitString(commitString: "EE" ); | 
| 6639 |         QGuiApplication::sendEvent(receiver: textInput, event: &event); | 
| 6640 |     } | 
| 6641 |     QCOMPARE(textInput->cursorPosition(), 6); | 
| 6642 |     QCOMPARE(textInput->text(), QStringLiteral("EE.EE." )); | 
| 6643 |     { | 
| 6644 |         QList<QInputMethodEvent::Attribute> attributes; | 
| 6645 |         QInputMethodEvent event("" , attributes); | 
| 6646 |         event.setCommitString(commitString: "EE" ); | 
| 6647 |         QGuiApplication::sendEvent(receiver: textInput, event: &event); | 
| 6648 |     } | 
| 6649 |     QCOMPARE(textInput->cursorPosition(), 8); | 
| 6650 |     QCOMPARE(textInput->text(), QStringLiteral("EE.EE.EE" )); | 
| 6651 | } | 
| 6652 |  | 
| 6653 | void tst_qquicktextinput::hasAcceptableInputMask_data() | 
| 6654 | { | 
| 6655 |     QTest::addColumn<QString>(name: "optionalMask" ); | 
| 6656 |     QTest::addColumn<QString>(name: "requiredMask" ); | 
| 6657 |     QTest::addColumn<QString>(name: "invalid" ); | 
| 6658 |     QTest::addColumn<QString>(name: "valid" ); | 
| 6659 |  | 
| 6660 |     QTest::newRow(dataTag: "Alphabetic optional and required" ) | 
| 6661 |         << QString("aaaa" ) << QString("AAAA" ) << QString("ab" ) << QString("abcd" ); | 
| 6662 |     QTest::newRow(dataTag: "Alphanumeric optional and require" ) | 
| 6663 |         << QString("nnnn" ) << QString("NNNN" ) << QString("R2" ) << QString("R2D2" ); | 
| 6664 |     QTest::newRow(dataTag: "Any optional and required" ) | 
| 6665 |         << QString("xxxx" ) << QString("XXXX" ) << QString("+-" ) << QString("+-*/" ); | 
| 6666 |     QTest::newRow(dataTag: "Numeric (0-9) required" ) | 
| 6667 |         << QString("0000" ) << QString("9999" ) << QString("11" ) << QString("1138" ); | 
| 6668 |     QTest::newRow(dataTag: "Numeric (1-9) optional and required" ) | 
| 6669 |         << QString("dddd" ) << QString("DDDD" ) << QString("12" ) << QString("1234" ); | 
| 6670 | } | 
| 6671 |  | 
| 6672 | void tst_qquicktextinput::hasAcceptableInputMask() | 
| 6673 | { | 
| 6674 |     QFETCH(QString, optionalMask); | 
| 6675 |     QFETCH(QString, requiredMask); | 
| 6676 |     QFETCH(QString, invalid); | 
| 6677 |     QFETCH(QString, valid); | 
| 6678 |  | 
| 6679 |     QString componentStr = "import QtQuick 2.0\nTextInput { inputMask: \""  + optionalMask + "\" }" ; | 
| 6680 |     QQmlComponent textInputComponent(&engine); | 
| 6681 |     textInputComponent.setData(componentStr.toLatin1(), baseUrl: QUrl()); | 
| 6682 |     QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(object: textInputComponent.create()); | 
| 6683 |     QVERIFY(textInput != nullptr); | 
| 6684 |  | 
| 6685 |     // test that invalid input (for required) work for optionalMask | 
| 6686 |     textInput->setText(invalid); | 
| 6687 |     QVERIFY(textInput->hasAcceptableInput()); | 
| 6688 |  | 
| 6689 |     // test requiredMask | 
| 6690 |     textInput->setInputMask(requiredMask); | 
| 6691 |     textInput->setText(invalid); | 
| 6692 |     // invalid text gets the input mask applied when setting, text becomes acceptable. | 
| 6693 |     QVERIFY(textInput->hasAcceptableInput()); | 
| 6694 |  | 
| 6695 |     textInput->setText(valid); | 
| 6696 |     QVERIFY(textInput->hasAcceptableInput()); | 
| 6697 | } | 
| 6698 |  | 
| 6699 | void tst_qquicktextinput::maskCharacter_data() | 
| 6700 | { | 
| 6701 |     QTest::addColumn<QString>(name: "mask" ); | 
| 6702 |     QTest::addColumn<QString>(name: "input" ); | 
| 6703 |     QTest::addColumn<bool>(name: "expectedValid" ); | 
| 6704 |  | 
| 6705 |     QTest::newRow(dataTag: "Hex" ) << QString("H" ) | 
| 6706 |                          << QString("0123456789abcdefABCDEF" ) << true; | 
| 6707 |     QTest::newRow(dataTag: "hex" ) << QString("h" ) | 
| 6708 |                          << QString("0123456789abcdefABCDEF" ) << true; | 
| 6709 |     QTest::newRow(dataTag: "HexInvalid" ) << QString("H" ) | 
| 6710 |                                 << QString("ghijklmnopqrstuvwxyzGHIJKLMNOPQRSTUVWXYZ" ) | 
| 6711 |                                 << false; | 
| 6712 |     QTest::newRow(dataTag: "hexInvalid" ) << QString("h" ) | 
| 6713 |                                 << QString("ghijklmnopqrstuvwxyzGHIJKLMNOPQRSTUVWXYZ" ) | 
| 6714 |                                 << false; | 
| 6715 |     QTest::newRow(dataTag: "Bin" ) << QString("B" ) | 
| 6716 |                          << QString("01" ) << true; | 
| 6717 |     QTest::newRow(dataTag: "bin" ) << QString("b" ) | 
| 6718 |                          << QString("01" ) << true; | 
| 6719 |     QTest::newRow(dataTag: "BinInvalid" ) << QString("B" ) | 
| 6720 |                                 << QString("23456789qwertyuiopasdfghjklzxcvbnm" ) | 
| 6721 |                                 << false; | 
| 6722 |     QTest::newRow(dataTag: "binInvalid" ) << QString("b" ) | 
| 6723 |                                 << QString("23456789qwertyuiopasdfghjklzxcvbnm" ) | 
| 6724 |                                 << false; | 
| 6725 | } | 
| 6726 |  | 
| 6727 | void tst_qquicktextinput::maskCharacter() | 
| 6728 | { | 
| 6729 |     QFETCH(QString, mask); | 
| 6730 |     QFETCH(QString, input); | 
| 6731 |     QFETCH(bool, expectedValid); | 
| 6732 |  | 
| 6733 |     QString componentStr = "import QtQuick 2.0\nTextInput { inputMask: \""  + mask + "\" }" ; | 
| 6734 |     QQmlComponent textInputComponent(&engine); | 
| 6735 |     textInputComponent.setData(componentStr.toLatin1(), baseUrl: QUrl()); | 
| 6736 |     QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(object: textInputComponent.create()); | 
| 6737 |     QVERIFY(textInput != nullptr); | 
| 6738 |  | 
| 6739 |     for (int i = 0; i < input.size(); ++i) { | 
| 6740 |         QString in = QString(input.at(i)); | 
| 6741 |         QString expected = expectedValid ? in : QString(); | 
| 6742 |         textInput->setText(QString(input.at(i))); | 
| 6743 |         QCOMPARE(textInput->text(), expected); | 
| 6744 |     } | 
| 6745 | } | 
| 6746 |  | 
| 6747 | class TestValidator : public QValidator | 
| 6748 | { | 
| 6749 | public: | 
| 6750 |     TestValidator(QObject *parent = nullptr) : QValidator(parent) { } | 
| 6751 |  | 
| 6752 |     State validate(QString &input, int &) const { return input == QStringLiteral("ok" ) ? Acceptable : Intermediate; } | 
| 6753 |     void fixup(QString &input) const { input = QStringLiteral("ok" ); } | 
| 6754 | }; | 
| 6755 |  | 
| 6756 | void tst_qquicktextinput::fixup() | 
| 6757 | { | 
| 6758 |     QQuickWindow window; | 
| 6759 |     window.show(); | 
| 6760 |     window.requestActivate(); | 
| 6761 |     QVERIFY(QTest::qWaitForWindowActive(&window)); | 
| 6762 |  | 
| 6763 |     QQuickTextInput *input = new QQuickTextInput(window.contentItem()); | 
| 6764 |     input->setValidator(new TestValidator(input)); | 
| 6765 |  | 
| 6766 |     // fixup() on accept | 
| 6767 |     input->setFocus(true); | 
| 6768 |     QVERIFY(input->hasActiveFocus()); | 
| 6769 |     QTest::keyClick(window: &window, key: Qt::Key_Enter); | 
| 6770 |     QCOMPARE(input->text(), QStringLiteral("ok" )); | 
| 6771 |  | 
| 6772 |     // fixup() on defocus | 
| 6773 |     input->setText(QString()); | 
| 6774 |     input->setFocus(false); | 
| 6775 |     QVERIFY(!input->hasActiveFocus()); | 
| 6776 |     QCOMPARE(input->text(), QStringLiteral("ok" )); | 
| 6777 | } | 
| 6778 |  | 
| 6779 | typedef qreal (*ExpectedBaseline)(QQuickTextInput *item); | 
| 6780 | Q_DECLARE_METATYPE(ExpectedBaseline) | 
| 6781 |  | 
| 6782 | static qreal expectedBaselineTop(QQuickTextInput *item) | 
| 6783 | { | 
| 6784 |     QFontMetricsF fm(item->font()); | 
| 6785 |     return fm.ascent() + item->topPadding(); | 
| 6786 | } | 
| 6787 |  | 
| 6788 | static qreal expectedBaselineBottom(QQuickTextInput *item) | 
| 6789 | { | 
| 6790 |     QFontMetricsF fm(item->font()); | 
| 6791 |     return item->height() - item->contentHeight() - item->bottomPadding() + fm.ascent(); | 
| 6792 | } | 
| 6793 |  | 
| 6794 | static qreal expectedBaselineCenter(QQuickTextInput *item) | 
| 6795 | { | 
| 6796 |     QFontMetricsF fm(item->font()); | 
| 6797 |     return ((item->height() - item->contentHeight() - item->topPadding() - item->bottomPadding()) / 2) + fm.ascent() + item->topPadding(); | 
| 6798 | } | 
| 6799 |  | 
| 6800 | static qreal expectedBaselineMultilineBottom(QQuickTextInput *item) | 
| 6801 | { | 
| 6802 |     QFontMetricsF fm(item->font()); | 
| 6803 |     return item->height() - item->contentHeight() - item->bottomPadding() + fm.ascent(); | 
| 6804 | } | 
| 6805 |  | 
| 6806 | void tst_qquicktextinput::baselineOffset_data() | 
| 6807 | { | 
| 6808 |     QTest::addColumn<QString>(name: "text" ); | 
| 6809 |     QTest::addColumn<QByteArray>(name: "bindings" ); | 
| 6810 |     QTest::addColumn<qreal>(name: "setHeight" ); | 
| 6811 |     QTest::addColumn<ExpectedBaseline>(name: "expectedBaseline" ); | 
| 6812 |     QTest::addColumn<ExpectedBaseline>(name: "expectedBaselineEmpty" ); | 
| 6813 |  | 
| 6814 |     QTest::newRow(dataTag: "normal" ) | 
| 6815 |             << "Typography"  | 
| 6816 |             << QByteArray() | 
| 6817 |             << -1. | 
| 6818 |             << &expectedBaselineTop | 
| 6819 |             << &expectedBaselineTop; | 
| 6820 |  | 
| 6821 |     QTest::newRow(dataTag: "top align" ) | 
| 6822 |             << "Typography"  | 
| 6823 |             << QByteArray("height: 200; verticalAlignment: Text.AlignTop" ) | 
| 6824 |             << -1. | 
| 6825 |             << &expectedBaselineTop | 
| 6826 |             << &expectedBaselineTop; | 
| 6827 |  | 
| 6828 |     QTest::newRow(dataTag: "bottom align" ) | 
| 6829 |             << "Typography"  | 
| 6830 |             << QByteArray("height: 200; verticalAlignment: Text.AlignBottom" ) | 
| 6831 |             << 100. | 
| 6832 |             << &expectedBaselineBottom | 
| 6833 |             << &expectedBaselineBottom; | 
| 6834 |  | 
| 6835 |     QTest::newRow(dataTag: "center align" ) | 
| 6836 |             << "Typography"  | 
| 6837 |             << QByteArray("height: 200; verticalAlignment: Text.AlignVCenter" ) | 
| 6838 |             << 100. | 
| 6839 |             << &expectedBaselineCenter | 
| 6840 |             << &expectedBaselineCenter; | 
| 6841 |  | 
| 6842 |     QTest::newRow(dataTag: "multiline bottom aligned" ) | 
| 6843 |             << "The quick brown fox jumps over the lazy dog"  | 
| 6844 |             << QByteArray("height: 200; width: 30; verticalAlignment: Text.AlignBottom; wrapMode: TextInput.WordWrap" ) | 
| 6845 |             << -1. | 
| 6846 |             << &expectedBaselineMultilineBottom | 
| 6847 |             << &expectedBaselineBottom; | 
| 6848 |  | 
| 6849 |     QTest::newRow(dataTag: "padding" ) | 
| 6850 |             << "Typography"  | 
| 6851 |             << QByteArray("topPadding: 10; bottomPadding: 20" ) | 
| 6852 |             << -1. | 
| 6853 |             << &expectedBaselineTop | 
| 6854 |             << &expectedBaselineTop; | 
| 6855 |  | 
| 6856 |     QTest::newRow(dataTag: "top align with padding" ) | 
| 6857 |             << "Typography"  | 
| 6858 |             << QByteArray("height: 200; verticalAlignment: Text.AlignTop; topPadding: 10; bottomPadding: 20" ) | 
| 6859 |             << -1. | 
| 6860 |             << &expectedBaselineTop | 
| 6861 |             << &expectedBaselineTop; | 
| 6862 |  | 
| 6863 |     QTest::newRow(dataTag: "bottom align with padding" ) | 
| 6864 |             << "Typography"  | 
| 6865 |             << QByteArray("height: 200; verticalAlignment: Text.AlignBottom; topPadding: 10; bottomPadding: 20" ) | 
| 6866 |             << 100. | 
| 6867 |             << &expectedBaselineBottom | 
| 6868 |             << &expectedBaselineBottom; | 
| 6869 |  | 
| 6870 |     QTest::newRow(dataTag: "center align with padding" ) | 
| 6871 |             << "Typography"  | 
| 6872 |             << QByteArray("height: 200; verticalAlignment: Text.AlignVCenter; topPadding: 10; bottomPadding: 20" ) | 
| 6873 |             << 100. | 
| 6874 |             << &expectedBaselineCenter | 
| 6875 |             << &expectedBaselineCenter; | 
| 6876 |  | 
| 6877 |     QTest::newRow(dataTag: "multiline bottom aligned with padding" ) | 
| 6878 |             << "The quick brown fox jumps over the lazy dog"  | 
| 6879 |             << QByteArray("height: 200; width: 30; verticalAlignment: Text.AlignBottom; wrapMode: TextInput.WordWrap; topPadding: 10; bottomPadding: 20" ) | 
| 6880 |             << -1. | 
| 6881 |             << &expectedBaselineMultilineBottom | 
| 6882 |             << &expectedBaselineBottom; | 
| 6883 | } | 
| 6884 |  | 
| 6885 | void tst_qquicktextinput::baselineOffset() | 
| 6886 | { | 
| 6887 |     QFETCH(QString, text); | 
| 6888 |     QFETCH(QByteArray, bindings); | 
| 6889 |     QFETCH(qreal, setHeight); | 
| 6890 |     QFETCH(ExpectedBaseline, expectedBaseline); | 
| 6891 |     QFETCH(ExpectedBaseline, expectedBaselineEmpty); | 
| 6892 |  | 
| 6893 |     QQmlComponent component(&engine); | 
| 6894 |     component.setData( | 
| 6895 |             "import QtQuick 2.6\n"  | 
| 6896 |             "TextInput {\n"  | 
| 6897 |                 + bindings + "\n"  | 
| 6898 |             "}" , baseUrl: QUrl()); | 
| 6899 |  | 
| 6900 |     QScopedPointer<QObject> object(component.create()); | 
| 6901 |     QQuickTextInput *item = qobject_cast<QQuickTextInput *>(object: object.data()); | 
| 6902 |  | 
| 6903 |     int passes = setHeight >= 0 ? 2 : 1; | 
| 6904 |     while (passes--) { | 
| 6905 |         QVERIFY(item); | 
| 6906 |         QCOMPARE(item->baselineOffset(), expectedBaselineEmpty(item)); | 
| 6907 |         item->setText(text); | 
| 6908 |         QCOMPARE(item->baselineOffset(), expectedBaseline(item)); | 
| 6909 |         item->setText(QString()); | 
| 6910 |         QCOMPARE(item->baselineOffset(), expectedBaselineEmpty(item)); | 
| 6911 |         if (setHeight >= 0) | 
| 6912 |             item->setHeight(setHeight); | 
| 6913 |     } | 
| 6914 | } | 
| 6915 |  | 
| 6916 | void tst_qquicktextinput::ensureVisible() | 
| 6917 | { | 
| 6918 |     QQmlComponent component(&engine); | 
| 6919 |     component.setData("import QtQuick 2.0\n TextInput {}" , baseUrl: QUrl()); | 
| 6920 |     QScopedPointer<QObject> object(component.create()); | 
| 6921 |     QQuickTextInput *input = qobject_cast<QQuickTextInput *>(object: object.data()); | 
| 6922 |     QVERIFY(input); | 
| 6923 |  | 
| 6924 |     input->setWidth(QFontMetrics(input->font()).averageCharWidth() * 3); | 
| 6925 |     input->setText("Hello World" ); | 
| 6926 |  | 
| 6927 |     QTextLayout layout; | 
| 6928 |     layout.setText(input->text()); | 
| 6929 |     layout.setFont(input->font()); | 
| 6930 |  | 
| 6931 |     if (!qmlDisableDistanceField()) { | 
| 6932 |         QTextOption option; | 
| 6933 |         option.setUseDesignMetrics(true); | 
| 6934 |         layout.setTextOption(option); | 
| 6935 |     } | 
| 6936 |     layout.beginLayout(); | 
| 6937 |     QTextLine line = layout.createLine(); | 
| 6938 |     layout.endLayout(); | 
| 6939 |  | 
| 6940 |     input->ensureVisible(position: 0); | 
| 6941 |  | 
| 6942 |     QCOMPARE(input->boundingRect().x(), qreal(0)); | 
| 6943 |     QCOMPARE(input->boundingRect().y(), qreal(0)); | 
| 6944 |     QCOMPARE(input->boundingRect().width(), line.naturalTextWidth() + input->cursorRectangle().width()); | 
| 6945 |     QCOMPARE(input->boundingRect().height(), line.height()); | 
| 6946 |  | 
| 6947 |     QSignalSpy cursorSpy(input, SIGNAL(cursorRectangleChanged())); | 
| 6948 |     QVERIFY(cursorSpy.isValid()); | 
| 6949 |  | 
| 6950 |     input->ensureVisible(position: input->length()); | 
| 6951 |  | 
| 6952 |     QCOMPARE(cursorSpy.count(), 1); | 
| 6953 |  | 
| 6954 |     QCOMPARE(input->boundingRect().x(), input->width() - line.naturalTextWidth()); | 
| 6955 |     QCOMPARE(input->boundingRect().y(), qreal(0)); | 
| 6956 |     QCOMPARE(input->boundingRect().width(), line.naturalTextWidth() + input->cursorRectangle().width()); | 
| 6957 |     QCOMPARE(input->boundingRect().height(), line.height()); | 
| 6958 | } | 
| 6959 |  | 
| 6960 | void tst_qquicktextinput::padding() | 
| 6961 | { | 
| 6962 |     QScopedPointer<QQuickView> window(new QQuickView); | 
| 6963 |     window->setSource(testFileUrl(fileName: "padding.qml" )); | 
| 6964 |     QTRY_COMPARE(window->status(), QQuickView::Ready); | 
| 6965 |     window->show(); | 
| 6966 |     QVERIFY(QTest::qWaitForWindowExposed(window.data())); | 
| 6967 |     QQuickItem *root = window->rootObject(); | 
| 6968 |     QVERIFY(root); | 
| 6969 |     QQuickTextInput *obj = qobject_cast<QQuickTextInput*>(object: root); | 
| 6970 |     QVERIFY(obj != nullptr); | 
| 6971 |  | 
| 6972 |     qreal cw = obj->contentWidth(); | 
| 6973 |     qreal ch = obj->contentHeight(); | 
| 6974 |  | 
| 6975 |     QVERIFY(cw > 0); | 
| 6976 |     QVERIFY(ch > 0); | 
| 6977 |  | 
| 6978 |     QCOMPARE(obj->padding(), 10.0); | 
| 6979 |     QCOMPARE(obj->topPadding(), 20.0); | 
| 6980 |     QCOMPARE(obj->leftPadding(), 30.0); | 
| 6981 |     QCOMPARE(obj->rightPadding(), 40.0); | 
| 6982 |     QCOMPARE(obj->bottomPadding(), 50.0); | 
| 6983 |  | 
| 6984 |     QCOMPARE(obj->implicitWidth(), qCeil(cw) + obj->leftPadding() + obj->rightPadding()); | 
| 6985 |     QCOMPARE(obj->implicitHeight(), qCeil(ch) + obj->topPadding() + obj->bottomPadding()); | 
| 6986 |  | 
| 6987 |     obj->setTopPadding(2.25); | 
| 6988 |     QCOMPARE(obj->topPadding(), 2.25); | 
| 6989 |     QCOMPARE(obj->implicitHeight(), qCeil(ch) + obj->topPadding() + obj->bottomPadding()); | 
| 6990 |  | 
| 6991 |     obj->setLeftPadding(3.75); | 
| 6992 |     QCOMPARE(obj->leftPadding(), 3.75); | 
| 6993 |     QCOMPARE(obj->implicitWidth(), qCeil(cw) + obj->leftPadding() + obj->rightPadding()); | 
| 6994 |  | 
| 6995 |     obj->setRightPadding(4.4); | 
| 6996 |     QCOMPARE(obj->rightPadding(), 4.4); | 
| 6997 |     QCOMPARE(obj->implicitWidth(), qCeil(cw) + obj->leftPadding() + obj->rightPadding()); | 
| 6998 |  | 
| 6999 |     obj->setBottomPadding(1.11); | 
| 7000 |     QCOMPARE(obj->bottomPadding(), 1.11); | 
| 7001 |     QCOMPARE(obj->implicitHeight(), qCeil(ch) + obj->topPadding() + obj->bottomPadding()); | 
| 7002 |  | 
| 7003 |     obj->setText("Qt" ); | 
| 7004 |     QVERIFY(obj->contentWidth() < cw); | 
| 7005 |     QCOMPARE(obj->contentHeight(), ch); | 
| 7006 |     cw = obj->contentWidth(); | 
| 7007 |  | 
| 7008 |     QCOMPARE(obj->implicitWidth(), qCeil(cw) + obj->leftPadding() + obj->rightPadding()); | 
| 7009 |     QCOMPARE(obj->implicitHeight(), qCeil(ch) + obj->topPadding() + obj->bottomPadding()); | 
| 7010 |  | 
| 7011 |     obj->setFont(QFont("Courier" , 96)); | 
| 7012 |     QVERIFY(obj->contentWidth() > cw); | 
| 7013 |     QVERIFY(obj->contentHeight() > ch); | 
| 7014 |     cw = obj->contentWidth(); | 
| 7015 |     ch = obj->contentHeight(); | 
| 7016 |  | 
| 7017 |     QCOMPARE(obj->implicitWidth(), qCeil(cw) + obj->leftPadding() + obj->rightPadding()); | 
| 7018 |     QCOMPARE(obj->implicitHeight(), qCeil(ch) + obj->topPadding() + obj->bottomPadding()); | 
| 7019 |  | 
| 7020 |     obj->resetTopPadding(); | 
| 7021 |     QCOMPARE(obj->topPadding(), 10.0); | 
| 7022 |     obj->resetLeftPadding(); | 
| 7023 |     QCOMPARE(obj->leftPadding(), 10.0); | 
| 7024 |     obj->resetRightPadding(); | 
| 7025 |     QCOMPARE(obj->rightPadding(), 10.0); | 
| 7026 |     obj->resetBottomPadding(); | 
| 7027 |     QCOMPARE(obj->bottomPadding(), 10.0); | 
| 7028 |  | 
| 7029 |     obj->resetPadding(); | 
| 7030 |     QCOMPARE(obj->padding(), 0.0); | 
| 7031 |     QCOMPARE(obj->topPadding(), 0.0); | 
| 7032 |     QCOMPARE(obj->leftPadding(), 0.0); | 
| 7033 |     QCOMPARE(obj->rightPadding(), 0.0); | 
| 7034 |     QCOMPARE(obj->bottomPadding(), 0.0); | 
| 7035 |  | 
| 7036 |     delete root; | 
| 7037 | } | 
| 7038 |  | 
| 7039 | void tst_qquicktextinput::QTBUG_51115_readOnlyResetsSelection() | 
| 7040 | { | 
| 7041 |     QQuickView view; | 
| 7042 |     view.setSource(testFileUrl(fileName: "qtbug51115.qml" )); | 
| 7043 |     view.show(); | 
| 7044 |     QVERIFY(QTest::qWaitForWindowExposed(&view)); | 
| 7045 |     QQuickTextInput *obj = qobject_cast<QQuickTextInput*>(object: view.rootObject()); | 
| 7046 |  | 
| 7047 |     QCOMPARE(obj->selectedText(), QString()); | 
| 7048 | } | 
| 7049 |  | 
| 7050 | void tst_qquicktextinput::QTBUG_77814_InsertRemoveNoSelection() | 
| 7051 | { | 
| 7052 |     QQuickView view; | 
| 7053 |     view.setSource(testFileUrl(fileName: "qtbug77841.qml" )); | 
| 7054 |     view.show(); | 
| 7055 |     QVERIFY(QTest::qWaitForWindowExposed(&view)); | 
| 7056 |     QQuickTextInput *textInput = view.rootObject()->findChild<QQuickTextInput*>(aName: "qwe" ); | 
| 7057 |     QVERIFY(textInput); | 
| 7058 |  | 
| 7059 |     QCOMPARE(textInput->selectedText(), QString()); | 
| 7060 | } | 
| 7061 |  | 
| 7062 | void tst_qquicktextinput::checkCursorDelegateWhenPaddingChanged() | 
| 7063 | { | 
| 7064 |     QQuickView view; | 
| 7065 |     view.setSource(testFileUrl(fileName: "checkCursorDelegateWhenPaddingChanged.qml" )); | 
| 7066 |     view.show(); | 
| 7067 |     QVERIFY(QTest::qWaitForWindowExposed(&view)); | 
| 7068 |  | 
| 7069 |     QQuickTextInput *textInput = view.rootObject()->findChild<QQuickTextInput *>(aName: "textInput" ); | 
| 7070 |     QVERIFY(textInput); | 
| 7071 |  | 
| 7072 |     QQuickItem *cursorDelegate = textInput->findChild<QQuickItem *>(aName: "cursorDelegate" ); | 
| 7073 |     QVERIFY(cursorDelegate); | 
| 7074 |  | 
| 7075 |     QCOMPARE(cursorDelegate->x(), textInput->leftPadding()); | 
| 7076 |     QCOMPARE(cursorDelegate->y(), textInput->topPadding()); | 
| 7077 |  | 
| 7078 |     textInput->setPadding(5); | 
| 7079 |     QCOMPARE(cursorDelegate->x(), textInput->leftPadding()); | 
| 7080 |     QCOMPARE(cursorDelegate->y(), textInput->topPadding()); | 
| 7081 |  | 
| 7082 |     textInput->setTopPadding(10); | 
| 7083 |     QCOMPARE(cursorDelegate->x(), textInput->leftPadding()); | 
| 7084 |     QCOMPARE(cursorDelegate->y(), textInput->topPadding()); | 
| 7085 |  | 
| 7086 |     textInput->setLeftPadding(10); | 
| 7087 |     QCOMPARE(cursorDelegate->x(), textInput->leftPadding()); | 
| 7088 |     QCOMPARE(cursorDelegate->y(), textInput->topPadding()); | 
| 7089 | } | 
| 7090 |  | 
| 7091 | /*! | 
| 7092 |     Verifies that TextInput items get focus in/out events with the | 
| 7093 |     correct focus reason set. | 
| 7094 |  | 
| 7095 |     Up and Down keys translates to Backtab and Tab focus reasons. | 
| 7096 |  | 
| 7097 |     See QTBUG-75862. | 
| 7098 | */ | 
| 7099 | void tst_qquicktextinput::focusReason() | 
| 7100 | { | 
| 7101 |     QQuickView view; | 
| 7102 |     view.setSource(testFileUrl(fileName: "focusReason.qml" )); | 
| 7103 |  | 
| 7104 |     QQuickTextInput *first = view.rootObject()->findChild<QQuickTextInput *>(aName: "first" ); | 
| 7105 |     QQuickTextInput *second = view.rootObject()->findChild<QQuickTextInput *>(aName: "second" ); | 
| 7106 |     QQuickTextInput *third = view.rootObject()->findChild<QQuickTextInput *>(aName: "third" ); | 
| 7107 |     QVERIFY(first && second && third); | 
| 7108 |  | 
| 7109 |     class FocusEventFilter : public QObject | 
| 7110 |     { | 
| 7111 |     public: | 
| 7112 |         using QObject::QObject; | 
| 7113 |  | 
| 7114 |         QHash<QObject*, Qt::FocusReason> lastFocusReason; | 
| 7115 |     protected: | 
| 7116 |         bool eventFilter(QObject *o, QEvent *e) | 
| 7117 |         { | 
| 7118 |             if (e->type() == QEvent::FocusIn || e->type() == QEvent::FocusOut) { | 
| 7119 |                 QFocusEvent *fe = static_cast<QFocusEvent*>(e); | 
| 7120 |                 lastFocusReason[o] = fe->reason(); | 
| 7121 |             } | 
| 7122 |             return QObject::eventFilter(watched: o, event: e); | 
| 7123 |         } | 
| 7124 |     } eventFilter; | 
| 7125 |     first->installEventFilter(filterObj: &eventFilter); | 
| 7126 |     second->installEventFilter(filterObj: &eventFilter); | 
| 7127 |     third->installEventFilter(filterObj: &eventFilter); | 
| 7128 |  | 
| 7129 |     view.show(); | 
| 7130 |     QVERIFY(QTest::qWaitForWindowActive(&view)); | 
| 7131 |  | 
| 7132 |     QCOMPARE(qApp->focusObject(), first); | 
| 7133 |     // on some platforms we don't get ActiveWindowFocusReason; tolerate this, | 
| 7134 |     // it's not what we are testing in this test | 
| 7135 |     if (eventFilter.lastFocusReason[first] != Qt::ActiveWindowFocusReason) { | 
| 7136 |         QEXPECT_FAIL("" , qPrintable(QString("No window activation event on the %1 platform" ) | 
| 7137 |                                             .arg(QGuiApplication::platformName())), | 
| 7138 |                      Continue); | 
| 7139 |     } | 
| 7140 |     QCOMPARE(eventFilter.lastFocusReason[first], Qt::ActiveWindowFocusReason); | 
| 7141 |  | 
| 7142 |     QTest::mouseClick(window: &view, button: Qt::LeftButton, stateKey: {}, | 
| 7143 |                       pos: (second->boundingRect().center() + second->position()).toPoint()); | 
| 7144 |     QTRY_COMPARE(qApp->focusObject(), second); | 
| 7145 |     QCOMPARE(eventFilter.lastFocusReason[first], Qt::MouseFocusReason); | 
| 7146 |     QCOMPARE(eventFilter.lastFocusReason[second], Qt::MouseFocusReason); | 
| 7147 |  | 
| 7148 |     QTest::keyClick(window: &view, key: Qt::Key_Tab); | 
| 7149 |     QCOMPARE(qApp->focusObject(), third); | 
| 7150 |     QCOMPARE(eventFilter.lastFocusReason[second], Qt::TabFocusReason); | 
| 7151 |     QCOMPARE(eventFilter.lastFocusReason[third], Qt::TabFocusReason); | 
| 7152 |  | 
| 7153 |     QTest::keyClick(window: &view, key: Qt::Key_Backtab); | 
| 7154 |     QCOMPARE(qApp->focusObject(), second); | 
| 7155 |     QCOMPARE(eventFilter.lastFocusReason[third], Qt::BacktabFocusReason); | 
| 7156 |     QCOMPARE(eventFilter.lastFocusReason[second], Qt::BacktabFocusReason); | 
| 7157 |  | 
| 7158 |     QTest::keyClick(window: &view, key: Qt::Key_Up); | 
| 7159 |     QCOMPARE(qApp->focusObject(), first); | 
| 7160 |     QCOMPARE(eventFilter.lastFocusReason[second], Qt::BacktabFocusReason); | 
| 7161 |     QCOMPARE(eventFilter.lastFocusReason[first], Qt::BacktabFocusReason); | 
| 7162 |  | 
| 7163 |     QTest::keyClick(window: &view, key: Qt::Key_Down); | 
| 7164 |     QCOMPARE(qApp->focusObject(), second); | 
| 7165 |     QCOMPARE(eventFilter.lastFocusReason[second], Qt::TabFocusReason); | 
| 7166 |     QCOMPARE(eventFilter.lastFocusReason[first], Qt::TabFocusReason); | 
| 7167 | } | 
| 7168 |  | 
| 7169 | QTEST_MAIN(tst_qquicktextinput) | 
| 7170 |  | 
| 7171 | #include "tst_qquicktextinput.moc" | 
| 7172 |  |