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