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
70Q_LOGGING_CATEGORY(lcTests, "qt.widgets.tests")
71
72QT_BEGIN_NAMESPACE
73class QPainter;
74QT_END_NAMESPACE
75
76using namespace QTestPrivate;
77
78class StyleOptionTestStyle : public QCommonStyle
79{
80public:
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
108class tst_QLineEdit : public QObject
109{
110Q_OBJECT
111
112public:
113 enum EventStates { Press, Release, Click };
114
115 tst_QLineEdit();
116
117private 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();
307protected 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
316private:
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
337typedef QList<int> IntList;
338Q_DECLARE_METATYPE(QLineEdit::EchoMode)
339
340// Testing get/set functions
341void 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
361tst_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
373QLineEdit *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
389void 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
399void tst_QLineEdit::cleanupTestCase()
400{
401 QInputMethodPrivate *inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod());
402 inputMethodPrivate->testContext = 0;
403}
404
405void tst_QLineEdit::init()
406{
407 return_count = 0;
408}
409
410void tst_QLineEdit::cleanup()
411{
412 delete m_testWidget;
413 m_testWidget = 0;
414 m_platformInputContext.m_commitString.clear();
415}
416
417void 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
435void 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
444void 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
647void 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
675void 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
698void 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
708void 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
717void 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
795void 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
810void 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
842void 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
861void 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
890static const int chars = 8;
891class ValidatorWithFixup : public QValidator
892{
893public:
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
917void 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
936void 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
964void 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
986void 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
1113void 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
1178void 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
1207void 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
1257void 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
1479void 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
1495void 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
1529void 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
1552void tst_QLineEdit::editingFinished()
1553{
1554 if (m_testWidget->hasAcceptableInput())
1555 validInput = true;
1556 else
1557 validInput = false;
1558}
1559
1560void 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
1573void tst_QLineEdit::text()
1574{
1575 QFETCH(QString, insertString);
1576 QLineEdit *testWidget = ensureTestWidget();
1577 testWidget->setText(insertString);
1578 QCOMPARE(testWidget->text(), insertString);
1579}
1580
1581void tst_QLineEdit::textMask_data()
1582{
1583 QTest::addColumn<QString>(name: "insertString");
1584
1585 QTest::newRow( dataTag: "Plain text1" ) << QString( "" );
1586}
1587
1588void 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
1597void 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
1607void 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
1694void 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
1708void 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
1745void 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
1812void 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
1823void 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
1834void 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
1852void 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
1891void 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
1919class BlinkTestLineEdit : public QLineEdit
1920{
1921public:
1922 void paintEvent(QPaintEvent *e)
1923 {
1924 ++updates;
1925 QLineEdit::paintEvent(e);
1926 }
1927
1928 int updates;
1929};
1930
1931void 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
1959static 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
1981void 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
1987void 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
1993void 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
2000void 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
2072void tst_QLineEdit::cursorLeft()
2073void tst_QLineEdit::cursorRight()
2074void tst_QLineEdit::cursorForward()
2075void tst_QLineEdit::cursorBackward()
2076void tst_QLineEdit::cursorWordForward()
2077void tst_QLineEdit::cursorWordBackward()
2078void tst_QLineEdit::home()
2079void tst_QLineEdit::end()
2080*/
2081
2082void 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
2213void 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
2227void 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
2259void tst_QLineEdit::backspace()
2260void tst_QLineEdit::del()
2261void tst_QLineEdit::selectionChanged()
2262void tst_QLineEdit::selectAll()
2263void tst_QLineEdit::deselect()
2264*/
2265
2266void tst_QLineEdit::onSelectionChanged()
2267{
2268 selection_count++;
2269}
2270
2271void 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 *menu = 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
2298class ToUpperValidator : public QValidator
2299{
2300public:
2301 ToUpperValidator() {}
2302 State validate(QString &input, int &) const override
2303 {
2304 input = input.toUpper();
2305 return QValidator::Acceptable;
2306 }
2307};
2308
2309void 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
2368void tst_QLineEdit::onTextChanged(const QString &text)
2369{
2370 changed_count++;
2371 changed_string = text;
2372}
2373
2374void tst_QLineEdit::onTextEdited(const QString &/*text*/)
2375{
2376 edited_count++;
2377}
2378
2379
2380void tst_QLineEdit::onCursorPositionChanged(int oldPos, int newPos)
2381{
2382 lastCursorPos = oldPos;
2383 newCursorPos = newPos;
2384}
2385
2386void 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'
2416class QIntFixValidator : public QIntValidator {
2417public:
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
2427void 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
2530void 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
2552void tst_QLineEdit::onReturnPressed()
2553{
2554 return_count++;
2555}
2556
2557void 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
2578void 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
2722void 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
2755void 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
2769void 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
2791void 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
2807void 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
2847void 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
2882void 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
2914void 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
2937void 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
2957static inline QByteArray selectionTestName(int start, int length)
2958{
2959 return "selection start: " + QByteArray::number(start) + " length: " + QByteArray::number(length);
2960}
2961
2962void 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
3012void 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
3031void 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
3099void 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
3133class InputMaskValidator : public QValidator
3134{
3135public:
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
3148void 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
3162void 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
3180void 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
3202class LineEdit : public QLineEdit
3203{
3204public:
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
3228Q_DECLARE_METATYPE(LineEdit::State);
3229void 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
3247void 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
3265void 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
3291void 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
3319void 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
3347Q_DECLARE_METATYPE(Qt::KeyboardModifiers)
3348
3349void 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
3364void 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
3378void 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
3398void 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
3485void 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
3494void 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
3528void 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
3587void 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
3599class task180999_Widget : public QWidget
3600{
3601public:
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
3615void 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
3637void 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 *testMenu1 = 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 *testMenu2 = 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)
3703class task198789_Widget : public QWidget
3704{
3705 Q_OBJECT
3706public:
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
3723private slots:
3724 void textChanged(const QString &)
3725 {
3726 currentCompletion = completer->currentCompletion();
3727 }
3728};
3729
3730void 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
3741void 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
3767void 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
3784void 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
3820void 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
3841void 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
3878void 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
3891void 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
3912void 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
3928void 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
3950void tst_QLineEdit::taskQTBUG_7902_contextMenuCrash()
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
3969void 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
3994void 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
4026void 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
4041class UpdateRegionLineEdit : public QLineEdit
4042{
4043public:
4044 QRegion updateRegion;
4045protected:
4046 void paintEvent(QPaintEvent *event)
4047 {
4048 updateRegion = event->region();
4049 }
4050};
4051
4052void 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
4069void 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
4081void 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
4121void 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
4165void tst_QLineEdit::bidiLogicalMovement_data()
4166{
4167 bidiVisualMovement_data();
4168}
4169
4170void 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
4214void 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
4225void 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
4266void 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
4314Q_DECLARE_METATYPE(Qt::InputMethodHints)
4315void 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
4324void 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
4334void 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
4388void 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
4417void 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
4451void 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
4505void 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
4553static 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
4560void 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
4594template <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
4603void 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*/
4654void 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
4715Q_DECLARE_METATYPE(Qt::AlignmentFlag)
4716void 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
4739void 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
4769void 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
4779void 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
4804void 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
4838void 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
4864bool 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
4881void 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
4892void 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
4980void 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
5038QTEST_MAIN(tst_QLineEdit)
5039#include "tst_qlineedit.moc"
5040

source code of qtbase/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp