| 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 | |
| 29 | |
| 30 | #include <QtTest/QtTest> |
| 31 | #include <QtTest/private/qtesthelpers_p.h> |
| 32 | #include "qlineedit.h" |
| 33 | #include "qapplication.h" |
| 34 | #include "qstringlist.h" |
| 35 | #include "qstyle.h" |
| 36 | #include "qvalidator.h" |
| 37 | #include "qwidgetaction.h" |
| 38 | #include "qimage.h" |
| 39 | #include "qicon.h" |
| 40 | #include "qcompleter.h" |
| 41 | #include "qstandarditemmodel.h" |
| 42 | #include <qpa/qplatformtheme.h> |
| 43 | #include "qstylehints.h" |
| 44 | #include <private/qapplication_p.h> |
| 45 | #include "qclipboard.h" |
| 46 | |
| 47 | #include <qlineedit.h> |
| 48 | #include <private/qlineedit_p.h> |
| 49 | #include <private/qwidgetlinecontrol_p.h> |
| 50 | #include <qmenu.h> |
| 51 | #include <qlabel.h> |
| 52 | #include <qlayout.h> |
| 53 | #include <qspinbox.h> |
| 54 | #include <qlistview.h> |
| 55 | #include <qstringlistmodel.h> |
| 56 | #include <qsortfilterproxymodel.h> |
| 57 | #include <qdebug.h> |
| 58 | #include <qscreen.h> |
| 59 | #include <qshortcut.h> |
| 60 | |
| 61 | #include "qcommonstyle.h" |
| 62 | #include "qstyleoption.h" |
| 63 | |
| 64 | #include "qplatformdefs.h" |
| 65 | |
| 66 | #include "../../../shared/platformclipboard.h" |
| 67 | #include "../../../shared/platforminputcontext.h" |
| 68 | #include <private/qinputmethod_p.h> |
| 69 | |
| 70 | Q_LOGGING_CATEGORY(lcTests, "qt.widgets.tests" ) |
| 71 | |
| 72 | QT_BEGIN_NAMESPACE |
| 73 | class QPainter; |
| 74 | QT_END_NAMESPACE |
| 75 | |
| 76 | using namespace QTestPrivate; |
| 77 | |
| 78 | class StyleOptionTestStyle : public QCommonStyle |
| 79 | { |
| 80 | public: |
| 81 | bool readOnly = false; |
| 82 | mutable bool wasDrawn = false; |
| 83 | |
| 84 | using QCommonStyle::QCommonStyle; |
| 85 | void setReadOnly(bool readOnly) |
| 86 | { |
| 87 | this->readOnly = readOnly; |
| 88 | } |
| 89 | |
| 90 | void drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPainter *, |
| 91 | const QWidget *) const override |
| 92 | { |
| 93 | switch (pe) { |
| 94 | case PE_PanelLineEdit: |
| 95 | wasDrawn = true; |
| 96 | if (readOnly) |
| 97 | QVERIFY(opt->state & QStyle::State_ReadOnly); |
| 98 | else |
| 99 | QVERIFY(!(opt->state & QStyle::State_ReadOnly)); |
| 100 | break; |
| 101 | |
| 102 | default: |
| 103 | break; |
| 104 | } |
| 105 | } |
| 106 | }; |
| 107 | |
| 108 | class tst_QLineEdit : public QObject |
| 109 | { |
| 110 | Q_OBJECT |
| 111 | |
| 112 | public: |
| 113 | enum EventStates { Press, Release, Click }; |
| 114 | |
| 115 | tst_QLineEdit(); |
| 116 | |
| 117 | private slots: |
| 118 | void initTestCase(); |
| 119 | void cleanupTestCase(); |
| 120 | void init(); |
| 121 | void cleanup(); |
| 122 | |
| 123 | void getSetCheck(); |
| 124 | void experimental(); |
| 125 | |
| 126 | void upperAndLowercase(); |
| 127 | |
| 128 | void setInputMask_data(); |
| 129 | void setInputMask(); |
| 130 | |
| 131 | void inputMask_data(); |
| 132 | void inputMask(); |
| 133 | |
| 134 | void clearInputMask(); |
| 135 | |
| 136 | void keypress_inputMask_data(); |
| 137 | void keypress_inputMask(); |
| 138 | void keypress_inputMethod_inputMask(); |
| 139 | |
| 140 | void inputMaskAndValidator_data(); |
| 141 | void inputMaskAndValidator(); |
| 142 | |
| 143 | void hasAcceptableInputMask_data(); |
| 144 | void hasAcceptableInputMask(); |
| 145 | |
| 146 | void hasAcceptableInputValidator(); |
| 147 | |
| 148 | |
| 149 | void redo_data(); |
| 150 | void redo(); |
| 151 | |
| 152 | void undo_data(); |
| 153 | void undo(); |
| 154 | |
| 155 | void undo_keypressevents_data(); |
| 156 | void undo_keypressevents(); |
| 157 | |
| 158 | #ifndef QT_NO_CLIPBOARD |
| 159 | void QTBUG5786_undoPaste(); |
| 160 | #endif |
| 161 | |
| 162 | void clear(); |
| 163 | |
| 164 | void text_data(); |
| 165 | void text(); |
| 166 | void textMask_data(); |
| 167 | void textMask(); |
| 168 | void maskCharacter(); |
| 169 | void maskCharacter_data(); |
| 170 | void setText(); |
| 171 | |
| 172 | void displayText_data(); |
| 173 | void displayText(); |
| 174 | void passwordEchoOnEdit(); |
| 175 | void passwordEchoDelay(); |
| 176 | |
| 177 | void maxLength_mask_data(); |
| 178 | void maxLength_mask(); |
| 179 | |
| 180 | void maxLength_data(); |
| 181 | void maxLength(); |
| 182 | |
| 183 | void isReadOnly(); |
| 184 | |
| 185 | void noCursorBlinkWhenReadOnly(); |
| 186 | |
| 187 | void cursorPosition(); |
| 188 | |
| 189 | void cursorPositionChanged_data(); |
| 190 | void cursorPositionChanged(); |
| 191 | |
| 192 | void selectedText(); |
| 193 | void deleteSelectedText(); |
| 194 | |
| 195 | void textChangedAndTextEdited(); |
| 196 | void returnPressed(); |
| 197 | void returnPressed_maskvalidator_data(); |
| 198 | void returnPressed_maskvalidator(); |
| 199 | |
| 200 | void setValidator(); |
| 201 | void setValidator_QIntValidator_data(); |
| 202 | void setValidator_QIntValidator(); |
| 203 | |
| 204 | void frame_data(); |
| 205 | void frame(); |
| 206 | |
| 207 | void leftKeyOnSelectedText(); |
| 208 | |
| 209 | void setAlignment_data(); |
| 210 | void setAlignment(); |
| 211 | |
| 212 | void isModified(); |
| 213 | void edited(); |
| 214 | void fixupDoesNotModify_QTBUG_49295(); |
| 215 | |
| 216 | void insert(); |
| 217 | void setSelection_data(); |
| 218 | void setSelection(); |
| 219 | |
| 220 | #ifndef QT_NO_CLIPBOARD |
| 221 | void cut(); |
| 222 | void cutWithoutSelection(); |
| 223 | #endif |
| 224 | void maxLengthAndInputMask(); |
| 225 | void returnPressedKeyEvent(); |
| 226 | |
| 227 | void keepSelectionOnTabFocusIn(); |
| 228 | |
| 229 | void readOnlyStyleOption(); |
| 230 | |
| 231 | void validateOnFocusOut(); |
| 232 | |
| 233 | void editInvalidText(); |
| 234 | |
| 235 | void charWithAltOrCtrlModifier_data(); |
| 236 | void charWithAltOrCtrlModifier(); |
| 237 | |
| 238 | void inlineCompletion(); |
| 239 | |
| 240 | void noTextEditedOnClear(); |
| 241 | |
| 242 | #ifndef QT_NO_CURSOR |
| 243 | void cursor(); |
| 244 | #endif |
| 245 | |
| 246 | void textMargin_data(); |
| 247 | void textMargin(); |
| 248 | |
| 249 | // task-specific tests: |
| 250 | void task180999_focus(); |
| 251 | void task174640_editingFinished(); |
| 252 | #if QT_CONFIG(completer) |
| 253 | void task198789_currentCompletion(); |
| 254 | void task210502_caseInsensitiveInlineCompletion(); |
| 255 | #endif |
| 256 | void task229938_dontEmitChangedWhenTextIsNotChanged(); |
| 257 | void task233101_cursorPosAfterInputMethod_data(); |
| 258 | void task233101_cursorPosAfterInputMethod(); |
| 259 | void task241436_passwordEchoOnEditRestoreEchoMode(); |
| 260 | void task248948_redoRemovedSelection(); |
| 261 | void taskQTBUG_4401_enterKeyClearsPassword(); |
| 262 | void taskQTBUG_4679_moveToStartEndOfBlock(); |
| 263 | void taskQTBUG_4679_selectToStartEndOfBlock(); |
| 264 | #ifndef QT_NO_CONTEXTMENU |
| 265 | void taskQTBUG_7902_contextMenuCrash(); |
| 266 | #endif |
| 267 | void taskQTBUG_7395_readOnlyShortcut(); |
| 268 | void QTBUG697_paletteCurrentColorGroup(); |
| 269 | void QTBUG13520_textNotVisible(); |
| 270 | void QTBUG7174_inputMaskCursorBlink(); |
| 271 | void QTBUG16850_setSelection(); |
| 272 | |
| 273 | void bidiVisualMovement_data(); |
| 274 | void bidiVisualMovement(); |
| 275 | |
| 276 | void bidiLogicalMovement_data(); |
| 277 | void bidiLogicalMovement(); |
| 278 | |
| 279 | void selectAndCursorPosition(); |
| 280 | void inputMethod(); |
| 281 | void inputMethodSelection(); |
| 282 | |
| 283 | void inputMethodQueryImHints_data(); |
| 284 | void inputMethodQueryImHints(); |
| 285 | |
| 286 | void inputMethodUpdate(); |
| 287 | |
| 288 | void undoRedoAndEchoModes_data(); |
| 289 | void undoRedoAndEchoModes(); |
| 290 | |
| 291 | void clearButton(); |
| 292 | void clearButtonVisibleAfterSettingText_QTBUG_45518(); |
| 293 | void sideWidgets(); |
| 294 | void sideWidgetsActionEvents(); |
| 295 | void sideWidgetsEffectiveMargins(); |
| 296 | |
| 297 | void shouldShowPlaceholderText_data(); |
| 298 | void shouldShowPlaceholderText(); |
| 299 | void QTBUG1266_setInputMaskEmittingTextEdited(); |
| 300 | |
| 301 | void shortcutOverrideOnReadonlyLineEdit_data(); |
| 302 | void shortcutOverrideOnReadonlyLineEdit(); |
| 303 | void QTBUG59957_clearButtonLeftmostAction(); |
| 304 | void QTBUG_60319_setInputMaskCheckImSurroundingText(); |
| 305 | void testQuickSelectionWithMouse(); |
| 306 | void inputRejected(); |
| 307 | protected slots: |
| 308 | void editingFinished(); |
| 309 | |
| 310 | void onTextChanged( const QString &newString ); |
| 311 | void onTextEdited( const QString &newString ); |
| 312 | void onReturnPressed(); |
| 313 | void onSelectionChanged(); |
| 314 | void onCursorPositionChanged(int oldpos, int newpos); |
| 315 | |
| 316 | private: |
| 317 | // keyClicks(..) is moved to QtTestCase |
| 318 | void psKeyClick(QWidget *target, Qt::Key key, Qt::KeyboardModifiers pressState = {}); |
| 319 | void psKeyClick(QTestEventList &keys, Qt::Key key, Qt::KeyboardModifiers pressState = {}); |
| 320 | bool unselectingWithLeftOrRightChangesCursorPosition(); |
| 321 | void addKeySequenceStandardKey(QTestEventList &keys, QKeySequence::StandardKey); |
| 322 | QLineEdit *ensureTestWidget(); |
| 323 | |
| 324 | bool validInput; |
| 325 | QString changed_string; |
| 326 | int changed_count; |
| 327 | int edited_count; |
| 328 | int return_count; |
| 329 | int selection_count; |
| 330 | int lastCursorPos; |
| 331 | int newCursorPos; |
| 332 | QLineEdit *m_testWidget; |
| 333 | int m_keyboardScheme; |
| 334 | PlatformInputContext m_platformInputContext; |
| 335 | }; |
| 336 | |
| 337 | typedef QList<int> IntList; |
| 338 | Q_DECLARE_METATYPE(QLineEdit::EchoMode) |
| 339 | |
| 340 | // Testing get/set functions |
| 341 | void tst_QLineEdit::getSetCheck() |
| 342 | { |
| 343 | QLineEdit obj1; |
| 344 | // const QValidator * QLineEdit::validator() |
| 345 | // void QLineEdit::setValidator(const QValidator *) |
| 346 | QIntValidator *var1 = new QIntValidator(0); |
| 347 | obj1.setValidator(var1); |
| 348 | QCOMPARE((const QValidator *)var1, obj1.validator()); |
| 349 | obj1.setValidator((QValidator *)0); |
| 350 | QCOMPARE((const QValidator *)0, obj1.validator()); |
| 351 | delete var1; |
| 352 | |
| 353 | // bool QLineEdit::dragEnabled() |
| 354 | // void QLineEdit::setDragEnabled(bool) |
| 355 | obj1.setDragEnabled(false); |
| 356 | QCOMPARE(false, obj1.dragEnabled()); |
| 357 | obj1.setDragEnabled(true); |
| 358 | QCOMPARE(true, obj1.dragEnabled()); |
| 359 | } |
| 360 | |
| 361 | tst_QLineEdit::tst_QLineEdit() : validInput(false), m_testWidget(0), m_keyboardScheme(0) |
| 362 | { |
| 363 | if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) |
| 364 | m_keyboardScheme = theme->themeHint(hint: QPlatformTheme::KeyboardScheme).toInt(); |
| 365 | // Generalize for X11 |
| 366 | if (m_keyboardScheme == QPlatformTheme::KdeKeyboardScheme |
| 367 | || m_keyboardScheme == QPlatformTheme::GnomeKeyboardScheme |
| 368 | || m_keyboardScheme == QPlatformTheme::CdeKeyboardScheme) { |
| 369 | m_keyboardScheme = QPlatformTheme::X11KeyboardScheme; |
| 370 | } |
| 371 | } |
| 372 | |
| 373 | QLineEdit *tst_QLineEdit::ensureTestWidget() |
| 374 | { |
| 375 | if (!m_testWidget) { |
| 376 | m_testWidget = new QLineEdit; |
| 377 | m_testWidget->setObjectName("testWidget" ); |
| 378 | connect(sender: m_testWidget, SIGNAL(cursorPositionChanged(int,int)), receiver: this, SLOT(onCursorPositionChanged(int,int))); |
| 379 | connect(sender: m_testWidget, SIGNAL(textChanged(QString)), receiver: this, SLOT(onTextChanged(QString))); |
| 380 | connect(sender: m_testWidget, SIGNAL(textEdited(QString)), receiver: this, SLOT(onTextEdited(QString))); |
| 381 | connect(sender: m_testWidget, SIGNAL(returnPressed()), receiver: this, SLOT(onReturnPressed())); |
| 382 | connect(sender: m_testWidget, SIGNAL(selectionChanged()), receiver: this, SLOT(onSelectionChanged())); |
| 383 | connect(sender: m_testWidget, SIGNAL(editingFinished()), receiver: this, SLOT(editingFinished())); |
| 384 | m_testWidget->resize(w: 200,h: 50); |
| 385 | } |
| 386 | return m_testWidget; |
| 387 | } |
| 388 | |
| 389 | void tst_QLineEdit::initTestCase() |
| 390 | { |
| 391 | changed_count = 0; |
| 392 | edited_count = 0; |
| 393 | selection_count = 0; |
| 394 | |
| 395 | QInputMethodPrivate *inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod()); |
| 396 | inputMethodPrivate->testContext = &m_platformInputContext; |
| 397 | } |
| 398 | |
| 399 | void tst_QLineEdit::cleanupTestCase() |
| 400 | { |
| 401 | QInputMethodPrivate *inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod()); |
| 402 | inputMethodPrivate->testContext = 0; |
| 403 | } |
| 404 | |
| 405 | void tst_QLineEdit::init() |
| 406 | { |
| 407 | return_count = 0; |
| 408 | } |
| 409 | |
| 410 | void tst_QLineEdit::cleanup() |
| 411 | { |
| 412 | delete m_testWidget; |
| 413 | m_testWidget = 0; |
| 414 | m_platformInputContext.m_commitString.clear(); |
| 415 | } |
| 416 | |
| 417 | void tst_QLineEdit::experimental() |
| 418 | { |
| 419 | QLineEdit *testWidget = ensureTestWidget(); |
| 420 | QIntValidator intValidator(3, 7, 0); |
| 421 | testWidget->setValidator(&intValidator); |
| 422 | testWidget->setText("" ); |
| 423 | |
| 424 | |
| 425 | // test the order of setting these |
| 426 | testWidget->setInputMask("" ); |
| 427 | testWidget->setText("abc123" ); |
| 428 | testWidget->setInputMask("000.000.000.000" ); |
| 429 | QCOMPARE(testWidget->text(), QString("123..." )); |
| 430 | testWidget->setText("" ); |
| 431 | |
| 432 | |
| 433 | } |
| 434 | |
| 435 | void tst_QLineEdit::upperAndLowercase() |
| 436 | { |
| 437 | QLineEdit *testWidget = ensureTestWidget(); |
| 438 | |
| 439 | QTest::keyClicks(widget: testWidget, sequence: "aAzZ`1234567890-=~!@#$%^&*()_+[]{}\\|;:'\",.<>/?" ); |
| 440 | qApp->processEvents(); |
| 441 | QCOMPARE(testWidget->text(), QString("aAzZ`1234567890-=~!@#$%^&*()_+[]{}\\|;:'\",.<>/?" )); |
| 442 | } |
| 443 | |
| 444 | void tst_QLineEdit::setInputMask_data() |
| 445 | { |
| 446 | QTest::addColumn<QString>(name: "mask" ); |
| 447 | QTest::addColumn<QString>(name: "input" ); |
| 448 | QTest::addColumn<QString>(name: "expectedText" ); |
| 449 | QTest::addColumn<QString>(name: "expectedDisplay" ); |
| 450 | QTest::addColumn<bool>(name: "insert_text" ); |
| 451 | |
| 452 | // both keyboard and insert() |
| 453 | for (int i=0; i<2; i++) { |
| 454 | bool insert_text = i==0 ? false : true; |
| 455 | QString insert_mode = "keys " ; |
| 456 | if (insert_text) |
| 457 | insert_mode = "insert " ; |
| 458 | |
| 459 | QTest::newRow(dataTag: QString(insert_mode + "ip_localhost" ).toLatin1()) |
| 460 | << QString("000.000.000.000" ) |
| 461 | << QString("127.0.0.1" ) |
| 462 | << QString("127.0.0.1" ) |
| 463 | << QString("127.0 .0 .1 " ) |
| 464 | << bool(insert_text); |
| 465 | QTest::newRow(dataTag: QString(insert_mode + "mac" ).toLatin1()) |
| 466 | << QString("HH:HH:HH:HH:HH:HH;#" ) |
| 467 | << QString("00:E0:81:21:9E:8E" ) |
| 468 | << QString("00:E0:81:21:9E:8E" ) |
| 469 | << QString("00:E0:81:21:9E:8E" ) |
| 470 | << bool(insert_text); |
| 471 | QTest::newRow(dataTag: QString(insert_mode + "mac2" ).toLatin1()) |
| 472 | << QString("<HH:>HH:!HH:HH:HH:HH;#" ) |
| 473 | << QString("AAe081219E8E" ) |
| 474 | << QString("aa:E0:81:21:9E:8E" ) |
| 475 | << QString("aa:E0:81:21:9E:8E" ) |
| 476 | << bool(insert_text); |
| 477 | QTest::newRow(dataTag: QString(insert_mode + "byte" ).toLatin1()) |
| 478 | << QString("BBBBBBBB;0" ) |
| 479 | << QString("11011001" ) |
| 480 | << QString("11111" ) |
| 481 | << QString("11011001" ) |
| 482 | << bool(insert_text); |
| 483 | QTest::newRow(dataTag: QString(insert_mode + "halfbytes" ).toLatin1()) |
| 484 | << QString("bbbb.bbbb;-" ) |
| 485 | << QString("110. 0001" ) |
| 486 | << QString("110.0001" ) |
| 487 | << QString("110-.0001" ) |
| 488 | << bool(insert_text); |
| 489 | QTest::newRow(dataTag: QString(insert_mode + "blank char same type as content" ).toLatin1()) |
| 490 | << QString("000.000.000.000;0" ) |
| 491 | << QString("127.0.0.1" ) |
| 492 | << QString("127...1" ) |
| 493 | << QString("127.000.000.100" ) |
| 494 | << bool(insert_text); |
| 495 | QTest::newRow(dataTag: QString(insert_mode + "parts of ip_localhost" ).toLatin1()) |
| 496 | << QString("000.000.000.000" ) |
| 497 | << QString(".0.0.1" ) |
| 498 | << QString(".0.0.1" ) |
| 499 | << QString(" .0 .0 .1 " ) |
| 500 | << bool(insert_text); |
| 501 | QTest::newRow(dataTag: QString(insert_mode + "ip_null" ).toLatin1()) |
| 502 | << QString("000.000.000.000" ) |
| 503 | << QString() |
| 504 | << QString("..." ) |
| 505 | << QString(" . . . " ) |
| 506 | << bool(insert_text); |
| 507 | QTest::newRow(dataTag: QString(insert_mode + "ip_null_hash" ).toLatin1()) |
| 508 | << QString("000.000.000.000;#" ) |
| 509 | << QString() |
| 510 | << QString("..." ) |
| 511 | << QString("###.###.###.###" ) |
| 512 | << bool(insert_text); |
| 513 | QTest::newRow(dataTag: QString(insert_mode + "ip_overflow" ).toLatin1()) |
| 514 | << QString("000.000.000.000" ) |
| 515 | << QString("1234123412341234" ) |
| 516 | << QString("123.412.341.234" ) |
| 517 | << QString("123.412.341.234" ) |
| 518 | << bool(insert_text); |
| 519 | QTest::newRow(dataTag: QString(insert_mode + "uppercase" ).toLatin1()) |
| 520 | << QString(">AAAA" ) |
| 521 | << QString("AbCd" ) |
| 522 | << QString("ABCD" ) |
| 523 | << QString("ABCD" ) |
| 524 | << bool(insert_text); |
| 525 | QTest::newRow(dataTag: QString(insert_mode + "lowercase" ).toLatin1()) |
| 526 | << QString("<AAAA" ) |
| 527 | << QString("AbCd" ) |
| 528 | << QString("abcd" ) |
| 529 | << QString("abcd" ) |
| 530 | << bool(insert_text); |
| 531 | |
| 532 | QTest::newRow(dataTag: QString(insert_mode + "nocase" ).toLatin1()) |
| 533 | << QString("!AAAA" ) |
| 534 | << QString("AbCd" ) |
| 535 | << QString("AbCd" ) |
| 536 | << QString("AbCd" ) |
| 537 | << bool(insert_text); |
| 538 | QTest::newRow(dataTag: QString(insert_mode + "nocase1" ).toLatin1()) |
| 539 | << QString("!A!A!A!A" ) |
| 540 | << QString("AbCd" ) |
| 541 | << QString("AbCd" ) |
| 542 | << QString("AbCd" ) |
| 543 | << bool(insert_text); |
| 544 | QTest::newRow(dataTag: QString(insert_mode + "nocase2" ).toLatin1()) |
| 545 | << QString("AAAA" ) |
| 546 | << QString("AbCd" ) |
| 547 | << QString("AbCd" ) |
| 548 | << QString("AbCd" ) |
| 549 | << bool(insert_text); |
| 550 | |
| 551 | QTest::newRow(dataTag: QString(insert_mode + "reserved" ).toLatin1()) |
| 552 | << QString("{n}[0]" ) |
| 553 | << QString("A9" ) |
| 554 | << QString("A9" ) |
| 555 | << QString("A9" ) |
| 556 | << bool(insert_text); |
| 557 | QTest::newRow(dataTag: QString(insert_mode + "escape01" ).toLatin1()) |
| 558 | << QString("\\N\\n00" ) |
| 559 | << QString("9" ) |
| 560 | << QString("Nn9" ) |
| 561 | << QString("Nn9 " ) |
| 562 | << bool(insert_text); |
| 563 | QTest::newRow(dataTag: QString(insert_mode + "escape02" ).toLatin1()) |
| 564 | << QString("\\\\00" ) |
| 565 | << QString("0" ) |
| 566 | << QString("\\0" ) |
| 567 | << QString("\\0 " ) |
| 568 | << bool(insert_text); |
| 569 | QTest::newRow(dataTag: QString(insert_mode + "escape03" ).toLatin1()) |
| 570 | << QString("\\(00\\)" ) |
| 571 | << QString("0" ) |
| 572 | << QString("(0)" ) |
| 573 | << QString("(0 )" ) |
| 574 | << bool(insert_text); |
| 575 | |
| 576 | QTest::newRow(dataTag: QString(insert_mode + "upper_lower_nocase1" ).toLatin1()) |
| 577 | << QString(">AAAA<AAAA!AAAA" ) |
| 578 | << QString("AbCdEfGhIjKl" ) |
| 579 | << QString("ABCDefghIjKl" ) |
| 580 | << QString("ABCDefghIjKl" ) |
| 581 | << bool(insert_text); |
| 582 | QTest::newRow(dataTag: QString(insert_mode + "upper_lower_nocase2" ).toLatin1()) |
| 583 | << QString(">aaaa<aaaa!aaaa" ) |
| 584 | << QString("AbCdEfGhIjKl" ) |
| 585 | << QString("ABCDefghIjKl" ) |
| 586 | << QString("ABCDefghIjKl" ) |
| 587 | << bool(insert_text); |
| 588 | |
| 589 | QTest::newRow(dataTag: QString(insert_mode + "exact_case1" ).toLatin1()) |
| 590 | << QString(">A<A<A>A>A<A!A!A" ) |
| 591 | << QString("AbCdEFGH" ) |
| 592 | << QString("AbcDEfGH" ) |
| 593 | << QString("AbcDEfGH" ) |
| 594 | << bool(insert_text); |
| 595 | QTest::newRow(dataTag: QString(insert_mode + "exact_case2" ).toLatin1()) |
| 596 | << QString(">A<A<A>A>A<A!A!A" ) |
| 597 | << QString("aBcDefgh" ) |
| 598 | << QString("AbcDEfgh" ) |
| 599 | << QString("AbcDEfgh" ) |
| 600 | << bool(insert_text); |
| 601 | QTest::newRow(dataTag: QString(insert_mode + "exact_case3" ).toLatin1()) |
| 602 | << QString(">a<a<a>a>a<a!a!a" ) |
| 603 | << QString("AbCdEFGH" ) |
| 604 | << QString("AbcDEfGH" ) |
| 605 | << QString("AbcDEfGH" ) |
| 606 | << bool(insert_text); |
| 607 | QTest::newRow(dataTag: QString(insert_mode + "exact_case4" ).toLatin1()) |
| 608 | << QString(">a<a<a>a>a<a!a!a" ) |
| 609 | << QString("aBcDefgh" ) |
| 610 | << QString("AbcDEfgh" ) |
| 611 | << QString("AbcDEfgh" ) |
| 612 | << bool(insert_text); |
| 613 | QTest::newRow(dataTag: QString(insert_mode + "exact_case5" ).toLatin1()) |
| 614 | << QString(">H<H<H>H>H<H!H!H" ) |
| 615 | << QString("aBcDef01" ) |
| 616 | << QString("AbcDEf01" ) |
| 617 | << QString("AbcDEf01" ) |
| 618 | << bool(insert_text); |
| 619 | QTest::newRow(dataTag: QString(insert_mode + "exact_case6" ).toLatin1()) |
| 620 | << QString(">h<h<h>h>h<h!h!h" ) |
| 621 | << QString("aBcDef92" ) |
| 622 | << QString("AbcDEf92" ) |
| 623 | << QString("AbcDEf92" ) |
| 624 | << bool(insert_text); |
| 625 | |
| 626 | QTest::newRow(dataTag: QString(insert_mode + "illegal_keys1" ).toLatin1()) |
| 627 | << QString("AAAAAAAA" ) |
| 628 | << QString("A2#a;.0!" ) |
| 629 | << QString("Aa" ) |
| 630 | << QString("Aa " ) |
| 631 | << bool(insert_text); |
| 632 | QTest::newRow(dataTag: QString(insert_mode + "illegal_keys2" ).toLatin1()) |
| 633 | << QString("AAAA" ) |
| 634 | << QString("f4f4f4f4" ) |
| 635 | << QString("ffff" ) |
| 636 | << QString("ffff" ) |
| 637 | << bool(insert_text); |
| 638 | QTest::newRow(dataTag: QString(insert_mode + "blank=input" ).toLatin1()) |
| 639 | << QString("9999;0" ) |
| 640 | << QString("2004" ) |
| 641 | << QString("2004" ) |
| 642 | << QString("2004" ) |
| 643 | << bool(insert_text); |
| 644 | } |
| 645 | } |
| 646 | |
| 647 | void tst_QLineEdit::setInputMask() |
| 648 | { |
| 649 | QFETCH(QString, mask); |
| 650 | QFETCH(QString, input); |
| 651 | QFETCH(QString, expectedText); |
| 652 | QFETCH(QString, expectedDisplay); |
| 653 | QFETCH(bool, insert_text); |
| 654 | |
| 655 | QEXPECT_FAIL( "keys blank=input" , "To eat blanks or not? Known issue. Task 43172" , Abort); |
| 656 | QEXPECT_FAIL( "insert blank=input" , "To eat blanks or not? Known issue. Task 43172" , Abort); |
| 657 | |
| 658 | // First set the input mask |
| 659 | QLineEdit *testWidget = ensureTestWidget(); |
| 660 | testWidget->setInputMask(mask); |
| 661 | |
| 662 | // then either insert using insert() or keyboard |
| 663 | if (insert_text) { |
| 664 | testWidget->insert(input); |
| 665 | } else { |
| 666 | psKeyClick(target: testWidget, key: Qt::Key_Home); |
| 667 | for (int i=0; i<input.length(); i++) |
| 668 | QTest::keyClick(widget: testWidget, key: input.at(i).toLatin1()); |
| 669 | } |
| 670 | |
| 671 | QCOMPARE(testWidget->text(), expectedText); |
| 672 | QCOMPARE(testWidget->displayText(), expectedDisplay); |
| 673 | } |
| 674 | |
| 675 | void tst_QLineEdit::inputMask_data() |
| 676 | { |
| 677 | QTest::addColumn<QString>(name: "mask" ); |
| 678 | QTest::addColumn<QString>(name: "expectedMask" ); |
| 679 | |
| 680 | // if no mask is set a nul string should be returned |
| 681 | QTest::newRow(dataTag: "nul 1" ) << QString("" ) << QString(); |
| 682 | QTest::newRow(dataTag: "nul 2" ) << QString() << QString(); |
| 683 | |
| 684 | // try different masks |
| 685 | QTest::newRow(dataTag: "mask 1" ) << QString("000.000.000.000" ) << QString("000.000.000.000" ); |
| 686 | QTest::newRow(dataTag: "mask 2" ) << QString("000.000.000.000;#" ) << QString("000.000.000.000;#" ); |
| 687 | QTest::newRow(dataTag: "mask 3" ) << QString("AAA.aa.999.###;" ) << QString("AAA.aa.999.###" ); |
| 688 | QTest::newRow(dataTag: "mask 4" ) << QString(">abcdef<GHIJK" ) << QString(">abcdef<GHIJK" ); |
| 689 | |
| 690 | // set an invalid input mask... |
| 691 | // the current behaviour is that this exact (faulty) string is returned. |
| 692 | QTest::newRow(dataTag: "invalid" ) << QString("ABCDEFGHIKLMNOP;" ) << QString("ABCDEFGHIKLMNOP" ); |
| 693 | |
| 694 | // verify that we can unset the mask again |
| 695 | QTest::newRow(dataTag: "unset" ) << QString("" ) << QString(); |
| 696 | } |
| 697 | |
| 698 | void tst_QLineEdit::inputMask() |
| 699 | { |
| 700 | QFETCH(QString, mask); |
| 701 | QFETCH(QString, expectedMask); |
| 702 | |
| 703 | QLineEdit *testWidget = ensureTestWidget(); |
| 704 | testWidget->setInputMask(mask); |
| 705 | QCOMPARE(testWidget->inputMask(), expectedMask); |
| 706 | } |
| 707 | |
| 708 | void tst_QLineEdit::clearInputMask() |
| 709 | { |
| 710 | QLineEdit *testWidget = ensureTestWidget(); |
| 711 | testWidget->setInputMask("000.000.000.000" ); |
| 712 | QVERIFY(!testWidget->inputMask().isNull()); |
| 713 | testWidget->setInputMask(QString()); |
| 714 | QCOMPARE(testWidget->inputMask(), QString()); |
| 715 | } |
| 716 | |
| 717 | void tst_QLineEdit::keypress_inputMask_data() |
| 718 | { |
| 719 | QTest::addColumn<QString>(name: "mask" ); |
| 720 | QTest::addColumn<QTestEventList>(name: "keys" ); |
| 721 | QTest::addColumn<QString>(name: "expectedText" ); |
| 722 | QTest::addColumn<QString>(name: "expectedDisplayText" ); |
| 723 | |
| 724 | { |
| 725 | QTestEventList keys; |
| 726 | // inserting 'A1.2B' |
| 727 | addKeySequenceStandardKey(keys, QKeySequence::MoveToStartOfLine); |
| 728 | keys.addKeyClick(qtKey: Qt::Key_A); |
| 729 | keys.addKeyClick(qtKey: Qt::Key_1); |
| 730 | keys.addKeyClick(qtKey: Qt::Key_Period); |
| 731 | keys.addKeyClick(qtKey: Qt::Key_2); |
| 732 | keys.addKeyClick(qtKey: Qt::Key_B); |
| 733 | QTest::newRow(dataTag: "jumping on period(separator)" ) << QString("000.000;_" ) << keys << QString("1.2" ) << QString("1__.2__" ); |
| 734 | } |
| 735 | { |
| 736 | QTestEventList keys; |
| 737 | // inserting 'A1.2B' |
| 738 | addKeySequenceStandardKey(keys, QKeySequence::MoveToStartOfLine); |
| 739 | keys.addKeyClick(qtKey: Qt::Key_0); |
| 740 | keys.addKeyClick(qtKey: Qt::Key_Exclam); |
| 741 | keys.addKeyClick(ascii: 'P'); |
| 742 | keys.addKeyClick(qtKey: Qt::Key_3); |
| 743 | QTest::newRow(dataTag: "jumping on input" ) << QString("D0.AA.XX.AA.00;_" ) << keys << QString("0..!P..3" ) << QString("_0.__.!P.__.3_" ); |
| 744 | } |
| 745 | { |
| 746 | QTestEventList keys; |
| 747 | // pressing delete |
| 748 | addKeySequenceStandardKey(keys, QKeySequence::MoveToStartOfLine); |
| 749 | keys.addKeyClick(qtKey: Qt::Key_Delete); |
| 750 | QTest::newRow(dataTag: "delete" ) << QString("000.000;_" ) << keys << QString("." ) << QString("___.___" ); |
| 751 | } |
| 752 | { |
| 753 | QTestEventList keys; |
| 754 | // selecting all and delete |
| 755 | keys.addKeyClick(qtKey: Qt::Key_1); |
| 756 | keys.addKeyClick(qtKey: Qt::Key_2); |
| 757 | addKeySequenceStandardKey(keys, QKeySequence::MoveToStartOfLine); |
| 758 | addKeySequenceStandardKey(keys, QKeySequence::SelectEndOfLine); |
| 759 | keys.addKeyClick(qtKey: Qt::Key_Delete); |
| 760 | QTest::newRow(dataTag: "deleting all" ) << QString("000.000;_" ) << keys << QString("." ) << QString("___.___" ); |
| 761 | } |
| 762 | { |
| 763 | QTestEventList keys; |
| 764 | // inserting at end |
| 765 | addKeySequenceStandardKey(keys, QKeySequence::MoveToEndOfLine); |
| 766 | keys.addKeyClick(qtKey: Qt::Key_Left); |
| 767 | keys.addKeyClick(qtKey: Qt::Key_0); |
| 768 | QTest::newRow(dataTag: "insert at end" ) << QString("9-9-9" ) << keys << QString("--0" ) << QString(" - -0" ); |
| 769 | } |
| 770 | { |
| 771 | QTestEventList keys; |
| 772 | // inserting '12.12' then two backspaces |
| 773 | addKeySequenceStandardKey(keys, QKeySequence::MoveToStartOfLine); |
| 774 | keys.addKeyClick(qtKey: Qt::Key_1); |
| 775 | keys.addKeyClick(qtKey: Qt::Key_2); |
| 776 | keys.addKeyClick(qtKey: Qt::Key_Period); |
| 777 | keys.addKeyClick(qtKey: Qt::Key_1); |
| 778 | keys.addKeyClick(qtKey: Qt::Key_2); |
| 779 | keys.addKeyClick(qtKey: Qt::Key_Backspace); |
| 780 | keys.addKeyClick(qtKey: Qt::Key_Backspace); |
| 781 | QTest::newRow(dataTag: "backspace" ) << QString("000.000;_" ) << keys << QString("12." ) << QString("12_.___" ); |
| 782 | } |
| 783 | { |
| 784 | QTestEventList keys; |
| 785 | // inserting '12ab' |
| 786 | addKeySequenceStandardKey(keys, QKeySequence::MoveToStartOfLine); |
| 787 | keys.addKeyClick(qtKey: Qt::Key_1); |
| 788 | keys.addKeyClick(qtKey: Qt::Key_2); |
| 789 | keys.addKeyClick(qtKey: Qt::Key_A); |
| 790 | keys.addKeyClick(qtKey: Qt::Key_B); |
| 791 | QTest::newRow(dataTag: "uppercase" ) << QString("9999 >AA;_" ) << keys << QString("12 AB" ) << QString("12__ AB" ); |
| 792 | } |
| 793 | } |
| 794 | |
| 795 | void tst_QLineEdit::keypress_inputMask() |
| 796 | { |
| 797 | QFETCH(QString, mask); |
| 798 | QFETCH(QTestEventList, keys); |
| 799 | QFETCH(QString, expectedText); |
| 800 | QFETCH(QString, expectedDisplayText); |
| 801 | |
| 802 | QLineEdit *testWidget = ensureTestWidget(); |
| 803 | testWidget->setInputMask(mask); |
| 804 | keys.simulate(w: testWidget); |
| 805 | |
| 806 | QCOMPARE(testWidget->text(), expectedText); |
| 807 | QCOMPARE(testWidget->displayText(), expectedDisplayText); |
| 808 | } |
| 809 | |
| 810 | void tst_QLineEdit::keypress_inputMethod_inputMask() |
| 811 | { |
| 812 | // Similar to the keypress_inputMask test, but this is done solely via |
| 813 | // input methods |
| 814 | QLineEdit *testWidget = ensureTestWidget(); |
| 815 | testWidget->setInputMask("AA.AA.AA" ); |
| 816 | { |
| 817 | QList<QInputMethodEvent::Attribute> attributes; |
| 818 | QInputMethodEvent event("" , attributes); |
| 819 | event.setCommitString(commitString: "EE" ); |
| 820 | QApplication::sendEvent(receiver: testWidget, event: &event); |
| 821 | } |
| 822 | QCOMPARE(testWidget->cursorPosition(), 3); |
| 823 | QCOMPARE(testWidget->text(), QStringLiteral("EE.." )); |
| 824 | { |
| 825 | QList<QInputMethodEvent::Attribute> attributes; |
| 826 | QInputMethodEvent event("" , attributes); |
| 827 | event.setCommitString(commitString: "EE" ); |
| 828 | QApplication::sendEvent(receiver: testWidget, event: &event); |
| 829 | } |
| 830 | QCOMPARE(testWidget->cursorPosition(), 6); |
| 831 | QCOMPARE(testWidget->text(), QStringLiteral("EE.EE." )); |
| 832 | { |
| 833 | QList<QInputMethodEvent::Attribute> attributes; |
| 834 | QInputMethodEvent event("" , attributes); |
| 835 | event.setCommitString(commitString: "EE" ); |
| 836 | QApplication::sendEvent(receiver: testWidget, event: &event); |
| 837 | } |
| 838 | QCOMPARE(testWidget->cursorPosition(), 8); |
| 839 | QCOMPARE(testWidget->text(), QStringLiteral("EE.EE.EE" )); |
| 840 | } |
| 841 | |
| 842 | void tst_QLineEdit::hasAcceptableInputMask_data() |
| 843 | { |
| 844 | QTest::addColumn<QString>(name: "optionalMask" ); |
| 845 | QTest::addColumn<QString>(name: "requiredMask" ); |
| 846 | QTest::addColumn<QString>(name: "invalid" ); |
| 847 | QTest::addColumn<QString>(name: "valid" ); |
| 848 | |
| 849 | QTest::newRow(dataTag: "Alphabetic optional and required" ) |
| 850 | << QString("aaaa" ) << QString("AAAA" ) << QString("ab" ) << QString("abcd" ); |
| 851 | QTest::newRow(dataTag: "Alphanumeric optional and require" ) |
| 852 | << QString("nnnn" ) << QString("NNNN" ) << QString("R2" ) << QString("R2D2" ); |
| 853 | QTest::newRow(dataTag: "Any optional and required" ) |
| 854 | << QString("xxxx" ) << QString("XXXX" ) << QString("+-" ) << QString("+-*/" ); |
| 855 | QTest::newRow(dataTag: "Numeric (0-9) required" ) |
| 856 | << QString("0000" ) << QString("9999" ) << QString("11" ) << QString("1138" ); |
| 857 | QTest::newRow(dataTag: "Numeric (1-9) optional and required" ) |
| 858 | << QString("dddd" ) << QString("DDDD" ) << QString("12" ) << QString("1234" ); |
| 859 | } |
| 860 | |
| 861 | void tst_QLineEdit::hasAcceptableInputMask() |
| 862 | { |
| 863 | QFocusEvent lostFocus(QEvent::FocusOut); |
| 864 | QFETCH(QString, optionalMask); |
| 865 | QFETCH(QString, requiredMask); |
| 866 | QFETCH(QString, invalid); |
| 867 | QFETCH(QString, valid); |
| 868 | |
| 869 | // test that invalid input (for required) work for optionalMask |
| 870 | QLineEdit *testWidget = ensureTestWidget(); |
| 871 | testWidget->setInputMask(optionalMask); |
| 872 | validInput = false; |
| 873 | testWidget->setText(invalid); |
| 874 | qApp->sendEvent(receiver: testWidget, event: &lostFocus); |
| 875 | QVERIFY(validInput); |
| 876 | |
| 877 | // test requiredMask |
| 878 | testWidget->setInputMask(requiredMask); |
| 879 | validInput = true; |
| 880 | testWidget->setText(invalid); |
| 881 | validInput = testWidget->hasAcceptableInput(); |
| 882 | QVERIFY(!validInput); |
| 883 | |
| 884 | validInput = false; |
| 885 | testWidget->setText(valid); |
| 886 | qApp->sendEvent(receiver: testWidget, event: &lostFocus); |
| 887 | QVERIFY(validInput); |
| 888 | } |
| 889 | |
| 890 | static const int chars = 8; |
| 891 | class ValidatorWithFixup : public QValidator |
| 892 | { |
| 893 | public: |
| 894 | ValidatorWithFixup(QWidget *parent = 0) |
| 895 | : QValidator(parent) |
| 896 | {} |
| 897 | |
| 898 | QValidator::State validate(QString &str, int &) const |
| 899 | { |
| 900 | const int s = str.size(); |
| 901 | if (s < chars) { |
| 902 | return Intermediate; |
| 903 | } else if (s > chars) { |
| 904 | return Invalid; |
| 905 | } |
| 906 | return Acceptable; |
| 907 | } |
| 908 | |
| 909 | void fixup(QString &str) const |
| 910 | { |
| 911 | str = str.leftJustified(width: chars, fill: 'X', trunc: true); |
| 912 | } |
| 913 | }; |
| 914 | |
| 915 | |
| 916 | |
| 917 | void tst_QLineEdit::hasAcceptableInputValidator() |
| 918 | { |
| 919 | QLineEdit *testWidget = ensureTestWidget(); |
| 920 | QSignalSpy spyChanged(testWidget, SIGNAL(textChanged(QString))); |
| 921 | QSignalSpy spyEdited(testWidget, SIGNAL(textEdited(QString))); |
| 922 | |
| 923 | QFocusEvent lostFocus(QEvent::FocusOut); |
| 924 | ValidatorWithFixup val; |
| 925 | testWidget->setValidator(&val); |
| 926 | testWidget->setText("foobar" ); |
| 927 | qApp->sendEvent(receiver: testWidget, event: &lostFocus); |
| 928 | QVERIFY(testWidget->hasAcceptableInput()); |
| 929 | |
| 930 | QCOMPARE(spyChanged.count(), 2); |
| 931 | QCOMPARE(spyEdited.count(), 0); |
| 932 | } |
| 933 | |
| 934 | |
| 935 | |
| 936 | void tst_QLineEdit::maskCharacter_data() |
| 937 | { |
| 938 | QTest::addColumn<QString>(name: "mask" ); |
| 939 | QTest::addColumn<QString>(name: "input" ); |
| 940 | QTest::addColumn<bool>(name: "expectedValid" ); |
| 941 | |
| 942 | QTest::newRow(dataTag: "Hex" ) << QString("H" ) |
| 943 | << QString("0123456789abcdefABCDEF" ) << true; |
| 944 | QTest::newRow(dataTag: "hex" ) << QString("h" ) |
| 945 | << QString("0123456789abcdefABCDEF" ) << true; |
| 946 | QTest::newRow(dataTag: "HexInvalid" ) << QString("H" ) |
| 947 | << QString("ghijklmnopqrstuvwxyzGHIJKLMNOPQRSTUVWXYZ" ) |
| 948 | << false; |
| 949 | QTest::newRow(dataTag: "hexInvalid" ) << QString("h" ) |
| 950 | << QString("ghijklmnopqrstuvwxyzGHIJKLMNOPQRSTUVWXYZ" ) |
| 951 | << false; |
| 952 | QTest::newRow(dataTag: "Bin" ) << QString("B" ) |
| 953 | << QString("01" ) << true; |
| 954 | QTest::newRow(dataTag: "bin" ) << QString("b" ) |
| 955 | << QString("01" ) << true; |
| 956 | QTest::newRow(dataTag: "BinInvalid" ) << QString("B" ) |
| 957 | << QString("23456789qwertyuiopasdfghjklzxcvbnm" ) |
| 958 | << false; |
| 959 | QTest::newRow(dataTag: "binInvalid" ) << QString("b" ) |
| 960 | << QString("23456789qwertyuiopasdfghjklzxcvbnm" ) |
| 961 | << false; |
| 962 | } |
| 963 | |
| 964 | void tst_QLineEdit::maskCharacter() |
| 965 | { |
| 966 | QFETCH(QString, mask); |
| 967 | QFETCH(QString, input); |
| 968 | QFETCH(bool, expectedValid); |
| 969 | |
| 970 | QLineEdit *testWidget = ensureTestWidget(); |
| 971 | QFocusEvent lostFocus(QEvent::FocusOut); |
| 972 | |
| 973 | testWidget->setInputMask(mask); |
| 974 | for (int i = 0; i < input.size(); ++i) { |
| 975 | QString in = QString(input.at(i)); |
| 976 | QString expected = expectedValid ? in : QString(); |
| 977 | testWidget->setText(QString(input.at(i))); |
| 978 | qApp->sendEvent(receiver: testWidget, event: &lostFocus); |
| 979 | QCOMPARE(testWidget->text(), expected); |
| 980 | } |
| 981 | } |
| 982 | |
| 983 | #define NORMAL 0 |
| 984 | #define REPLACE_UNTIL_END 1 |
| 985 | |
| 986 | void tst_QLineEdit::undo_data() |
| 987 | { |
| 988 | QTest::addColumn<QStringList>(name: "insertString" ); |
| 989 | QTest::addColumn<IntList>(name: "insertIndex" ); |
| 990 | QTest::addColumn<IntList>(name: "insertMode" ); |
| 991 | QTest::addColumn<QStringList>(name: "expectedString" ); |
| 992 | QTest::addColumn<bool>(name: "use_keys" ); |
| 993 | |
| 994 | for (int i=0; i<2; i++) { |
| 995 | QString keys_str = "keyboard" ; |
| 996 | bool use_keys = true; |
| 997 | if (i==0) { |
| 998 | keys_str = "insert" ; |
| 999 | use_keys = false; |
| 1000 | } |
| 1001 | |
| 1002 | { |
| 1003 | IntList insertIndex; |
| 1004 | IntList insertMode; |
| 1005 | QStringList insertString; |
| 1006 | QStringList expectedString; |
| 1007 | |
| 1008 | insertIndex << -1; |
| 1009 | insertMode << NORMAL; |
| 1010 | insertString << "1" ; |
| 1011 | |
| 1012 | insertIndex << -1; |
| 1013 | insertMode << NORMAL; |
| 1014 | insertString << "5" ; |
| 1015 | |
| 1016 | insertIndex << 1; |
| 1017 | insertMode << NORMAL; |
| 1018 | insertString << "3" ; |
| 1019 | |
| 1020 | insertIndex << 1; |
| 1021 | insertMode << NORMAL; |
| 1022 | insertString << "2" ; |
| 1023 | |
| 1024 | insertIndex << 3; |
| 1025 | insertMode << NORMAL; |
| 1026 | insertString << "4" ; |
| 1027 | |
| 1028 | expectedString << "12345" ; |
| 1029 | expectedString << "1235" ; |
| 1030 | expectedString << "135" ; |
| 1031 | expectedString << "15" ; |
| 1032 | expectedString << "" ; |
| 1033 | |
| 1034 | QTest::newRow(dataTag: QString(keys_str + "_numbers" ).toLatin1()) << |
| 1035 | insertString << |
| 1036 | insertIndex << |
| 1037 | insertMode << |
| 1038 | expectedString << |
| 1039 | bool(use_keys); |
| 1040 | } |
| 1041 | { |
| 1042 | IntList insertIndex; |
| 1043 | IntList insertMode; |
| 1044 | QStringList insertString; |
| 1045 | QStringList expectedString; |
| 1046 | |
| 1047 | insertIndex << -1; |
| 1048 | insertMode << NORMAL; |
| 1049 | insertString << "World" ; // World |
| 1050 | |
| 1051 | insertIndex << 0; |
| 1052 | insertMode << NORMAL; |
| 1053 | insertString << "Hello" ; // HelloWorld |
| 1054 | |
| 1055 | insertIndex << 0; |
| 1056 | insertMode << NORMAL; |
| 1057 | insertString << "Well" ; // WellHelloWorld |
| 1058 | |
| 1059 | insertIndex << 9; |
| 1060 | insertMode << NORMAL; |
| 1061 | insertString << "There" ; // WellHelloThereWorld; |
| 1062 | |
| 1063 | expectedString << "WellHelloThereWorld" ; |
| 1064 | expectedString << "WellHelloWorld" ; |
| 1065 | expectedString << "HelloWorld" ; |
| 1066 | expectedString << "World" ; |
| 1067 | expectedString << "" ; |
| 1068 | |
| 1069 | QTest::newRow(dataTag: QString(keys_str + "_helloworld" ).toLatin1()) << |
| 1070 | insertString << |
| 1071 | insertIndex << |
| 1072 | insertMode << |
| 1073 | expectedString << |
| 1074 | bool(use_keys); |
| 1075 | } |
| 1076 | { |
| 1077 | IntList insertIndex; |
| 1078 | IntList insertMode; |
| 1079 | QStringList insertString; |
| 1080 | QStringList expectedString; |
| 1081 | |
| 1082 | insertIndex << -1; |
| 1083 | insertMode << NORMAL; |
| 1084 | insertString << "Ensuring" ; |
| 1085 | |
| 1086 | insertIndex << -1; |
| 1087 | insertMode << NORMAL; |
| 1088 | insertString << " instan" ; |
| 1089 | |
| 1090 | insertIndex << 9; |
| 1091 | insertMode << NORMAL; |
| 1092 | insertString << "an " ; |
| 1093 | |
| 1094 | insertIndex << 10; |
| 1095 | insertMode << REPLACE_UNTIL_END; |
| 1096 | insertString << " unique instance." ; |
| 1097 | |
| 1098 | expectedString << "Ensuring a unique instance." ; |
| 1099 | expectedString << "Ensuring an instan" ; |
| 1100 | expectedString << "Ensuring instan" ; |
| 1101 | expectedString << "" ; |
| 1102 | |
| 1103 | QTest::newRow(dataTag: QString(keys_str + "_patterns" ).toLatin1()) << |
| 1104 | insertString << |
| 1105 | insertIndex << |
| 1106 | insertMode << |
| 1107 | expectedString << |
| 1108 | bool(use_keys); |
| 1109 | } |
| 1110 | } |
| 1111 | } |
| 1112 | |
| 1113 | void tst_QLineEdit::undo() |
| 1114 | { |
| 1115 | QFETCH(QStringList, insertString); |
| 1116 | QFETCH(IntList, insertIndex); |
| 1117 | QFETCH(IntList, insertMode); |
| 1118 | QFETCH(QStringList, expectedString); |
| 1119 | QFETCH(bool, use_keys); |
| 1120 | |
| 1121 | QLineEdit *testWidget = ensureTestWidget(); |
| 1122 | QVERIFY(!testWidget->isUndoAvailable()); |
| 1123 | |
| 1124 | int i; |
| 1125 | |
| 1126 | // STEP 1: First build up an undo history by inserting or typing some strings... |
| 1127 | for (i=0; i<insertString.size(); ++i) { |
| 1128 | if (insertIndex[i] > -1) |
| 1129 | testWidget->setCursorPosition(insertIndex[i]); |
| 1130 | |
| 1131 | // experimental stuff |
| 1132 | if (insertMode[i] == REPLACE_UNTIL_END) { |
| 1133 | testWidget->setSelection(insertIndex[i], 8); |
| 1134 | |
| 1135 | // This is what I actually want... |
| 1136 | // QTest::keyClick(testWidget, Qt::Key_End, Qt::ShiftModifier); |
| 1137 | } |
| 1138 | |
| 1139 | if (use_keys) |
| 1140 | QTest::keyClicks(widget: testWidget, sequence: insertString[i]); |
| 1141 | else |
| 1142 | testWidget->insert(insertString[i]); |
| 1143 | } |
| 1144 | |
| 1145 | // STEP 2: Next call undo several times and see if we can restore to the previous state |
| 1146 | for (i=0; i<expectedString.size()-1; ++i) { |
| 1147 | QCOMPARE(testWidget->text(), expectedString[i]); |
| 1148 | QVERIFY(testWidget->isUndoAvailable()); |
| 1149 | testWidget->undo(); |
| 1150 | } |
| 1151 | |
| 1152 | // STEP 3: Verify that we have undone everything |
| 1153 | QVERIFY(!testWidget->isUndoAvailable()); |
| 1154 | QVERIFY(testWidget->text().isEmpty()); |
| 1155 | |
| 1156 | |
| 1157 | if (m_keyboardScheme == QPlatformTheme::WindowsKeyboardScheme) { |
| 1158 | // Repeat the test using shortcut instead of undo() |
| 1159 | for (i=0; i<insertString.size(); ++i) { |
| 1160 | if (insertIndex[i] > -1) |
| 1161 | testWidget->setCursorPosition(insertIndex[i]); |
| 1162 | if (insertMode[i] == REPLACE_UNTIL_END) |
| 1163 | testWidget->setSelection(insertIndex[i], 8); |
| 1164 | if (use_keys) |
| 1165 | QTest::keyClicks(widget: testWidget, sequence: insertString[i]); |
| 1166 | else |
| 1167 | testWidget->insert(insertString[i]); |
| 1168 | } |
| 1169 | for (i=0; i<expectedString.size()-1; ++i) { |
| 1170 | QCOMPARE(testWidget->text(), expectedString[i]); |
| 1171 | QVERIFY(testWidget->isUndoAvailable()); |
| 1172 | QTest::keyClick(widget: testWidget, key: Qt::Key_Backspace, modifier: Qt::AltModifier); |
| 1173 | } |
| 1174 | } |
| 1175 | |
| 1176 | } |
| 1177 | |
| 1178 | void tst_QLineEdit::redo_data() |
| 1179 | { |
| 1180 | QTest::addColumn<QStringList>(name: "insertString" ); |
| 1181 | QTest::addColumn<IntList>(name: "insertIndex" ); |
| 1182 | QTest::addColumn<QStringList>(name: "expectedString" ); |
| 1183 | |
| 1184 | { |
| 1185 | IntList insertIndex; |
| 1186 | QStringList insertString; |
| 1187 | QStringList expectedString; |
| 1188 | |
| 1189 | insertIndex << -1; |
| 1190 | insertString << "World" ; // World |
| 1191 | insertIndex << 0; |
| 1192 | insertString << "Hello" ; // HelloWorld |
| 1193 | insertIndex << 0; |
| 1194 | insertString << "Well" ; // WellHelloWorld |
| 1195 | insertIndex << 9; |
| 1196 | insertString << "There" ; // WellHelloThereWorld; |
| 1197 | |
| 1198 | expectedString << "World" ; |
| 1199 | expectedString << "HelloWorld" ; |
| 1200 | expectedString << "WellHelloWorld" ; |
| 1201 | expectedString << "WellHelloThereWorld" ; |
| 1202 | |
| 1203 | QTest::newRow(dataTag: "Inserts and setting cursor" ) << insertString << insertIndex << expectedString; |
| 1204 | } |
| 1205 | } |
| 1206 | |
| 1207 | void tst_QLineEdit::redo() |
| 1208 | { |
| 1209 | QFETCH(QStringList, insertString); |
| 1210 | QFETCH(IntList, insertIndex); |
| 1211 | QFETCH(QStringList, expectedString); |
| 1212 | |
| 1213 | QLineEdit *testWidget = ensureTestWidget(); |
| 1214 | QVERIFY(!testWidget->isUndoAvailable()); |
| 1215 | QVERIFY(!testWidget->isRedoAvailable()); |
| 1216 | |
| 1217 | int i; |
| 1218 | // inserts the diff strings at diff positions |
| 1219 | for (i=0; i<insertString.size(); ++i) { |
| 1220 | if (insertIndex[i] > -1) |
| 1221 | testWidget->setCursorPosition(insertIndex[i]); |
| 1222 | testWidget->insert(insertString[i]); |
| 1223 | } |
| 1224 | |
| 1225 | QVERIFY(!testWidget->isRedoAvailable()); |
| 1226 | |
| 1227 | // undo everything |
| 1228 | while (!testWidget->text().isEmpty()) |
| 1229 | testWidget->undo(); |
| 1230 | |
| 1231 | for (i=0; i<expectedString.size(); ++i) { |
| 1232 | QVERIFY(testWidget->isRedoAvailable()); |
| 1233 | testWidget->redo(); |
| 1234 | QCOMPARE(testWidget->text() , expectedString[i]); |
| 1235 | } |
| 1236 | |
| 1237 | QVERIFY(!testWidget->isRedoAvailable()); |
| 1238 | |
| 1239 | |
| 1240 | if (m_keyboardScheme == QPlatformTheme::WindowsKeyboardScheme) { |
| 1241 | // repeat test, this time using shortcuts instead of undo()/redo() |
| 1242 | |
| 1243 | while (!testWidget->text().isEmpty()) |
| 1244 | QTest::keyClick(widget: testWidget, key: Qt::Key_Backspace, modifier: Qt::AltModifier); |
| 1245 | |
| 1246 | for (i = 0; i < expectedString.size(); ++i) { |
| 1247 | QVERIFY(testWidget->isRedoAvailable()); |
| 1248 | QTest::keyClick(widget: testWidget, key: Qt::Key_Backspace, |
| 1249 | modifier: Qt::ShiftModifier | Qt::AltModifier); |
| 1250 | QCOMPARE(testWidget->text() , expectedString[i]); |
| 1251 | } |
| 1252 | |
| 1253 | QVERIFY(!testWidget->isRedoAvailable()); |
| 1254 | } |
| 1255 | } |
| 1256 | |
| 1257 | void tst_QLineEdit::undo_keypressevents_data() |
| 1258 | { |
| 1259 | QTest::addColumn<QTestEventList>(name: "keys" ); |
| 1260 | QTest::addColumn<QStringList>(name: "expectedString" ); |
| 1261 | |
| 1262 | { |
| 1263 | QTestEventList keys; |
| 1264 | QStringList expectedString; |
| 1265 | |
| 1266 | keys.addKeyClick(ascii: 'A'); |
| 1267 | keys.addKeyClick(ascii: 'F'); |
| 1268 | keys.addKeyClick(ascii: 'R'); |
| 1269 | keys.addKeyClick(ascii: 'A'); |
| 1270 | keys.addKeyClick(ascii: 'I'); |
| 1271 | keys.addKeyClick(ascii: 'D'); |
| 1272 | psKeyClick(keys, key: Qt::Key_Home); |
| 1273 | |
| 1274 | keys.addKeyClick(ascii: 'V'); |
| 1275 | keys.addKeyClick(ascii: 'E'); |
| 1276 | keys.addKeyClick(ascii: 'R'); |
| 1277 | keys.addKeyClick(ascii: 'Y'); |
| 1278 | |
| 1279 | keys.addKeyClick(qtKey: Qt::Key_Left); |
| 1280 | keys.addKeyClick(qtKey: Qt::Key_Left); |
| 1281 | keys.addKeyClick(qtKey: Qt::Key_Left); |
| 1282 | keys.addKeyClick(qtKey: Qt::Key_Left); |
| 1283 | |
| 1284 | keys.addKeyClick(ascii: 'B'); |
| 1285 | keys.addKeyClick(ascii: 'E'); |
| 1286 | psKeyClick(keys, key: Qt::Key_End); |
| 1287 | |
| 1288 | keys.addKeyClick(qtKey: Qt::Key_Exclam); |
| 1289 | |
| 1290 | expectedString << "BEVERYAFRAID!" ; |
| 1291 | expectedString << "BEVERYAFRAID" ; |
| 1292 | expectedString << "VERYAFRAID" ; |
| 1293 | expectedString << "AFRAID" ; |
| 1294 | |
| 1295 | QTest::newRow(dataTag: "Inserts and moving cursor" ) << keys << expectedString; |
| 1296 | } |
| 1297 | |
| 1298 | { |
| 1299 | QTestEventList keys; |
| 1300 | QStringList expectedString; |
| 1301 | |
| 1302 | // inserting '1234' |
| 1303 | keys.addKeyClick(qtKey: Qt::Key_1); |
| 1304 | keys.addKeyClick(qtKey: Qt::Key_2); |
| 1305 | keys.addKeyClick(qtKey: Qt::Key_3); |
| 1306 | keys.addKeyClick(qtKey: Qt::Key_4); |
| 1307 | psKeyClick(keys, key: Qt::Key_Home); |
| 1308 | |
| 1309 | // skipping '12' |
| 1310 | keys.addKeyClick(qtKey: Qt::Key_Right); |
| 1311 | keys.addKeyClick(qtKey: Qt::Key_Right); |
| 1312 | |
| 1313 | // selecting '34' |
| 1314 | keys.addKeyClick(qtKey: Qt::Key_Right, modifiers: Qt::ShiftModifier); |
| 1315 | keys.addKeyClick(qtKey: Qt::Key_Right, modifiers: Qt::ShiftModifier); |
| 1316 | |
| 1317 | // deleting '34' |
| 1318 | keys.addKeyClick(qtKey: Qt::Key_Delete); |
| 1319 | |
| 1320 | expectedString << "12" ; |
| 1321 | expectedString << "1234" ; |
| 1322 | |
| 1323 | QTest::newRow(dataTag: "Inserts,moving,selection and delete" ) << keys << expectedString; |
| 1324 | } |
| 1325 | |
| 1326 | { |
| 1327 | QTestEventList keys; |
| 1328 | QStringList expectedString; |
| 1329 | |
| 1330 | // inserting 'AB12' |
| 1331 | keys.addKeyClick(ascii: 'A'); |
| 1332 | keys.addKeyClick(ascii: 'B'); |
| 1333 | |
| 1334 | keys.addKeyClick(qtKey: Qt::Key_1); |
| 1335 | keys.addKeyClick(qtKey: Qt::Key_2); |
| 1336 | |
| 1337 | psKeyClick(keys, key: Qt::Key_Home); |
| 1338 | |
| 1339 | // selecting 'AB' |
| 1340 | keys.addKeyClick(qtKey: Qt::Key_Right, modifiers: Qt::ShiftModifier); |
| 1341 | keys.addKeyClick(qtKey: Qt::Key_Right, modifiers: Qt::ShiftModifier); |
| 1342 | |
| 1343 | // deleting 'AB' |
| 1344 | keys.addKeyClick(qtKey: Qt::Key_Delete); |
| 1345 | |
| 1346 | // undoing deletion of 'AB' |
| 1347 | keys.addKeyClick(qtKey: Qt::Key_Z, modifiers: Qt::ControlModifier); |
| 1348 | |
| 1349 | // unselect any current selection |
| 1350 | keys.addKeyClick(qtKey: Qt::Key_Right); |
| 1351 | |
| 1352 | // If previous right changed cursor position, go back left |
| 1353 | if (unselectingWithLeftOrRightChangesCursorPosition()) |
| 1354 | keys.addKeyClick(qtKey: Qt::Key_Left); |
| 1355 | |
| 1356 | // selecting '12' |
| 1357 | keys.addKeyClick(qtKey: Qt::Key_Right, modifiers: Qt::ShiftModifier); |
| 1358 | keys.addKeyClick(qtKey: Qt::Key_Right, modifiers: Qt::ShiftModifier); |
| 1359 | |
| 1360 | // deleting '12' |
| 1361 | keys.addKeyClick(qtKey: Qt::Key_Delete); |
| 1362 | |
| 1363 | expectedString << "AB" ; |
| 1364 | expectedString << "AB12" ; |
| 1365 | |
| 1366 | QTest::newRow(dataTag: "Inserts,moving,selection, delete and undo" ) << keys << expectedString; |
| 1367 | } |
| 1368 | |
| 1369 | { |
| 1370 | QTestEventList keys; |
| 1371 | QStringList expectedString; |
| 1372 | |
| 1373 | // inserting 'ABCD' |
| 1374 | keys.addKeyClick(qtKey: Qt::Key_A); |
| 1375 | keys.addKeyClick(qtKey: Qt::Key_B); |
| 1376 | keys.addKeyClick(qtKey: Qt::Key_C); |
| 1377 | keys.addKeyClick(qtKey: Qt::Key_D); |
| 1378 | |
| 1379 | //move left two |
| 1380 | keys.addKeyClick(qtKey: Qt::Key_Left); |
| 1381 | keys.addKeyClick(qtKey: Qt::Key_Left); |
| 1382 | |
| 1383 | // inserting '1234' |
| 1384 | keys.addKeyClick(qtKey: Qt::Key_1); |
| 1385 | keys.addKeyClick(qtKey: Qt::Key_2); |
| 1386 | keys.addKeyClick(qtKey: Qt::Key_3); |
| 1387 | keys.addKeyClick(qtKey: Qt::Key_4); |
| 1388 | |
| 1389 | // selecting '1234' |
| 1390 | keys.addKeyClick(qtKey: Qt::Key_Left, modifiers: Qt::ShiftModifier); |
| 1391 | keys.addKeyClick(qtKey: Qt::Key_Left, modifiers: Qt::ShiftModifier); |
| 1392 | keys.addKeyClick(qtKey: Qt::Key_Left, modifiers: Qt::ShiftModifier); |
| 1393 | keys.addKeyClick(qtKey: Qt::Key_Left, modifiers: Qt::ShiftModifier); |
| 1394 | |
| 1395 | // overwriting '1234' with '5' |
| 1396 | keys.addKeyClick(qtKey: Qt::Key_5); |
| 1397 | |
| 1398 | // undoing deletion of 'AB' |
| 1399 | keys.addKeyClick(qtKey: Qt::Key_Z, modifiers: Qt::ControlModifier); |
| 1400 | |
| 1401 | // overwriting '1234' with '6' |
| 1402 | keys.addKeyClick(qtKey: Qt::Key_6); |
| 1403 | |
| 1404 | expectedString << "ab6cd" ; |
| 1405 | // for versions previous to 3.2 we overwrite needed two undo operations |
| 1406 | expectedString << "ab1234cd" ; |
| 1407 | expectedString << "abcd" ; |
| 1408 | |
| 1409 | QTest::newRow(dataTag: "Inserts,moving,selection and undo, removing selection" ) << keys << expectedString; |
| 1410 | } |
| 1411 | |
| 1412 | { |
| 1413 | QTestEventList keys; |
| 1414 | QStringList expectedString; |
| 1415 | |
| 1416 | // inserting 'ABC' |
| 1417 | keys.addKeyClick(ascii: 'A'); |
| 1418 | keys.addKeyClick(ascii: 'B'); |
| 1419 | keys.addKeyClick(ascii: 'C'); |
| 1420 | |
| 1421 | // removes 'C' |
| 1422 | keys.addKeyClick(qtKey: Qt::Key_Backspace); |
| 1423 | |
| 1424 | expectedString << "AB" ; |
| 1425 | expectedString << "ABC" ; |
| 1426 | |
| 1427 | QTest::newRow(dataTag: "Inserts,backspace" ) << keys << expectedString; |
| 1428 | } |
| 1429 | |
| 1430 | { |
| 1431 | QTestEventList keys; |
| 1432 | QStringList expectedString; |
| 1433 | |
| 1434 | // inserting 'ABC' |
| 1435 | keys.addKeyClick(ascii: 'A'); |
| 1436 | keys.addKeyClick(ascii: 'B'); |
| 1437 | keys.addKeyClick(ascii: 'C'); |
| 1438 | |
| 1439 | // removes 'C' |
| 1440 | keys.addKeyClick(qtKey: Qt::Key_Backspace); |
| 1441 | |
| 1442 | // inserting 'Z' |
| 1443 | keys.addKeyClick(ascii: 'Z'); |
| 1444 | |
| 1445 | expectedString << "ABZ" ; |
| 1446 | expectedString << "AB" ; |
| 1447 | expectedString << "ABC" ; |
| 1448 | |
| 1449 | QTest::newRow(dataTag: "Inserts,backspace,inserts" ) << keys << expectedString; |
| 1450 | } |
| 1451 | |
| 1452 | |
| 1453 | { |
| 1454 | QTestEventList keys; |
| 1455 | QStringList expectedString; |
| 1456 | |
| 1457 | // inserting '123' |
| 1458 | keys.addKeyClick(qtKey: Qt::Key_1); |
| 1459 | keys.addKeyClick(qtKey: Qt::Key_2); |
| 1460 | keys.addKeyClick(qtKey: Qt::Key_3); |
| 1461 | psKeyClick(keys, key: Qt::Key_Home); |
| 1462 | |
| 1463 | // selecting '123' |
| 1464 | psKeyClick(keys, key: Qt::Key_End, pressState: Qt::ShiftModifier); |
| 1465 | |
| 1466 | // overwriting '123' with 'ABC' |
| 1467 | keys.addKeyClick(ascii: 'A'); |
| 1468 | keys.addKeyClick(ascii: 'B'); |
| 1469 | keys.addKeyClick(ascii: 'C'); |
| 1470 | |
| 1471 | expectedString << "ABC" ; |
| 1472 | // for versions previous to 3.2 we overwrite needed two undo operations |
| 1473 | expectedString << "123" ; |
| 1474 | |
| 1475 | QTest::newRow(dataTag: "Inserts,moving,selection and overwriting" ) << keys << expectedString; |
| 1476 | } |
| 1477 | } |
| 1478 | |
| 1479 | void tst_QLineEdit::undo_keypressevents() |
| 1480 | { |
| 1481 | QFETCH(QTestEventList, keys); |
| 1482 | QFETCH(QStringList, expectedString); |
| 1483 | |
| 1484 | QLineEdit *testWidget = ensureTestWidget(); |
| 1485 | keys.simulate(w: testWidget); |
| 1486 | |
| 1487 | for (int i=0; i<expectedString.size(); ++i) { |
| 1488 | QCOMPARE(testWidget->text() , expectedString[i]); |
| 1489 | testWidget->undo(); |
| 1490 | } |
| 1491 | QVERIFY(testWidget->text().isEmpty()); |
| 1492 | } |
| 1493 | |
| 1494 | #ifndef QT_NO_CLIPBOARD |
| 1495 | void tst_QLineEdit::QTBUG5786_undoPaste() |
| 1496 | { |
| 1497 | if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) |
| 1498 | QSKIP("Wayland: This fails. Figure out why." ); |
| 1499 | |
| 1500 | if (!PlatformClipboard::isAvailable()) |
| 1501 | QSKIP("this machine doesn't support the clipboard" ); |
| 1502 | QString initial("initial" ); |
| 1503 | QString string("test" ); |
| 1504 | QString additional("add" ); |
| 1505 | QApplication::clipboard()->setText(string); |
| 1506 | QLineEdit edit(initial); |
| 1507 | QCOMPARE(edit.text(), initial); |
| 1508 | edit.paste(); |
| 1509 | QCOMPARE(edit.text(), initial + string); |
| 1510 | edit.paste(); |
| 1511 | QCOMPARE(edit.text(), initial + string + string); |
| 1512 | edit.insert(additional); |
| 1513 | QCOMPARE(edit.text(), initial + string + string + additional); |
| 1514 | edit.undo(); |
| 1515 | QCOMPARE(edit.text(), initial + string + string); |
| 1516 | edit.undo(); |
| 1517 | QCOMPARE(edit.text(), initial + string); |
| 1518 | edit.undo(); |
| 1519 | QCOMPARE(edit.text(), initial); |
| 1520 | edit.selectAll(); |
| 1521 | QApplication::clipboard()->setText(QString()); |
| 1522 | edit.paste(); |
| 1523 | QVERIFY(edit.text().isEmpty()); |
| 1524 | |
| 1525 | } |
| 1526 | #endif |
| 1527 | |
| 1528 | |
| 1529 | void tst_QLineEdit::clear() |
| 1530 | { |
| 1531 | // checking that clear of empty/nullstring doesn't add to undo history |
| 1532 | QLineEdit *testWidget = ensureTestWidget(); |
| 1533 | int max = 5000; |
| 1534 | while (max > 0 && testWidget->isUndoAvailable()) { |
| 1535 | max--; |
| 1536 | testWidget->undo(); |
| 1537 | } |
| 1538 | |
| 1539 | testWidget->clear(); |
| 1540 | // QVERIFY(!testWidget->isUndoAvailable()); |
| 1541 | |
| 1542 | // checks that clear actually clears |
| 1543 | testWidget->insert("I am Legend" ); |
| 1544 | testWidget->clear(); |
| 1545 | QVERIFY(testWidget->text().isEmpty()); |
| 1546 | |
| 1547 | // checks that clears can be undone |
| 1548 | testWidget->undo(); |
| 1549 | QCOMPARE(testWidget->text(), QString("I am Legend" )); |
| 1550 | } |
| 1551 | |
| 1552 | void tst_QLineEdit::editingFinished() |
| 1553 | { |
| 1554 | if (m_testWidget->hasAcceptableInput()) |
| 1555 | validInput = true; |
| 1556 | else |
| 1557 | validInput = false; |
| 1558 | } |
| 1559 | |
| 1560 | void tst_QLineEdit::text_data() |
| 1561 | { |
| 1562 | QTest::addColumn<QString>(name: "insertString" ); |
| 1563 | |
| 1564 | QTest::newRow(dataTag: "Plain text0" ) << QString("Hello World" ); |
| 1565 | QTest::newRow(dataTag: "Plain text1" ) << QString("" ); |
| 1566 | QTest::newRow(dataTag: "Plain text2" ) << QString("A" ); |
| 1567 | QTest::newRow(dataTag: "Plain text3" ) << QString("ryyryryryryryryryryryryryryryryryryryryryryryryryryryrryryryryryryryryryryryryryryryryryryryryryryryryryryryryryryryryryrryryryryryryryryryryryryry" ); |
| 1568 | QTest::newRow(dataTag: "Plain text4" ) << QString("abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890`~!@#$%^&*()_-+={[}]|\\:;'?/>.<,\"" ); |
| 1569 | QTest::newRow(dataTag: "Newlines" ) << QString("A\nB\nC\n" ); |
| 1570 | QTest::newRow(dataTag: "Text with nbsp" ) << QString("Hello" ) + QChar(0xa0) + "World" ; |
| 1571 | } |
| 1572 | |
| 1573 | void tst_QLineEdit::text() |
| 1574 | { |
| 1575 | QFETCH(QString, insertString); |
| 1576 | QLineEdit *testWidget = ensureTestWidget(); |
| 1577 | testWidget->setText(insertString); |
| 1578 | QCOMPARE(testWidget->text(), insertString); |
| 1579 | } |
| 1580 | |
| 1581 | void tst_QLineEdit::textMask_data() |
| 1582 | { |
| 1583 | QTest::addColumn<QString>(name: "insertString" ); |
| 1584 | |
| 1585 | QTest::newRow( dataTag: "Plain text1" ) << QString( "" ); |
| 1586 | } |
| 1587 | |
| 1588 | void tst_QLineEdit::textMask() |
| 1589 | { |
| 1590 | QFETCH( QString, insertString ); |
| 1591 | QLineEdit *testWidget = ensureTestWidget(); |
| 1592 | testWidget->setInputMask( "#" ); |
| 1593 | testWidget->setText( insertString ); |
| 1594 | QCOMPARE( testWidget->text(), insertString ); |
| 1595 | } |
| 1596 | |
| 1597 | void tst_QLineEdit::setText() |
| 1598 | { |
| 1599 | QLineEdit *testWidget = ensureTestWidget(); |
| 1600 | QSignalSpy editedSpy(testWidget, SIGNAL(textEdited(QString))); |
| 1601 | QSignalSpy changedSpy(testWidget, SIGNAL(textChanged(QString))); |
| 1602 | testWidget->setText("hello" ); |
| 1603 | QCOMPARE(editedSpy.count(), 0); |
| 1604 | QCOMPARE(changedSpy.value(0).value(0).toString(), QString("hello" )); |
| 1605 | } |
| 1606 | |
| 1607 | void tst_QLineEdit::displayText_data() |
| 1608 | { |
| 1609 | QTest::addColumn<QString>(name: "insertString" ); |
| 1610 | QTest::addColumn<QString>(name: "expectedString" ); |
| 1611 | QTest::addColumn<QLineEdit::EchoMode>(name: "mode" ); |
| 1612 | QTest::addColumn<bool>(name: "use_setText" ); |
| 1613 | |
| 1614 | QString s; |
| 1615 | QLineEdit::EchoMode m; |
| 1616 | |
| 1617 | for (int i=0; i<2; i++) { |
| 1618 | QString key_mode_str; |
| 1619 | bool use_setText; |
| 1620 | if (i==0) { |
| 1621 | key_mode_str = "setText_" ; |
| 1622 | use_setText = true; |
| 1623 | } else { |
| 1624 | key_mode_str = "useKeys_" ; |
| 1625 | use_setText = false; |
| 1626 | } |
| 1627 | s = key_mode_str + "Normal" ; |
| 1628 | m = QLineEdit::Normal; |
| 1629 | QTest::newRow(dataTag: QString(s + " text0" ).toLatin1()) << QString("Hello World" ) << |
| 1630 | QString("Hello World" ) << |
| 1631 | m << bool(use_setText); |
| 1632 | QTest::newRow(dataTag: QString(s + " text1" ).toLatin1()) << QString("" ) << |
| 1633 | QString("" ) << |
| 1634 | m << bool(use_setText); |
| 1635 | QTest::newRow(dataTag: QString(s + " text2" ).toLatin1()) << QString("A" ) << |
| 1636 | QString("A" ) << |
| 1637 | m << bool(use_setText); |
| 1638 | QTest::newRow(dataTag: QString(s + " text3" ).toLatin1()) << QString("ryyryryryryryryryryryryryryryryryryryryryryryryryryryrryryryryryryryryryryryryryryryryryryryryryryryryryryryryryryryryryrryryryryryryryryryryryryry" ) << |
| 1639 | QString("ryyryryryryryryryryryryryryryryryryryryryryryryryryryrryryryryryryryryryryryryryryryryryryryryryryryryryryryryryryryryryrryryryryryryryryryryryryry" ) << |
| 1640 | m << bool(use_setText); |
| 1641 | QTest::newRow(dataTag: QString(s + " text4" ).toLatin1()) << QString("abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890`~!@#$%^&*()_-+={[}]|\\:;'?/>.<,\"" ) << |
| 1642 | QString("abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890`~!@#$%^&*()_-+={[}]|\\:;'?/>.<,\"" ) << |
| 1643 | m << bool(use_setText); |
| 1644 | QTest::newRow(dataTag: QString(s + " text with nbsp" ).toLatin1()) << QString("Hello" ) + QChar(0xa0) + "World" << |
| 1645 | QString("Hello" ) + QChar(0xa0) + "World" << |
| 1646 | m << bool(use_setText); |
| 1647 | s = key_mode_str + "NoEcho" ; |
| 1648 | m = QLineEdit::NoEcho; |
| 1649 | QTest::newRow(dataTag: QString(s + " text0" ).toLatin1()) << QString("Hello World" ) << |
| 1650 | QString("" ) << |
| 1651 | m << bool(use_setText); |
| 1652 | QTest::newRow(dataTag: QString(s + " text1" ).toLatin1()) << QString("" ) << |
| 1653 | QString("" ) << |
| 1654 | m << bool(use_setText); |
| 1655 | QTest::newRow(dataTag: QString(s + " text2" ).toLatin1()) << QString("A" ) << |
| 1656 | QString("" ) << |
| 1657 | m << bool(use_setText); |
| 1658 | QTest::newRow(dataTag: QString(s + " text3" ).toLatin1()) << QString("ryyryryryryryryryryryryryryryryryryryryryryryryryryryrryryryryryryryryryryryryryryryryryryryryryryryryryryryryryryryryryrryryryryryryryryryryryryry" ) << |
| 1659 | QString("" ) << |
| 1660 | m << bool(use_setText); |
| 1661 | QTest::newRow(dataTag: QString(s + " text4" ).toLatin1()) << QString("abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890`~!@#$%^&*()_-+={[}]|\\:;'?/>.<,\"" ) << |
| 1662 | QString("" ) << |
| 1663 | m << bool(use_setText); |
| 1664 | QTest::newRow(dataTag: QString(s + " text with nbsp" ).toLatin1()) << QString("Hello" ) + QChar(0xa0) + "World" << |
| 1665 | QString("" ) << |
| 1666 | m << bool(use_setText); |
| 1667 | s = key_mode_str + "Password" ; |
| 1668 | m = QLineEdit::Password; |
| 1669 | QChar passChar = qApp->style()->styleHint(stylehint: QStyle::SH_LineEdit_PasswordCharacter, opt: 0, widget: m_testWidget); |
| 1670 | QString input; |
| 1671 | QString pass; |
| 1672 | input = "Hello World" ; |
| 1673 | pass.resize(size: input.length()); |
| 1674 | pass.fill(c: passChar); |
| 1675 | QTest::newRow(dataTag: QString(s + " text0" ).toLatin1()) << input << pass << m << bool(use_setText); |
| 1676 | QTest::newRow(dataTag: QString(s + " text1" ).toLatin1()) << QString("" ) << |
| 1677 | QString("" ) << |
| 1678 | m << bool(use_setText); |
| 1679 | QTest::newRow(dataTag: QString(s + " text2" ).toLatin1()) << QString("A" ) << QString(passChar) << m << bool(use_setText); |
| 1680 | input = QString("ryyryryryryryryryryryryryryryryryryryryryryryryryryryrryryryryryryryryryryryryryryryryryryryryryryryryryryryryryryryryryrryryryryryryryryryryryryry" ); |
| 1681 | pass.resize(size: input.length()); |
| 1682 | pass.fill(c: passChar); |
| 1683 | QTest::newRow(dataTag: QString(s + " text3" ).toLatin1()) << input << pass << m << bool(use_setText); |
| 1684 | input = QString("abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890`~!@#$%^&*()_-+={[}]|\\:;'?/>.<,\"" ); |
| 1685 | pass.fill(c: passChar, size: input.length()); |
| 1686 | QTest::newRow(dataTag: QString(s + " text4" ).toLatin1()) << input << pass << m << bool(use_setText); |
| 1687 | input = QString("Hello" ) + QChar(0xa0) + "World" ; |
| 1688 | pass.resize(size: input.length()); |
| 1689 | pass.fill(c: passChar); |
| 1690 | QTest::newRow(dataTag: QString(s + " text with nbsp" ).toLatin1()) << input << pass << m << bool(use_setText); |
| 1691 | } |
| 1692 | } |
| 1693 | |
| 1694 | void tst_QLineEdit::displayText() |
| 1695 | { |
| 1696 | QFETCH(QString, insertString); |
| 1697 | QFETCH(QString, expectedString); |
| 1698 | QFETCH(QLineEdit::EchoMode, mode); |
| 1699 | //QFETCH(bool, use_setText); Currently unused. |
| 1700 | |
| 1701 | QLineEdit *testWidget = ensureTestWidget(); |
| 1702 | testWidget->setEchoMode(mode); |
| 1703 | testWidget->setText(insertString); |
| 1704 | QCOMPARE(testWidget->displayText(), expectedString); |
| 1705 | QCOMPARE(testWidget->echoMode(), mode); |
| 1706 | } |
| 1707 | |
| 1708 | void tst_QLineEdit::passwordEchoOnEdit() |
| 1709 | { |
| 1710 | if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) |
| 1711 | QSKIP("Wayland: This fails. Figure out why." ); |
| 1712 | |
| 1713 | QStyleOptionFrame opt; |
| 1714 | QLineEdit *testWidget = ensureTestWidget(); |
| 1715 | QChar fillChar = testWidget->style()->styleHint(stylehint: QStyle::SH_LineEdit_PasswordCharacter, opt: &opt, widget: testWidget); |
| 1716 | |
| 1717 | testWidget->setEchoMode(QLineEdit::PasswordEchoOnEdit); |
| 1718 | testWidget->setFocus(); |
| 1719 | centerOnScreen(w: testWidget); |
| 1720 | testWidget->show(); |
| 1721 | testWidget->raise(); |
| 1722 | QVERIFY(QTest::qWaitForWindowExposed(testWidget)); |
| 1723 | QTRY_VERIFY(testWidget->hasFocus()); |
| 1724 | |
| 1725 | QTest::keyPress(widget: testWidget, key: '0'); |
| 1726 | QTest::keyPress(widget: testWidget, key: '1'); |
| 1727 | QTest::keyPress(widget: testWidget, key: '2'); |
| 1728 | QTest::keyPress(widget: testWidget, key: '3'); |
| 1729 | QTest::keyPress(widget: testWidget, key: '4'); |
| 1730 | QCOMPARE(testWidget->displayText(), QString("01234" )); |
| 1731 | testWidget->clearFocus(); |
| 1732 | QVERIFY(!testWidget->hasFocus()); |
| 1733 | QCOMPARE(testWidget->displayText(), QString(5, fillChar)); |
| 1734 | testWidget->setFocus(); |
| 1735 | QTRY_VERIFY(testWidget->hasFocus()); |
| 1736 | |
| 1737 | QCOMPARE(testWidget->displayText(), QString(5, fillChar)); |
| 1738 | QTest::keyPress(widget: testWidget, key: '0'); |
| 1739 | QCOMPARE(testWidget->displayText(), QString("0" )); |
| 1740 | |
| 1741 | // restore clean state |
| 1742 | testWidget->setEchoMode(QLineEdit::Normal); |
| 1743 | } |
| 1744 | |
| 1745 | void tst_QLineEdit::passwordEchoDelay() |
| 1746 | { |
| 1747 | if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) |
| 1748 | QSKIP("Wayland: This fails. Figure out why." ); |
| 1749 | |
| 1750 | QLineEdit *testWidget = ensureTestWidget(); |
| 1751 | int delay = qGuiApp->styleHints()->passwordMaskDelay(); |
| 1752 | #if defined QT_BUILD_INTERNAL |
| 1753 | QLineEditPrivate *priv = QLineEditPrivate::get(lineEdit: testWidget); |
| 1754 | QWidgetLineControl *control = priv->control; |
| 1755 | control->m_passwordMaskDelayOverride = 200; |
| 1756 | delay = 200; |
| 1757 | #endif |
| 1758 | if (delay <= 0) |
| 1759 | QSKIP("Platform not defining echo delay and overriding only possible in internal build" ); |
| 1760 | |
| 1761 | QStyleOptionFrame opt; |
| 1762 | QChar fillChar = testWidget->style()->styleHint(stylehint: QStyle::SH_LineEdit_PasswordCharacter, opt: &opt, widget: testWidget); |
| 1763 | |
| 1764 | testWidget->setEchoMode(QLineEdit::Password); |
| 1765 | testWidget->setFocus(); |
| 1766 | centerOnScreen(w: testWidget); |
| 1767 | testWidget->show(); |
| 1768 | testWidget->raise(); |
| 1769 | QVERIFY(QTest::qWaitForWindowExposed(testWidget)); |
| 1770 | QTRY_VERIFY(testWidget->hasFocus()); |
| 1771 | |
| 1772 | QTest::keyPress(widget: testWidget, key: '0'); |
| 1773 | QTest::keyPress(widget: testWidget, key: '1'); |
| 1774 | QTest::keyPress(widget: testWidget, key: '2'); |
| 1775 | QCOMPARE(testWidget->displayText(), QString(2, fillChar) + QLatin1Char('2')); |
| 1776 | QTest::keyPress(widget: testWidget, key: '3'); |
| 1777 | QTest::keyPress(widget: testWidget, key: '4'); |
| 1778 | QCOMPARE(testWidget->displayText(), QString(4, fillChar) + QLatin1Char('4')); |
| 1779 | QTest::keyPress(widget: testWidget, key: Qt::Key_Backspace); |
| 1780 | QCOMPARE(testWidget->displayText(), QString(4, fillChar)); |
| 1781 | QTest::keyPress(widget: testWidget, key: '4'); |
| 1782 | QCOMPARE(testWidget->displayText(), QString(4, fillChar) + QLatin1Char('4')); |
| 1783 | QTest::qWait(ms: delay); |
| 1784 | QTRY_COMPARE(testWidget->displayText(), QString(5, fillChar)); |
| 1785 | QTest::keyPress(widget: testWidget, key: '5'); |
| 1786 | QCOMPARE(testWidget->displayText(), QString(5, fillChar) + QLatin1Char('5')); |
| 1787 | testWidget->clearFocus(); |
| 1788 | QVERIFY(!testWidget->hasFocus()); |
| 1789 | QCOMPARE(testWidget->displayText(), QString(6, fillChar)); |
| 1790 | testWidget->setFocus(); |
| 1791 | QTRY_VERIFY(testWidget->hasFocus()); |
| 1792 | QCOMPARE(testWidget->displayText(), QString(6, fillChar)); |
| 1793 | QTest::keyPress(widget: testWidget, key: '6'); |
| 1794 | QCOMPARE(testWidget->displayText(), QString(6, fillChar) + QLatin1Char('6')); |
| 1795 | |
| 1796 | QInputMethodEvent ev; |
| 1797 | ev.setCommitString(commitString: QLatin1String("7" )); |
| 1798 | QApplication::sendEvent(receiver: testWidget, event: &ev); |
| 1799 | QCOMPARE(testWidget->displayText(), QString(7, fillChar) + QLatin1Char('7')); |
| 1800 | |
| 1801 | testWidget->setCursorPosition(3); |
| 1802 | QCOMPARE(testWidget->displayText(), QString(7, fillChar) + QLatin1Char('7')); |
| 1803 | QTest::keyPress(widget: testWidget, key: 'a'); |
| 1804 | QCOMPARE(testWidget->displayText(), QString(3, fillChar) + QLatin1Char('a') + QString(5, fillChar)); |
| 1805 | QTest::keyPress(widget: testWidget, key: Qt::Key_Backspace); |
| 1806 | QCOMPARE(testWidget->displayText(), QString(8, fillChar)); |
| 1807 | |
| 1808 | // restore clean state |
| 1809 | testWidget->setEchoMode(QLineEdit::Normal); |
| 1810 | } |
| 1811 | |
| 1812 | void tst_QLineEdit::maxLength_mask_data() |
| 1813 | { |
| 1814 | QTest::addColumn<QString>(name: "mask" ); |
| 1815 | QTest::addColumn<int>(name: "expectedLength" ); |
| 1816 | |
| 1817 | QTest::newRow(dataTag: "mask_case" ) << QString(">000<>00<000" ) << 8; |
| 1818 | QTest::newRow(dataTag: "mask_nocase" ) << QString("00000000" ) << 8; |
| 1819 | QTest::newRow(dataTag: "mask_null" ) << QString() << 32767; |
| 1820 | QTest::newRow(dataTag: "mask_escape" ) << QString("\\A\\aAA" ) << 4; |
| 1821 | } |
| 1822 | |
| 1823 | void tst_QLineEdit::maxLength_mask() |
| 1824 | { |
| 1825 | QFETCH(QString, mask); |
| 1826 | QFETCH(int, expectedLength); |
| 1827 | |
| 1828 | QLineEdit *testWidget = ensureTestWidget(); |
| 1829 | testWidget->setInputMask(mask); |
| 1830 | |
| 1831 | QCOMPARE(testWidget->maxLength(), expectedLength); |
| 1832 | } |
| 1833 | |
| 1834 | void tst_QLineEdit::maxLength_data() |
| 1835 | { |
| 1836 | QTest::addColumn<QString>(name: "insertString" ); |
| 1837 | QTest::addColumn<QString>(name: "expectedString" ); |
| 1838 | QTest::addColumn<int>(name: "length" ); |
| 1839 | QTest::addColumn<bool>(name: "insertBeforeSettingMaxLength" ); |
| 1840 | QTest::addColumn<bool>(name: "use_setText" ); |
| 1841 | |
| 1842 | QTest::newRow(dataTag: "keyclick before0" ) << QString("this is a test." ) << QString("this is a test." ) << 20 << bool(true) << bool(false); |
| 1843 | QTest::newRow(dataTag: "keyclick before1" ) << QString("this is a test." ) << QString("this is a " ) << 10 << bool(true) << bool(false); |
| 1844 | QTest::newRow(dataTag: "keyclick after0" ) << QString("this is a test." ) << QString("this is a test." ) << 20 << bool(false) << bool(false); |
| 1845 | QTest::newRow(dataTag: "keyclick after1" ) << QString("this is a test." ) << QString("this is a " ) << 10 << bool(false) << bool(false); |
| 1846 | QTest::newRow(dataTag: "settext before0" ) << QString("this is a test." ) << QString("this is a test." ) << 20 << bool(true) << bool(true); |
| 1847 | QTest::newRow(dataTag: "settext before1" ) << QString("this is a test." ) << QString("this is a " ) << 10 << bool(true) << bool(true); |
| 1848 | QTest::newRow(dataTag: "settext after0" ) << QString("this is a test." ) << QString("this is a test." ) << 20 << bool(false) << bool(true); |
| 1849 | QTest::newRow(dataTag: "settext after1" ) << QString("this is a test." ) << QString("this is a " ) << 10 << bool(false) << bool(true); |
| 1850 | } |
| 1851 | |
| 1852 | void tst_QLineEdit::maxLength() |
| 1853 | { |
| 1854 | QFETCH(QString, insertString); |
| 1855 | QFETCH(QString, expectedString); |
| 1856 | QFETCH(int, length); |
| 1857 | QFETCH(bool, insertBeforeSettingMaxLength); |
| 1858 | QFETCH(bool, use_setText); |
| 1859 | |
| 1860 | // in some cases we set the maxLength _before_ entering the text. |
| 1861 | QLineEdit *testWidget = ensureTestWidget(); |
| 1862 | if (!insertBeforeSettingMaxLength) |
| 1863 | testWidget->setMaxLength(length); |
| 1864 | |
| 1865 | // I expect MaxLength to work BOTH with entering live characters AND with setting the text. |
| 1866 | if (use_setText) { |
| 1867 | // Enter insertString using setText. |
| 1868 | testWidget->setText(insertString); |
| 1869 | } else { |
| 1870 | // Enter insertString as a sequence of keyClicks |
| 1871 | QTest::keyClicks(widget: testWidget, sequence: insertString); |
| 1872 | } |
| 1873 | |
| 1874 | // in all other cases we set the maxLength _after_ entering the text. |
| 1875 | if (insertBeforeSettingMaxLength) { |
| 1876 | changed_count = 0; |
| 1877 | testWidget->setMaxLength(length); |
| 1878 | |
| 1879 | // Make sure that the textChanged is not emitted unless the text is actually changed |
| 1880 | if (insertString == expectedString) { |
| 1881 | QCOMPARE(changed_count, 0); |
| 1882 | } else { |
| 1883 | QCOMPARE(changed_count, 1); |
| 1884 | } |
| 1885 | } |
| 1886 | |
| 1887 | // and check if we get the expected string back |
| 1888 | QCOMPARE(testWidget->text(), expectedString); |
| 1889 | } |
| 1890 | |
| 1891 | void tst_QLineEdit::isReadOnly() |
| 1892 | { |
| 1893 | QLineEdit *testWidget = ensureTestWidget(); |
| 1894 | QVERIFY(!testWidget->isReadOnly()); |
| 1895 | |
| 1896 | // start with a basic text |
| 1897 | QTest::keyClicks(widget: testWidget, sequence: "the quick brown fox" ); |
| 1898 | QCOMPARE(testWidget->text(), QString("the quick brown fox" )); |
| 1899 | |
| 1900 | // do a quick check to verify that we can indeed edit the text |
| 1901 | testWidget->home(mark: false); |
| 1902 | testWidget->cursorForward(mark: false, steps: 10); |
| 1903 | QTest::keyClicks(widget: testWidget, sequence: "dark " ); |
| 1904 | QCOMPARE(testWidget->text(), QString("the quick dark brown fox" )); |
| 1905 | |
| 1906 | testWidget->setReadOnly(true); |
| 1907 | QVERIFY(testWidget->isReadOnly()); |
| 1908 | |
| 1909 | // verify that we cannot edit the text anymore |
| 1910 | testWidget->home(mark: false); |
| 1911 | testWidget->cursorForward(mark: false, steps: 10); |
| 1912 | QTest::keyClick(widget: testWidget, key: Qt::Key_Delete); |
| 1913 | QCOMPARE(testWidget->text(), QString("the quick dark brown fox" )); |
| 1914 | testWidget->cursorForward(mark: false, steps: 10); |
| 1915 | QTest::keyClicks(widget: testWidget, sequence: "this should not have any effect!! " ); |
| 1916 | QCOMPARE(testWidget->text(), QString("the quick dark brown fox" )); |
| 1917 | } |
| 1918 | |
| 1919 | class BlinkTestLineEdit : public QLineEdit |
| 1920 | { |
| 1921 | public: |
| 1922 | void paintEvent(QPaintEvent *e) |
| 1923 | { |
| 1924 | ++updates; |
| 1925 | QLineEdit::paintEvent(e); |
| 1926 | } |
| 1927 | |
| 1928 | int updates; |
| 1929 | }; |
| 1930 | |
| 1931 | void tst_QLineEdit::noCursorBlinkWhenReadOnly() |
| 1932 | { |
| 1933 | if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) |
| 1934 | QSKIP("Wayland: This fails. Figure out why." ); |
| 1935 | |
| 1936 | int cursorFlashTime = QApplication::cursorFlashTime(); |
| 1937 | if (cursorFlashTime == 0) |
| 1938 | return; |
| 1939 | BlinkTestLineEdit le; |
| 1940 | centerOnScreen(w: &le); |
| 1941 | le.show(); |
| 1942 | le.setFocus(); |
| 1943 | QVERIFY(QTest::qWaitForWindowActive(&le)); |
| 1944 | le.updates = 0; |
| 1945 | QTest::qWait(ms: cursorFlashTime); |
| 1946 | QVERIFY(le.updates > 0); |
| 1947 | le.setReadOnly(true); |
| 1948 | QTest::qWait(ms: 10); |
| 1949 | le.updates = 0; |
| 1950 | QTest::qWait(ms: cursorFlashTime); |
| 1951 | QCOMPARE(le.updates, 0); |
| 1952 | le.setReadOnly(false); |
| 1953 | QTest::qWait(ms: 10); |
| 1954 | le.updates = 0; |
| 1955 | QTest::qWait(ms: cursorFlashTime); |
| 1956 | QVERIFY(le.updates > 0); |
| 1957 | } |
| 1958 | |
| 1959 | static void figureOutProperKey(Qt::Key &key, Qt::KeyboardModifiers &pressState) |
| 1960 | { |
| 1961 | #ifdef Q_OS_MAC |
| 1962 | long roll = QRandomGenerator::global()->bounded(3); |
| 1963 | switch (roll) { |
| 1964 | case 0: |
| 1965 | key = key == Qt::Key_Home ? Qt::Key_Up : Qt::Key_Down; |
| 1966 | break; |
| 1967 | case 1: |
| 1968 | case 2: |
| 1969 | key = key == Qt::Key_Home ? Qt::Key_Left : Qt::Key_Right; |
| 1970 | pressState |= (roll == 1) ? Qt::ControlModifier : Qt::MetaModifier; |
| 1971 | break; |
| 1972 | } |
| 1973 | #else |
| 1974 | Q_UNUSED(key); |
| 1975 | Q_UNUSED(pressState); |
| 1976 | #endif |
| 1977 | } |
| 1978 | |
| 1979 | // Platform specific move. Home and End do nothing on the Mac, |
| 1980 | // so do something a bit smarter than tons of #ifdefs |
| 1981 | void tst_QLineEdit::psKeyClick(QWidget *target, Qt::Key key, Qt::KeyboardModifiers pressState) |
| 1982 | { |
| 1983 | figureOutProperKey(key, pressState); |
| 1984 | QTest::keyClick(widget: target, key, modifier: pressState); |
| 1985 | } |
| 1986 | |
| 1987 | void tst_QLineEdit::psKeyClick(QTestEventList &keys, Qt::Key key, Qt::KeyboardModifiers pressState) |
| 1988 | { |
| 1989 | figureOutProperKey(key, pressState); |
| 1990 | keys.addKeyClick(qtKey: key, modifiers: pressState); |
| 1991 | } |
| 1992 | |
| 1993 | void tst_QLineEdit::addKeySequenceStandardKey(QTestEventList &keys, QKeySequence::StandardKey key) |
| 1994 | { |
| 1995 | QKeySequence keyseq = QKeySequence(key); |
| 1996 | for (int i = 0; i < keyseq.count(); ++i) |
| 1997 | keys.addKeyClick( qtKey: Qt::Key( keyseq[i] & ~Qt::KeyboardModifierMask), modifiers: Qt::KeyboardModifier(keyseq[i] & Qt::KeyboardModifierMask) ); |
| 1998 | } |
| 1999 | |
| 2000 | void tst_QLineEdit::cursorPosition() |
| 2001 | { |
| 2002 | QLineEdit *testWidget = ensureTestWidget(); |
| 2003 | QCOMPARE(testWidget->cursorPosition(), 0); |
| 2004 | |
| 2005 | // start with a basic text |
| 2006 | QTest::keyClicks(widget: testWidget, sequence: "The" ); |
| 2007 | QCOMPARE(testWidget->cursorPosition(), 3); |
| 2008 | QTest::keyClicks(widget: testWidget, sequence: " quick" ); |
| 2009 | QCOMPARE(testWidget->cursorPosition(), 9); |
| 2010 | QTest::keyClicks(widget: testWidget, sequence: " brown fox jumps over the lazy dog" ); |
| 2011 | QCOMPARE(testWidget->cursorPosition(), 43); |
| 2012 | |
| 2013 | // The text we have now is: |
| 2014 | // 1 2 3 4 5 |
| 2015 | // 012345678901234567890123456789012345678901234567890 |
| 2016 | // The quick brown fox jumps over the lazy dog |
| 2017 | |
| 2018 | // next we will check some of the cursor movement functions |
| 2019 | testWidget->end(mark: false); |
| 2020 | QCOMPARE(testWidget->cursorPosition() , 43); |
| 2021 | testWidget->cursorForward(mark: false, steps: -1); |
| 2022 | QCOMPARE(testWidget->cursorPosition() , 42); |
| 2023 | testWidget->cursorBackward(mark: false, steps: 1); |
| 2024 | QCOMPARE(testWidget->cursorPosition() , 41); |
| 2025 | testWidget->home(mark: false); |
| 2026 | QCOMPARE(testWidget->cursorPosition() , 0); |
| 2027 | testWidget->cursorForward(mark: false, steps: 1); |
| 2028 | QCOMPARE(testWidget->cursorPosition() , 1); |
| 2029 | testWidget->cursorForward(mark: false, steps: 9); |
| 2030 | QCOMPARE(testWidget->cursorPosition() , 10); |
| 2031 | testWidget->cursorWordForward(mark: false); // 'fox' |
| 2032 | QCOMPARE(testWidget->cursorPosition(), 16); |
| 2033 | testWidget->cursorWordForward(mark: false); // 'jumps' |
| 2034 | QCOMPARE(testWidget->cursorPosition(), 20); |
| 2035 | testWidget->cursorWordBackward(mark: false); // 'fox' |
| 2036 | QCOMPARE(testWidget->cursorPosition(), 16); |
| 2037 | testWidget->cursorWordBackward(mark: false); // 'brown' |
| 2038 | testWidget->cursorWordBackward(mark: false); // 'quick' |
| 2039 | testWidget->cursorWordBackward(mark: false); // 'The' |
| 2040 | QCOMPARE(testWidget->cursorPosition(), 0); |
| 2041 | testWidget->cursorWordBackward(mark: false); // 'The' |
| 2042 | QCOMPARE(testWidget->cursorPosition(), 0); |
| 2043 | |
| 2044 | // Cursor position should be 0 here! |
| 2045 | int i; |
| 2046 | for (i=0; i<5; i++) |
| 2047 | QTest::keyClick(widget: testWidget, key: Qt::Key_Right); |
| 2048 | QCOMPARE(testWidget->cursorPosition(), 5); |
| 2049 | psKeyClick(target: testWidget, key: Qt::Key_End); |
| 2050 | QCOMPARE(testWidget->cursorPosition(), 43); |
| 2051 | QTest::keyClick(widget: testWidget, key: Qt::Key_Left); |
| 2052 | QCOMPARE(testWidget->cursorPosition(), 42); |
| 2053 | QTest::keyClick(widget: testWidget, key: Qt::Key_Left); |
| 2054 | QCOMPARE(testWidget->cursorPosition(), 41); |
| 2055 | psKeyClick(target: testWidget, key: Qt::Key_Home); |
| 2056 | QCOMPARE(testWidget->cursorPosition(), 0); |
| 2057 | |
| 2058 | // cursorposition when maxlength is set |
| 2059 | int maxLength = 9; |
| 2060 | testWidget->clear(); |
| 2061 | testWidget->setMaxLength(maxLength); |
| 2062 | QCOMPARE(testWidget->cursorPosition() , 0); |
| 2063 | QTest::keyClicks(widget: testWidget, sequence: "123ABC123" ); |
| 2064 | QCOMPARE(testWidget->cursorPosition() , maxLength); |
| 2065 | psKeyClick(target: testWidget, key: Qt::Key_Home); |
| 2066 | QCOMPARE(testWidget->cursorPosition() , 0); |
| 2067 | psKeyClick(target: testWidget, key: Qt::Key_End); |
| 2068 | QCOMPARE(testWidget->cursorPosition() , maxLength); |
| 2069 | } |
| 2070 | |
| 2071 | /* // tested in cursorPosition |
| 2072 | void tst_QLineEdit::cursorLeft() |
| 2073 | void tst_QLineEdit::cursorRight() |
| 2074 | void tst_QLineEdit::cursorForward() |
| 2075 | void tst_QLineEdit::cursorBackward() |
| 2076 | void tst_QLineEdit::cursorWordForward() |
| 2077 | void tst_QLineEdit::cursorWordBackward() |
| 2078 | void tst_QLineEdit::home() |
| 2079 | void tst_QLineEdit::end() |
| 2080 | */ |
| 2081 | |
| 2082 | void tst_QLineEdit::cursorPositionChanged_data() |
| 2083 | { |
| 2084 | QTest::addColumn<QTestEventList>(name: "input" ); |
| 2085 | QTest::addColumn<int>(name: "lastPos" ); |
| 2086 | QTest::addColumn<int>(name: "newPos" ); |
| 2087 | |
| 2088 | QTestEventList keys; |
| 2089 | keys.addKeyClick(qtKey: Qt::Key_A); |
| 2090 | QTest::newRow(dataTag: "a" ) << keys << -1 << 1; |
| 2091 | keys.clear(); |
| 2092 | |
| 2093 | keys.addKeyClick(qtKey: Qt::Key_A); |
| 2094 | keys.addKeyClick(qtKey: Qt::Key_B); |
| 2095 | keys.addKeyClick(qtKey: Qt::Key_C); |
| 2096 | psKeyClick(keys, key: Qt::Key_Home); |
| 2097 | QTest::newRow(dataTag: "abc<home>" ) << keys << 3 << 0; |
| 2098 | keys.clear(); |
| 2099 | |
| 2100 | keys.addKeyClick(qtKey: Qt::Key_A); |
| 2101 | keys.addKeyClick(qtKey: Qt::Key_B); |
| 2102 | keys.addKeyClick(qtKey: Qt::Key_C); |
| 2103 | keys.addKeyClick(qtKey: Qt::Key_Left); |
| 2104 | QTest::newRow(dataTag: "abc<left>" ) << keys << 3 << 2; |
| 2105 | keys.clear(); |
| 2106 | |
| 2107 | keys.addKeyClick(qtKey: Qt::Key_A); |
| 2108 | keys.addKeyClick(qtKey: Qt::Key_B); |
| 2109 | keys.addKeyClick(qtKey: Qt::Key_C); |
| 2110 | keys.addKeyClick(qtKey: Qt::Key_Right); |
| 2111 | QTest::newRow(dataTag: "abc<right>" ) << keys << 2 << 3; |
| 2112 | keys.clear(); |
| 2113 | |
| 2114 | keys.addKeyClick(qtKey: Qt::Key_A); |
| 2115 | keys.addKeyClick(qtKey: Qt::Key_B); |
| 2116 | keys.addKeyClick(qtKey: Qt::Key_C); |
| 2117 | psKeyClick(keys, key: Qt::Key_Home); |
| 2118 | keys.addKeyClick(qtKey: Qt::Key_Right); |
| 2119 | QTest::newRow(dataTag: "abc<home><right>" ) << keys << 0 << 1; |
| 2120 | keys.clear(); |
| 2121 | |
| 2122 | keys.addKeyClick(qtKey: Qt::Key_A); |
| 2123 | keys.addKeyClick(qtKey: Qt::Key_B); |
| 2124 | keys.addKeyClick(qtKey: Qt::Key_C); |
| 2125 | keys.addKeyClick(qtKey: Qt::Key_Backspace); |
| 2126 | QTest::newRow(dataTag: "abc<backspace>" ) << keys << 3 << 2; |
| 2127 | keys.clear(); |
| 2128 | |
| 2129 | keys.addKeyClick(qtKey: Qt::Key_A); |
| 2130 | keys.addKeyClick(qtKey: Qt::Key_B); |
| 2131 | keys.addKeyClick(qtKey: Qt::Key_C); |
| 2132 | keys.addKeyClick(qtKey: Qt::Key_Delete); |
| 2133 | QTest::newRow(dataTag: "abc<delete>" ) << keys << 2 << 3; |
| 2134 | keys.clear(); |
| 2135 | |
| 2136 | keys.addKeyClick(qtKey: Qt::Key_A); |
| 2137 | keys.addKeyClick(qtKey: Qt::Key_B); |
| 2138 | keys.addKeyClick(qtKey: Qt::Key_C); |
| 2139 | keys.addKeyClick(qtKey: Qt::Key_Left); |
| 2140 | keys.addKeyClick(qtKey: Qt::Key_Delete); |
| 2141 | QTest::newRow(dataTag: "abc<left><delete>" ) << keys << 3 << 2; |
| 2142 | keys.clear(); |
| 2143 | |
| 2144 | keys.addKeyClick(qtKey: Qt::Key_A); |
| 2145 | keys.addKeyClick(qtKey: Qt::Key_B); |
| 2146 | keys.addKeyClick(qtKey: Qt::Key_C); |
| 2147 | psKeyClick(keys, key: Qt::Key_Home); |
| 2148 | psKeyClick(keys, key: Qt::Key_End); |
| 2149 | QTest::newRow(dataTag: "abc<home><end>" ) << keys << 0 << 3; |
| 2150 | keys.clear(); |
| 2151 | |
| 2152 | keys.addKeyClick(qtKey: Qt::Key_A); |
| 2153 | keys.addKeyClick(qtKey: Qt::Key_B); |
| 2154 | keys.addKeyClick(qtKey: Qt::Key_C); |
| 2155 | keys.addKeyClick(qtKey: Qt::Key_Space); |
| 2156 | keys.addKeyClick(qtKey: Qt::Key_D); |
| 2157 | keys.addKeyClick(qtKey: Qt::Key_E); |
| 2158 | keys.addKeyClick(qtKey: Qt::Key_F); |
| 2159 | keys.addKeyClick(qtKey: Qt::Key_Home); |
| 2160 | keys.addKeyClick(qtKey: Qt::Key_Right, modifiers: Qt::ControlModifier); |
| 2161 | QTest::newRow(dataTag: "abc efg<home><ctrl-right>" ) << keys |
| 2162 | #ifndef Q_OS_MAC |
| 2163 | << 0 << 4; |
| 2164 | #else |
| 2165 | << 6 << 7; |
| 2166 | #endif |
| 2167 | keys.clear(); |
| 2168 | |
| 2169 | #ifdef Q_OS_MAC |
| 2170 | keys.addKeyClick(Qt::Key_A); |
| 2171 | keys.addKeyClick(Qt::Key_B); |
| 2172 | keys.addKeyClick(Qt::Key_C); |
| 2173 | keys.addKeyClick(Qt::Key_Space); |
| 2174 | keys.addKeyClick(Qt::Key_D); |
| 2175 | keys.addKeyClick(Qt::Key_E); |
| 2176 | keys.addKeyClick(Qt::Key_F); |
| 2177 | keys.addKeyClick(Qt::Key_Up); |
| 2178 | keys.addKeyClick(Qt::Key_Right, Qt::AltModifier); |
| 2179 | QTest::newRow("mac equivalent abc efg<up><option-right>" ) << keys << 0 << 4; |
| 2180 | keys.clear(); |
| 2181 | #endif |
| 2182 | |
| 2183 | keys.addKeyClick(qtKey: Qt::Key_A); |
| 2184 | keys.addKeyClick(qtKey: Qt::Key_B); |
| 2185 | keys.addKeyClick(qtKey: Qt::Key_C); |
| 2186 | keys.addKeyClick(qtKey: Qt::Key_Space); |
| 2187 | keys.addKeyClick(qtKey: Qt::Key_D); |
| 2188 | keys.addKeyClick(qtKey: Qt::Key_E); |
| 2189 | keys.addKeyClick(qtKey: Qt::Key_F); |
| 2190 | keys.addKeyClick(qtKey: Qt::Key_Left, modifiers: Qt::ControlModifier); |
| 2191 | QTest::newRow(dataTag: "abc efg<ctrl-left>" ) << keys << 7 |
| 2192 | #ifndef Q_OS_MAC |
| 2193 | << 4; |
| 2194 | #else |
| 2195 | << 0; |
| 2196 | #endif |
| 2197 | keys.clear(); |
| 2198 | #ifdef Q_OS_MAC |
| 2199 | keys.addKeyClick(Qt::Key_A); |
| 2200 | keys.addKeyClick(Qt::Key_B); |
| 2201 | keys.addKeyClick(Qt::Key_C); |
| 2202 | keys.addKeyClick(Qt::Key_Space); |
| 2203 | keys.addKeyClick(Qt::Key_D); |
| 2204 | keys.addKeyClick(Qt::Key_E); |
| 2205 | keys.addKeyClick(Qt::Key_F); |
| 2206 | keys.addKeyClick(Qt::Key_Left, Qt::AltModifier); |
| 2207 | QTest::newRow("mac equivalent abc efg<option-left>" ) << keys << 7 << 4; |
| 2208 | keys.clear(); |
| 2209 | #endif |
| 2210 | } |
| 2211 | |
| 2212 | |
| 2213 | void tst_QLineEdit::cursorPositionChanged() |
| 2214 | { |
| 2215 | QFETCH(QTestEventList, input); |
| 2216 | QFETCH(int, lastPos); |
| 2217 | QFETCH(int, newPos); |
| 2218 | |
| 2219 | lastCursorPos = 0; |
| 2220 | newCursorPos = 0; |
| 2221 | QLineEdit *testWidget = ensureTestWidget(); |
| 2222 | input.simulate(w: testWidget); |
| 2223 | QCOMPARE(lastCursorPos, lastPos); |
| 2224 | QCOMPARE(newCursorPos, newPos); |
| 2225 | } |
| 2226 | |
| 2227 | void tst_QLineEdit::selectedText() |
| 2228 | { |
| 2229 | QString testString = "Abc defg hijklmno, p 'qrst' uvw xyz" ; |
| 2230 | |
| 2231 | // start with a basic text |
| 2232 | QLineEdit *testWidget = ensureTestWidget(); |
| 2233 | testWidget->setText(testString); |
| 2234 | selection_count = 0; |
| 2235 | |
| 2236 | // The text we have now is: |
| 2237 | // 1 2 3 4 5 |
| 2238 | // 012345678901234567890123456789012345678901234567890 |
| 2239 | // Abc defg hijklmno, p 'qrst' uvw xyz |
| 2240 | |
| 2241 | testWidget->home(mark: false); |
| 2242 | QVERIFY(!testWidget->hasSelectedText()); |
| 2243 | QCOMPARE(testWidget->selectedText(), QString()); |
| 2244 | |
| 2245 | // play a bit with the cursorForward, cursorBackward(), etc |
| 2246 | testWidget->cursorForward(mark: true, steps: 9); |
| 2247 | QVERIFY(testWidget->hasSelectedText()); |
| 2248 | QCOMPARE(testWidget->selectedText(), QString("Abc defg " )); |
| 2249 | QCOMPARE(selection_count, 1); |
| 2250 | |
| 2251 | // reset selection |
| 2252 | testWidget->home(mark: false); |
| 2253 | QVERIFY(!testWidget->hasSelectedText()); |
| 2254 | QCOMPARE(testWidget->selectedText(), QString()); |
| 2255 | selection_count = 0; |
| 2256 | } |
| 2257 | |
| 2258 | /* // tested in selectedText |
| 2259 | void tst_QLineEdit::backspace() |
| 2260 | void tst_QLineEdit::del() |
| 2261 | void tst_QLineEdit::selectionChanged() |
| 2262 | void tst_QLineEdit::selectAll() |
| 2263 | void tst_QLineEdit::deselect() |
| 2264 | */ |
| 2265 | |
| 2266 | void tst_QLineEdit::onSelectionChanged() |
| 2267 | { |
| 2268 | selection_count++; |
| 2269 | } |
| 2270 | |
| 2271 | void tst_QLineEdit::deleteSelectedText() |
| 2272 | { |
| 2273 | const QString text = QString::fromLatin1(str: "bar" ); |
| 2274 | QLineEdit edit( text ); |
| 2275 | QCOMPARE(edit.text(), text); |
| 2276 | |
| 2277 | edit.selectAll(); |
| 2278 | |
| 2279 | QTest::keyClick(widget: &edit, key: Qt::Key_Delete, modifier: {}); |
| 2280 | QVERIFY(edit.text().isEmpty()); |
| 2281 | |
| 2282 | edit.setText(text); |
| 2283 | edit.selectAll(); |
| 2284 | |
| 2285 | #ifndef QT_NO_CONTEXTMENU |
| 2286 | QMenu * = edit.createStandardContextMenu(); |
| 2287 | for (int i = 0; i < menu->actions().count(); ++i) { |
| 2288 | QAction *current = menu->actions().at(i); |
| 2289 | if (current->text() == QLineEdit::tr(s: "Delete" )) { |
| 2290 | current->trigger(); //this will delete the whole text selected |
| 2291 | QVERIFY(edit.text().isEmpty()); |
| 2292 | } |
| 2293 | } |
| 2294 | #endif // QT_NO_CONTEXTMENU |
| 2295 | |
| 2296 | } |
| 2297 | |
| 2298 | class ToUpperValidator : public QValidator |
| 2299 | { |
| 2300 | public: |
| 2301 | ToUpperValidator() {} |
| 2302 | State validate(QString &input, int &) const override |
| 2303 | { |
| 2304 | input = input.toUpper(); |
| 2305 | return QValidator::Acceptable; |
| 2306 | } |
| 2307 | }; |
| 2308 | |
| 2309 | void tst_QLineEdit::textChangedAndTextEdited() |
| 2310 | { |
| 2311 | changed_count = 0; |
| 2312 | edited_count = 0; |
| 2313 | |
| 2314 | QLineEdit *testWidget = ensureTestWidget(); |
| 2315 | QTest::keyClick(widget: testWidget, key: Qt::Key_A); |
| 2316 | QCOMPARE(changed_count, 1); |
| 2317 | QCOMPARE(edited_count, changed_count); |
| 2318 | QTest::keyClick(widget: testWidget, key: 'b'); |
| 2319 | QCOMPARE(changed_count, 2); |
| 2320 | QCOMPARE(edited_count, changed_count); |
| 2321 | QTest::keyClick(widget: testWidget, key: 'c'); |
| 2322 | QCOMPARE(changed_count, 3); |
| 2323 | QCOMPARE(edited_count, changed_count); |
| 2324 | QTest::keyClick(widget: testWidget, key: ' '); |
| 2325 | QCOMPARE(changed_count, 4); |
| 2326 | QCOMPARE(edited_count, changed_count); |
| 2327 | QTest::keyClick(widget: testWidget, key: 'd'); |
| 2328 | QCOMPARE(changed_count, 5); |
| 2329 | QCOMPARE(edited_count, changed_count); |
| 2330 | |
| 2331 | changed_count = 0; |
| 2332 | edited_count = 0; |
| 2333 | changed_string.clear(); |
| 2334 | |
| 2335 | testWidget->setText("foo" ); |
| 2336 | QCOMPARE(changed_count, 1); |
| 2337 | QCOMPARE(edited_count, 0); |
| 2338 | QCOMPARE(changed_string, QString("foo" )); |
| 2339 | |
| 2340 | changed_count = 0; |
| 2341 | edited_count = 0; |
| 2342 | changed_string.clear(); |
| 2343 | |
| 2344 | testWidget->setText("" ); |
| 2345 | QCOMPARE(changed_count, 1); |
| 2346 | QCOMPARE(edited_count, 0); |
| 2347 | QVERIFY(changed_string.isEmpty()); |
| 2348 | QVERIFY(!changed_string.isNull()); |
| 2349 | |
| 2350 | changed_count = 0; |
| 2351 | edited_count = 0; |
| 2352 | changed_string.clear(); |
| 2353 | |
| 2354 | QScopedPointer<ToUpperValidator> validator(new ToUpperValidator()); |
| 2355 | testWidget->setValidator(validator.data()); |
| 2356 | testWidget->setText("foo" ); |
| 2357 | QCOMPARE(changed_count, 1); |
| 2358 | QCOMPARE(edited_count, 0); |
| 2359 | QCOMPARE(changed_string, QLatin1String("FOO" )); |
| 2360 | testWidget->setCursorPosition(sizeof("foo" )); |
| 2361 | QTest::keyClick(widget: testWidget, key: 'b'); |
| 2362 | QCOMPARE(changed_count, 2); |
| 2363 | QCOMPARE(edited_count, 1); |
| 2364 | QCOMPARE(changed_string, QLatin1String("FOOB" )); |
| 2365 | testWidget->setValidator(nullptr); |
| 2366 | } |
| 2367 | |
| 2368 | void tst_QLineEdit::onTextChanged(const QString &text) |
| 2369 | { |
| 2370 | changed_count++; |
| 2371 | changed_string = text; |
| 2372 | } |
| 2373 | |
| 2374 | void tst_QLineEdit::onTextEdited(const QString &/*text*/) |
| 2375 | { |
| 2376 | edited_count++; |
| 2377 | } |
| 2378 | |
| 2379 | |
| 2380 | void tst_QLineEdit::onCursorPositionChanged(int oldPos, int newPos) |
| 2381 | { |
| 2382 | lastCursorPos = oldPos; |
| 2383 | newCursorPos = newPos; |
| 2384 | } |
| 2385 | |
| 2386 | void tst_QLineEdit::returnPressed() |
| 2387 | { |
| 2388 | return_count = 0; |
| 2389 | |
| 2390 | QLineEdit *testWidget = ensureTestWidget(); |
| 2391 | QTest::keyClick(widget: testWidget, key: Qt::Key_Return); |
| 2392 | QCOMPARE(return_count, 1); |
| 2393 | return_count = 0; |
| 2394 | |
| 2395 | QTest::keyClick(widget: testWidget, key: 'A'); |
| 2396 | QCOMPARE(return_count, 0); |
| 2397 | QTest::keyClick(widget: testWidget, key: 'b'); |
| 2398 | QCOMPARE(return_count, 0); |
| 2399 | QTest::keyClick(widget: testWidget, key: 'c'); |
| 2400 | QCOMPARE(return_count, 0); |
| 2401 | QTest::keyClick(widget: testWidget, key: ' '); |
| 2402 | QCOMPARE(return_count, 0); |
| 2403 | QTest::keyClick(widget: testWidget, key: 'd'); |
| 2404 | QCOMPARE(return_count, 0); |
| 2405 | psKeyClick(target: testWidget, key: Qt::Key_Home); |
| 2406 | QCOMPARE(return_count, 0); |
| 2407 | psKeyClick(target: testWidget, key: Qt::Key_End); |
| 2408 | QCOMPARE(return_count, 0); |
| 2409 | QTest::keyClick(widget: testWidget, key: Qt::Key_Escape); |
| 2410 | QCOMPARE(return_count, 0); |
| 2411 | QTest::keyClick(widget: testWidget, key: Qt::Key_Return); |
| 2412 | QCOMPARE(return_count, 1); |
| 2413 | } |
| 2414 | |
| 2415 | // int validator that fixes all !isNumber to '0' |
| 2416 | class QIntFixValidator : public QIntValidator { |
| 2417 | public: |
| 2418 | QIntFixValidator(int min, int max, QObject *parent) : QIntValidator(min, max, parent) {} |
| 2419 | void fixup (QString &input) const { |
| 2420 | for (int i=0; i<input.length(); ++i) |
| 2421 | if (!input.at(i).isNumber()) { |
| 2422 | input[(int)i] = QChar('0'); |
| 2423 | } |
| 2424 | } |
| 2425 | }; |
| 2426 | |
| 2427 | void tst_QLineEdit::returnPressed_maskvalidator_data() { |
| 2428 | QTest::addColumn<QString>(name: "inputMask" ); |
| 2429 | QTest::addColumn<bool>(name: "hasValidator" ); |
| 2430 | QTest::addColumn<QTestEventList>(name: "input" ); |
| 2431 | QTest::addColumn<QString>(name: "expectedText" ); |
| 2432 | QTest::addColumn<bool>(name: "returnPressed" ); |
| 2433 | |
| 2434 | { |
| 2435 | QTestEventList keys; |
| 2436 | keys.addKeyClick(qtKey: Qt::Key_Home); |
| 2437 | keys.addKeyClick(qtKey: Qt::Key_1); |
| 2438 | keys.addKeyClick(qtKey: Qt::Key_2); |
| 2439 | keys.addKeyClick(qtKey: Qt::Key_3); |
| 2440 | keys.addKeyClick(qtKey: Qt::Key_Return); |
| 2441 | QTest::newRow(dataTag: "no mask, no validator, input '123<cr>'" ) |
| 2442 | << QString() |
| 2443 | << false |
| 2444 | << keys |
| 2445 | << QString("123" ) |
| 2446 | << true; |
| 2447 | } |
| 2448 | { |
| 2449 | QTestEventList keys; |
| 2450 | keys.addKeyClick(qtKey: Qt::Key_Home); |
| 2451 | keys.addKeyClick(qtKey: Qt::Key_1); |
| 2452 | keys.addKeyClick(qtKey: Qt::Key_2); |
| 2453 | keys.addKeyClick(qtKey: Qt::Key_Return); |
| 2454 | QTest::newRow(dataTag: "mask '999', no validator, input '12<cr>'" ) |
| 2455 | << QString("999" ) |
| 2456 | << false |
| 2457 | << keys |
| 2458 | << QString("12" ) |
| 2459 | << false; |
| 2460 | } |
| 2461 | { |
| 2462 | QTestEventList keys; |
| 2463 | keys.addKeyClick(qtKey: Qt::Key_Home); |
| 2464 | keys.addKeyClick(qtKey: Qt::Key_1); |
| 2465 | keys.addKeyClick(qtKey: Qt::Key_2); |
| 2466 | keys.addKeyClick(qtKey: Qt::Key_3); |
| 2467 | keys.addKeyClick(qtKey: Qt::Key_Return); |
| 2468 | QTest::newRow(dataTag: "mask '999', no validator, input '123<cr>'" ) |
| 2469 | << QString("999" ) |
| 2470 | << false |
| 2471 | << keys |
| 2472 | << QString("123" ) |
| 2473 | << true; |
| 2474 | } |
| 2475 | { |
| 2476 | QTestEventList keys; |
| 2477 | keys.addKeyClick(qtKey: Qt::Key_Home); |
| 2478 | keys.addKeyClick(qtKey: Qt::Key_1); |
| 2479 | keys.addKeyClick(qtKey: Qt::Key_2); |
| 2480 | keys.addKeyClick(qtKey: Qt::Key_3); |
| 2481 | keys.addKeyClick(qtKey: Qt::Key_Return); |
| 2482 | QTest::newRow(dataTag: "no mask, intfix validator(0,999), input '123<cr>'" ) |
| 2483 | << QString() |
| 2484 | << true |
| 2485 | << keys |
| 2486 | << QString("123" ) |
| 2487 | << true; |
| 2488 | } |
| 2489 | { |
| 2490 | QTestEventList keys; |
| 2491 | keys.addKeyClick(qtKey: Qt::Key_Home); |
| 2492 | keys.addKeyClick(qtKey: Qt::Key_7); |
| 2493 | keys.addKeyClick(qtKey: Qt::Key_7); |
| 2494 | keys.addKeyClick(qtKey: Qt::Key_7); |
| 2495 | keys.addKeyClick(qtKey: Qt::Key_7); |
| 2496 | keys.addKeyClick(qtKey: Qt::Key_Return); |
| 2497 | QTest::newRow(dataTag: "no mask, intfix validator(0,999), input '7777<cr>'" ) |
| 2498 | << QString() |
| 2499 | << true |
| 2500 | << keys |
| 2501 | << QString("777" ) |
| 2502 | << true; |
| 2503 | } |
| 2504 | { |
| 2505 | QTestEventList keys; |
| 2506 | keys.addKeyClick(qtKey: Qt::Key_Home); |
| 2507 | keys.addKeyClick(qtKey: Qt::Key_1); |
| 2508 | keys.addKeyClick(qtKey: Qt::Key_2); |
| 2509 | keys.addKeyClick(qtKey: Qt::Key_Return); |
| 2510 | QTest::newRow(dataTag: "mask '999', intfix validator(0,999), input '12<cr>'" ) |
| 2511 | << QString("999" ) |
| 2512 | << true |
| 2513 | << keys |
| 2514 | << QString("12" ) |
| 2515 | << false; |
| 2516 | } |
| 2517 | { |
| 2518 | QTestEventList keys; |
| 2519 | keys.addKeyClick(qtKey: Qt::Key_Home); |
| 2520 | keys.addKeyClick(qtKey: Qt::Key_Return); |
| 2521 | QTest::newRow(dataTag: "mask '999', intfix validator(0,999), input '<cr>'" ) |
| 2522 | << QString("999" ) |
| 2523 | << true |
| 2524 | << keys |
| 2525 | << QString("000" ) |
| 2526 | << true; |
| 2527 | } |
| 2528 | } |
| 2529 | |
| 2530 | void tst_QLineEdit::returnPressed_maskvalidator() |
| 2531 | { |
| 2532 | QFETCH(QString, inputMask); |
| 2533 | QFETCH(bool, hasValidator); |
| 2534 | QFETCH(QTestEventList, input); |
| 2535 | QFETCH(QString, expectedText); |
| 2536 | QFETCH(bool, returnPressed); |
| 2537 | |
| 2538 | QEXPECT_FAIL("mask '999', intfix validator(0,999), input '12<cr>'" , "QIntValidator has changed behaviour. Does not accept spaces. Task 43082." , Abort); |
| 2539 | QLineEdit *testWidget = ensureTestWidget(); |
| 2540 | |
| 2541 | testWidget->setInputMask(inputMask); |
| 2542 | if (hasValidator) |
| 2543 | testWidget->setValidator(new QIntFixValidator(0, 999, testWidget)); |
| 2544 | |
| 2545 | return_count = 0; |
| 2546 | input.simulate(w: testWidget); |
| 2547 | |
| 2548 | QCOMPARE(testWidget->text(), expectedText); |
| 2549 | QCOMPARE(return_count , returnPressed ? 1 : 0); |
| 2550 | } |
| 2551 | |
| 2552 | void tst_QLineEdit::onReturnPressed() |
| 2553 | { |
| 2554 | return_count++; |
| 2555 | } |
| 2556 | |
| 2557 | void tst_QLineEdit::setValidator() |
| 2558 | { |
| 2559 | // Verify that we can set and re-set a validator. |
| 2560 | QLineEdit *testWidget = ensureTestWidget(); |
| 2561 | QVERIFY(!testWidget->validator()); |
| 2562 | |
| 2563 | QIntValidator iv1(0); |
| 2564 | testWidget->setValidator(&iv1); |
| 2565 | QCOMPARE(testWidget->validator(), static_cast<const QValidator*>(&iv1)); |
| 2566 | |
| 2567 | testWidget->setValidator(0); |
| 2568 | QVERIFY(!testWidget->validator()); |
| 2569 | |
| 2570 | QIntValidator iv2(0, 99, 0); |
| 2571 | testWidget->setValidator(&iv2); |
| 2572 | QCOMPARE(testWidget->validator(), static_cast<const QValidator *>(&iv2)); |
| 2573 | |
| 2574 | testWidget->setValidator(0); |
| 2575 | QVERIFY(!testWidget->validator()); |
| 2576 | } |
| 2577 | |
| 2578 | void tst_QLineEdit::setValidator_QIntValidator_data() |
| 2579 | { |
| 2580 | QTest::addColumn<int>(name: "mini" ); |
| 2581 | QTest::addColumn<int>(name: "maxi" ); |
| 2582 | QTest::addColumn<QString>(name: "input" ); |
| 2583 | QTest::addColumn<QString>(name: "expectedText" ); |
| 2584 | QTest::addColumn<bool>(name: "useKeys" ); |
| 2585 | QTest::addColumn<bool>(name: "is_valid" ); |
| 2586 | QTest::addColumn<uint>(name: "echoMode" ); |
| 2587 | |
| 2588 | for (int i=0; i<2; i++) { |
| 2589 | bool useKeys = false; |
| 2590 | QString inputMode = "insert " ; |
| 2591 | if (i!=0) { |
| 2592 | inputMode = "useKeys " ; |
| 2593 | useKeys = true; |
| 2594 | } |
| 2595 | |
| 2596 | // valid data |
| 2597 | QTest::newRow(dataTag: QString(inputMode + "range [0,9] valid '1'" ).toLatin1()) |
| 2598 | << 0 |
| 2599 | << 9 |
| 2600 | << QString("1" ) |
| 2601 | << QString("1" ) |
| 2602 | << bool(useKeys) |
| 2603 | << bool(true) |
| 2604 | << uint(QLineEdit::Normal); |
| 2605 | |
| 2606 | QTest::newRow(dataTag: QString(inputMode + "range [3,7] valid '3'" ).toLatin1()) |
| 2607 | << 3 |
| 2608 | << 7 |
| 2609 | << QString("3" ) |
| 2610 | << QString("3" ) |
| 2611 | << bool(useKeys) |
| 2612 | << bool(true) |
| 2613 | << uint(QLineEdit::Normal); |
| 2614 | |
| 2615 | QTest::newRow(dataTag: QString(inputMode + "range [3,7] valid '7'" ).toLatin1()) |
| 2616 | << 3 |
| 2617 | << 7 |
| 2618 | << QString("7" ) |
| 2619 | << QString("7" ) |
| 2620 | << bool(useKeys) |
| 2621 | << bool(true) |
| 2622 | << uint(QLineEdit::Normal); |
| 2623 | |
| 2624 | QTest::newRow(dataTag: QString(inputMode + "range [0,100] valid '9'" ).toLatin1()) |
| 2625 | << 0 |
| 2626 | << 100 |
| 2627 | << QString("9" ) |
| 2628 | << QString("9" ) |
| 2629 | << bool(useKeys) |
| 2630 | << bool(true) |
| 2631 | << uint(QLineEdit::Normal); |
| 2632 | |
| 2633 | QTest::newRow(dataTag: QString(inputMode + "range [0,100] valid '12'" ).toLatin1()) |
| 2634 | << 0 |
| 2635 | << 100 |
| 2636 | << QString("12" ) |
| 2637 | << QString("12" ) |
| 2638 | << bool(useKeys) |
| 2639 | << bool(true) |
| 2640 | << uint(QLineEdit::Normal); |
| 2641 | |
| 2642 | QTest::newRow(dataTag: QString(inputMode + "range [-100,100] valid '-12'" ).toLatin1()) |
| 2643 | << -100 |
| 2644 | << 100 |
| 2645 | << QString("-12" ) |
| 2646 | << QString("-12" ) |
| 2647 | << bool(useKeys) |
| 2648 | << bool(true) |
| 2649 | << uint(QLineEdit::Normal); |
| 2650 | |
| 2651 | // invalid data |
| 2652 | // characters not allowed in QIntValidator |
| 2653 | QTest::newRow(dataTag: QString(inputMode + "range [0,9] inv 'a-a'" ).toLatin1()) |
| 2654 | << 0 |
| 2655 | << 9 |
| 2656 | << QString("a" ) |
| 2657 | << QString("" ) |
| 2658 | << bool(useKeys) |
| 2659 | << bool(false) |
| 2660 | << uint(QLineEdit::Normal); |
| 2661 | |
| 2662 | QTest::newRow(dataTag: QString(inputMode + "range [0,9] inv 'A'" ).toLatin1()) |
| 2663 | << 0 |
| 2664 | << 9 |
| 2665 | << QString("A" ) |
| 2666 | << QString("" ) |
| 2667 | << bool(useKeys) |
| 2668 | << bool(false) |
| 2669 | << uint(QLineEdit::Normal); |
| 2670 | // minus sign only allowed with a range on the negative side |
| 2671 | QTest::newRow(dataTag: QString(inputMode + "range [0,100] inv '-'" ).toLatin1()) |
| 2672 | << 0 |
| 2673 | << 100 |
| 2674 | << QString("-" ) |
| 2675 | << QString("" ) |
| 2676 | << bool(useKeys) |
| 2677 | << bool(false) |
| 2678 | << uint(QLineEdit::Normal); |
| 2679 | QTest::newRow(dataTag: QString(inputMode + "range [0,100] int '153'" ).toLatin1()) |
| 2680 | << 0 |
| 2681 | << 100 |
| 2682 | << QString("153" ) |
| 2683 | << QString("153" ) |
| 2684 | << bool(useKeys) |
| 2685 | << bool(false) |
| 2686 | << uint(QLineEdit::Normal); |
| 2687 | QTest::newRow(dataTag: QString(inputMode + "range [-100,100] int '-153'" ).toLatin1()) |
| 2688 | << -100 |
| 2689 | << 100 |
| 2690 | << QString("-153" ) |
| 2691 | << QString(useKeys ? "-15" : "" ) |
| 2692 | << bool(useKeys) |
| 2693 | << bool(useKeys ? true : false) |
| 2694 | << uint(QLineEdit::Normal); |
| 2695 | QTest::newRow(dataTag: QString(inputMode + "range [3,7] int '2'" ).toLatin1()) |
| 2696 | << 3 |
| 2697 | << 7 |
| 2698 | << QString("2" ) |
| 2699 | << QString("2" ) |
| 2700 | << bool(useKeys) |
| 2701 | << bool(false) |
| 2702 | << uint(QLineEdit::Normal); |
| 2703 | QTest::newRow(dataTag: QString(inputMode + "range [3,7] int '8'" ).toLatin1()) |
| 2704 | << 3 |
| 2705 | << 7 |
| 2706 | << QString("" ) |
| 2707 | << QString("" ) |
| 2708 | << bool(useKeys) |
| 2709 | << bool(false) |
| 2710 | << uint(QLineEdit::Normal); |
| 2711 | QTest::newRow(dataTag: QString(inputMode + "range [0,99] inv 'a-a'" ).toLatin1()) |
| 2712 | << 0 |
| 2713 | << 99 |
| 2714 | << QString("19a" ) |
| 2715 | << QString(useKeys ? "19" : "" ) |
| 2716 | << bool(useKeys) |
| 2717 | << bool(useKeys ? true : false) |
| 2718 | << uint(QLineEdit::Password); |
| 2719 | } |
| 2720 | } |
| 2721 | |
| 2722 | void tst_QLineEdit::setValidator_QIntValidator() |
| 2723 | { |
| 2724 | QFETCH(int, mini); |
| 2725 | QFETCH(int, maxi); |
| 2726 | QFETCH(QString, input); |
| 2727 | QFETCH(QString, expectedText); |
| 2728 | QFETCH(bool, useKeys); |
| 2729 | QFETCH(bool, is_valid); |
| 2730 | QFETCH(uint, echoMode); |
| 2731 | |
| 2732 | QIntValidator intValidator(mini, maxi, 0); |
| 2733 | QLineEdit *testWidget = ensureTestWidget(); |
| 2734 | testWidget->setEchoMode((QLineEdit::EchoMode)echoMode); |
| 2735 | testWidget->setValidator(&intValidator); |
| 2736 | QVERIFY(testWidget->text().isEmpty()); |
| 2737 | //qDebug("1 input: '" + input + "' Exp: '" + expectedText + "'"); |
| 2738 | |
| 2739 | // tests valid input |
| 2740 | if (!useKeys) { |
| 2741 | testWidget->insert(input); |
| 2742 | } else { |
| 2743 | QTest::keyClicks(widget: testWidget, sequence: input); |
| 2744 | return_count = 0; |
| 2745 | QTest::keyClick(widget: testWidget, key: Qt::Key_Return); |
| 2746 | QCOMPARE(return_count, int(is_valid)); // assuming that is_valid = true equals 1 |
| 2747 | } |
| 2748 | //qDebug("2 input: '" + input + "' Exp: '" + expectedText + "'"); |
| 2749 | // QCOMPARE(testWidget->displayText(), expectedText); |
| 2750 | QCOMPARE(testWidget->text(), expectedText); |
| 2751 | } |
| 2752 | |
| 2753 | #define NO_PIXMAP_TESTS |
| 2754 | |
| 2755 | void tst_QLineEdit::frame_data() |
| 2756 | { |
| 2757 | #ifndef NO_PIXMAP_TESTS |
| 2758 | #if defined Q_OS_WIN |
| 2759 | QTest::addColumn<QPixmap>("noFrame" ); |
| 2760 | QTest::addColumn<QPixmap>("useFrame" ); |
| 2761 | |
| 2762 | QTest::newRow("win" ); |
| 2763 | //#else |
| 2764 | // QTest::newRow("x11"); |
| 2765 | #endif |
| 2766 | #endif |
| 2767 | } |
| 2768 | |
| 2769 | void tst_QLineEdit::frame() |
| 2770 | { |
| 2771 | QLineEdit *testWidget = ensureTestWidget(); |
| 2772 | testWidget->setFrame(false); |
| 2773 | // verify that the editor is shown without a frame |
| 2774 | #ifndef NO_PIXMAP_TESTS |
| 2775 | #if defined Q_OS_WIN |
| 2776 | QTEST(testWidget, "noFrame" ); |
| 2777 | #endif |
| 2778 | #endif |
| 2779 | QVERIFY(!testWidget->hasFrame()); |
| 2780 | |
| 2781 | testWidget->setFrame(true); |
| 2782 | // verify that the editor is shown with a frame |
| 2783 | #ifndef NO_PIXMAP_TESTS |
| 2784 | #if defined Q_OS_WIN |
| 2785 | QTEST(testWidget, "useFrame" ); |
| 2786 | #endif |
| 2787 | #endif |
| 2788 | QVERIFY(testWidget->hasFrame()); |
| 2789 | } |
| 2790 | |
| 2791 | void tst_QLineEdit::setAlignment_data() |
| 2792 | { |
| 2793 | #ifndef NO_PIXMAP_TESTS |
| 2794 | #if defined Q_OS_WIN |
| 2795 | QTest::addColumn<QPixmap>("left" ); |
| 2796 | QTest::addColumn<QPixmap>("right" ); |
| 2797 | QTest::addColumn<QPixmap>("hcenter" ); |
| 2798 | QTest::addColumn<QPixmap>("auto" ); |
| 2799 | |
| 2800 | QTest::newRow("win" ); |
| 2801 | //#else |
| 2802 | // QTest::newRow("x11"); |
| 2803 | #endif |
| 2804 | #endif |
| 2805 | } |
| 2806 | |
| 2807 | void tst_QLineEdit::setAlignment() |
| 2808 | { |
| 2809 | QLineEdit *testWidget = ensureTestWidget(); |
| 2810 | testWidget->setText("left" ); |
| 2811 | testWidget->setAlignment(Qt::AlignLeft); |
| 2812 | #ifndef NO_PIXMAP_TESTS |
| 2813 | #if defined Q_OS_WIN |
| 2814 | QTEST(testWidget, "left" ); |
| 2815 | #endif |
| 2816 | #endif |
| 2817 | QCOMPARE(testWidget->alignment(), Qt::AlignLeft); |
| 2818 | |
| 2819 | testWidget->setText("hcenter" ); |
| 2820 | testWidget->setAlignment(Qt::AlignHCenter); |
| 2821 | #ifndef NO_PIXMAP_TESTS |
| 2822 | #if defined Q_OS_WIN |
| 2823 | QTEST(testWidget, "hcenter" ); |
| 2824 | #endif |
| 2825 | #endif |
| 2826 | QCOMPARE(testWidget->alignment(), Qt::AlignHCenter); |
| 2827 | |
| 2828 | testWidget->setText("right" ); |
| 2829 | testWidget->setAlignment(Qt::AlignRight); |
| 2830 | #ifndef NO_PIXMAP_TESTS |
| 2831 | #if defined Q_OS_WIN |
| 2832 | QTEST(testWidget, "right" ); |
| 2833 | #endif |
| 2834 | #endif |
| 2835 | QCOMPARE(testWidget->alignment(), Qt::AlignRight); |
| 2836 | |
| 2837 | testWidget->setAlignment(Qt::AlignTop); |
| 2838 | QCOMPARE(testWidget->alignment(), Qt::AlignTop); |
| 2839 | |
| 2840 | testWidget->setAlignment(Qt::AlignBottom); |
| 2841 | QCOMPARE(testWidget->alignment(), Qt::AlignBottom); |
| 2842 | |
| 2843 | testWidget->setAlignment(Qt::AlignCenter); |
| 2844 | QCOMPARE(testWidget->alignment(), Qt::AlignCenter); |
| 2845 | } |
| 2846 | |
| 2847 | void tst_QLineEdit::isModified() |
| 2848 | { |
| 2849 | QLineEdit *testWidget = ensureTestWidget(); |
| 2850 | QVERIFY(!testWidget->isModified()); |
| 2851 | testWidget->setText("bla" ); |
| 2852 | QVERIFY(!testWidget->isModified()); |
| 2853 | |
| 2854 | psKeyClick(target: testWidget, key: Qt::Key_Home); |
| 2855 | QVERIFY(!testWidget->isModified()); |
| 2856 | QTest::keyClick(widget: testWidget, key: Qt::Key_Right); |
| 2857 | QVERIFY(!testWidget->isModified()); |
| 2858 | QTest::keyClick(widget: testWidget, key: Qt::Key_Right); |
| 2859 | QVERIFY(!testWidget->isModified()); |
| 2860 | QTest::keyClick(widget: testWidget, key: Qt::Key_Right); |
| 2861 | QVERIFY(!testWidget->isModified()); |
| 2862 | QTest::keyClick(widget: testWidget, key: Qt::Key_Left); |
| 2863 | QVERIFY(!testWidget->isModified()); |
| 2864 | psKeyClick(target: testWidget, key: Qt::Key_End); |
| 2865 | QVERIFY(!testWidget->isModified()); |
| 2866 | |
| 2867 | QTest::keyClicks(widget: testWidget, sequence: "T" ); |
| 2868 | QVERIFY(testWidget->isModified()); |
| 2869 | QTest::keyClicks(widget: testWidget, sequence: "his is a string" ); |
| 2870 | QVERIFY(testWidget->isModified()); |
| 2871 | |
| 2872 | testWidget->setText("" ); |
| 2873 | QVERIFY(!testWidget->isModified()); |
| 2874 | testWidget->setText("foo" ); |
| 2875 | QVERIFY(!testWidget->isModified()); |
| 2876 | } |
| 2877 | |
| 2878 | /* |
| 2879 | Obsolete function but as long as we provide it, it needs to work. |
| 2880 | */ |
| 2881 | |
| 2882 | void tst_QLineEdit::edited() |
| 2883 | { |
| 2884 | QLineEdit *testWidget = ensureTestWidget(); |
| 2885 | QVERIFY(!testWidget->isModified()); |
| 2886 | testWidget->setText("bla" ); |
| 2887 | QVERIFY(!testWidget->isModified()); |
| 2888 | |
| 2889 | psKeyClick(target: testWidget, key: Qt::Key_Home); |
| 2890 | QVERIFY(!testWidget->isModified()); |
| 2891 | QTest::keyClick(widget: testWidget, key: Qt::Key_Right); |
| 2892 | QVERIFY(!testWidget->isModified()); |
| 2893 | QTest::keyClick(widget: testWidget, key: Qt::Key_Right); |
| 2894 | QVERIFY(!testWidget->isModified()); |
| 2895 | QTest::keyClick(widget: testWidget, key: Qt::Key_Right); |
| 2896 | QVERIFY(!testWidget->isModified()); |
| 2897 | QTest::keyClick(widget: testWidget, key: Qt::Key_Left); |
| 2898 | QVERIFY(!testWidget->isModified()); |
| 2899 | psKeyClick(target: testWidget, key: Qt::Key_End); |
| 2900 | QVERIFY(!testWidget->isModified()); |
| 2901 | |
| 2902 | QTest::keyClicks(widget: testWidget, sequence: "T" ); |
| 2903 | QVERIFY(testWidget->isModified()); |
| 2904 | QTest::keyClicks(widget: testWidget, sequence: "his is a string" ); |
| 2905 | QVERIFY(testWidget->isModified()); |
| 2906 | |
| 2907 | testWidget->setModified(false); |
| 2908 | QVERIFY(!testWidget->isModified()); |
| 2909 | |
| 2910 | testWidget->setModified(true); |
| 2911 | QVERIFY(testWidget->isModified()); |
| 2912 | } |
| 2913 | |
| 2914 | void tst_QLineEdit::fixupDoesNotModify_QTBUG_49295() |
| 2915 | { |
| 2916 | QLineEdit *testWidget = ensureTestWidget(); |
| 2917 | |
| 2918 | ValidatorWithFixup val; |
| 2919 | testWidget->setValidator(&val); |
| 2920 | testWidget->setText("foo" ); |
| 2921 | QVERIFY(!testWidget->isModified()); |
| 2922 | QVERIFY(!testWidget->hasAcceptableInput()); |
| 2923 | |
| 2924 | QTest::keyClicks(widget: testWidget, QStringLiteral("bar" )); |
| 2925 | QVERIFY(testWidget->isModified()); |
| 2926 | QVERIFY(!testWidget->hasAcceptableInput()); |
| 2927 | |
| 2928 | // trigger a fixup, which should not reset the modified flag |
| 2929 | QFocusEvent lostFocus(QEvent::FocusOut); |
| 2930 | qApp->sendEvent(receiver: testWidget, event: &lostFocus); |
| 2931 | |
| 2932 | QVERIFY(testWidget->hasAcceptableInput()); |
| 2933 | QEXPECT_FAIL("" , "QTBUG-49295: a fixup of a line edit should keep it modified" , Continue); |
| 2934 | QVERIFY(testWidget->isModified()); |
| 2935 | } |
| 2936 | |
| 2937 | void tst_QLineEdit::insert() |
| 2938 | { |
| 2939 | QLineEdit *testWidget = ensureTestWidget(); |
| 2940 | testWidget->insert("This" ); |
| 2941 | testWidget->insert(" is" ); |
| 2942 | testWidget->insert(" a" ); |
| 2943 | testWidget->insert(" test" ); |
| 2944 | |
| 2945 | QCOMPARE(testWidget->text(), QString("This is a test" )); |
| 2946 | |
| 2947 | testWidget->cursorWordBackward(mark: false); |
| 2948 | testWidget->cursorBackward(mark: false, steps: 1); |
| 2949 | testWidget->insert(" nice" ); |
| 2950 | QCOMPARE(testWidget->text(), QString("This is a nice test" )); |
| 2951 | |
| 2952 | testWidget->setCursorPosition(-1); |
| 2953 | testWidget->insert("No Crash! " ); |
| 2954 | QCOMPARE(testWidget->text(), QString("No Crash! This is a nice test" )); |
| 2955 | } |
| 2956 | |
| 2957 | static inline QByteArray selectionTestName(int start, int length) |
| 2958 | { |
| 2959 | return "selection start: " + QByteArray::number(start) + " length: " + QByteArray::number(length); |
| 2960 | } |
| 2961 | |
| 2962 | void tst_QLineEdit::setSelection_data() |
| 2963 | { |
| 2964 | QTest::addColumn<QString>(name: "text" ); |
| 2965 | QTest::addColumn<int>(name: "start" ); |
| 2966 | QTest::addColumn<int>(name: "length" ); |
| 2967 | QTest::addColumn<int>(name: "expectedCursor" ); |
| 2968 | QTest::addColumn<QString>(name: "expectedText" ); |
| 2969 | QTest::addColumn<bool>(name: "expectedHasSelectedText" ); |
| 2970 | |
| 2971 | QString text = "Abc defg hijklmno, p 'qrst' uvw xyz" ; |
| 2972 | int start, length, pos; |
| 2973 | |
| 2974 | start = 0; length = 1; pos = 1; |
| 2975 | QTest::newRow(dataTag: selectionTestName(start, length).constData()) |
| 2976 | << text << start << length << pos << QString("A" ) << true; |
| 2977 | |
| 2978 | start = 0; length = 2; pos = 2; |
| 2979 | QTest::newRow(dataTag: selectionTestName(start, length).constData()) |
| 2980 | << text << start << length << pos << QString("Ab" ) << true; |
| 2981 | |
| 2982 | start = 0; length = 4; pos = 4; |
| 2983 | QTest::newRow(dataTag: selectionTestName(start, length).constData()) |
| 2984 | << text << start << length << pos << QString("Abc " ) << true; |
| 2985 | |
| 2986 | start = -1; length = 0; pos = text.length(); |
| 2987 | QTest::newRow(dataTag: selectionTestName(start, length).constData()) |
| 2988 | << text << start << length << pos << QString() << false; |
| 2989 | |
| 2990 | start = 34; length = 1; pos = 35; |
| 2991 | QTest::newRow(dataTag: selectionTestName(start, length).constData()) |
| 2992 | << text << start << length << pos << QString("z" ) << true; |
| 2993 | |
| 2994 | start = 34; length = 2; pos = 35; |
| 2995 | QTest::newRow(dataTag: selectionTestName(start, length).constData()) |
| 2996 | << text << start << length << pos << QString("z" ) << true; |
| 2997 | |
| 2998 | start = 34; length = -1; pos = 33; |
| 2999 | QTest::newRow(dataTag: selectionTestName(start, length).constData()) |
| 3000 | << text << start << length << pos << QString("y" ) << true; |
| 3001 | |
| 3002 | start = 1; length = -2; pos = 0; |
| 3003 | QTest::newRow(dataTag: selectionTestName(start, length).constData()) |
| 3004 | << text << start << length << pos << QString("A" ) << true; |
| 3005 | |
| 3006 | start = -1; length = -1; pos = text.length(); |
| 3007 | QTest::newRow(dataTag: selectionTestName(start, length).constData()) |
| 3008 | << text << start << length << pos << QString() << false; |
| 3009 | } |
| 3010 | |
| 3011 | |
| 3012 | void tst_QLineEdit::setSelection() |
| 3013 | { |
| 3014 | QFETCH(QString, text); |
| 3015 | QFETCH(int, start); |
| 3016 | QFETCH(int, length); |
| 3017 | QFETCH(int, expectedCursor); |
| 3018 | QFETCH(QString, expectedText); |
| 3019 | QFETCH(bool, expectedHasSelectedText); |
| 3020 | |
| 3021 | QLineEdit *testWidget = ensureTestWidget(); |
| 3022 | testWidget->setText(text); |
| 3023 | testWidget->setSelection(start, length); |
| 3024 | QCOMPARE(testWidget->hasSelectedText(), expectedHasSelectedText); |
| 3025 | QCOMPARE(testWidget->selectedText(), expectedText); |
| 3026 | if (expectedCursor >= 0) |
| 3027 | QCOMPARE(testWidget->cursorPosition(), expectedCursor); |
| 3028 | } |
| 3029 | |
| 3030 | #ifndef QT_NO_CLIPBOARD |
| 3031 | void tst_QLineEdit::cut() |
| 3032 | { |
| 3033 | if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) |
| 3034 | QSKIP("Wayland: This fails. Figure out why." ); |
| 3035 | |
| 3036 | if (!PlatformClipboard::isAvailable()) |
| 3037 | QSKIP("Autotests run from cron and pasteboard don't get along quite ATM" ); |
| 3038 | |
| 3039 | // test newlines in cut'n'paste |
| 3040 | QLineEdit *testWidget = ensureTestWidget(); |
| 3041 | testWidget->setText("A\nB\nC\n" ); |
| 3042 | testWidget->setSelection(0, 6); |
| 3043 | testWidget->cut(); |
| 3044 | psKeyClick(target: testWidget, key: Qt::Key_Home); |
| 3045 | testWidget->paste(); |
| 3046 | QCOMPARE(testWidget->text(), QString("A\nB\nC\n" )); |
| 3047 | // 1 2 3 4 |
| 3048 | // 01234567890123456789012345678901234567890 |
| 3049 | testWidget->setText("Abc defg hijklmno" ); |
| 3050 | |
| 3051 | testWidget->setSelection(0, 3); |
| 3052 | testWidget->cut(); |
| 3053 | QCOMPARE(testWidget->text(), QString(" defg hijklmno" )); |
| 3054 | |
| 3055 | psKeyClick(target: testWidget, key: Qt::Key_End); |
| 3056 | testWidget->paste(); |
| 3057 | QCOMPARE(testWidget->text(), QString(" defg hijklmnoAbc" )); |
| 3058 | |
| 3059 | psKeyClick(target: testWidget, key: Qt::Key_Home); |
| 3060 | testWidget->del(); |
| 3061 | QCOMPARE(testWidget->text(), QString("defg hijklmnoAbc" )); |
| 3062 | |
| 3063 | testWidget->setSelection(0, 4); |
| 3064 | testWidget->copy(); |
| 3065 | psKeyClick(target: testWidget, key: Qt::Key_End); |
| 3066 | testWidget->paste(); |
| 3067 | QCOMPARE(testWidget->text(), QString("defg hijklmnoAbcdefg" )); |
| 3068 | |
| 3069 | QTest::keyClick(widget: testWidget, key: Qt::Key_Left); |
| 3070 | QTest::keyClick(widget: testWidget, key: Qt::Key_Left); |
| 3071 | QTest::keyClick(widget: testWidget, key: Qt::Key_Left); |
| 3072 | QTest::keyClick(widget: testWidget, key: Qt::Key_Left); |
| 3073 | QTest::keyClick(widget: testWidget, key: Qt::Key_Left); |
| 3074 | QTest::keyClick(widget: testWidget, key: Qt::Key_Left); |
| 3075 | QTest::keyClick(widget: testWidget, key: Qt::Key_Left); |
| 3076 | QTest::keyClick(widget: testWidget, key: ' '); |
| 3077 | QCOMPARE(testWidget->text(), QString("defg hijklmno Abcdefg" )); |
| 3078 | |
| 3079 | testWidget->setSelection(0, 5); |
| 3080 | testWidget->del(); |
| 3081 | QCOMPARE(testWidget->text(), QString("hijklmno Abcdefg" )); |
| 3082 | |
| 3083 | testWidget->end(mark: false); |
| 3084 | QTest::keyClick(widget: testWidget, key: ' '); |
| 3085 | testWidget->paste(); |
| 3086 | QCOMPARE(testWidget->text(), QString("hijklmno Abcdefg defg" )); |
| 3087 | |
| 3088 | testWidget->home(mark: false); |
| 3089 | testWidget->cursorWordForward(mark: true); |
| 3090 | testWidget->cut(); |
| 3091 | testWidget->end(mark: false); |
| 3092 | QTest::keyClick(widget: testWidget, key: ' '); |
| 3093 | testWidget->paste(); |
| 3094 | testWidget->cursorBackward(mark: true, steps: 1); |
| 3095 | testWidget->cut(); |
| 3096 | QCOMPARE(testWidget->text(), QString("Abcdefg defg hijklmno" )); |
| 3097 | } |
| 3098 | |
| 3099 | void tst_QLineEdit::cutWithoutSelection() |
| 3100 | { |
| 3101 | if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) |
| 3102 | QSKIP("Wayland: This fails. Figure out why." ); |
| 3103 | |
| 3104 | enum { selectionLength = 1 }; |
| 3105 | |
| 3106 | if (QKeySequence(QKeySequence::Cut).toString() != QLatin1String("Ctrl+X" )) |
| 3107 | QSKIP("Platform with non-standard keybindings" ); |
| 3108 | QClipboard *clipboard = QGuiApplication::clipboard(); |
| 3109 | if (!PlatformClipboard::isAvailable() |
| 3110 | || !QGuiApplication::platformName().compare(s: "xcb" , cs: Qt::CaseInsensitive)) { // Avoid unstable X11 clipboard |
| 3111 | clipboard = nullptr; |
| 3112 | } |
| 3113 | |
| 3114 | if (clipboard) |
| 3115 | clipboard->clear(); |
| 3116 | const QString origText = QStringLiteral("test" ); |
| 3117 | QLineEdit lineEdit(origText); |
| 3118 | lineEdit.setCursorPosition(0); |
| 3119 | QVERIFY(!lineEdit.hasSelectedText()); |
| 3120 | QTest::keyClick(widget: &lineEdit, key: Qt::Key_X, modifier: Qt::ControlModifier); |
| 3121 | QCOMPARE(lineEdit.text(), origText); // No selection, unmodified. |
| 3122 | if (clipboard) |
| 3123 | QVERIFY(clipboard->text().isEmpty()); |
| 3124 | lineEdit.setSelection(0, selectionLength); |
| 3125 | QTest::keyClick(widget: &lineEdit, key: Qt::Key_X, modifier: Qt::ControlModifier); |
| 3126 | QCOMPARE(lineEdit.text(), origText.right(origText.size() - selectionLength)); |
| 3127 | if (clipboard) |
| 3128 | QCOMPARE(clipboard->text(), origText.left(selectionLength)); |
| 3129 | } |
| 3130 | |
| 3131 | #endif // !QT_NO_CLIPBOARD |
| 3132 | |
| 3133 | class InputMaskValidator : public QValidator |
| 3134 | { |
| 3135 | public: |
| 3136 | InputMaskValidator(QObject *parent, const char *name = 0) : QValidator(parent) { setObjectName(name); } |
| 3137 | State validate(QString &text, int &pos) const |
| 3138 | { |
| 3139 | InputMaskValidator *that = (InputMaskValidator *)this; |
| 3140 | that->validateText = text; |
| 3141 | that->validatePos = pos; |
| 3142 | return Acceptable; |
| 3143 | } |
| 3144 | QString validateText; |
| 3145 | int validatePos; |
| 3146 | }; |
| 3147 | |
| 3148 | void tst_QLineEdit::inputMaskAndValidator_data() |
| 3149 | { |
| 3150 | QTest::addColumn<QString>(name: "inputMask" ); |
| 3151 | QTest::addColumn<QTestEventList>(name: "keys" ); |
| 3152 | QTest::addColumn<QString>(name: "validateText" ); |
| 3153 | QTest::addColumn<int>(name: "validatePos" ); |
| 3154 | |
| 3155 | QTestEventList inputKeys; |
| 3156 | inputKeys.addKeyClick(qtKey: Qt::Key_1); |
| 3157 | inputKeys.addKeyClick(qtKey: Qt::Key_2); |
| 3158 | |
| 3159 | QTest::newRow(dataTag: "task28291" ) << "000;_" << inputKeys << "12_" << 2; |
| 3160 | } |
| 3161 | |
| 3162 | void tst_QLineEdit::inputMaskAndValidator() |
| 3163 | { |
| 3164 | QFETCH(QString, inputMask); |
| 3165 | QFETCH(QTestEventList, keys); |
| 3166 | QFETCH(QString, validateText); |
| 3167 | QFETCH(int, validatePos); |
| 3168 | |
| 3169 | QLineEdit *testWidget = ensureTestWidget(); |
| 3170 | InputMaskValidator imv(testWidget); |
| 3171 | testWidget->setValidator(&imv); |
| 3172 | |
| 3173 | testWidget->setInputMask(inputMask); |
| 3174 | keys.simulate(w: testWidget); |
| 3175 | |
| 3176 | QCOMPARE(imv.validateText, validateText); |
| 3177 | QCOMPARE(imv.validatePos, validatePos); |
| 3178 | } |
| 3179 | |
| 3180 | void tst_QLineEdit::maxLengthAndInputMask() |
| 3181 | { |
| 3182 | QLineEdit *testWidget = ensureTestWidget(); |
| 3183 | QVERIFY(testWidget->inputMask().isNull()); |
| 3184 | testWidget->setMaxLength(10); |
| 3185 | QCOMPARE(testWidget->maxLength(), 10); |
| 3186 | testWidget->setInputMask(QString()); |
| 3187 | QVERIFY(testWidget->inputMask().isNull()); |
| 3188 | QCOMPARE(testWidget->maxLength(), 10); |
| 3189 | |
| 3190 | testWidget->setInputMask("XXXX" ); |
| 3191 | QCOMPARE(testWidget->maxLength(), 4); |
| 3192 | |
| 3193 | testWidget->setMaxLength(15); |
| 3194 | QCOMPARE(testWidget->maxLength(), 4); |
| 3195 | |
| 3196 | // 8 \ => raw string with 4 \ => input mask with 2 \ => maxLength = 2 |
| 3197 | testWidget->setInputMask("\\\\\\\\" ); |
| 3198 | QCOMPARE(testWidget->maxLength(), 2); |
| 3199 | } |
| 3200 | |
| 3201 | |
| 3202 | class LineEdit : public QLineEdit |
| 3203 | { |
| 3204 | public: |
| 3205 | LineEdit() { state = Other; } |
| 3206 | |
| 3207 | void keyPressEvent(QKeyEvent *e) |
| 3208 | { |
| 3209 | QLineEdit::keyPressEvent(e); |
| 3210 | if (e->key() == Qt::Key_Enter) { |
| 3211 | state = e->isAccepted() ? Accepted : Ignored; |
| 3212 | } else { |
| 3213 | state = Other; |
| 3214 | } |
| 3215 | |
| 3216 | } |
| 3217 | enum State { |
| 3218 | Accepted, |
| 3219 | Ignored, |
| 3220 | Other |
| 3221 | }; |
| 3222 | |
| 3223 | State state; |
| 3224 | |
| 3225 | friend class tst_QLineEdit; |
| 3226 | }; |
| 3227 | |
| 3228 | Q_DECLARE_METATYPE(LineEdit::State); |
| 3229 | void tst_QLineEdit::returnPressedKeyEvent() |
| 3230 | { |
| 3231 | LineEdit lineedit; |
| 3232 | centerOnScreen(w: &lineedit); |
| 3233 | lineedit.show(); |
| 3234 | QCOMPARE((int)lineedit.state, (int)LineEdit::Other); |
| 3235 | QTest::keyClick(widget: &lineedit, key: Qt::Key_Enter); |
| 3236 | QCOMPARE((int)lineedit.state, (int)LineEdit::Ignored); |
| 3237 | connect(sender: &lineedit, SIGNAL(returnPressed()), receiver: this, SLOT(onReturnPressed())); |
| 3238 | QTest::keyClick(widget: &lineedit, key: Qt::Key_Enter); |
| 3239 | QCOMPARE((int)lineedit.state, (int)LineEdit::Ignored); |
| 3240 | disconnect(sender: &lineedit, SIGNAL(returnPressed()), receiver: this, SLOT(onReturnPressed())); |
| 3241 | QTest::keyClick(widget: &lineedit, key: Qt::Key_Enter); |
| 3242 | QCOMPARE((int)lineedit.state, (int)LineEdit::Ignored); |
| 3243 | QTest::keyClick(widget: &lineedit, key: Qt::Key_1); |
| 3244 | QCOMPARE((int)lineedit.state, (int)LineEdit::Other); |
| 3245 | } |
| 3246 | |
| 3247 | void tst_QLineEdit::keepSelectionOnTabFocusIn() |
| 3248 | { |
| 3249 | QLineEdit *testWidget = ensureTestWidget(); |
| 3250 | testWidget->setText("hello world" ); |
| 3251 | { |
| 3252 | QFocusEvent e(QEvent::FocusIn, Qt::TabFocusReason); |
| 3253 | QApplication::sendEvent(receiver: testWidget, event: &e); |
| 3254 | } |
| 3255 | QCOMPARE(testWidget->selectedText(), QString("hello world" )); |
| 3256 | testWidget->setSelection(0, 5); |
| 3257 | QCOMPARE(testWidget->selectedText(), QString("hello" )); |
| 3258 | { |
| 3259 | QFocusEvent e(QEvent::FocusIn, Qt::TabFocusReason); |
| 3260 | QApplication::sendEvent(receiver: testWidget, event: &e); |
| 3261 | } |
| 3262 | QCOMPARE(testWidget->selectedText(), QString("hello" )); |
| 3263 | } |
| 3264 | |
| 3265 | void tst_QLineEdit::readOnlyStyleOption() |
| 3266 | { |
| 3267 | QLineEdit *testWidget = ensureTestWidget(); |
| 3268 | bool wasReadOnly = testWidget->isReadOnly(); |
| 3269 | QStyle *oldStyle = testWidget->style(); |
| 3270 | testWidget->show(); |
| 3271 | QTRY_VERIFY(QTest::qWaitForWindowExposed(testWidget)); |
| 3272 | |
| 3273 | StyleOptionTestStyle myStyle; |
| 3274 | testWidget->setStyle(&myStyle); |
| 3275 | |
| 3276 | myStyle.setReadOnly(true); |
| 3277 | testWidget->setReadOnly(true); |
| 3278 | testWidget->update(); |
| 3279 | QTRY_VERIFY(myStyle.wasDrawn); |
| 3280 | myStyle.wasDrawn = false; |
| 3281 | |
| 3282 | testWidget->setReadOnly(false); |
| 3283 | myStyle.setReadOnly(false); |
| 3284 | testWidget->update(); |
| 3285 | QTRY_VERIFY(myStyle.wasDrawn); |
| 3286 | |
| 3287 | testWidget->setReadOnly(wasReadOnly); |
| 3288 | testWidget->setStyle(oldStyle); |
| 3289 | } |
| 3290 | |
| 3291 | void tst_QLineEdit::validateOnFocusOut() |
| 3292 | { |
| 3293 | if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) |
| 3294 | QSKIP("Wayland: This fails. Figure out why." ); |
| 3295 | |
| 3296 | QLineEdit *testWidget = ensureTestWidget(); |
| 3297 | QSignalSpy editingFinishedSpy(testWidget, SIGNAL(editingFinished())); |
| 3298 | testWidget->setValidator(new QIntValidator(100, 999, 0)); |
| 3299 | QTest::keyPress(widget: testWidget, key: '1'); |
| 3300 | QTest::keyPress(widget: testWidget, key: '0'); |
| 3301 | QCOMPARE(testWidget->text(), QString("10" )); |
| 3302 | testWidget->clearFocus(); |
| 3303 | QCOMPARE(editingFinishedSpy.count(), 0); |
| 3304 | |
| 3305 | testWidget->setFocus(); |
| 3306 | centerOnScreen(w: testWidget); |
| 3307 | testWidget->show(); |
| 3308 | testWidget->activateWindow(); |
| 3309 | QVERIFY(QTest::qWaitForWindowActive(testWidget)); |
| 3310 | QVERIFY(testWidget->hasFocus()); |
| 3311 | |
| 3312 | QTest::keyPress(widget: testWidget, key: '0'); |
| 3313 | QTRY_COMPARE(testWidget->text(), QString("100" )); |
| 3314 | |
| 3315 | testWidget->clearFocus(); |
| 3316 | QCOMPARE(editingFinishedSpy.count(), 1); |
| 3317 | } |
| 3318 | |
| 3319 | void tst_QLineEdit::editInvalidText() |
| 3320 | { |
| 3321 | QLineEdit *testWidget = ensureTestWidget(); |
| 3322 | testWidget->clear(); |
| 3323 | testWidget->setValidator(new QIntValidator(0, 12, 0)); |
| 3324 | testWidget->setText("1234" ); |
| 3325 | |
| 3326 | QVERIFY(!testWidget->hasAcceptableInput()); |
| 3327 | QTest::keyPress(widget: testWidget, key: Qt::Key_Backspace); |
| 3328 | QTest::keyPress(widget: testWidget, key: Qt::Key_Backspace); |
| 3329 | QTest::keyPress(widget: testWidget, key: Qt::Key_A); |
| 3330 | QTest::keyPress(widget: testWidget, key: Qt::Key_B); |
| 3331 | QTest::keyPress(widget: testWidget, key: Qt::Key_C); |
| 3332 | QTest::keyPress(widget: testWidget, key: Qt::Key_1); |
| 3333 | QVERIFY(testWidget->hasAcceptableInput()); |
| 3334 | QCOMPARE(testWidget->text(), QString("12" )); |
| 3335 | testWidget->cursorBackward(mark: false); |
| 3336 | testWidget->cursorBackward(mark: true, steps: 2); |
| 3337 | QTest::keyPress(widget: testWidget, key: Qt::Key_Delete); |
| 3338 | QVERIFY(testWidget->hasAcceptableInput()); |
| 3339 | QCOMPARE(testWidget->text(), QString("2" )); |
| 3340 | QTest::keyPress(widget: testWidget, key: Qt::Key_1); |
| 3341 | QVERIFY(testWidget->hasAcceptableInput()); |
| 3342 | QCOMPARE(testWidget->text(), QString("12" )); |
| 3343 | |
| 3344 | testWidget->setValidator(0); |
| 3345 | } |
| 3346 | |
| 3347 | Q_DECLARE_METATYPE(Qt::KeyboardModifiers) |
| 3348 | |
| 3349 | void tst_QLineEdit::charWithAltOrCtrlModifier_data() |
| 3350 | { |
| 3351 | QTest::addColumn<Qt::KeyboardModifiers>(name: "modifiers" ); |
| 3352 | QTest::addColumn<bool>(name: "textExpected" ); |
| 3353 | QTest::newRow(dataTag: "no-modifiers" ) << Qt::KeyboardModifiers() << true; |
| 3354 | // Ctrl, Ctrl+Shift: No text (QTBUG-35734) |
| 3355 | QTest::newRow(dataTag: "ctrl" ) << Qt::KeyboardModifiers(Qt::ControlModifier) |
| 3356 | << false; |
| 3357 | QTest::newRow(dataTag: "ctrl-shift" ) << Qt::KeyboardModifiers(Qt::ShiftModifier | Qt::ControlModifier) |
| 3358 | << false; |
| 3359 | QTest::newRow(dataTag: "alt" ) << Qt::KeyboardModifiers(Qt::AltModifier) << true; |
| 3360 | // Alt-Ctrl (Alt-Gr on German keyboards, Task 129098): Expect text |
| 3361 | QTest::newRow(dataTag: "alt-ctrl" ) << (Qt::AltModifier | Qt::ControlModifier) << true; |
| 3362 | } |
| 3363 | |
| 3364 | void tst_QLineEdit::charWithAltOrCtrlModifier() |
| 3365 | { |
| 3366 | QFETCH(Qt::KeyboardModifiers, modifiers); |
| 3367 | QFETCH(bool, textExpected); |
| 3368 | |
| 3369 | QLineEdit *testWidget = ensureTestWidget(); |
| 3370 | testWidget->clear(); |
| 3371 | QVERIFY(testWidget->text().isEmpty()); |
| 3372 | |
| 3373 | QTest::keyPress(widget: testWidget, key: Qt::Key_Plus, modifier: modifiers); |
| 3374 | const QString expectedText = textExpected ? QLatin1String("+" ) : QString(); |
| 3375 | QCOMPARE(testWidget->text(), expectedText); |
| 3376 | } |
| 3377 | |
| 3378 | void tst_QLineEdit::leftKeyOnSelectedText() |
| 3379 | { |
| 3380 | QLineEdit *testWidget = ensureTestWidget(); |
| 3381 | testWidget->clear(); |
| 3382 | testWidget->setText("0123" ); |
| 3383 | testWidget->setCursorPosition(4); |
| 3384 | QTest::keyClick(widget: testWidget, key: Qt::Key_Left, modifier: Qt::ShiftModifier); |
| 3385 | QCOMPARE(testWidget->cursorPosition(), 3); |
| 3386 | QCOMPARE(testWidget->selectedText(), QString("3" )); |
| 3387 | QTest::keyClick(widget: testWidget, key: Qt::Key_Left, modifier: Qt::ShiftModifier); |
| 3388 | QCOMPARE(testWidget->cursorPosition(), 2); |
| 3389 | QCOMPARE(testWidget->selectedText(), QString("23" )); |
| 3390 | QTest::keyClick(widget: testWidget, key: Qt::Key_Left); |
| 3391 | |
| 3392 | if (unselectingWithLeftOrRightChangesCursorPosition()) |
| 3393 | QCOMPARE(testWidget->cursorPosition(), 1); |
| 3394 | else |
| 3395 | QCOMPARE(testWidget->cursorPosition(), 2); |
| 3396 | } |
| 3397 | |
| 3398 | void tst_QLineEdit::inlineCompletion() |
| 3399 | { |
| 3400 | if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) |
| 3401 | QSKIP("Wayland: This fails. Figure out why." ); |
| 3402 | |
| 3403 | QLineEdit *testWidget = ensureTestWidget(); |
| 3404 | testWidget->clear(); |
| 3405 | QStandardItemModel *model = new QStandardItemModel; |
| 3406 | QStandardItem *root = model->invisibleRootItem(); |
| 3407 | QStandardItem *items[5]; |
| 3408 | for (int i = 0; i < 5; i++) { |
| 3409 | items[i] = new QStandardItem(QLatin1String("item" ) + QString::number(i)); |
| 3410 | if ((i+2)%2 == 0) { // disable 0,2,4 |
| 3411 | items[i]->setFlags(items[i]->flags() & ~Qt::ItemIsEnabled); |
| 3412 | } |
| 3413 | root->appendRow(aitem: items[i]); |
| 3414 | } |
| 3415 | QCompleter *completer = new QCompleter(model); |
| 3416 | completer->setCompletionMode(QCompleter::InlineCompletion); |
| 3417 | completer->setCaseSensitivity(Qt::CaseInsensitive); |
| 3418 | centerOnScreen(w: testWidget); |
| 3419 | testWidget->show(); |
| 3420 | QVERIFY(QTest::qWaitForWindowExposed(testWidget)); |
| 3421 | testWidget->setFocus(); |
| 3422 | QTRY_COMPARE(qApp->activeWindow(), (QWidget*)testWidget); |
| 3423 | testWidget->setCompleter(completer); |
| 3424 | |
| 3425 | // sanity |
| 3426 | QTest::keyClick(widget: testWidget, key: Qt::Key_X); |
| 3427 | QCOMPARE(testWidget->selectedText(), QString()); |
| 3428 | QCOMPARE(testWidget->text(), QString("x" )); |
| 3429 | QTest::keyClick(widget: testWidget, key: Qt::Key_Down, modifier: Qt::ControlModifier); |
| 3430 | QCOMPARE(testWidget->selectedText(), QString()); |
| 3431 | QCOMPARE(testWidget->text(), QString("x" )); |
| 3432 | QTest::keyClick(widget: testWidget, key: Qt::Key_Up, modifier: Qt::ControlModifier); |
| 3433 | QCOMPARE(testWidget->selectedText(), QString()); |
| 3434 | QCOMPARE(testWidget->text(), QString("x" )); |
| 3435 | |
| 3436 | testWidget->clear(); |
| 3437 | QTest::keyClick(widget: testWidget, key: Qt::Key_I); |
| 3438 | QCOMPARE(testWidget->selectedText(), QString("tem1" )); |
| 3439 | |
| 3440 | Qt::KeyboardModifiers keyboardModifiers = Qt::ControlModifier; |
| 3441 | #ifdef Q_OS_MAC |
| 3442 | keyboardModifiers |= Qt::AltModifier; |
| 3443 | #endif |
| 3444 | QTest::keyClick(widget: testWidget, key: Qt::Key_Down, modifier: keyboardModifiers); |
| 3445 | QCOMPARE(testWidget->selectedText(), QString("tem3" )); |
| 3446 | |
| 3447 | // wraps around (Default) |
| 3448 | QTest::keyClick(widget: testWidget, key: Qt::Key_Down, modifier: keyboardModifiers); |
| 3449 | QCOMPARE(testWidget->selectedText(), QString("tem1" )); |
| 3450 | |
| 3451 | QTest::keyClick(widget: testWidget, key: Qt::Key_Up, modifier: keyboardModifiers); |
| 3452 | QCOMPARE(testWidget->selectedText(), QString("tem3" )); |
| 3453 | |
| 3454 | // should not wrap |
| 3455 | completer->setWrapAround(false); |
| 3456 | QTest::keyClick(widget: testWidget, key: Qt::Key_Down, modifier: keyboardModifiers); |
| 3457 | QCOMPARE(testWidget->selectedText(), QString("tem3" )); |
| 3458 | QTest::keyClick(widget: testWidget, key: Qt::Key_Up, modifier: keyboardModifiers); // item1 |
| 3459 | QTest::keyClick(widget: testWidget, key: Qt::Key_Up, modifier: keyboardModifiers); // item1 |
| 3460 | QCOMPARE(testWidget->selectedText(), QString("tem1" )); |
| 3461 | |
| 3462 | // trivia :) |
| 3463 | root->appendRow(aitem: new QStandardItem("item11" )); |
| 3464 | root->appendRow(aitem: new QStandardItem("item12" )); |
| 3465 | testWidget->clear(); |
| 3466 | QTest::keyClick(widget: testWidget, key: Qt::Key_I); |
| 3467 | QCOMPARE(testWidget->selectedText(), QString("tem1" )); |
| 3468 | QTest::keyClick(widget: testWidget, key: Qt::Key_Delete); |
| 3469 | QCOMPARE(testWidget->selectedText(), QString()); |
| 3470 | QTest::keyClick(widget: testWidget, key: Qt::Key_Down, modifier: keyboardModifiers); |
| 3471 | QCOMPARE(testWidget->selectedText(), QString("tem1" )); // neato |
| 3472 | testWidget->setText("item1" ); |
| 3473 | testWidget->setSelection(1, 2); |
| 3474 | QTest::keyClick(widget: testWidget, key: Qt::Key_Down, modifier: keyboardModifiers); |
| 3475 | testWidget->end(mark: false); |
| 3476 | QCOMPARE(testWidget->text(), QString("item1" )); // no effect for selection in "middle" |
| 3477 | QTest::keyClick(widget: testWidget, key: Qt::Key_Down, modifier: keyboardModifiers); // item1 |
| 3478 | QTest::keyClick(widget: testWidget, key: Qt::Key_Down, modifier: keyboardModifiers); // item11 |
| 3479 | QCOMPARE(testWidget->text(), QString("item11" )); |
| 3480 | |
| 3481 | delete model; |
| 3482 | delete completer; |
| 3483 | } |
| 3484 | |
| 3485 | void tst_QLineEdit::noTextEditedOnClear() |
| 3486 | { |
| 3487 | QLineEdit *testWidget = ensureTestWidget(); |
| 3488 | testWidget->setText("Test" ); |
| 3489 | QSignalSpy textEditedSpy(testWidget, SIGNAL(textEdited(QString))); |
| 3490 | testWidget->clear(); |
| 3491 | QCOMPARE(textEditedSpy.count(), 0); |
| 3492 | } |
| 3493 | |
| 3494 | void tst_QLineEdit::textMargin_data() |
| 3495 | { |
| 3496 | QTest::addColumn<int>(name: "left" ); |
| 3497 | QTest::addColumn<int>(name: "top" ); |
| 3498 | QTest::addColumn<int>(name: "right" ); |
| 3499 | QTest::addColumn<int>(name: "bottom" ); |
| 3500 | |
| 3501 | QTest::addColumn<QPoint>(name: "mousePressPos" ); |
| 3502 | QTest::addColumn<int>(name: "cursorPosition" ); |
| 3503 | |
| 3504 | QLineEdit testWidget; |
| 3505 | QFontMetrics metrics(testWidget.font()); |
| 3506 | const QString s = QLatin1String("MMM MMM MMM" ); |
| 3507 | |
| 3508 | // Different styles generate different offsets, so |
| 3509 | // calculate the width rather than hardcode it. |
| 3510 | const int pixelWidthOfM = metrics.horizontalAdvance(s, len: 1); |
| 3511 | const int pixelWidthOfMMM_MM = metrics.horizontalAdvance(s, len: 6); |
| 3512 | |
| 3513 | QTest::newRow(dataTag: "default-0" ) << 0 << 0 << 0 << 0 << QPoint(pixelWidthOfMMM_MM, 0) << 6; |
| 3514 | QTest::newRow(dataTag: "default-1" ) << 0 << 0 << 0 << 0 << QPoint(1, 1) << 0; |
| 3515 | QTest::newRow(dataTag: "default-2" ) << -1 << 0 << -1 << 0 << QPoint(pixelWidthOfMMM_MM, 0) << 6; |
| 3516 | QTest::newRow(dataTag: "default-3" ) << 0 << 0 << 0 << 0 << QPoint(pixelWidthOfM, 1) << 1; |
| 3517 | |
| 3518 | QTest::newRow(dataTag: "hor-0" ) << 10 << 0 << 10 << 0 << QPoint(1, 1) << 0; |
| 3519 | QTest::newRow(dataTag: "hor-1" ) << 10 << 0 << 10 << 0 << QPoint(10, 1) << 0; |
| 3520 | QTest::newRow(dataTag: "hor-2" ) << 20 << 0 << 10 << 0 << QPoint(20, 1) << 0; |
| 3521 | |
| 3522 | if (!qApp->style()->inherits(classname: "QMacStyle" )) { //MacStyle doesn't support verticals margins. |
| 3523 | QTest::newRow(dataTag: "default-2-ver" ) << -1 << -1 << -1 << -1 << QPoint(pixelWidthOfMMM_MM, 0) << 6; |
| 3524 | QTest::newRow(dataTag: "ver" ) << 0 << 10 << 0 << 10 << QPoint(1, 1) << 0; |
| 3525 | } |
| 3526 | } |
| 3527 | |
| 3528 | void tst_QLineEdit::textMargin() |
| 3529 | { |
| 3530 | QFETCH(int, left); |
| 3531 | QFETCH(int, top); |
| 3532 | QFETCH(int, right); |
| 3533 | QFETCH(int, bottom); |
| 3534 | QFETCH(QPoint, mousePressPos); |
| 3535 | QFETCH(int, cursorPosition); |
| 3536 | |
| 3537 | // Put the line edit into a toplevel window to avoid |
| 3538 | // resizing by the window system. |
| 3539 | QWidget tlw; |
| 3540 | QLineEdit testWidget(&tlw); |
| 3541 | testWidget.setGeometry(ax: 100, ay: 100, aw: 100, ah: 30); |
| 3542 | testWidget.setText("MMM MMM MMM" ); |
| 3543 | testWidget.setCursorPosition(6); |
| 3544 | |
| 3545 | QSize sizeHint = testWidget.sizeHint(); |
| 3546 | QSize minSizeHint = testWidget.minimumSizeHint(); |
| 3547 | testWidget.setTextMargins(left, top, right, bottom); |
| 3548 | |
| 3549 | sizeHint.setWidth(sizeHint.width() + left + right); |
| 3550 | sizeHint.setHeight(sizeHint.height() + top +bottom); |
| 3551 | QCOMPARE(testWidget.sizeHint(), sizeHint); |
| 3552 | |
| 3553 | if (minSizeHint.width() > -1) { |
| 3554 | minSizeHint.setWidth(minSizeHint.width() + left + right); |
| 3555 | minSizeHint.setHeight(minSizeHint.height() + top + bottom); |
| 3556 | QCOMPARE(testWidget.minimumSizeHint(), minSizeHint); |
| 3557 | } |
| 3558 | |
| 3559 | |
| 3560 | testWidget.setFrame(false); |
| 3561 | centerOnScreen(w: &tlw); |
| 3562 | tlw.show(); |
| 3563 | |
| 3564 | const QMargins margins = testWidget.textMargins(); |
| 3565 | QCOMPARE(left, margins.left()); |
| 3566 | QCOMPARE(top, margins.top()); |
| 3567 | QCOMPARE(right, margins.right()); |
| 3568 | QCOMPARE(bottom, margins.bottom()); |
| 3569 | |
| 3570 | #if QT_DEPRECATED_SINCE(5, 14) |
| 3571 | int l; |
| 3572 | int t; |
| 3573 | int r; |
| 3574 | int b; |
| 3575 | testWidget.getTextMargins(left: &l, top: &t, right: &r, bottom: &b); |
| 3576 | QCOMPARE(left, l); |
| 3577 | QCOMPARE(top, t); |
| 3578 | QCOMPARE(right, r); |
| 3579 | QCOMPARE(bottom, b); |
| 3580 | #endif |
| 3581 | |
| 3582 | QTest::mouseClick(widget: &testWidget, button: Qt::LeftButton, stateKey: {}, pos: mousePressPos); |
| 3583 | QTRY_COMPARE(testWidget.cursorPosition(), cursorPosition); |
| 3584 | } |
| 3585 | |
| 3586 | #ifndef QT_NO_CURSOR |
| 3587 | void tst_QLineEdit::cursor() |
| 3588 | { |
| 3589 | QLineEdit *testWidget = ensureTestWidget(); |
| 3590 | testWidget->setReadOnly(false); |
| 3591 | QCOMPARE(testWidget->cursor().shape(), Qt::IBeamCursor); |
| 3592 | testWidget->setReadOnly(true); |
| 3593 | QCOMPARE(testWidget->cursor().shape(), Qt::ArrowCursor); |
| 3594 | testWidget->setReadOnly(false); |
| 3595 | QCOMPARE(testWidget->cursor().shape(), Qt::IBeamCursor); |
| 3596 | } |
| 3597 | #endif |
| 3598 | |
| 3599 | class task180999_Widget : public QWidget |
| 3600 | { |
| 3601 | public: |
| 3602 | task180999_Widget(QWidget *parent = 0) : QWidget(parent) |
| 3603 | { |
| 3604 | QHBoxLayout *layout = new QHBoxLayout(this); |
| 3605 | lineEdit1.setText("some text 1 ..." ); |
| 3606 | lineEdit2.setText("some text 2 ..." ); |
| 3607 | layout->addWidget(&lineEdit1); |
| 3608 | layout->addWidget(&lineEdit2); |
| 3609 | } |
| 3610 | |
| 3611 | QLineEdit lineEdit1; |
| 3612 | QLineEdit lineEdit2; |
| 3613 | }; |
| 3614 | |
| 3615 | void tst_QLineEdit::task180999_focus() |
| 3616 | { |
| 3617 | if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) |
| 3618 | QSKIP("Wayland: This fails. Figure out why." ); |
| 3619 | |
| 3620 | task180999_Widget widget; |
| 3621 | |
| 3622 | widget.lineEdit1.setFocus(); |
| 3623 | widget.show(); |
| 3624 | |
| 3625 | widget.lineEdit2.setFocus(); |
| 3626 | widget.lineEdit2.selectAll(); |
| 3627 | widget.hide(); |
| 3628 | |
| 3629 | widget.lineEdit1.setFocus(); |
| 3630 | widget.show(); |
| 3631 | QTest::qWait(ms: 200); |
| 3632 | widget.activateWindow(); |
| 3633 | |
| 3634 | QTRY_VERIFY(!widget.lineEdit2.hasSelectedText()); |
| 3635 | } |
| 3636 | |
| 3637 | void tst_QLineEdit::task174640_editingFinished() |
| 3638 | { |
| 3639 | if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) |
| 3640 | QSKIP("Wayland: This fails. Figure out why." ); |
| 3641 | |
| 3642 | QWidget mw; |
| 3643 | QVBoxLayout *layout = new QVBoxLayout(&mw); |
| 3644 | QLineEdit *le1 = new QLineEdit(&mw); |
| 3645 | QLineEdit *le2 = new QLineEdit(&mw); |
| 3646 | layout->addWidget(le1); |
| 3647 | layout->addWidget(le2); |
| 3648 | |
| 3649 | mw.show(); |
| 3650 | QApplication::setActiveWindow(&mw); |
| 3651 | mw.activateWindow(); |
| 3652 | QVERIFY(QTest::qWaitForWindowActive(&mw)); |
| 3653 | QCOMPARE(&mw, QApplication::activeWindow()); |
| 3654 | |
| 3655 | QSignalSpy editingFinishedSpy(le1, SIGNAL(editingFinished())); |
| 3656 | |
| 3657 | le1->setFocus(); |
| 3658 | QTRY_VERIFY(le1->hasFocus()); |
| 3659 | QCOMPARE(editingFinishedSpy.count(), 0); |
| 3660 | |
| 3661 | le2->setFocus(); |
| 3662 | QTRY_VERIFY(le2->hasFocus()); |
| 3663 | // editingFinished will not be emitted anew because no editing happened |
| 3664 | QCOMPARE(editingFinishedSpy.count(), 0); |
| 3665 | |
| 3666 | le1->setFocus(); |
| 3667 | QTRY_VERIFY(le1->hasFocus()); |
| 3668 | QTest::keyPress(widget: le1, key: Qt::Key_Plus); |
| 3669 | le2->setFocus(); |
| 3670 | QTRY_VERIFY(le2->hasFocus()); |
| 3671 | QCOMPARE(editingFinishedSpy.count(), 1); |
| 3672 | editingFinishedSpy.clear(); |
| 3673 | |
| 3674 | le1->setFocus(); |
| 3675 | QTRY_VERIFY(le1->hasFocus()); |
| 3676 | |
| 3677 | QMenu * = new QMenu(le1); |
| 3678 | testMenu1->addAction(text: "foo" ); |
| 3679 | testMenu1->addAction(text: "bar" ); |
| 3680 | testMenu1->show(); |
| 3681 | QVERIFY(QTest::qWaitForWindowExposed(testMenu1)); |
| 3682 | QTest::qWait(ms: 20); |
| 3683 | mw.activateWindow(); |
| 3684 | |
| 3685 | delete testMenu1; |
| 3686 | QCOMPARE(editingFinishedSpy.count(), 0); |
| 3687 | QTRY_VERIFY(le1->hasFocus()); |
| 3688 | // Ensure le1 has been edited |
| 3689 | QTest::keyPress(widget: le1, key: Qt::Key_Plus); |
| 3690 | |
| 3691 | QMenu * = new QMenu(le2); |
| 3692 | testMenu2->addAction(text: "foo2" ); |
| 3693 | testMenu2->addAction(text: "bar2" ); |
| 3694 | testMenu2->show(); |
| 3695 | QVERIFY(QTest::qWaitForWindowExposed(testMenu2)); |
| 3696 | QTest::qWait(ms: 20); |
| 3697 | mw.activateWindow(); |
| 3698 | delete testMenu2; |
| 3699 | QCOMPARE(editingFinishedSpy.count(), 1); |
| 3700 | } |
| 3701 | |
| 3702 | #if QT_CONFIG(completer) |
| 3703 | class task198789_Widget : public QWidget |
| 3704 | { |
| 3705 | Q_OBJECT |
| 3706 | public: |
| 3707 | task198789_Widget(QWidget *parent = 0) : QWidget(parent) |
| 3708 | { |
| 3709 | QStringList wordList; |
| 3710 | wordList << "alpha" << "omega" << "omicron" << "zeta" ; |
| 3711 | |
| 3712 | lineEdit = new QLineEdit(this); |
| 3713 | completer = new QCompleter(wordList, this); |
| 3714 | lineEdit->setCompleter(completer); |
| 3715 | |
| 3716 | connect(sender: lineEdit, SIGNAL(textChanged(QString)), receiver: this, SLOT(textChanged(QString))); |
| 3717 | } |
| 3718 | |
| 3719 | QLineEdit *lineEdit; |
| 3720 | QCompleter *completer; |
| 3721 | QString currentCompletion; |
| 3722 | |
| 3723 | private slots: |
| 3724 | void textChanged(const QString &) |
| 3725 | { |
| 3726 | currentCompletion = completer->currentCompletion(); |
| 3727 | } |
| 3728 | }; |
| 3729 | |
| 3730 | void tst_QLineEdit::task198789_currentCompletion() |
| 3731 | { |
| 3732 | task198789_Widget widget; |
| 3733 | widget.show(); |
| 3734 | qApp->processEvents(); |
| 3735 | QTest::keyPress(widget: widget.lineEdit, key: 'o'); |
| 3736 | QTest::keyPress(widget: widget.lineEdit, key: 'm'); |
| 3737 | QTest::keyPress(widget: widget.lineEdit, key: 'i'); |
| 3738 | QCOMPARE(widget.currentCompletion, QLatin1String("omicron" )); |
| 3739 | } |
| 3740 | |
| 3741 | void tst_QLineEdit::task210502_caseInsensitiveInlineCompletion() |
| 3742 | { |
| 3743 | if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) |
| 3744 | QSKIP("Wayland: This fails. Figure out why." ); |
| 3745 | |
| 3746 | QString completion("ABCD" ); |
| 3747 | QStringList completions; |
| 3748 | completions << completion; |
| 3749 | QLineEdit lineEdit; |
| 3750 | QCompleter completer(completions); |
| 3751 | completer.setCaseSensitivity(Qt::CaseInsensitive); |
| 3752 | completer.setCompletionMode(QCompleter::InlineCompletion); |
| 3753 | lineEdit.setCompleter(&completer); |
| 3754 | lineEdit.show(); |
| 3755 | QApplication::setActiveWindow(&lineEdit); |
| 3756 | QVERIFY(QTest::qWaitForWindowActive(&lineEdit)); |
| 3757 | lineEdit.setFocus(); |
| 3758 | QTRY_VERIFY(lineEdit.hasFocus()); |
| 3759 | QTest::keyPress(widget: &lineEdit, key: 'a'); |
| 3760 | QTest::keyPress(widget: &lineEdit, key: Qt::Key_Return); |
| 3761 | QCOMPARE(lineEdit.text(), completion); |
| 3762 | } |
| 3763 | |
| 3764 | #endif // QT_CONFIG(completer) |
| 3765 | |
| 3766 | |
| 3767 | void tst_QLineEdit::task229938_dontEmitChangedWhenTextIsNotChanged() |
| 3768 | { |
| 3769 | QLineEdit lineEdit; |
| 3770 | lineEdit.setMaxLength(5); |
| 3771 | lineEdit.show(); |
| 3772 | QVERIFY(QTest::qWaitForWindowExposed(&lineEdit)); // to be safe and avoid failing setFocus with window managers |
| 3773 | lineEdit.setFocus(); |
| 3774 | QSignalSpy changedSpy(&lineEdit, SIGNAL(textChanged(QString))); |
| 3775 | QTest::keyPress(widget: &lineEdit, key: 'a'); |
| 3776 | QTest::keyPress(widget: &lineEdit, key: 'b'); |
| 3777 | QTest::keyPress(widget: &lineEdit, key: 'c'); |
| 3778 | QTest::keyPress(widget: &lineEdit, key: 'd'); |
| 3779 | QTest::keyPress(widget: &lineEdit, key: 'e'); |
| 3780 | QTest::keyPress(widget: &lineEdit, key: 'f'); |
| 3781 | QCOMPARE(changedSpy.count(), 5); |
| 3782 | } |
| 3783 | |
| 3784 | void tst_QLineEdit::task233101_cursorPosAfterInputMethod_data() |
| 3785 | { |
| 3786 | QTest::addColumn<int>(name: "maxLength" ); |
| 3787 | QTest::addColumn<int>(name: "cursorPos" ); |
| 3788 | QTest::addColumn<int>(name: "replacementStart" ); |
| 3789 | QTest::addColumn<int>(name: "replacementLength" ); |
| 3790 | QTest::addColumn<QString>(name: "commitString" ); |
| 3791 | |
| 3792 | QTest::newRow(dataTag: "data1" ) << 4 << 4 << 0 << 0 << QString("" ); |
| 3793 | QTest::newRow(dataTag: "data2" ) << 4 << 4 << 0 << 0 << QString("x" ); |
| 3794 | QTest::newRow(dataTag: "data3" ) << 4 << 4 << 0 << 0 << QString("xxxxxxxxxxxxxxxx" ); |
| 3795 | QTest::newRow(dataTag: "data4" ) << 4 << 3 << 0 << 0 << QString("" ); |
| 3796 | QTest::newRow(dataTag: "data5" ) << 4 << 3 << 0 << 0 << QString("x" ); |
| 3797 | QTest::newRow(dataTag: "data6" ) << 4 << 3 << 0 << 0 << QString("xxxxxxxxxxxxxxxx" ); |
| 3798 | QTest::newRow(dataTag: "data7" ) << 4 << 0 << 0 << 0 << QString("" ); |
| 3799 | QTest::newRow(dataTag: "data8" ) << 4 << 0 << 0 << 0 << QString("x" ); |
| 3800 | QTest::newRow(dataTag: "data9" ) << 4 << 0 << 0 << 0 << QString("xxxxxxxxxxxxxxxx" ); |
| 3801 | |
| 3802 | QTest::newRow(dataTag: "data10" ) << 4 << 4 << -4 << 4 << QString("" ); |
| 3803 | QTest::newRow(dataTag: "data11" ) << 4 << 4 << -4 << 4 << QString("x" ); |
| 3804 | QTest::newRow(dataTag: "data12" ) << 4 << 4 << -4 << 4 << QString("xxxxxxxxxxxxxxxx" ); |
| 3805 | QTest::newRow(dataTag: "data13" ) << 4 << 3 << -3 << 4 << QString("" ); |
| 3806 | QTest::newRow(dataTag: "data14" ) << 4 << 3 << -3 << 4 << QString("x" ); |
| 3807 | QTest::newRow(dataTag: "data15" ) << 4 << 3 << -3 << 4 << QString("xxxxxxxxxxxxxxxx" ); |
| 3808 | QTest::newRow(dataTag: "data16" ) << 4 << 0 << 0 << 4 << QString("" ); |
| 3809 | QTest::newRow(dataTag: "data17" ) << 4 << 0 << 0 << 4 << QString("x" ); |
| 3810 | QTest::newRow(dataTag: "data18" ) << 4 << 0 << 0 << 4 << QString("xxxxxxxxxxxxxxxx" ); |
| 3811 | |
| 3812 | QTest::newRow(dataTag: "data19" ) << 4 << 4 << -4 << 0 << QString("" ); |
| 3813 | QTest::newRow(dataTag: "data20" ) << 4 << 4 << -4 << 0 << QString("x" ); |
| 3814 | QTest::newRow(dataTag: "data21" ) << 4 << 4 << -4 << 0 << QString("xxxxxxxxxxxxxxxx" ); |
| 3815 | QTest::newRow(dataTag: "data22" ) << 4 << 3 << -3 << 0 << QString("" ); |
| 3816 | QTest::newRow(dataTag: "data23" ) << 4 << 3 << -3 << 0 << QString("x" ); |
| 3817 | QTest::newRow(dataTag: "data24" ) << 4 << 3 << -3 << 0 << QString("xxxxxxxxxxxxxxxx" ); |
| 3818 | } |
| 3819 | |
| 3820 | void tst_QLineEdit::task233101_cursorPosAfterInputMethod() |
| 3821 | { |
| 3822 | QFETCH(int, maxLength); |
| 3823 | QFETCH(int, cursorPos); |
| 3824 | QFETCH(int, replacementStart); |
| 3825 | QFETCH(int, replacementLength); |
| 3826 | QFETCH(QString, commitString); |
| 3827 | |
| 3828 | QLineEdit lineEdit; |
| 3829 | lineEdit.setMaxLength(maxLength); |
| 3830 | lineEdit.insert(QString().fill(c: QLatin1Char('a'), size: cursorPos)); |
| 3831 | QCOMPARE(lineEdit.cursorPosition(), cursorPos); |
| 3832 | |
| 3833 | QInputMethodEvent event; |
| 3834 | event.setCommitString(commitString: QLatin1String("x" ), replaceFrom: replacementStart, replaceLength: replacementLength); |
| 3835 | qApp->sendEvent(receiver: &lineEdit, event: &event); |
| 3836 | QVERIFY(lineEdit.cursorPosition() >= 0); |
| 3837 | QVERIFY(lineEdit.cursorPosition() <= lineEdit.text().size()); |
| 3838 | QVERIFY(lineEdit.text().size() <= lineEdit.maxLength()); |
| 3839 | } |
| 3840 | |
| 3841 | void tst_QLineEdit::task241436_passwordEchoOnEditRestoreEchoMode() |
| 3842 | { |
| 3843 | if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) |
| 3844 | QSKIP("Wayland: This fails. Figure out why." ); |
| 3845 | |
| 3846 | QStyleOptionFrame opt; |
| 3847 | QLineEdit *testWidget = ensureTestWidget(); |
| 3848 | QChar fillChar = testWidget->style()->styleHint(stylehint: QStyle::SH_LineEdit_PasswordCharacter, opt: &opt, widget: testWidget); |
| 3849 | |
| 3850 | testWidget->setEchoMode(QLineEdit::PasswordEchoOnEdit); |
| 3851 | testWidget->setFocus(); |
| 3852 | centerOnScreen(w: testWidget); |
| 3853 | testWidget->show(); |
| 3854 | QApplication::setActiveWindow(testWidget); |
| 3855 | QVERIFY(QTest::qWaitForWindowActive(testWidget)); |
| 3856 | QVERIFY(testWidget->hasFocus()); |
| 3857 | |
| 3858 | QTest::keyPress(widget: testWidget, key: '0'); |
| 3859 | QCOMPARE(testWidget->displayText(), QString("0" )); |
| 3860 | testWidget->setEchoMode(QLineEdit::Normal); |
| 3861 | testWidget->clearFocus(); |
| 3862 | QCOMPARE(testWidget->displayText(), QString("0" )); |
| 3863 | |
| 3864 | testWidget->activateWindow(); |
| 3865 | testWidget->setFocus(); |
| 3866 | testWidget->setEchoMode(QLineEdit::PasswordEchoOnEdit); |
| 3867 | QTest::keyPress(widget: testWidget, key: '0'); |
| 3868 | QCOMPARE(testWidget->displayText(), QString("0" )); |
| 3869 | testWidget->setEchoMode(QLineEdit::PasswordEchoOnEdit); |
| 3870 | QCOMPARE(testWidget->displayText(), QString("0" )); |
| 3871 | testWidget->clearFocus(); |
| 3872 | QCOMPARE(testWidget->displayText(), QString(fillChar)); |
| 3873 | |
| 3874 | // restore clean state |
| 3875 | testWidget->setEchoMode(QLineEdit::Normal); |
| 3876 | } |
| 3877 | |
| 3878 | void tst_QLineEdit::task248948_redoRemovedSelection() |
| 3879 | { |
| 3880 | QLineEdit *testWidget = ensureTestWidget(); |
| 3881 | testWidget->setText("a" ); |
| 3882 | testWidget->selectAll(); |
| 3883 | QTest::keyPress(widget: testWidget, key: Qt::Key_Delete); |
| 3884 | testWidget->undo(); |
| 3885 | testWidget->redo(); |
| 3886 | QTest::keyPress(widget: testWidget, key: 'a'); |
| 3887 | QTest::keyPress(widget: testWidget, key: 'b'); |
| 3888 | QCOMPARE(testWidget->text(), QLatin1String("ab" )); |
| 3889 | } |
| 3890 | |
| 3891 | void tst_QLineEdit::taskQTBUG_4401_enterKeyClearsPassword() |
| 3892 | { |
| 3893 | if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) |
| 3894 | QSKIP("Wayland: This fails. Figure out why." ); |
| 3895 | |
| 3896 | QString password("Wanna guess?" ); |
| 3897 | |
| 3898 | QLineEdit *testWidget = ensureTestWidget(); |
| 3899 | testWidget->setText(password); |
| 3900 | testWidget->setEchoMode(QLineEdit::PasswordEchoOnEdit); |
| 3901 | testWidget->setFocus(); |
| 3902 | testWidget->selectAll(); |
| 3903 | centerOnScreen(w: testWidget); |
| 3904 | testWidget->show(); |
| 3905 | QApplication::setActiveWindow(testWidget); |
| 3906 | QVERIFY(QTest::qWaitForWindowActive(testWidget)); |
| 3907 | |
| 3908 | QTest::keyPress(widget: testWidget, key: Qt::Key_Enter); |
| 3909 | QTRY_COMPARE(testWidget->text(), password); |
| 3910 | } |
| 3911 | |
| 3912 | void tst_QLineEdit::taskQTBUG_4679_moveToStartEndOfBlock() |
| 3913 | { |
| 3914 | #ifdef Q_OS_MAC |
| 3915 | const QString text("there are no blocks for lineEdit" ); |
| 3916 | QLineEdit *testWidget = ensureTestWidget(); |
| 3917 | testWidget->setText(text); |
| 3918 | testWidget->setCursorPosition(5); |
| 3919 | QCOMPARE(testWidget->cursorPosition(), 5); |
| 3920 | testWidget->setFocus(); |
| 3921 | QTest::keyPress(testWidget, Qt::Key_A, Qt::MetaModifier); |
| 3922 | QCOMPARE(testWidget->cursorPosition(), 0); |
| 3923 | QTest::keyPress(testWidget, Qt::Key_E, Qt::MetaModifier); |
| 3924 | QCOMPARE(testWidget->cursorPosition(), text.size()); |
| 3925 | #endif // Q_OS_MAC |
| 3926 | } |
| 3927 | |
| 3928 | void tst_QLineEdit::taskQTBUG_4679_selectToStartEndOfBlock() |
| 3929 | { |
| 3930 | #ifdef Q_OS_MAC |
| 3931 | const QString text("there are no blocks for lineEdit, select all" ); |
| 3932 | QLineEdit *testWidget = ensureTestWidget(); |
| 3933 | testWidget->setText(text); |
| 3934 | testWidget->setCursorPosition(5); |
| 3935 | QCOMPARE(testWidget->cursorPosition(), 5); |
| 3936 | testWidget->setFocus(); |
| 3937 | QTest::keyPress(testWidget, Qt::Key_A, Qt::MetaModifier | Qt::ShiftModifier); |
| 3938 | QCOMPARE(testWidget->cursorPosition(), 0); |
| 3939 | QVERIFY(testWidget->hasSelectedText()); |
| 3940 | QCOMPARE(testWidget->selectedText(), text.mid(0, 5)); |
| 3941 | |
| 3942 | QTest::keyPress(testWidget, Qt::Key_E, Qt::MetaModifier | Qt::ShiftModifier); |
| 3943 | QCOMPARE(testWidget->cursorPosition(), text.size()); |
| 3944 | QVERIFY(testWidget->hasSelectedText()); |
| 3945 | QCOMPARE(testWidget->selectedText(), text.mid(5)); |
| 3946 | #endif // Q_OS_MAC |
| 3947 | } |
| 3948 | |
| 3949 | #ifndef QT_NO_CONTEXTMENU |
| 3950 | void tst_QLineEdit::() |
| 3951 | { |
| 3952 | // Would pass before the associated commit, but left as a guard. |
| 3953 | QLineEdit *w = new QLineEdit; |
| 3954 | w->show(); |
| 3955 | QVERIFY(QTest::qWaitForWindowExposed(w)); |
| 3956 | |
| 3957 | QTimer ti; |
| 3958 | w->connect(sender: &ti, SIGNAL(timeout()), receiver: w, SLOT(deleteLater())); |
| 3959 | ti.start(msec: 200); |
| 3960 | |
| 3961 | QContextMenuEvent *cme = new QContextMenuEvent(QContextMenuEvent::Mouse, w->rect().center()); |
| 3962 | qApp->postEvent(receiver: w, event: cme); |
| 3963 | |
| 3964 | QTest::qWait(ms: 300); |
| 3965 | // No crash, it's allright. |
| 3966 | } |
| 3967 | #endif |
| 3968 | |
| 3969 | void tst_QLineEdit::taskQTBUG_7395_readOnlyShortcut() |
| 3970 | { |
| 3971 | if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) |
| 3972 | QSKIP("Wayland: This fails. Figure out why." ); |
| 3973 | |
| 3974 | //ReadOnly QLineEdit should not intercept shortcut. |
| 3975 | QLineEdit le; |
| 3976 | le.setReadOnly(true); |
| 3977 | |
| 3978 | QAction action(QString::fromLatin1(str: "hello" ), &le); |
| 3979 | action.setShortcut(QString::fromLatin1(str: "p" )); |
| 3980 | QSignalSpy spy(&action, SIGNAL(triggered())); |
| 3981 | le.addAction(action: &action); |
| 3982 | |
| 3983 | le.show(); |
| 3984 | QVERIFY(QTest::qWaitForWindowExposed(&le)); |
| 3985 | QApplication::setActiveWindow(&le); |
| 3986 | QVERIFY(QTest::qWaitForWindowActive(&le)); |
| 3987 | le.setFocus(); |
| 3988 | QTRY_VERIFY(le.hasFocus()); |
| 3989 | |
| 3990 | QTest::keyClick(widget: static_cast<QWidget *>(0), key: Qt::Key_P); |
| 3991 | QCOMPARE(spy.count(), 1); |
| 3992 | } |
| 3993 | |
| 3994 | void tst_QLineEdit::QTBUG697_paletteCurrentColorGroup() |
| 3995 | { |
| 3996 | if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) |
| 3997 | QSKIP("Wayland: This fails. Figure out why." ); |
| 3998 | |
| 3999 | QLineEdit le; |
| 4000 | le.setText(" " ); |
| 4001 | QPalette p = le.palette(); |
| 4002 | p.setBrush(cg: QPalette::Active, cr: QPalette::Highlight, brush: Qt::green); |
| 4003 | p.setBrush(cg: QPalette::Inactive, cr: QPalette::Highlight, brush: Qt::red); |
| 4004 | le.setPalette(p); |
| 4005 | |
| 4006 | le.show(); |
| 4007 | QApplication::setActiveWindow(&le); |
| 4008 | QVERIFY(QTest::qWaitForWindowActive(&le)); |
| 4009 | le.setFocus(); |
| 4010 | QTRY_VERIFY(le.hasFocus()); |
| 4011 | le.selectAll(); |
| 4012 | |
| 4013 | QImage img(le.size(),QImage::Format_ARGB32 ); |
| 4014 | le.render(target: &img); |
| 4015 | QCOMPARE(img.pixel(10, le.height()/2), QColor(Qt::green).rgb()); |
| 4016 | |
| 4017 | QWindow window; |
| 4018 | window.resize(w: 100, h: 50); |
| 4019 | window.show(); |
| 4020 | window.requestActivate(); |
| 4021 | QVERIFY(QTest::qWaitForWindowActive(&window)); |
| 4022 | le.render(target: &img); |
| 4023 | QCOMPARE(img.pixel(10, le.height()/2), QColor(Qt::red).rgb()); |
| 4024 | } |
| 4025 | |
| 4026 | void tst_QLineEdit::QTBUG13520_textNotVisible() |
| 4027 | { |
| 4028 | LineEdit le; |
| 4029 | le.setAlignment( Qt::AlignRight | Qt::AlignVCenter); |
| 4030 | le.show(); |
| 4031 | QVERIFY(QTest::qWaitForWindowExposed(&le)); |
| 4032 | le.setText("01-ST16-01SIL-MPL001wfgsdfgsdgsdfgsdfgsdfgsdfgsdfg" ); |
| 4033 | le.setCursorPosition(0); |
| 4034 | QTest::qWait(ms: 100); //just make sure we get he lineedit correcly painted |
| 4035 | |
| 4036 | QVERIFY(le.cursorRect().center().x() < le.width() / 2); |
| 4037 | |
| 4038 | |
| 4039 | } |
| 4040 | |
| 4041 | class UpdateRegionLineEdit : public QLineEdit |
| 4042 | { |
| 4043 | public: |
| 4044 | QRegion updateRegion; |
| 4045 | protected: |
| 4046 | void paintEvent(QPaintEvent *event) |
| 4047 | { |
| 4048 | updateRegion = event->region(); |
| 4049 | } |
| 4050 | }; |
| 4051 | |
| 4052 | void tst_QLineEdit::QTBUG7174_inputMaskCursorBlink() |
| 4053 | { |
| 4054 | if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) |
| 4055 | QSKIP("Wayland: This fails. Figure out why." ); |
| 4056 | |
| 4057 | UpdateRegionLineEdit edit; |
| 4058 | edit.setInputMask(QLatin1String("AAAA" )); |
| 4059 | edit.setFocus(); |
| 4060 | edit.setText(QLatin1String("AAAA" )); |
| 4061 | edit.show(); |
| 4062 | QRect cursorRect = edit.inputMethodQuery(Qt::ImCursorRectangle).toRect(); |
| 4063 | QVERIFY(QTest::qWaitForWindowExposed(&edit)); |
| 4064 | edit.updateRegion = QRegion(); |
| 4065 | QTest::qWait(ms: QApplication::cursorFlashTime()); |
| 4066 | QVERIFY(edit.updateRegion.contains(cursorRect)); |
| 4067 | } |
| 4068 | |
| 4069 | void tst_QLineEdit::QTBUG16850_setSelection() |
| 4070 | { |
| 4071 | QLineEdit le; |
| 4072 | le.setInputMask("00:0" ); |
| 4073 | le.setText(" 1" ); |
| 4074 | le.setSelection(3, 1); |
| 4075 | QCOMPARE(le.selectionStart(), 3); |
| 4076 | QCOMPARE(le.selectionEnd(), 4); |
| 4077 | QCOMPARE(le.selectionLength(), 1); |
| 4078 | QCOMPARE(le.selectedText(), QString("1" )); |
| 4079 | } |
| 4080 | |
| 4081 | void tst_QLineEdit::bidiVisualMovement_data() |
| 4082 | { |
| 4083 | QTest::addColumn<QString>(name: "logical" ); |
| 4084 | QTest::addColumn<int>(name: "basicDir" ); |
| 4085 | QTest::addColumn<IntList>(name: "positionList" ); |
| 4086 | |
| 4087 | QTest::newRow(dataTag: "Latin text" ) |
| 4088 | << QString::fromUtf8(str: "abc" ) |
| 4089 | << (int) QChar::DirL |
| 4090 | << (IntList() << 0 << 1 << 2 << 3); |
| 4091 | QTest::newRow(dataTag: "Hebrew text, one item" ) |
| 4092 | << QString::fromUtf8(str: "\327\220\327\221\327\222" ) |
| 4093 | << (int) QChar::DirR |
| 4094 | << (QList<int>() << 0 << 1 << 2 << 3); |
| 4095 | QTest::newRow(dataTag: "Hebrew text after Latin text" ) |
| 4096 | << QString::fromUtf8(str: "abc\327\220\327\221\327\222" ) |
| 4097 | << (int) QChar::DirL |
| 4098 | << (QList<int>() << 0 << 1 << 2 << 6 << 5 << 4 << 3); |
| 4099 | QTest::newRow(dataTag: "Latin text after Hebrew text" ) |
| 4100 | << QString::fromUtf8(str: "\327\220\327\221\327\222abc" ) |
| 4101 | << (int) QChar::DirR |
| 4102 | << (QList<int>() << 0 << 1 << 2 << 6 << 5 << 4 << 3); |
| 4103 | QTest::newRow(dataTag: "LTR, 3 items" ) |
| 4104 | << QString::fromUtf8(str: "abc\327\220\327\221\327\222abc" ) |
| 4105 | << (int) QChar::DirL |
| 4106 | << (QList<int>() << 0 << 1 << 2 << 5 << 4 << 3 << 6 << 7 << 8 << 9); |
| 4107 | QTest::newRow(dataTag: "RTL, 3 items" ) |
| 4108 | << QString::fromUtf8(str: "\327\220\327\221\327\222abc\327\220\327\221\327\222" ) |
| 4109 | << (int) QChar::DirR |
| 4110 | << (QList<int>() << 0 << 1 << 2 << 5 << 4 << 3 << 6 << 7 << 8 << 9); |
| 4111 | QTest::newRow(dataTag: "LTR, 4 items" ) |
| 4112 | << QString::fromUtf8(str: "abc\327\220\327\221\327\222abc\327\220\327\221\327\222" ) |
| 4113 | << (int) QChar::DirL |
| 4114 | << (QList<int>() << 0 << 1 << 2 << 5 << 4 << 3 << 6 << 7 << 8 << 12 << 11 << 10 << 9); |
| 4115 | QTest::newRow(dataTag: "RTL, 4 items" ) |
| 4116 | << QString::fromUtf8(str: "\327\220\327\221\327\222abc\327\220\327\221\327\222abc" ) |
| 4117 | << (int) QChar::DirR |
| 4118 | << (QList<int>() << 0 << 1 << 2 << 5 << 4 << 3 << 6 << 7 << 8 << 12 << 11 << 10 << 9); |
| 4119 | } |
| 4120 | |
| 4121 | void tst_QLineEdit::bidiVisualMovement() |
| 4122 | { |
| 4123 | QFETCH(QString, logical); |
| 4124 | QFETCH(int, basicDir); |
| 4125 | QFETCH(IntList, positionList); |
| 4126 | |
| 4127 | QLineEdit le; |
| 4128 | le.setText(logical); |
| 4129 | |
| 4130 | le.setCursorMoveStyle(Qt::VisualMoveStyle); |
| 4131 | le.setCursorPosition(0); |
| 4132 | |
| 4133 | bool moved; |
| 4134 | int i = 0, oldPos, newPos = 0; |
| 4135 | |
| 4136 | do { |
| 4137 | oldPos = newPos; |
| 4138 | QCOMPARE(oldPos, positionList[i]); |
| 4139 | if (basicDir == QChar::DirL) { |
| 4140 | QTest::keyClick(widget: &le, key: Qt::Key_Right); |
| 4141 | } else |
| 4142 | QTest::keyClick(widget: &le, key: Qt::Key_Left); |
| 4143 | newPos = le.cursorPosition(); |
| 4144 | moved = (oldPos != newPos); |
| 4145 | i++; |
| 4146 | } while (moved); |
| 4147 | |
| 4148 | QCOMPARE(i, positionList.size()); |
| 4149 | |
| 4150 | do { |
| 4151 | i--; |
| 4152 | oldPos = newPos; |
| 4153 | QCOMPARE(oldPos, positionList[i]); |
| 4154 | if (basicDir == QChar::DirL) { |
| 4155 | QTest::keyClick(widget: &le, key: Qt::Key_Left); |
| 4156 | } else |
| 4157 | { |
| 4158 | QTest::keyClick(widget: &le, key: Qt::Key_Right); |
| 4159 | } |
| 4160 | newPos = le.cursorPosition(); |
| 4161 | moved = (oldPos != newPos); |
| 4162 | } while (moved && i >= 0); |
| 4163 | } |
| 4164 | |
| 4165 | void tst_QLineEdit::bidiLogicalMovement_data() |
| 4166 | { |
| 4167 | bidiVisualMovement_data(); |
| 4168 | } |
| 4169 | |
| 4170 | void tst_QLineEdit::bidiLogicalMovement() |
| 4171 | { |
| 4172 | QFETCH(QString, logical); |
| 4173 | QFETCH(int, basicDir); |
| 4174 | QFETCH(IntList, positionList); |
| 4175 | |
| 4176 | QLineEdit le; |
| 4177 | le.setText(logical); |
| 4178 | |
| 4179 | le.setCursorMoveStyle(Qt::LogicalMoveStyle); |
| 4180 | le.setCursorPosition(0); |
| 4181 | |
| 4182 | bool moved; |
| 4183 | int i = 0, oldPos, newPos = 0; |
| 4184 | |
| 4185 | do { |
| 4186 | oldPos = newPos; |
| 4187 | QCOMPARE(oldPos, i); |
| 4188 | if (basicDir == QChar::DirL) { |
| 4189 | QTest::keyClick(widget: &le, key: Qt::Key_Right); |
| 4190 | } else |
| 4191 | QTest::keyClick(widget: &le, key: Qt::Key_Left); |
| 4192 | newPos = le.cursorPosition(); |
| 4193 | moved = (oldPos != newPos); |
| 4194 | i++; |
| 4195 | } while (moved); |
| 4196 | |
| 4197 | QCOMPARE(i, positionList.size()); |
| 4198 | |
| 4199 | do { |
| 4200 | i--; |
| 4201 | oldPos = newPos; |
| 4202 | QCOMPARE(oldPos, i); |
| 4203 | if (basicDir == QChar::DirL) { |
| 4204 | QTest::keyClick(widget: &le, key: Qt::Key_Left); |
| 4205 | } else |
| 4206 | { |
| 4207 | QTest::keyClick(widget: &le, key: Qt::Key_Right); |
| 4208 | } |
| 4209 | newPos = le.cursorPosition(); |
| 4210 | moved = (oldPos != newPos); |
| 4211 | } while (moved && i >= 0); |
| 4212 | } |
| 4213 | |
| 4214 | void tst_QLineEdit::selectAndCursorPosition() |
| 4215 | { |
| 4216 | QLineEdit *testWidget = ensureTestWidget(); |
| 4217 | testWidget->setText("This is a long piece of text" ); |
| 4218 | |
| 4219 | testWidget->setSelection(0, 5); |
| 4220 | QCOMPARE(testWidget->cursorPosition(), 5); |
| 4221 | testWidget->setSelection(5, -5); |
| 4222 | QCOMPARE(testWidget->cursorPosition(), 0); |
| 4223 | } |
| 4224 | |
| 4225 | void tst_QLineEdit::inputMethod() |
| 4226 | { |
| 4227 | if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) |
| 4228 | QSKIP("Wayland: This fails. Figure out why." ); |
| 4229 | |
| 4230 | QLineEdit *testWidget = ensureTestWidget(); |
| 4231 | centerOnScreen(w: testWidget); |
| 4232 | testWidget->show(); |
| 4233 | QVERIFY(QTest::qWaitForWindowExposed(testWidget)); |
| 4234 | // widget accepts input |
| 4235 | QInputMethodQueryEvent queryEvent(Qt::ImEnabled); |
| 4236 | QApplication::sendEvent(receiver: testWidget, event: &queryEvent); |
| 4237 | QCOMPARE(queryEvent.value(Qt::ImEnabled).toBool(), true); |
| 4238 | |
| 4239 | testWidget->setEnabled(false); |
| 4240 | QApplication::sendEvent(receiver: testWidget, event: &queryEvent); |
| 4241 | QCOMPARE(queryEvent.value(Qt::ImEnabled).toBool(), false); |
| 4242 | testWidget->setEnabled(true); |
| 4243 | |
| 4244 | // removing focus allows input method to commit preedit |
| 4245 | testWidget->setText("" ); |
| 4246 | testWidget->activateWindow(); |
| 4247 | // TODO setFocus should not be necessary here, because activateWindow |
| 4248 | // should focus it, and the window is the QLineEdit. But the test can fail |
| 4249 | // on Windows if we don't do this. If each test had a unique QLineEdit |
| 4250 | // instance, maybe such problems would go away. |
| 4251 | testWidget->setFocus(); |
| 4252 | QTRY_VERIFY(testWidget->hasFocus()); |
| 4253 | QTRY_COMPARE(qApp->focusObject(), testWidget); |
| 4254 | |
| 4255 | m_platformInputContext.setCommitString("text" ); |
| 4256 | m_platformInputContext.m_commitCallCount = 0; |
| 4257 | QList<QInputMethodEvent::Attribute> attributes; |
| 4258 | QInputMethodEvent preeditEvent("preedit text" , attributes); |
| 4259 | QApplication::sendEvent(receiver: testWidget, event: &preeditEvent); |
| 4260 | |
| 4261 | testWidget->clearFocus(); |
| 4262 | QCOMPARE(m_platformInputContext.m_commitCallCount, 1); |
| 4263 | QCOMPARE(testWidget->text(), QString("text" )); |
| 4264 | } |
| 4265 | |
| 4266 | void tst_QLineEdit::inputMethodSelection() |
| 4267 | { |
| 4268 | QLineEdit *testWidget = ensureTestWidget(); |
| 4269 | testWidget->setText("Lorem ipsum dolor sit amet, consectetur adipiscing elit." ); |
| 4270 | testWidget->setSelection(0,0); |
| 4271 | QSignalSpy selectionSpy(testWidget, SIGNAL(selectionChanged())); |
| 4272 | |
| 4273 | QCOMPARE(selectionSpy.count(), 0); |
| 4274 | QCOMPARE(testWidget->selectionStart(), -1); |
| 4275 | QCOMPARE(testWidget->selectionEnd(), -1); |
| 4276 | QCOMPARE(testWidget->selectionLength(), 0); |
| 4277 | |
| 4278 | testWidget->setSelection(0,5); |
| 4279 | |
| 4280 | QCOMPARE(selectionSpy.count(), 1); |
| 4281 | QCOMPARE(testWidget->selectionStart(), 0); |
| 4282 | QCOMPARE(testWidget->selectionEnd(), 5); |
| 4283 | QCOMPARE(testWidget->selectionLength(), 5); |
| 4284 | |
| 4285 | |
| 4286 | // selection gained |
| 4287 | { |
| 4288 | QList<QInputMethodEvent::Attribute> attributes; |
| 4289 | attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 12, 5, QVariant()); |
| 4290 | QInputMethodEvent event("" , attributes); |
| 4291 | QApplication::sendEvent(receiver: testWidget, event: &event); |
| 4292 | } |
| 4293 | |
| 4294 | QCOMPARE(selectionSpy.count(), 2); |
| 4295 | QCOMPARE(testWidget->selectionStart(), 12); |
| 4296 | QCOMPARE(testWidget->selectionEnd(), 17); |
| 4297 | QCOMPARE(testWidget->selectionLength(), 5); |
| 4298 | |
| 4299 | // selection removed |
| 4300 | { |
| 4301 | QList<QInputMethodEvent::Attribute> attributes; |
| 4302 | attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 0, 0, QVariant()); |
| 4303 | QInputMethodEvent event("" , attributes); |
| 4304 | QApplication::sendEvent(receiver: testWidget, event: &event); |
| 4305 | } |
| 4306 | |
| 4307 | QCOMPARE(selectionSpy.count(), 3); |
| 4308 | QCOMPARE(testWidget->selectionStart(), -1); |
| 4309 | QCOMPARE(testWidget->selectionEnd(), -1); |
| 4310 | QCOMPARE(testWidget->selectionLength(), 0); |
| 4311 | |
| 4312 | } |
| 4313 | |
| 4314 | Q_DECLARE_METATYPE(Qt::InputMethodHints) |
| 4315 | void tst_QLineEdit::inputMethodQueryImHints_data() |
| 4316 | { |
| 4317 | QTest::addColumn<Qt::InputMethodHints>(name: "hints" ); |
| 4318 | |
| 4319 | QTest::newRow(dataTag: "None" ) << static_cast<Qt::InputMethodHints>(Qt::ImhNone); |
| 4320 | QTest::newRow(dataTag: "Password" ) << static_cast<Qt::InputMethodHints>(Qt::ImhHiddenText); |
| 4321 | QTest::newRow(dataTag: "Normal" ) << static_cast<Qt::InputMethodHints>(Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText | Qt::ImhSensitiveData); |
| 4322 | } |
| 4323 | |
| 4324 | void tst_QLineEdit::inputMethodQueryImHints() |
| 4325 | { |
| 4326 | QFETCH(Qt::InputMethodHints, hints); |
| 4327 | QLineEdit *testWidget = ensureTestWidget(); |
| 4328 | testWidget->setInputMethodHints(hints); |
| 4329 | |
| 4330 | QVariant value = testWidget->inputMethodQuery(Qt::ImHints); |
| 4331 | QCOMPARE(static_cast<Qt::InputMethodHints>(value.toInt()), hints); |
| 4332 | } |
| 4333 | |
| 4334 | void tst_QLineEdit::inputMethodUpdate() |
| 4335 | { |
| 4336 | if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) |
| 4337 | QSKIP("Wayland: This fails. Figure out why." ); |
| 4338 | |
| 4339 | QLineEdit *testWidget = ensureTestWidget(); |
| 4340 | |
| 4341 | centerOnScreen(w: testWidget); |
| 4342 | testWidget->show(); |
| 4343 | QVERIFY(QTest::qWaitForWindowExposed(testWidget)); |
| 4344 | |
| 4345 | testWidget->setText("" ); |
| 4346 | testWidget->activateWindow(); |
| 4347 | testWidget->setFocus(); |
| 4348 | QTRY_VERIFY(testWidget->hasFocus()); |
| 4349 | QTRY_COMPARE(qApp->focusObject(), testWidget); |
| 4350 | |
| 4351 | m_platformInputContext.m_updateCallCount = 0; |
| 4352 | { |
| 4353 | QList<QInputMethodEvent::Attribute> attributes; |
| 4354 | QInputMethodEvent event("preedit text" , attributes); |
| 4355 | QApplication::sendEvent(receiver: testWidget, event: &event); |
| 4356 | } |
| 4357 | QVERIFY(m_platformInputContext.m_updateCallCount >= 1); |
| 4358 | |
| 4359 | m_platformInputContext.m_updateCallCount = 0; |
| 4360 | { |
| 4361 | QList<QInputMethodEvent::Attribute> attributes; |
| 4362 | attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, 0, 1, QVariant()); |
| 4363 | QInputMethodEvent event("preedit text" , attributes); |
| 4364 | QApplication::sendEvent(receiver: testWidget, event: &event); |
| 4365 | } |
| 4366 | QVERIFY(m_platformInputContext.m_updateCallCount >= 1); |
| 4367 | |
| 4368 | m_platformInputContext.m_updateCallCount = 0; |
| 4369 | { |
| 4370 | QList<QInputMethodEvent::Attribute> attributes; |
| 4371 | QInputMethodEvent event("" , attributes); |
| 4372 | event.setCommitString(commitString: "preedit text" ); |
| 4373 | QApplication::sendEvent(receiver: testWidget, event: &event); |
| 4374 | } |
| 4375 | QVERIFY(m_platformInputContext.m_updateCallCount >= 1); |
| 4376 | QCOMPARE(testWidget->text(), QString("preedit text" )); |
| 4377 | |
| 4378 | m_platformInputContext.m_updateCallCount = 0; |
| 4379 | { |
| 4380 | QList<QInputMethodEvent::Attribute> attributes; |
| 4381 | attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 0, 0, QVariant()); |
| 4382 | QInputMethodEvent event("" , attributes); |
| 4383 | QApplication::sendEvent(receiver: testWidget, event: &event); |
| 4384 | } |
| 4385 | QVERIFY(m_platformInputContext.m_updateCallCount >= 1); |
| 4386 | } |
| 4387 | |
| 4388 | void tst_QLineEdit::undoRedoAndEchoModes_data() |
| 4389 | { |
| 4390 | QTest::addColumn<int>(name: "echoMode" ); |
| 4391 | QTest::addColumn<QStringList>(name: "input" ); |
| 4392 | QTest::addColumn<QStringList>(name: "expected" ); |
| 4393 | |
| 4394 | QStringList input(QList<QString>() << "aaa" << "bbb" << "ccc" ); |
| 4395 | |
| 4396 | QTest::newRow(dataTag: "Normal" ) |
| 4397 | << (int) QLineEdit::Normal |
| 4398 | << input |
| 4399 | << QStringList(QList<QString>() << "aaa" << "ccc" << "" ); |
| 4400 | |
| 4401 | QTest::newRow(dataTag: "NoEcho" ) |
| 4402 | << (int) QLineEdit::NoEcho |
| 4403 | << input |
| 4404 | << QStringList(QList<QString>() << "" << "" << "" ); |
| 4405 | |
| 4406 | QTest::newRow(dataTag: "Password" ) |
| 4407 | << (int) QLineEdit::Password |
| 4408 | << input |
| 4409 | << QStringList(QList<QString>() << "" << "" << "" ); |
| 4410 | |
| 4411 | QTest::newRow(dataTag: "PasswordEchoOnEdit" ) |
| 4412 | << (int) QLineEdit::PasswordEchoOnEdit |
| 4413 | << input |
| 4414 | << QStringList(QList<QString>() << "" << "" << "" ); |
| 4415 | } |
| 4416 | |
| 4417 | void tst_QLineEdit::undoRedoAndEchoModes() |
| 4418 | { |
| 4419 | QFETCH(int, echoMode); |
| 4420 | QFETCH(QStringList, input); |
| 4421 | QFETCH(QStringList, expected); |
| 4422 | |
| 4423 | // create some history for the QLineEdit |
| 4424 | QLineEdit *testWidget = ensureTestWidget(); |
| 4425 | testWidget->setEchoMode(QLineEdit::EchoMode(echoMode)); |
| 4426 | testWidget->insert(input.at(i: 0)); |
| 4427 | testWidget->selectAll(); |
| 4428 | testWidget->backspace(); |
| 4429 | testWidget->insert(input.at(i: 1)); |
| 4430 | |
| 4431 | // test undo |
| 4432 | QVERIFY(testWidget->isUndoAvailable()); |
| 4433 | testWidget->undo(); |
| 4434 | QCOMPARE(testWidget->text(), expected.at(0)); |
| 4435 | testWidget->insert(input.at(i: 2)); |
| 4436 | testWidget->selectAll(); |
| 4437 | testWidget->backspace(); |
| 4438 | QCOMPARE(testWidget->isUndoAvailable(), echoMode == QLineEdit::Normal); |
| 4439 | testWidget->undo(); |
| 4440 | QCOMPARE(testWidget->text(), expected.at(1)); |
| 4441 | |
| 4442 | // test redo |
| 4443 | QCOMPARE(testWidget->isRedoAvailable(), echoMode == QLineEdit::Normal); |
| 4444 | testWidget->redo(); |
| 4445 | QCOMPARE(testWidget->text(), expected.at(2)); |
| 4446 | QVERIFY(!testWidget->isRedoAvailable()); |
| 4447 | testWidget->redo(); |
| 4448 | QCOMPARE(testWidget->text(), expected.at(2)); |
| 4449 | } |
| 4450 | |
| 4451 | void tst_QLineEdit::clearButton() |
| 4452 | { |
| 4453 | if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) |
| 4454 | QSKIP("Wayland: This fails. Figure out why." ); |
| 4455 | |
| 4456 | // Construct a listview with a stringlist model and filter model. |
| 4457 | QWidget testWidget; |
| 4458 | QVBoxLayout *l = new QVBoxLayout(&testWidget); |
| 4459 | QLineEdit *filterLineEdit = new QLineEdit(&testWidget); |
| 4460 | l->addWidget(filterLineEdit); |
| 4461 | QListView *listView = new QListView(&testWidget); |
| 4462 | QStringListModel *model = new QStringListModel(QStringList() << QStringLiteral("aa" ) << QStringLiteral("ab" ) << QStringLiteral("cc" ), listView); |
| 4463 | QSortFilterProxyModel *filterModel = new QSortFilterProxyModel(listView); |
| 4464 | filterModel->setSourceModel(model); |
| 4465 | connect(sender: filterLineEdit, SIGNAL(textChanged(QString)), receiver: filterModel, SLOT(setFilterFixedString(QString))); |
| 4466 | listView->setModel(filterModel); |
| 4467 | l->addWidget(listView); |
| 4468 | testWidget.move(ax: 300, ay: 300); |
| 4469 | testWidget.show(); |
| 4470 | qApp->setActiveWindow(&testWidget); |
| 4471 | QVERIFY(QTest::qWaitForWindowActive(&testWidget)); |
| 4472 | // Flip the clear button on,off, trying to detect crashes. |
| 4473 | filterLineEdit->setClearButtonEnabled(true); |
| 4474 | QVERIFY(filterLineEdit->isClearButtonEnabled()); |
| 4475 | filterLineEdit->setClearButtonEnabled(true); |
| 4476 | QVERIFY(filterLineEdit->isClearButtonEnabled()); |
| 4477 | filterLineEdit->setClearButtonEnabled(false); |
| 4478 | QVERIFY(!filterLineEdit->isClearButtonEnabled()); |
| 4479 | filterLineEdit->setClearButtonEnabled(false); |
| 4480 | QVERIFY(!filterLineEdit->isClearButtonEnabled()); |
| 4481 | filterLineEdit->setClearButtonEnabled(true); |
| 4482 | QVERIFY(filterLineEdit->isClearButtonEnabled()); |
| 4483 | // Emulate filtering |
| 4484 | QToolButton *clearButton = filterLineEdit->findChild<QToolButton *>(); |
| 4485 | QVERIFY(clearButton); |
| 4486 | QCOMPARE(filterModel->rowCount(), 3); |
| 4487 | QTest::keyClick(widget: filterLineEdit, key: 'a'); |
| 4488 | QTRY_COMPARE(clearButton->cursor().shape(), Qt::ArrowCursor); |
| 4489 | QTRY_COMPARE(filterModel->rowCount(), 2); // matches 'aa', 'ab' |
| 4490 | QTest::keyClick(widget: filterLineEdit, key: 'b'); |
| 4491 | QTRY_COMPARE(filterModel->rowCount(), 1); // matches 'ab' |
| 4492 | QSignalSpy spyEdited(filterLineEdit, &QLineEdit::textEdited); |
| 4493 | const QPoint clearButtonCenterPos = QRect(QPoint(0, 0), clearButton->size()).center(); |
| 4494 | QTest::mouseClick(widget: clearButton, button: Qt::LeftButton, stateKey: {}, pos: clearButtonCenterPos); |
| 4495 | QCOMPARE(spyEdited.count(), 1); |
| 4496 | QTRY_COMPARE(clearButton->cursor().shape(), filterLineEdit->cursor().shape()); |
| 4497 | QTRY_COMPARE(filterModel->rowCount(), 3); |
| 4498 | QCoreApplication::processEvents(); |
| 4499 | QCOMPARE(spyEdited.count(), 1); |
| 4500 | |
| 4501 | filterLineEdit->setReadOnly(true); // QTBUG-34315 |
| 4502 | QVERIFY(!clearButton->isEnabled()); |
| 4503 | } |
| 4504 | |
| 4505 | void tst_QLineEdit::clearButtonVisibleAfterSettingText_QTBUG_45518() |
| 4506 | { |
| 4507 | #ifndef QT_BUILD_INTERNAL |
| 4508 | QSKIP("This test requires a developer build" ); |
| 4509 | #else |
| 4510 | if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) |
| 4511 | QSKIP("Wayland: This fails. Figure out why." ); |
| 4512 | |
| 4513 | QLineEdit edit; |
| 4514 | edit.setMinimumWidth(200); |
| 4515 | centerOnScreen(w: &edit); |
| 4516 | QLineEditIconButton *clearButton; |
| 4517 | clearButton = edit.findChild<QLineEditIconButton *>(); |
| 4518 | QVERIFY(!clearButton); |
| 4519 | |
| 4520 | edit.setText(QStringLiteral("some text" )); |
| 4521 | edit.show(); |
| 4522 | QVERIFY(QTest::qWaitForWindowActive(&edit)); |
| 4523 | |
| 4524 | QVERIFY(!edit.isClearButtonEnabled()); |
| 4525 | |
| 4526 | clearButton = edit.findChild<QLineEditIconButton *>(); |
| 4527 | QVERIFY(!clearButton); |
| 4528 | |
| 4529 | edit.setClearButtonEnabled(true); |
| 4530 | QVERIFY(edit.isClearButtonEnabled()); |
| 4531 | |
| 4532 | clearButton = edit.findChild<QLineEditIconButton *>(); |
| 4533 | QVERIFY(clearButton); |
| 4534 | QVERIFY(clearButton->isVisible()); |
| 4535 | |
| 4536 | QTRY_VERIFY(clearButton->opacity() > 0); |
| 4537 | QTRY_COMPARE(clearButton->cursor().shape(), Qt::ArrowCursor); |
| 4538 | |
| 4539 | QTest::mouseClick(widget: clearButton, button: Qt::LeftButton, stateKey: {}, pos: clearButton->rect().center()); |
| 4540 | QTRY_COMPARE(edit.text(), QString()); |
| 4541 | |
| 4542 | QTRY_COMPARE(clearButton->opacity(), qreal(0)); |
| 4543 | QVERIFY(clearButton->isHidden()); |
| 4544 | QTRY_COMPARE(clearButton->cursor().shape(), clearButton->parentWidget()->cursor().shape()); |
| 4545 | |
| 4546 | edit.setClearButtonEnabled(false); |
| 4547 | QVERIFY(!edit.isClearButtonEnabled()); |
| 4548 | clearButton = edit.findChild<QLineEditIconButton *>(); |
| 4549 | QVERIFY(!clearButton); |
| 4550 | #endif // QT_BUILD_INTERNAL |
| 4551 | } |
| 4552 | |
| 4553 | static inline QIcon sideWidgetTestIcon(Qt::GlobalColor color = Qt::yellow) |
| 4554 | { |
| 4555 | QImage image(QSize(20, 20), QImage::Format_ARGB32); |
| 4556 | image.fill(color); |
| 4557 | return QIcon(QPixmap::fromImage(image)); |
| 4558 | } |
| 4559 | |
| 4560 | void tst_QLineEdit::sideWidgets() |
| 4561 | { |
| 4562 | QWidget testWidget; |
| 4563 | QVBoxLayout *l = new QVBoxLayout(&testWidget); |
| 4564 | QLineEdit *lineEdit = new QLineEdit(&testWidget); |
| 4565 | l->addWidget(lineEdit); |
| 4566 | l->addSpacerItem(spacerItem: new QSpacerItem(0, 50, QSizePolicy::Ignored, QSizePolicy::Fixed)); |
| 4567 | QAction *iconAction = new QAction(sideWidgetTestIcon(), QString(), lineEdit); |
| 4568 | QWidgetAction *label1Action = new QWidgetAction(lineEdit); |
| 4569 | label1Action->setDefaultWidget(new QLabel(QStringLiteral("l1" ))); |
| 4570 | QWidgetAction *label2Action = new QWidgetAction(lineEdit); |
| 4571 | label2Action->setDefaultWidget(new QLabel(QStringLiteral("l2" ))); |
| 4572 | QWidgetAction *label3Action = new QWidgetAction(lineEdit); |
| 4573 | label3Action->setDefaultWidget(new QLabel(QStringLiteral("l3" ))); |
| 4574 | lineEdit->addAction(action: iconAction, position: QLineEdit::LeadingPosition); |
| 4575 | lineEdit->addAction(action: label2Action, position: QLineEdit::LeadingPosition); |
| 4576 | lineEdit->addAction(action: label1Action, position: QLineEdit::TrailingPosition); |
| 4577 | lineEdit->addAction(action: label3Action, position: QLineEdit::TrailingPosition); |
| 4578 | testWidget.move(ax: 300, ay: 300); |
| 4579 | testWidget.show(); |
| 4580 | QVERIFY(QTest::qWaitForWindowExposed(&testWidget)); |
| 4581 | foreach (QToolButton *button, lineEdit->findChildren<QToolButton *>()) |
| 4582 | QCOMPARE(button->cursor().shape(), Qt::ArrowCursor); |
| 4583 | // Arbitrarily add/remove actions, trying to detect crashes. Add QTRY_VERIFY(false) to view the result. |
| 4584 | delete label3Action; |
| 4585 | lineEdit->removeAction(action: label2Action); |
| 4586 | lineEdit->removeAction(action: iconAction); |
| 4587 | lineEdit->removeAction(action: label1Action); |
| 4588 | lineEdit->removeAction(action: iconAction); |
| 4589 | lineEdit->removeAction(action: label1Action); |
| 4590 | lineEdit->addAction(action: iconAction); |
| 4591 | lineEdit->addAction(action: iconAction); |
| 4592 | } |
| 4593 | |
| 4594 | template <class T> T *findAssociatedWidget(const QAction *a) |
| 4595 | { |
| 4596 | foreach (QWidget *w, a->associatedWidgets()) { |
| 4597 | if (T *result = qobject_cast<T *>(w)) |
| 4598 | return result; |
| 4599 | } |
| 4600 | return nullptr; |
| 4601 | } |
| 4602 | |
| 4603 | void tst_QLineEdit::sideWidgetsActionEvents() |
| 4604 | { |
| 4605 | // QTBUG-39660, verify whether action events are handled by the widget. |
| 4606 | QWidget testWidget; |
| 4607 | QVBoxLayout *l = new QVBoxLayout(&testWidget); |
| 4608 | QLineEdit *lineEdit = new QLineEdit(&testWidget); |
| 4609 | l->addWidget(lineEdit); |
| 4610 | l->addSpacerItem(spacerItem: new QSpacerItem(0, 50, QSizePolicy::Ignored, QSizePolicy::Fixed)); |
| 4611 | QAction *iconAction1 = lineEdit->addAction(icon: sideWidgetTestIcon(color: Qt::red), position: QLineEdit::LeadingPosition); |
| 4612 | QAction *iconAction2 = lineEdit->addAction(icon: sideWidgetTestIcon(color: Qt::blue), position: QLineEdit::LeadingPosition); |
| 4613 | QAction *iconAction3 = lineEdit->addAction(icon: sideWidgetTestIcon(color: Qt::yellow), position: QLineEdit::LeadingPosition); |
| 4614 | iconAction3->setVisible(false); |
| 4615 | |
| 4616 | testWidget.move(ax: 300, ay: 300); |
| 4617 | testWidget.show(); |
| 4618 | QVERIFY(QTest::qWaitForWindowExposed(&testWidget)); |
| 4619 | |
| 4620 | QWidget *toolButton1 = findAssociatedWidget<QToolButton>(a: iconAction1); |
| 4621 | QWidget *toolButton2 = findAssociatedWidget<QToolButton>(a: iconAction2); |
| 4622 | QWidget *toolButton3 = findAssociatedWidget<QToolButton>(a: iconAction3); |
| 4623 | |
| 4624 | QVERIFY(toolButton1); |
| 4625 | QVERIFY(toolButton2); |
| 4626 | QVERIFY(toolButton3); |
| 4627 | |
| 4628 | QVERIFY(!toolButton3->isVisible()); // QTBUG-48899 , action hidden before show(). |
| 4629 | |
| 4630 | QVERIFY(toolButton1->isVisible()); |
| 4631 | QVERIFY(toolButton1->isEnabled()); |
| 4632 | |
| 4633 | QVERIFY(toolButton2->isVisible()); |
| 4634 | QVERIFY(toolButton2->isEnabled()); |
| 4635 | |
| 4636 | const int toolButton1X = toolButton1->x(); |
| 4637 | const int toolButton2X = toolButton2->x(); |
| 4638 | QVERIFY(toolButton1X < toolButton2X); // QTBUG-48806, positioned beside each other. |
| 4639 | |
| 4640 | iconAction1->setEnabled(false); |
| 4641 | QVERIFY(!toolButton1->isEnabled()); |
| 4642 | |
| 4643 | iconAction1->setVisible(false); |
| 4644 | QVERIFY(!toolButton1->isVisible()); |
| 4645 | |
| 4646 | // QTBUG-39660, button 2 takes position of invisible button 1. |
| 4647 | QCOMPARE(toolButton2->x(), toolButton1X); |
| 4648 | } |
| 4649 | |
| 4650 | /*! |
| 4651 | Verify that side widgets are positioned correctly and result in |
| 4652 | correct effective text margins. |
| 4653 | */ |
| 4654 | void tst_QLineEdit::sideWidgetsEffectiveMargins() |
| 4655 | { |
| 4656 | #ifndef QT_BUILD_INTERNAL |
| 4657 | QSKIP("This test requires a developer build." ); |
| 4658 | #else |
| 4659 | QLineEdit edit; |
| 4660 | edit.setPlaceholderText("placeholder" ); |
| 4661 | edit.setClearButtonEnabled(true); |
| 4662 | edit.show(); |
| 4663 | QLineEditPrivate *priv = QLineEditPrivate::get(lineEdit: &edit); |
| 4664 | const auto sideWidgetParameters = priv->sideWidgetParameters(); |
| 4665 | const int sideWidgetWidth = sideWidgetParameters.widgetWidth + sideWidgetParameters.margin; |
| 4666 | QVERIFY(QTest::qWaitForWindowExposed(&edit)); |
| 4667 | |
| 4668 | QCOMPARE(priv->effectiveTextMargins().left(), 0); |
| 4669 | QCOMPARE(priv->effectiveTextMargins().right(), 0); |
| 4670 | |
| 4671 | edit.setText("Left to right" ); // clear button fades in on the right |
| 4672 | QCOMPARE(priv->effectiveTextMargins().left(), 0); |
| 4673 | QCOMPARE(priv->effectiveTextMargins().right(), sideWidgetWidth); |
| 4674 | edit.clear(); |
| 4675 | QCOMPARE(priv->effectiveTextMargins().left(), 0); |
| 4676 | QCOMPARE(priv->effectiveTextMargins().right(), 0); |
| 4677 | |
| 4678 | edit.setLayoutDirection(Qt::RightToLeft); |
| 4679 | edit.setText("ئۇيغۇر تىلى" ); // clear button fades in on the left |
| 4680 | QCOMPARE(priv->effectiveTextMargins().left(), sideWidgetWidth); |
| 4681 | QCOMPARE(priv->effectiveTextMargins().right(), 0); |
| 4682 | edit.clear(); |
| 4683 | QCOMPARE(priv->effectiveTextMargins().left(), 0); |
| 4684 | QCOMPARE(priv->effectiveTextMargins().right(), 0); |
| 4685 | |
| 4686 | edit.setLayoutDirection(Qt::LeftToRight); |
| 4687 | |
| 4688 | const QIcon leftIcon = edit.style()->standardIcon(standardIcon: QStyle::SP_FileIcon); |
| 4689 | const QIcon rightIcon = edit.style()->standardIcon(standardIcon: QStyle::SP_DirIcon); |
| 4690 | edit.addAction(icon: leftIcon, position: QLineEdit::ActionPosition::LeadingPosition); |
| 4691 | QCOMPARE(priv->effectiveTextMargins().left(), sideWidgetWidth); |
| 4692 | QCOMPARE(priv->effectiveTextMargins().right(), 0); |
| 4693 | |
| 4694 | edit.addAction(icon: rightIcon, position: QLineEdit::ActionPosition::TrailingPosition); |
| 4695 | QCOMPARE(priv->effectiveTextMargins().left(), sideWidgetWidth); |
| 4696 | QCOMPARE(priv->effectiveTextMargins().right(), sideWidgetWidth); |
| 4697 | |
| 4698 | edit.setText("Left to right" ); // clear button on the right |
| 4699 | QCOMPARE(priv->effectiveTextMargins().left(), sideWidgetWidth); |
| 4700 | QCOMPARE(priv->effectiveTextMargins().right(), 2 * sideWidgetWidth); |
| 4701 | edit.clear(); |
| 4702 | QCOMPARE(priv->effectiveTextMargins().left(), sideWidgetWidth); |
| 4703 | QCOMPARE(priv->effectiveTextMargins().right(), sideWidgetWidth); |
| 4704 | |
| 4705 | edit.setLayoutDirection(Qt::RightToLeft); |
| 4706 | edit.setText("ئۇيغۇر تىلى" ); // clear button fades in on the left |
| 4707 | QCOMPARE(priv->effectiveTextMargins().left(), 2 * sideWidgetWidth); |
| 4708 | QCOMPARE(priv->effectiveTextMargins().right(), sideWidgetWidth); |
| 4709 | edit.clear(); |
| 4710 | QCOMPARE(priv->effectiveTextMargins().left(), sideWidgetWidth); |
| 4711 | QCOMPARE(priv->effectiveTextMargins().right(), sideWidgetWidth); |
| 4712 | #endif |
| 4713 | } |
| 4714 | |
| 4715 | Q_DECLARE_METATYPE(Qt::AlignmentFlag) |
| 4716 | void tst_QLineEdit::shouldShowPlaceholderText_data() |
| 4717 | { |
| 4718 | QTest::addColumn<QString>(name: "text" ); |
| 4719 | QTest::addColumn<bool>(name: "hasFocus" ); |
| 4720 | QTest::addColumn<Qt::AlignmentFlag>(name: "alignment" ); |
| 4721 | QTest::addColumn<bool>(name: "shouldShowPlaceholderText" ); |
| 4722 | |
| 4723 | QTest::newRow(dataTag: "empty, non-focused, left" ) << QString() << false << Qt::AlignLeft << true; |
| 4724 | QTest::newRow(dataTag: "empty, focused, left" ) << QString() << true << Qt::AlignLeft << true; |
| 4725 | QTest::newRow(dataTag: "non-empty, non-focused, left" ) << QStringLiteral("Qt" ) << false << Qt::AlignLeft << false; |
| 4726 | QTest::newRow(dataTag: "non-empty, focused, left" ) << QStringLiteral("Qt" ) << true << Qt::AlignLeft << false; |
| 4727 | |
| 4728 | QTest::newRow(dataTag: "empty, non-focused, center" ) << QString() << false << Qt::AlignHCenter << true; |
| 4729 | QTest::newRow(dataTag: "empty, focused, center" ) << QString() << true << Qt::AlignHCenter << false; |
| 4730 | QTest::newRow(dataTag: "non-empty, non-focused, center" ) << QStringLiteral("Qt" ) << false << Qt::AlignHCenter << false; |
| 4731 | QTest::newRow(dataTag: "non-empty, focused, center" ) << QStringLiteral("Qt" ) << true << Qt::AlignHCenter << false; |
| 4732 | |
| 4733 | QTest::newRow(dataTag: "empty, non-focused, right" ) << QString() << false << Qt::AlignRight << true; |
| 4734 | QTest::newRow(dataTag: "empty, focused, right" ) << QString() << true << Qt::AlignRight << true; |
| 4735 | QTest::newRow(dataTag: "non-empty, non-focused, right" ) << QStringLiteral("Qt" ) << false << Qt::AlignRight << false; |
| 4736 | QTest::newRow(dataTag: "non-empty, focused, right" ) << QStringLiteral("Qt" ) << true << Qt::AlignRight << false; |
| 4737 | } |
| 4738 | |
| 4739 | void tst_QLineEdit::shouldShowPlaceholderText() |
| 4740 | { |
| 4741 | #ifndef QT_BUILD_INTERNAL |
| 4742 | QSKIP("This test requires a developer build." ); |
| 4743 | #else |
| 4744 | QFETCH(QString, text); |
| 4745 | QFETCH(bool, hasFocus); |
| 4746 | QFETCH(Qt::AlignmentFlag, alignment); |
| 4747 | QFETCH(bool, shouldShowPlaceholderText); |
| 4748 | |
| 4749 | QLineEdit lineEdit; |
| 4750 | |
| 4751 | // avoid "Test input context to commit without focused object" warnings |
| 4752 | lineEdit.setAttribute(Qt::WA_InputMethodEnabled, on: false); |
| 4753 | |
| 4754 | if (hasFocus) { |
| 4755 | lineEdit.show(); |
| 4756 | QApplicationPrivate::setFocusWidget(focus: &lineEdit, reason: Qt::NoFocusReason); |
| 4757 | } |
| 4758 | QCOMPARE(lineEdit.hasFocus(), hasFocus); |
| 4759 | |
| 4760 | lineEdit.setText(text); |
| 4761 | lineEdit.setAlignment(alignment); |
| 4762 | |
| 4763 | QLineEditPrivate *priv = QLineEditPrivate::get(lineEdit: &lineEdit); |
| 4764 | QCOMPARE(priv->shouldShowPlaceholderText(), shouldShowPlaceholderText); |
| 4765 | #endif |
| 4766 | |
| 4767 | } |
| 4768 | |
| 4769 | void tst_QLineEdit::QTBUG1266_setInputMaskEmittingTextEdited() |
| 4770 | { |
| 4771 | QLineEdit lineEdit; |
| 4772 | lineEdit.setText("test" ); |
| 4773 | QSignalSpy spy(&lineEdit, SIGNAL(textEdited(QString))); |
| 4774 | lineEdit.setInputMask("AAAA" ); |
| 4775 | lineEdit.setInputMask(QString()); |
| 4776 | QCOMPARE(spy.count(), 0); |
| 4777 | } |
| 4778 | |
| 4779 | void tst_QLineEdit::shortcutOverrideOnReadonlyLineEdit_data() |
| 4780 | { |
| 4781 | QTest::addColumn<QKeySequence>(name: "keySequence" ); |
| 4782 | QTest::addColumn<bool>(name: "shouldBeHandledByQLineEdit" ); |
| 4783 | |
| 4784 | QTest::newRow(dataTag: "Copy" ) << QKeySequence(QKeySequence::Copy) << true; |
| 4785 | QTest::newRow(dataTag: "MoveToNextChar" ) << QKeySequence(QKeySequence::MoveToNextChar) << true; |
| 4786 | QTest::newRow(dataTag: "SelectAll" ) << QKeySequence(QKeySequence::SelectAll) << true; |
| 4787 | QTest::newRow(dataTag: "Right press" ) << QKeySequence(Qt::Key_Right) << true; |
| 4788 | QTest::newRow(dataTag: "Left press" ) << QKeySequence(Qt::Key_Left) << true; |
| 4789 | |
| 4790 | QTest::newRow(dataTag: "Paste" ) << QKeySequence(QKeySequence::Paste) << false; |
| 4791 | QTest::newRow(dataTag: "Paste" ) << QKeySequence(QKeySequence::Cut) << false; |
| 4792 | QTest::newRow(dataTag: "Undo" ) << QKeySequence(QKeySequence::Undo) << false; |
| 4793 | QTest::newRow(dataTag: "Redo" ) << QKeySequence(QKeySequence::Redo) << false; |
| 4794 | |
| 4795 | QTest::newRow(dataTag: "a" ) << QKeySequence(Qt::Key_A) << false; |
| 4796 | QTest::newRow(dataTag: "b" ) << QKeySequence(Qt::Key_B) << false; |
| 4797 | QTest::newRow(dataTag: "c" ) << QKeySequence(Qt::Key_C) << false; |
| 4798 | QTest::newRow(dataTag: "x" ) << QKeySequence(Qt::Key_X) << false; |
| 4799 | QTest::newRow(dataTag: "X" ) << QKeySequence(Qt::ShiftModifier + Qt::Key_X) << false; |
| 4800 | |
| 4801 | QTest::newRow(dataTag: "Alt+Home" ) << QKeySequence(Qt::AltModifier + Qt::Key_Home) << false; |
| 4802 | } |
| 4803 | |
| 4804 | void tst_QLineEdit::shortcutOverrideOnReadonlyLineEdit() |
| 4805 | { |
| 4806 | if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) |
| 4807 | QSKIP("Wayland: This fails. Figure out why." ); |
| 4808 | |
| 4809 | QFETCH(QKeySequence, keySequence); |
| 4810 | QFETCH(bool, shouldBeHandledByQLineEdit); |
| 4811 | |
| 4812 | QWidget widget; |
| 4813 | |
| 4814 | QShortcut *shortcut = new QShortcut(keySequence, &widget); |
| 4815 | QSignalSpy spy(shortcut, &QShortcut::activated); |
| 4816 | QVERIFY(spy.isValid()); |
| 4817 | |
| 4818 | QLineEdit *lineEdit = new QLineEdit(QStringLiteral("Test" ), &widget); |
| 4819 | lineEdit->setReadOnly(true); |
| 4820 | lineEdit->setFocus(); |
| 4821 | |
| 4822 | widget.show(); |
| 4823 | |
| 4824 | QVERIFY(QTest::qWaitForWindowActive(&widget)); |
| 4825 | |
| 4826 | const int keySequenceCount = keySequence.count(); |
| 4827 | for (int i = 0; i < keySequenceCount; ++i) { |
| 4828 | const uint key = keySequence[i]; |
| 4829 | QTest::keyClick(widget: lineEdit, |
| 4830 | key: Qt::Key(key & ~Qt::KeyboardModifierMask), |
| 4831 | modifier: Qt::KeyboardModifier(key & Qt::KeyboardModifierMask)); |
| 4832 | } |
| 4833 | |
| 4834 | const int activationCount = shouldBeHandledByQLineEdit ? 0 : 1; |
| 4835 | QCOMPARE(spy.count(), activationCount); |
| 4836 | } |
| 4837 | |
| 4838 | void tst_QLineEdit::QTBUG59957_clearButtonLeftmostAction() |
| 4839 | { |
| 4840 | #ifndef QT_BUILD_INTERNAL |
| 4841 | QSKIP("This test requires a developer build" ); |
| 4842 | #else |
| 4843 | QLineEdit lineEdit; |
| 4844 | lineEdit.setClearButtonEnabled(true); |
| 4845 | |
| 4846 | auto clearButton = lineEdit.findChild<QLineEditIconButton *>(); |
| 4847 | QVERIFY(clearButton); |
| 4848 | |
| 4849 | QPixmap pixmap(16, 16); |
| 4850 | lineEdit.addAction(icon: QIcon(pixmap), position: QLineEdit::TrailingPosition); |
| 4851 | lineEdit.addAction(icon: QIcon(pixmap), position: QLineEdit::TrailingPosition); |
| 4852 | |
| 4853 | lineEdit.show(); |
| 4854 | |
| 4855 | const auto buttons = lineEdit.findChildren<QLineEditIconButton *>(); |
| 4856 | for (const auto button : buttons) { |
| 4857 | if (button == clearButton) |
| 4858 | continue; |
| 4859 | QVERIFY(clearButton->x() < button->x()); |
| 4860 | } |
| 4861 | #endif // QT_BUILD_INTERNAL |
| 4862 | } |
| 4863 | |
| 4864 | bool tst_QLineEdit::unselectingWithLeftOrRightChangesCursorPosition() |
| 4865 | { |
| 4866 | #if defined Q_OS_WIN || defined Q_OS_QNX //Windows and QNX do not jump to the beginning of the selection |
| 4867 | return true; |
| 4868 | #endif |
| 4869 | // Platforms minimal/offscreen also need left after unselecting with right |
| 4870 | if (!QGuiApplication::platformName().compare(s: "minimal" , cs: Qt::CaseInsensitive) |
| 4871 | || !QGuiApplication::platformName().compare(s: "offscreen" , cs: Qt::CaseInsensitive)) { |
| 4872 | return true; |
| 4873 | } |
| 4874 | |
| 4875 | // Selection is cleared ands cursor remains at previous position. |
| 4876 | // X11 used to behave like window prior to 4.2. Changes caused by QKeySequence |
| 4877 | // resulted in an inadvertant change in behavior |
| 4878 | return false; |
| 4879 | } |
| 4880 | |
| 4881 | void tst_QLineEdit::QTBUG_60319_setInputMaskCheckImSurroundingText() |
| 4882 | { |
| 4883 | QLineEdit *testWidget = ensureTestWidget(); |
| 4884 | QString mask("+000(000)-000-00-00" ); |
| 4885 | testWidget->setInputMask(mask); |
| 4886 | testWidget->setCursorPosition(mask.length()); |
| 4887 | QString surroundingText = testWidget->inputMethodQuery(Qt::ImSurroundingText).toString(); |
| 4888 | int cursorPosition = testWidget->inputMethodQuery(Qt::ImCursorPosition).toInt(); |
| 4889 | QCOMPARE(surroundingText.length(), cursorPosition); |
| 4890 | } |
| 4891 | |
| 4892 | void tst_QLineEdit::testQuickSelectionWithMouse() |
| 4893 | { |
| 4894 | const auto text = QStringLiteral("This is quite a long line of text." ); |
| 4895 | const auto prefix = QStringLiteral("Th" ); |
| 4896 | const auto suffix = QStringLiteral("t." ); |
| 4897 | QVERIFY(text.startsWith(prefix)); |
| 4898 | QVERIFY(text.endsWith(suffix)); |
| 4899 | |
| 4900 | QLineEdit lineEdit; |
| 4901 | lineEdit.setText(text); |
| 4902 | lineEdit.show(); |
| 4903 | |
| 4904 | const QPoint center = lineEdit.contentsRect().center(); |
| 4905 | |
| 4906 | // Normal mouse selection from left to right, y doesn't change. |
| 4907 | QTest::mousePress(window: lineEdit.windowHandle(), button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: center); |
| 4908 | QTest::mouseMove(window: lineEdit.windowHandle(), pos: center + QPoint(20, 0)); |
| 4909 | qCDebug(lcTests) << "Selected text:" << lineEdit.selectedText(); |
| 4910 | #ifdef Q_OS_WINRT |
| 4911 | QEXPECT_FAIL("" , "WinRT does not support QTest::mousePress/-Move" , Abort); |
| 4912 | #endif |
| 4913 | QVERIFY(!lineEdit.selectedText().isEmpty()); |
| 4914 | QVERIFY(!lineEdit.selectedText().endsWith(suffix)); |
| 4915 | |
| 4916 | // Normal mouse selection from left to right, y change is below threshold. |
| 4917 | QTest::mousePress(window: lineEdit.windowHandle(), button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: center); |
| 4918 | QTest::mouseMove(window: lineEdit.windowHandle(), pos: center + QPoint(20, 5)); |
| 4919 | qCDebug(lcTests) << "Selected text:" << lineEdit.selectedText(); |
| 4920 | QVERIFY(!lineEdit.selectedText().isEmpty()); |
| 4921 | QVERIFY(!lineEdit.selectedText().endsWith(suffix)); |
| 4922 | |
| 4923 | // Normal mouse selection from right to left, y doesn't change. |
| 4924 | QTest::mousePress(window: lineEdit.windowHandle(), button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: center); |
| 4925 | QTest::mouseMove(window: lineEdit.windowHandle(), pos: center + QPoint(-20, 0)); |
| 4926 | qCDebug(lcTests) << "Selected text:" << lineEdit.selectedText(); |
| 4927 | QVERIFY(!lineEdit.selectedText().isEmpty()); |
| 4928 | QVERIFY(!lineEdit.selectedText().startsWith(prefix)); |
| 4929 | |
| 4930 | // Normal mouse selection from right to left, y change is below threshold. |
| 4931 | QTest::mousePress(window: lineEdit.windowHandle(), button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: center); |
| 4932 | QTest::mouseMove(window: lineEdit.windowHandle(), pos: center + QPoint(-20, -5)); |
| 4933 | qCDebug(lcTests) << "Selected text:" << lineEdit.selectedText(); |
| 4934 | QVERIFY(!lineEdit.selectedText().isEmpty()); |
| 4935 | QVERIFY(!lineEdit.selectedText().startsWith(prefix)); |
| 4936 | |
| 4937 | const int offset = QGuiApplication::styleHints()->mouseQuickSelectionThreshold() + 1; |
| 4938 | |
| 4939 | // Select the whole right half. |
| 4940 | QTest::mousePress(window: lineEdit.windowHandle(), button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: center); |
| 4941 | QTest::mouseMove(window: lineEdit.windowHandle(), pos: center + QPoint(1, offset)); |
| 4942 | qCDebug(lcTests) << "Selected text:" << lineEdit.selectedText(); |
| 4943 | QVERIFY(lineEdit.selectedText().endsWith(suffix)); |
| 4944 | |
| 4945 | // Select the whole left half. |
| 4946 | QTest::mousePress(window: lineEdit.windowHandle(), button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: center); |
| 4947 | QTest::mouseMove(window: lineEdit.windowHandle(), pos: center + QPoint(1, -offset)); |
| 4948 | qCDebug(lcTests) << "Selected text:" << lineEdit.selectedText(); |
| 4949 | QVERIFY(lineEdit.selectedText().startsWith(prefix)); |
| 4950 | |
| 4951 | // Normal selection -> quick selection -> back to normal selection. |
| 4952 | QTest::mousePress(window: lineEdit.windowHandle(), button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: center); |
| 4953 | QTest::mouseMove(window: lineEdit.windowHandle(), pos: center + QPoint(20, 0)); |
| 4954 | const auto partialSelection = lineEdit.selectedText(); |
| 4955 | qCDebug(lcTests) << "Selected text:" << lineEdit.selectedText(); |
| 4956 | QVERIFY(!partialSelection.endsWith(suffix)); |
| 4957 | QTest::mouseMove(window: lineEdit.windowHandle(), pos: center + QPoint(20, offset)); |
| 4958 | qCDebug(lcTests) << "Selected text:" << lineEdit.selectedText(); |
| 4959 | QVERIFY(lineEdit.selectedText().endsWith(suffix)); |
| 4960 | QTest::mouseMove(window: lineEdit.windowHandle(), pos: center + QPoint(20, 0)); |
| 4961 | qCDebug(lcTests) << "Selected text:" << lineEdit.selectedText(); |
| 4962 | #if defined(Q_PROCESSOR_ARM) && !defined(Q_OS_MACOS) |
| 4963 | QEXPECT_FAIL("" , "Currently fails on gcc-armv7, needs investigation." , Continue); |
| 4964 | #endif |
| 4965 | QCOMPARE(lineEdit.selectedText(), partialSelection); |
| 4966 | |
| 4967 | lineEdit.setLayoutDirection(Qt::RightToLeft); |
| 4968 | |
| 4969 | // Select the whole left half (RTL layout). |
| 4970 | QTest::mousePress(window: lineEdit.windowHandle(), button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: center); |
| 4971 | QTest::mouseMove(window: lineEdit.windowHandle(), pos: center + QPoint(1, offset)); |
| 4972 | QVERIFY(lineEdit.selectedText().startsWith(prefix)); |
| 4973 | |
| 4974 | // Select the whole right half (RTL layout). |
| 4975 | QTest::mousePress(window: lineEdit.windowHandle(), button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: center); |
| 4976 | QTest::mouseMove(window: lineEdit.windowHandle(), pos: center + QPoint(1, -offset)); |
| 4977 | QVERIFY(lineEdit.selectedText().endsWith(suffix)); |
| 4978 | } |
| 4979 | |
| 4980 | void tst_QLineEdit::inputRejected() |
| 4981 | { |
| 4982 | if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) |
| 4983 | QSKIP("Wayland: This fails. Figure out why." ); |
| 4984 | |
| 4985 | QLineEdit *testWidget = ensureTestWidget(); |
| 4986 | QSignalSpy spyInputRejected(testWidget, SIGNAL(inputRejected())); |
| 4987 | |
| 4988 | QTest::keyClicks(widget: testWidget, sequence: "abcde" ); |
| 4989 | QCOMPARE(spyInputRejected.count(), 0); |
| 4990 | testWidget->setText("fghij" ); |
| 4991 | QCOMPARE(spyInputRejected.count(), 0); |
| 4992 | testWidget->insert("k" ); |
| 4993 | QCOMPARE(spyInputRejected.count(), 0); |
| 4994 | |
| 4995 | testWidget->clear(); |
| 4996 | testWidget->setMaxLength(5); |
| 4997 | QTest::keyClicks(widget: testWidget, sequence: "abcde" ); |
| 4998 | QCOMPARE(spyInputRejected.count(), 0); |
| 4999 | QTest::keyClicks(widget: testWidget, sequence: "fgh" ); |
| 5000 | QCOMPARE(spyInputRejected.count(), 3); |
| 5001 | #if QT_CONFIG(clipboard) |
| 5002 | testWidget->clear(); |
| 5003 | spyInputRejected.clear(); |
| 5004 | QApplication::clipboard()->setText("ijklmno" ); |
| 5005 | testWidget->paste(); |
| 5006 | // The first 5 characters are accepted, but |
| 5007 | // the last 2 are not. |
| 5008 | QCOMPARE(spyInputRejected.count(), 1); |
| 5009 | #endif |
| 5010 | |
| 5011 | testWidget->setMaxLength(INT_MAX); |
| 5012 | testWidget->clear(); |
| 5013 | spyInputRejected.clear(); |
| 5014 | QIntValidator intValidator(1, 100); |
| 5015 | testWidget->setValidator(&intValidator); |
| 5016 | QTest::keyClicks(widget: testWidget, sequence: "11" ); |
| 5017 | QCOMPARE(spyInputRejected.count(), 0); |
| 5018 | QTest::keyClicks(widget: testWidget, sequence: "a#" ); |
| 5019 | QCOMPARE(spyInputRejected.count(), 2); |
| 5020 | #if QT_CONFIG(clipboard) |
| 5021 | testWidget->clear(); |
| 5022 | spyInputRejected.clear(); |
| 5023 | QApplication::clipboard()->setText("a#" ); |
| 5024 | testWidget->paste(); |
| 5025 | QCOMPARE(spyInputRejected.count(), 1); |
| 5026 | #endif |
| 5027 | |
| 5028 | testWidget->clear(); |
| 5029 | testWidget->setValidator(0); |
| 5030 | spyInputRejected.clear(); |
| 5031 | testWidget->setInputMask("999.999.999.999;_" ); |
| 5032 | QTest::keyClicks(widget: testWidget, sequence: "11" ); |
| 5033 | QCOMPARE(spyInputRejected.count(), 0); |
| 5034 | QTest::keyClicks(widget: testWidget, sequence: "a#" ); |
| 5035 | QCOMPARE(spyInputRejected.count(), 2); |
| 5036 | } |
| 5037 | |
| 5038 | QTEST_MAIN(tst_QLineEdit) |
| 5039 | #include "tst_qlineedit.moc" |
| 5040 | |