/
tst_qquicktextinput.cpp
4791 lines (4124 loc) · 181 KB
1
2
/****************************************************************************
**
3
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4
** Contact: http://www.qt-project.org/
5
6
7
8
9
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
10
11
12
13
14
15
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16
17
**
** In addition, as a special exception, Nokia gives you certain additional
18
** rights. These rights are described in the Nokia Qt LGPL Exception
19
20
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
21
22
23
24
25
26
27
28
29
30
31
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
32
33
34
35
36
**
**
**
**
**
38
39
40
41
42
** $QT_END_LICENSE$
**
****************************************************************************/
#include <qtest.h>
#include <QtTest/QSignalSpy>
43
#include "../../shared/util.h"
44
#include <private/qinputmethod_p.h>
45
46
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlexpression.h>
47
#include <QFile>
48
#include <QtQuick/qquickview.h>
49
#include <QtGui/qguiapplication.h>
50
#include <QtGui/qstylehints.h>
51
#include <QInputMethod>
52
53
#include <private/qquicktextinput_p.h>
#include <private/qquicktextinput_p_p.h>
54
55
#include <QDebug>
#include <QDir>
56
#include <math.h>
58
59
60
61
#ifdef Q_OS_MAC
#include <Carbon/Carbon.h>
#endif
62
#include "qplatformdefs.h"
63
#include "../../shared/platforminputcontext.h"
65
Q_DECLARE_METATYPE(QQuickTextInput::SelectionMode)
66
67
68
Q_DECLARE_METATYPE(QQuickTextInput::EchoMode)
Q_DECLARE_METATYPE(Qt::Key)
69
DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
70
71
72
73
QString createExpectedFileIfNotFound(const QString& filebasename, const QImage& actual)
{
// XXX This will be replaced by some clever persistent platform image store.
74
QString persistent_dir = QQmlDataTest::instance()->dataDirectory();
75
76
77
78
79
80
81
82
83
84
85
86
QString arch = "unknown-architecture"; // QTest needs to help with this.
QString expectfile = persistent_dir + QDir::separator() + filebasename + "-" + arch + ".png";
if (!QFile::exists(expectfile)) {
actual.save(expectfile);
qWarning() << "created" << expectfile;
}
return expectfile;
}
87
88
template <typename T> static T evaluate(QObject *scope, const QString &expression)
{
89
QQmlExpression expr(qmlContext(scope), scope, expression);
90
91
92
93
94
95
T result = expr.evaluate().value<T>();
if (expr.hasError())
qWarning() << expr.error().toString();
return result;
}
96
97
typedef QPair<int, QChar> Key;
98
class tst_qquicktextinput : public QQmlDataTest
99
100
101
102
{
Q_OBJECT
public:
103
tst_qquicktextinput();
104
105
private slots:
106
void cleanup();
107
108
109
110
void text();
void width();
void font();
void color();
111
void wrap();
112
void selection();
113
void persistentSelection();
114
115
116
117
118
119
120
121
122
void isRightToLeft_data();
void isRightToLeft();
void moveCursorSelection_data();
void moveCursorSelection();
void moveCursorSelectionSequence_data();
void moveCursorSelectionSequence();
void dragMouseSelection();
void mouseSelectionMode_data();
void mouseSelectionMode();
123
void tripleClickSelectsAll();
124
125
126
127
void horizontalAlignment_data();
void horizontalAlignment();
void horizontalAlignment_RightToLeft();
128
void verticalAlignment();
130
131
void boundingRect();
132
133
134
135
136
137
138
139
void positionAt();
void maxLength();
void masks();
void validators();
void inputMethods();
void passwordCharacter();
140
void cursorDelegate_data();
141
142
143
144
145
146
void cursorDelegate();
void cursorVisible();
void cursorRectangle();
void navigation();
void navigation_RTL();
void copyAndPaste();
147
void copyAndPasteKeySequence();
148
149
150
151
void canPasteEmpty();
void canPaste();
void readOnly();
152
void openInputPanel();
153
154
155
156
void setHAlignClearCache();
void focusOutClearSelection();
void echoMode();
157
158
159
#ifdef QT_GUI_PASSWORD_ECHO_DELAY
void passwordEchoDelay();
#endif
160
void geometrySignals();
161
void contentSize();
162
163
void preeditAutoScroll();
164
void preeditCursorRectangle();
165
void inputContextMouseHandler();
166
void inputMethodComposing();
167
void inputMethodUpdate();
168
169
void cursorRectangleSize();
170
171
172
173
174
175
176
void getText_data();
void getText();
void insert_data();
void insert();
void remove_data();
void remove();
177
178
179
180
181
182
183
184
185
186
void keySequence_data();
void keySequence();
void undo_data();
void undo();
void redo_data();
void redo();
void undo_keypressevents_data();
void undo_keypressevents();
187
188
189
190
void QTBUG_19956();
void QTBUG_19956_data();
void QTBUG_19956_regexp();
191
192
void negativeDimensions();
193
private:
194
void simulateKey(QWindow *, int key);
196
197
198
void simulateKeys(QWindow *window, const QList<Key> &keys);
void simulateKeys(QWindow *window, const QKeySequence &sequence);
199
QQmlEngine engine;
200
201
202
QStringList standard;
QStringList colorStrings;
};
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
typedef QList<int> IntList;
Q_DECLARE_METATYPE(IntList)
typedef QList<Key> KeyList;
Q_DECLARE_METATYPE(KeyList)
void tst_qquicktextinput::simulateKeys(QWindow *window, const QList<Key> &keys)
{
for (int i = 0; i < keys.count(); ++i) {
const int key = keys.at(i).first;
const int modifiers = key & Qt::KeyboardModifierMask;
const QString text = !keys.at(i).second.isNull() ? QString(keys.at(i).second) : QString();
QKeyEvent press(QEvent::KeyPress, Qt::Key(key), Qt::KeyboardModifiers(modifiers), text);
QKeyEvent release(QEvent::KeyRelease, Qt::Key(key), Qt::KeyboardModifiers(modifiers), text);
QGuiApplication::sendEvent(window, &press);
QGuiApplication::sendEvent(window, &release);
}
}
void tst_qquicktextinput::simulateKeys(QWindow *window, const QKeySequence &sequence)
{
227
for (int i = 0; i < sequence.count(); ++i) {
228
229
230
231
232
233
234
235
236
const int key = sequence[i];
const int modifiers = key & Qt::KeyboardModifierMask;
QTest::keyClick(window, Qt::Key(key & ~modifiers), Qt::KeyboardModifiers(modifiers));
}
}
QList<Key> &operator <<(QList<Key> &keys, const QKeySequence &sequence)
{
237
for (int i = 0; i < sequence.count(); ++i)
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
keys << Key(sequence[i], QChar());
return keys;
}
template <int N> QList<Key> &operator <<(QList<Key> &keys, const char (&characters)[N])
{
for (int i = 0; i < N - 1; ++i) {
int key = QTest::asciiToKey(characters[i]);
QChar character = QLatin1Char(characters[i]);
keys << Key(key, character);
}
return keys;
}
QList<Key> &operator <<(QList<Key> &keys, Qt::Key key)
{
keys << Key(key, QChar());
return keys;
}
258
259
260
void tst_qquicktextinput::cleanup()
{
// ensure not even skipped tests with custom input context leave it dangling
261
262
QInputMethodPrivate *inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod());
inputMethodPrivate->testContext = 0;
265
tst_qquicktextinput::tst_qquicktextinput()
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
{
standard << "the quick brown fox jumped over the lazy dog"
<< "It's supercalifragisiticexpialidocious!"
<< "Hello, world!"
<< "!dlrow ,olleH"
<< " spacey text ";
colorStrings << "aliceblue"
<< "antiquewhite"
<< "aqua"
<< "darkkhaki"
<< "darkolivegreen"
<< "dimgray"
<< "palevioletred"
<< "lightsteelblue"
<< "#000000"
<< "#AAAAAA"
<< "#FFFFFF"
<< "#2AC05F";
}
287
void tst_qquicktextinput::text()
288
289
{
{
290
QQmlComponent textinputComponent(&engine);
291
textinputComponent.setData("import QtQuick 2.0\nTextInput { text: \"\" }", QUrl());
292
QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput*>(textinputComponent.create());
293
294
295
QVERIFY(textinputObject != 0);
QCOMPARE(textinputObject->text(), QString(""));
296
QCOMPARE(textinputObject->length(), 0);
297
298
299
300
301
302
303
delete textinputObject;
}
for (int i = 0; i < standard.size(); i++)
{
QString componentStr = "import QtQuick 2.0\nTextInput { text: \"" + standard.at(i) + "\" }";
304
QQmlComponent textinputComponent(&engine);
305
textinputComponent.setData(componentStr.toLatin1(), QUrl());
306
QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput*>(textinputComponent.create());
307
308
309
QVERIFY(textinputObject != 0);
QCOMPARE(textinputObject->text(), standard.at(i));
310
QCOMPARE(textinputObject->length(), standard.at(i).length());
311
312
313
314
315
316
delete textinputObject;
}
}
317
void tst_qquicktextinput::width()
318
319
320
{
// uses Font metrics to find the width for standard
{
321
QQmlComponent textinputComponent(&engine);
322
textinputComponent.setData("import QtQuick 2.0\nTextInput { text: \"\" }", QUrl());
323
QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput*>(textinputComponent.create());
324
325
326
327
328
329
330
QVERIFY(textinputObject != 0);
QCOMPARE(textinputObject->width(), 0.0);
delete textinputObject;
}
331
332
bool requiresUnhintedMetrics = !qmlDisableDistanceField();
333
334
335
for (int i = 0; i < standard.size(); i++)
{
QString componentStr = "import QtQuick 2.0\nTextInput { text: \"" + standard.at(i) + "\" }";
336
QQmlComponent textinputComponent(&engine);
337
textinputComponent.setData(componentStr.toLatin1(), QUrl());
338
QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput*>(textinputComponent.create());
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
QString s = standard.at(i);
s.replace(QLatin1Char('\n'), QChar::LineSeparator);
QTextLayout layout(s);
layout.setFont(textinputObject->font());
layout.setFlags(Qt::TextExpandTabs | Qt::TextShowMnemonic);
if (requiresUnhintedMetrics) {
QTextOption option;
option.setUseDesignMetrics(true);
layout.setTextOption(option);
}
layout.beginLayout();
forever {
QTextLine line = layout.createLine();
if (!line.isValid())
break;
}
layout.endLayout();
qreal metricWidth = ceil(layout.boundingRect().width());
363
364
365
366
367
368
369
370
QVERIFY(textinputObject != 0);
int delta = abs(int(int(textinputObject->width()) - metricWidth));
QVERIFY(delta <= 3.0); // As best as we can hope for cross-platform.
delete textinputObject;
}
}
371
void tst_qquicktextinput::font()
372
373
{
//test size, then bold, then italic, then family
375
QString componentStr = "import QtQuick 2.0\nTextInput { font.pointSize: 40; text: \"Hello World\" }";
376
QQmlComponent textinputComponent(&engine);
377
textinputComponent.setData(componentStr.toLatin1(), QUrl());
378
QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput*>(textinputComponent.create());
379
380
381
382
383
384
385
386
387
QVERIFY(textinputObject != 0);
QCOMPARE(textinputObject->font().pointSize(), 40);
QCOMPARE(textinputObject->font().bold(), false);
QCOMPARE(textinputObject->font().italic(), false);
delete textinputObject;
}
389
QString componentStr = "import QtQuick 2.0\nTextInput { font.bold: true; text: \"Hello World\" }";
390
QQmlComponent textinputComponent(&engine);
391
textinputComponent.setData(componentStr.toLatin1(), QUrl());
392
QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput*>(textinputComponent.create());
393
394
395
396
397
398
399
400
QVERIFY(textinputObject != 0);
QCOMPARE(textinputObject->font().bold(), true);
QCOMPARE(textinputObject->font().italic(), false);
delete textinputObject;
}
402
QString componentStr = "import QtQuick 2.0\nTextInput { font.italic: true; text: \"Hello World\" }";
403
QQmlComponent textinputComponent(&engine);
404
textinputComponent.setData(componentStr.toLatin1(), QUrl());
405
QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput*>(textinputComponent.create());
406
407
408
409
410
411
412
QVERIFY(textinputObject != 0);
QCOMPARE(textinputObject->font().italic(), true);
QCOMPARE(textinputObject->font().bold(), false);
delete textinputObject;
}
413
414
{
415
QString componentStr = "import QtQuick 2.0\nTextInput { font.family: \"Helvetica\"; text: \"Hello World\" }";
416
QQmlComponent textinputComponent(&engine);
417
textinputComponent.setData(componentStr.toLatin1(), QUrl());
418
QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput*>(textinputComponent.create());
419
420
421
422
423
424
425
426
427
QVERIFY(textinputObject != 0);
QCOMPARE(textinputObject->font().family(), QString("Helvetica"));
QCOMPARE(textinputObject->font().bold(), false);
QCOMPARE(textinputObject->font().italic(), false);
delete textinputObject;
}
429
QString componentStr = "import QtQuick 2.0\nTextInput { font.family: \"\"; text: \"Hello World\" }";
430
QQmlComponent textinputComponent(&engine);
431
textinputComponent.setData(componentStr.toLatin1(), QUrl());
432
QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput*>(textinputComponent.create());
433
434
435
436
437
438
439
440
QVERIFY(textinputObject != 0);
QCOMPARE(textinputObject->font().family(), QString(""));
delete textinputObject;
}
}
441
void tst_qquicktextinput::color()
442
443
444
{
//test color
for (int i = 0; i < colorStrings.size(); i++)
446
QString componentStr = "import QtQuick 2.0\nTextInput { color: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
447
QQmlComponent textinputComponent(&engine);
448
textinputComponent.setData(componentStr.toLatin1(), QUrl());
449
QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput*>(textinputComponent.create());
450
451
452
453
454
455
456
457
458
459
QVERIFY(textinputObject != 0);
QCOMPARE(textinputObject->color(), QColor(colorStrings.at(i)));
delete textinputObject;
}
//test selection color
for (int i = 0; i < colorStrings.size(); i++)
{
QString componentStr = "import QtQuick 2.0\nTextInput { selectionColor: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
460
QQmlComponent textinputComponent(&engine);
461
textinputComponent.setData(componentStr.toLatin1(), QUrl());
462
QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput*>(textinputComponent.create());
463
464
465
466
467
468
469
470
QVERIFY(textinputObject != 0);
QCOMPARE(textinputObject->selectionColor(), QColor(colorStrings.at(i)));
delete textinputObject;
}
//test selected text color
for (int i = 0; i < colorStrings.size(); i++)
472
QString componentStr = "import QtQuick 2.0\nTextInput { selectedTextColor: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
473
QQmlComponent textinputComponent(&engine);
474
textinputComponent.setData(componentStr.toLatin1(), QUrl());
475
QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput*>(textinputComponent.create());
476
477
478
479
480
481
482
483
484
485
486
487
QVERIFY(textinputObject != 0);
QCOMPARE(textinputObject->selectedTextColor(), QColor(colorStrings.at(i)));
delete textinputObject;
}
{
QString colorStr = "#AA001234";
QColor testColor("#001234");
testColor.setAlpha(170);
QString componentStr = "import QtQuick 2.0\nTextInput { color: \"" + colorStr + "\"; text: \"Hello World\" }";
488
QQmlComponent textinputComponent(&engine);
489
textinputComponent.setData(componentStr.toLatin1(), QUrl());
490
QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput*>(textinputComponent.create());
491
492
493
494
495
496
497
498
QVERIFY(textinputObject != 0);
QCOMPARE(textinputObject->color(), testColor);
delete textinputObject;
}
}
499
500
501
502
503
void tst_qquicktextinput::wrap()
{
int textHeight = 0;
// for specified width and wrap set true
{
504
QQmlComponent textComponent(&engine);
505
506
507
508
509
510
511
512
513
514
515
516
517
textComponent.setData("import QtQuick 2.0\nTextInput { text: \"Hello\"; wrapMode: Text.WrapAnywhere; width: 300 }", QUrl::fromLocalFile(""));
QQuickTextInput *textObject = qobject_cast<QQuickTextInput*>(textComponent.create());
textHeight = textObject->height();
QVERIFY(textObject != 0);
QVERIFY(textObject->wrapMode() == QQuickTextInput::WrapAnywhere);
QCOMPARE(textObject->width(), 300.);
delete textObject;
}
for (int i = 0; i < standard.count(); i++) {
QString componentStr = "import QtQuick 2.0\nTextInput { wrapMode: Text.WrapAnywhere; width: 30; text: \"" + standard.at(i) + "\" }";
518
QQmlComponent textComponent(&engine);
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickTextInput *textObject = qobject_cast<QQuickTextInput*>(textComponent.create());
QVERIFY(textObject != 0);
QCOMPARE(textObject->width(), 30.);
QVERIFY(textObject->height() > textHeight);
int oldHeight = textObject->height();
textObject->setWidth(100);
QVERIFY(textObject->height() < oldHeight);
delete textObject;
}
}
534
void tst_qquicktextinput::selection()
535
536
537
{
QString testStr = standard[0];
QString componentStr = "import QtQuick 2.0\nTextInput { text: \""+ testStr +"\"; }";
538
QQmlComponent textinputComponent(&engine);
539
textinputComponent.setData(componentStr.toLatin1(), QUrl());
540
QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput*>(textinputComponent.create());
541
542
543
544
QVERIFY(textinputObject != 0);
//Test selection follows cursor
545
for (int i=0; i<= testStr.size(); i++) {
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
textinputObject->setCursorPosition(i);
QCOMPARE(textinputObject->cursorPosition(), i);
QCOMPARE(textinputObject->selectionStart(), i);
QCOMPARE(textinputObject->selectionEnd(), i);
QVERIFY(textinputObject->selectedText().isNull());
}
textinputObject->setCursorPosition(0);
QVERIFY(textinputObject->cursorPosition() == 0);
QVERIFY(textinputObject->selectionStart() == 0);
QVERIFY(textinputObject->selectionEnd() == 0);
QVERIFY(textinputObject->selectedText().isNull());
// Verify invalid positions are ignored.
textinputObject->setCursorPosition(-1);
QVERIFY(textinputObject->cursorPosition() == 0);
QVERIFY(textinputObject->selectionStart() == 0);
QVERIFY(textinputObject->selectionEnd() == 0);
QVERIFY(textinputObject->selectedText().isNull());
textinputObject->setCursorPosition(textinputObject->text().count()+1);
QVERIFY(textinputObject->cursorPosition() == 0);
QVERIFY(textinputObject->selectionStart() == 0);
QVERIFY(textinputObject->selectionEnd() == 0);
QVERIFY(textinputObject->selectedText().isNull());
//Test selection
573
for (int i=0; i<= testStr.size(); i++) {
574
575
576
textinputObject->select(0,i);
QCOMPARE(testStr.mid(0,i), textinputObject->selectedText());
}
577
for (int i=0; i<= testStr.size(); i++) {
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
textinputObject->select(i,testStr.size());
QCOMPARE(testStr.mid(i,testStr.size()-i), textinputObject->selectedText());
}
textinputObject->setCursorPosition(0);
QVERIFY(textinputObject->cursorPosition() == 0);
QVERIFY(textinputObject->selectionStart() == 0);
QVERIFY(textinputObject->selectionEnd() == 0);
QVERIFY(textinputObject->selectedText().isNull());
//Test Error Ignoring behaviour
textinputObject->setCursorPosition(0);
QVERIFY(textinputObject->selectedText().isNull());
textinputObject->select(-10,0);
QVERIFY(textinputObject->selectedText().isNull());
textinputObject->select(100,110);
QVERIFY(textinputObject->selectedText().isNull());
textinputObject->select(0,-10);
QVERIFY(textinputObject->selectedText().isNull());
textinputObject->select(0,100);
QVERIFY(textinputObject->selectedText().isNull());
textinputObject->select(0,10);
QVERIFY(textinputObject->selectedText().size() == 10);
textinputObject->select(-10,10);
QVERIFY(textinputObject->selectedText().size() == 10);
textinputObject->select(100,101);
QVERIFY(textinputObject->selectedText().size() == 10);
textinputObject->select(0,-10);
QVERIFY(textinputObject->selectedText().size() == 10);
textinputObject->select(0,100);
QVERIFY(textinputObject->selectedText().size() == 10);
textinputObject->deselect();
QVERIFY(textinputObject->selectedText().isNull());
textinputObject->select(0,10);
QVERIFY(textinputObject->selectedText().size() == 10);
textinputObject->deselect();
QVERIFY(textinputObject->selectedText().isNull());
617
618
619
620
621
622
623
// test input method selection
QSignalSpy selectionSpy(textinputObject, SIGNAL(selectedTextChanged()));
textinputObject->setFocus(true);
{
QList<QInputMethodEvent::Attribute> attributes;
attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 12, 5, QVariant());
QInputMethodEvent event("", attributes);
624
QGuiApplication::sendEvent(textinputObject, &event);
625
626
627
628
629
}
QCOMPARE(selectionSpy.count(), 1);
QCOMPARE(textinputObject->selectionStart(), 12);
QCOMPARE(textinputObject->selectionEnd(), 17);
630
631
632
delete textinputObject;
}
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
void tst_qquicktextinput::persistentSelection()
{
QQuickView canvas(testFileUrl("persistentSelection.qml"));
canvas.show();
canvas.requestActivateWindow();
QTest::qWaitForWindowShown(&canvas);
QTRY_COMPARE(&canvas, qGuiApp->focusWindow());
canvas.requestActivateWindow();
QQuickTextInput *input = qobject_cast<QQuickTextInput *>(canvas.rootObject());
QVERIFY(input);
QVERIFY(input->hasActiveFocus());
QSignalSpy spy(input, SIGNAL(persistentSelectionChanged()));
QCOMPARE(input->persistentSelection(), false);
input->setPersistentSelection(false);
QCOMPARE(input->persistentSelection(), false);
QCOMPARE(spy.count(), 0);
input->select(1, 4);
QCOMPARE(input->property("selected").toString(), QLatin1String("ell"));
input->setFocus(false);
QCOMPARE(input->property("selected").toString(), QString());
input->setFocus(true);
QCOMPARE(input->property("selected").toString(), QString());
input->setPersistentSelection(true);
QCOMPARE(input->persistentSelection(), true);
QCOMPARE(spy.count(), 1);
input->select(1, 4);
QCOMPARE(input->property("selected").toString(), QLatin1String("ell"));
input->setFocus(false);
QCOMPARE(input->property("selected").toString(), QLatin1String("ell"));
input->setFocus(true);
QCOMPARE(input->property("selected").toString(), QLatin1String("ell"));
}
677
void tst_qquicktextinput::isRightToLeft_data()
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
{
QTest::addColumn<QString>("text");
QTest::addColumn<bool>("emptyString");
QTest::addColumn<bool>("firstCharacter");
QTest::addColumn<bool>("lastCharacter");
QTest::addColumn<bool>("middleCharacter");
QTest::addColumn<bool>("startString");
QTest::addColumn<bool>("midString");
QTest::addColumn<bool>("endString");
const quint16 arabic_str[] = { 0x0638, 0x0643, 0x00646, 0x0647, 0x0633, 0x0638, 0x0643, 0x00646, 0x0647, 0x0633, 0x0647};
QTest::newRow("Empty") << "" << false << false << false << false << false << false << false;
QTest::newRow("Neutral") << "23244242" << false << false << false << false << false << false << false;
QTest::newRow("LTR") << "Hello world" << false << false << false << false << false << false << false;
QTest::newRow("RTL") << QString::fromUtf16(arabic_str, 11) << false << true << true << true << true << true << true;
QTest::newRow("Bidi RTL + LTR + RTL") << QString::fromUtf16(arabic_str, 11) + QString("Hello world") + QString::fromUtf16(arabic_str, 11) << false << true << true << false << true << true << true;
QTest::newRow("Bidi LTR + RTL + LTR") << QString("Hello world") + QString::fromUtf16(arabic_str, 11) + QString("Hello world") << false << false << false << true << false << false << false;
}
697
void tst_qquicktextinput::isRightToLeft()
698
699
700
701
702
703
704
705
706
707
{
QFETCH(QString, text);
QFETCH(bool, emptyString);
QFETCH(bool, firstCharacter);
QFETCH(bool, lastCharacter);
QFETCH(bool, middleCharacter);
QFETCH(bool, startString);
QFETCH(bool, midString);
QFETCH(bool, endString);
708
QQuickTextInput textInput;
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
textInput.setText(text);
// first test that the right string is delivered to the QString::isRightToLeft()
QCOMPARE(textInput.isRightToLeft(0,0), text.mid(0,0).isRightToLeft());
QCOMPARE(textInput.isRightToLeft(0,1), text.mid(0,1).isRightToLeft());
QCOMPARE(textInput.isRightToLeft(text.count()-2, text.count()-1), text.mid(text.count()-2, text.count()-1).isRightToLeft());
QCOMPARE(textInput.isRightToLeft(text.count()/2, text.count()/2 + 1), text.mid(text.count()/2, text.count()/2 + 1).isRightToLeft());
QCOMPARE(textInput.isRightToLeft(0,text.count()/4), text.mid(0,text.count()/4).isRightToLeft());
QCOMPARE(textInput.isRightToLeft(text.count()/4,3*text.count()/4), text.mid(text.count()/4,3*text.count()/4).isRightToLeft());
if (text.isEmpty())
QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML TextInput: isRightToLeft(start, end) called with the end property being smaller than the start.");
QCOMPARE(textInput.isRightToLeft(3*text.count()/4,text.count()-1), text.mid(3*text.count()/4,text.count()-1).isRightToLeft());
// then test that the feature actually works
QCOMPARE(textInput.isRightToLeft(0,0), emptyString);
QCOMPARE(textInput.isRightToLeft(0,1), firstCharacter);
QCOMPARE(textInput.isRightToLeft(text.count()-2, text.count()-1), lastCharacter);
QCOMPARE(textInput.isRightToLeft(text.count()/2, text.count()/2 + 1), middleCharacter);
QCOMPARE(textInput.isRightToLeft(0,text.count()/4), startString);
QCOMPARE(textInput.isRightToLeft(text.count()/4,3*text.count()/4), midString);
if (text.isEmpty())
QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML TextInput: isRightToLeft(start, end) called with the end property being smaller than the start.");
QCOMPARE(textInput.isRightToLeft(3*text.count()/4,text.count()-1), endString);
}
734
void tst_qquicktextinput::moveCursorSelection_data()
735
736
737
738
{
QTest::addColumn<QString>("testStr");
QTest::addColumn<int>("cursorPosition");
QTest::addColumn<int>("movePosition");
739
QTest::addColumn<QQuickTextInput::SelectionMode>("mode");
740
741
742
743
744
745
746
747
QTest::addColumn<int>("selectionStart");
QTest::addColumn<int>("selectionEnd");
QTest::addColumn<bool>("reversible");
// () contains the text selected by the cursor.
// <> contains the actual selection.
QTest::newRow("(t)he|characters")
748
<< standard[0] << 0 << 1 << QQuickTextInput::SelectCharacters << 0 << 1 << true;
749
QTest::newRow("do(g)|characters")
750
<< standard[0] << 43 << 44 << QQuickTextInput::SelectCharacters << 43 << 44 << true;
751
QTest::newRow("jum(p)ed|characters")
752
<< standard[0] << 23 << 24 << QQuickTextInput::SelectCharacters << 23 << 24 << true;
753
QTest::newRow("jumped( )over|characters")
754
<< standard[0] << 26 << 27 << QQuickTextInput::SelectCharacters << 26 << 27 << true;
755
QTest::newRow("(the )|characters")
756
<< standard[0] << 0 << 4 << QQuickTextInput::SelectCharacters << 0 << 4 << true;
757
QTest::newRow("( dog)|characters")
758
<< standard[0] << 40 << 44 << QQuickTextInput::SelectCharacters << 40 << 44 << true;
759
QTest::newRow("( jumped )|characters")
760
<< standard[0] << 19 << 27 << QQuickTextInput::SelectCharacters << 19 << 27 << true;
761
QTest::newRow("th(e qu)ick|characters")
762
<< standard[0] << 2 << 6 << QQuickTextInput::SelectCharacters << 2 << 6 << true;
763
QTest::newRow("la(zy d)og|characters")
764
<< standard[0] << 38 << 42 << QQuickTextInput::SelectCharacters << 38 << 42 << true;
765
QTest::newRow("jum(ped ov)er|characters")
766
<< standard[0] << 23 << 29 << QQuickTextInput::SelectCharacters << 23 << 29 << true;
767
QTest::newRow("()the|characters")
768
<< standard[0] << 0 << 0 << QQuickTextInput::SelectCharacters << 0 << 0 << true;
769
QTest::newRow("dog()|characters")
770
<< standard[0] << 44 << 44 << QQuickTextInput::SelectCharacters << 44 << 44 << true;
771
QTest::newRow("jum()ped|characters")
772
<< standard[0] << 23 << 23 << QQuickTextInput::SelectCharacters << 23 << 23 << true;
773
774
QTest::newRow("<(t)he>|words")
775
<< standard[0] << 0 << 1 << QQuickTextInput::SelectWords << 0 << 3 << true;
776
QTest::newRow("<do(g)>|words")
777
<< standard[0] << 43 << 44 << QQuickTextInput::SelectWords << 41 << 44 << true;
778
QTest::newRow("<jum(p)ed>|words")
779
<< standard[0] << 23 << 24 << QQuickTextInput::SelectWords << 20 << 26 << true;
780
QTest::newRow("<jumped( )>over|words,ltr")
781
<< standard[0] << 26 << 27 << QQuickTextInput::SelectWords << 20 << 27 << false;
782
QTest::newRow("jumped<( )over>|words,rtl")
783
<< standard[0] << 27 << 26 << QQuickTextInput::SelectWords << 26 << 31 << false;
784
QTest::newRow("<(the )>quick|words,ltr")
785
<< standard[0] << 0 << 4 << QQuickTextInput::SelectWords << 0 << 4 << false;
786
QTest::newRow("<(the )quick>|words,rtl")
787
<< standard[0] << 4 << 0 << QQuickTextInput::SelectWords << 0 << 9 << false;
788
QTest::newRow("<lazy( dog)>|words,ltr")
789
<< standard[0] << 40 << 44 << QQuickTextInput::SelectWords << 36 << 44 << false;
790
QTest::newRow("lazy<( dog)>|words,rtl")
791
<< standard[0] << 44 << 40 << QQuickTextInput::SelectWords << 40 << 44 << false;
792
QTest::newRow("<fox( jumped )>over|words,ltr")
793
<< standard[0] << 19 << 27 << QQuickTextInput::SelectWords << 16 << 27 << false;
794
QTest::newRow("fox<( jumped )over>|words,rtl")
795
<< standard[0] << 27 << 19 << QQuickTextInput::SelectWords << 19 << 31 << false;
796
QTest::newRow("<th(e qu)ick>|words")
797
<< standard[0] << 2 << 6 << QQuickTextInput::SelectWords << 0 << 9 << true;
798
QTest::newRow("<la(zy d)og|words>")
799
<< standard[0] << 38 << 42 << QQuickTextInput::SelectWords << 36 << 44 << true;
800
QTest::newRow("<jum(ped ov)er>|words")
801
<< standard[0] << 23 << 29 << QQuickTextInput::SelectWords << 20 << 31 << true;
802
QTest::newRow("<()>the|words")
803
<< standard[0] << 0 << 0 << QQuickTextInput::SelectWords << 0 << 0 << true;
804
QTest::newRow("dog<()>|words")
805
<< standard[0] << 44 << 44 << QQuickTextInput::SelectWords << 44 << 44 << true;
806
QTest::newRow("jum<()>ped|words")
807
<< standard[0] << 23 << 23 << QQuickTextInput::SelectWords << 23 << 23 << true;
808
809
QTest::newRow("Hello<(,)> |words")
810
<< standard[2] << 5 << 6 << QQuickTextInput::SelectWords << 5 << 6 << true;
811
QTest::newRow("Hello<(, )>world|words,ltr")
812
<< standard[2] << 5 << 7 << QQuickTextInput::SelectWords << 5 << 7 << false;
813
QTest::newRow("Hello<(, )world>|words,rtl")
814
<< standard[2] << 7 << 5 << QQuickTextInput::SelectWords << 5 << 12 << false;
815
QTest::newRow("<Hel(lo, )>world|words,ltr")
816
<< standard[2] << 3 << 7 << QQuickTextInput::SelectWords << 0 << 7 << false;
817
QTest::newRow("<Hel(lo, )world>|words,rtl")
818
<< standard[2] << 7 << 3 << QQuickTextInput::SelectWords << 0 << 12 << false;
819
QTest::newRow("<Hel(lo)>,|words")
820
<< standard[2] << 3 << 5 << QQuickTextInput::SelectWords << 0 << 5 << true;
821
QTest::newRow("Hello<()>,|words")
822
<< standard[2] << 5 << 5 << QQuickTextInput::SelectWords << 5 << 5 << true;
823
QTest::newRow("Hello,<()>|words")
824
<< standard[2] << 6 << 6 << QQuickTextInput::SelectWords << 6 << 6 << true;
825
QTest::newRow("Hello<,( )>world|words,ltr")
826
<< standard[2] << 6 << 7 << QQuickTextInput::SelectWords << 5 << 7 << false;
827
QTest::newRow("Hello,<( )world>|words,rtl")
828
<< standard[2] << 7 << 6 << QQuickTextInput::SelectWords << 6 << 12 << false;
829
QTest::newRow("Hello<,( world)>|words,ltr")
830
<< standard[2] << 6 << 12 << QQuickTextInput::SelectWords << 5 << 12 << false;
831
QTest::newRow("Hello,<( world)>|words,rtl")
832
<< standard[2] << 12 << 6 << QQuickTextInput::SelectWords << 6 << 12 << false;
833
QTest::newRow("Hello<,( world!)>|words,ltr")
834
<< standard[2] << 6 << 13 << QQuickTextInput::SelectWords << 5 << 13 << false;
835
QTest::newRow("Hello,<( world!)>|words,rtl")
836
<< standard[2] << 13 << 6 << QQuickTextInput::SelectWords << 6 << 13 << false;
837
QTest::newRow("Hello<(, world!)>|words")
838
<< standard[2] << 5 << 13 << QQuickTextInput::SelectWords << 5 << 13 << true;
839
840
841
// Fails due to an issue with QTextBoundaryFinder and punctuation at the end of strings.
// QTBUG-11365
// QTest::newRow("world<(!)>|words")
842
// << standard[2] << 12 << 13 << QQuickTextInput::SelectWords << 12 << 13 << true;
843
QTest::newRow("world!<()>)|words")
844
<< standard[2] << 13 << 13 << QQuickTextInput::SelectWords << 13 << 13 << true;
845
QTest::newRow("world<()>!)|words")
846
<< standard[2] << 12 << 12 << QQuickTextInput::SelectWords << 12 << 12 << true;
847
848
QTest::newRow("<(,)>olleH |words")
849
<< standard[3] << 7 << 8 << QQuickTextInput::SelectWords << 7 << 8 << true;
850
QTest::newRow("<dlrow( ,)>olleH|words,ltr")
851
<< standard[3] << 6 << 8 << QQuickTextInput::SelectWords << 1 << 8 << false;
852
QTest::newRow("dlrow<( ,)>olleH|words,rtl")
853
<< standard[3] << 8 << 6 << QQuickTextInput::SelectWords << 6 << 8 << false;
854
QTest::newRow("<dlrow( ,ol)leH>|words,ltr")
855
<< standard[3] << 6 << 10 << QQuickTextInput::SelectWords << 1 << 13 << false;
856
QTest::newRow("dlrow<( ,ol)leH>|words,rtl")
857
<< standard[3] << 10 << 6 << QQuickTextInput::SelectWords << 6 << 13 << false;
858
QTest::newRow(",<(ol)leH>,|words")
859
<< standard[3] << 8 << 10 << QQuickTextInput::SelectWords << 8 << 13 << true;
860
QTest::newRow(",<()>olleH|words")
861
<< standard[3] << 8 << 8 << QQuickTextInput::SelectWords << 8 << 8 << true;
862
QTest::newRow("<()>,olleH|words")
863
<< standard[3] << 7 << 7 << QQuickTextInput::SelectWords << 7 << 7 << true;
864
QTest::newRow("<dlrow( )>,olleH|words,ltr")
865
<< standard[3] << 6 << 7 << QQuickTextInput::SelectWords << 1 << 7 << false;
866
QTest::newRow("dlrow<( ),>olleH|words,rtl")
867
<< standard[3] << 7 << 6 << QQuickTextInput::SelectWords << 6 << 8 << false;
868
QTest::newRow("<(dlrow )>,olleH|words,ltr")
869
<< standard[3] << 1 << 7 << QQuickTextInput::SelectWords << 1 << 7 << false;
870
QTest::newRow("<(dlrow ),>olleH|words,rtl")
871
<< standard[3] << 7 << 1 << QQuickTextInput::SelectWords << 1 << 8 << false;
872
QTest::newRow("<(!dlrow )>,olleH|words,ltr")
873
<< standard[3] << 0 << 7 << QQuickTextInput::SelectWords << 0 << 7 << false;
874
QTest::newRow("<(!dlrow ),>olleH|words,rtl")
875
<< standard[3] << 7 << 0 << QQuickTextInput::SelectWords << 0 << 8 << false;
876
QTest::newRow("(!dlrow ,)olleH|words")
877
<< standard[3] << 0 << 8 << QQuickTextInput::SelectWords << 0 << 8 << true;
878
QTest::newRow("<(!)>dlrow|words")
879
<< standard[3] << 0 << 1 << QQuickTextInput::SelectWords << 0 << 1 << true;
880
QTest::newRow("<()>!dlrow|words")
881
<< standard[3] << 0 << 0 << QQuickTextInput::SelectWords << 0 << 0 << true;
882
QTest::newRow("!<()>dlrow|words")
883
<< standard[3] << 1 << 1 << QQuickTextInput::SelectWords << 1 << 1 << true;
884
885
QTest::newRow(" <s(pac)ey> text |words")
886
<< standard[4] << 1 << 4 << QQuickTextInput::SelectWords << 1 << 7 << true;
887
QTest::newRow(" spacey <t(ex)t> |words")
888
<< standard[4] << 11 << 13 << QQuickTextInput::SelectWords << 10 << 14 << false; // Should be reversible. QTBUG-11365
889
QTest::newRow("<( )>spacey text |words|ltr")
890
<< standard[4] << 0 << 1 << QQuickTextInput::SelectWords << 0 << 1 << false;
891
QTest::newRow("<( )spacey> text |words|rtl")
892
<< standard[4] << 1 << 0 << QQuickTextInput::SelectWords << 0 << 7 << false;
893
QTest::newRow("spacey <text( )>|words|ltr")
894
<< standard[4] << 14 << 15 << QQuickTextInput::SelectWords << 10 << 15 << false;
895
896
// QTBUG-11365
// QTest::newRow("spacey text<( )>|words|rtl")
897
// << standard[4] << 15 << 14 << QQuickTextInput::SelectWords << 14 << 15 << false;
898
QTest::newRow("<()> spacey text |words")
899
<< standard[4] << 0 << 0 << QQuickTextInput::SelectWords << 0 << 0 << false;
900
QTest::newRow(" spacey text <()>|words")
901
<< standard[4] << 15 << 15 << QQuickTextInput::SelectWords << 15 << 15 << false;
904
void tst_qquicktextinput::moveCursorSelection()
905
906
907
908
{
QFETCH(QString, testStr);
QFETCH(int, cursorPosition);
QFETCH(int, movePosition);
909
QFETCH(QQuickTextInput::SelectionMode, mode);
910
911
912
913
914
QFETCH(int, selectionStart);
QFETCH(int, selectionEnd);
QFETCH(bool, reversible);
QString componentStr = "import QtQuick 2.0\nTextInput { text: \""+ testStr +"\"; }";
915
QQmlComponent textinputComponent(&engine);
916
textinputComponent.setData(componentStr.toLatin1(), QUrl());
917
QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput*>(textinputComponent.create());
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
QVERIFY(textinputObject != 0);
textinputObject->setCursorPosition(cursorPosition);
textinputObject->moveCursorSelection(movePosition, mode);
QCOMPARE(textinputObject->selectedText(), testStr.mid(selectionStart, selectionEnd - selectionStart));
QCOMPARE(textinputObject->selectionStart(), selectionStart);
QCOMPARE(textinputObject->selectionEnd(), selectionEnd);
if (reversible) {
textinputObject->setCursorPosition(movePosition);
textinputObject->moveCursorSelection(cursorPosition, mode);
QCOMPARE(textinputObject->selectedText(), testStr.mid(selectionStart, selectionEnd - selectionStart));
QCOMPARE(textinputObject->selectionStart(), selectionStart);
QCOMPARE(textinputObject->selectionEnd(), selectionEnd);
}
delete textinputObject;
}
939
void tst_qquicktextinput::moveCursorSelectionSequence_data()
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
{
QTest::addColumn<QString>("testStr");
QTest::addColumn<int>("cursorPosition");
QTest::addColumn<int>("movePosition1");
QTest::addColumn<int>("movePosition2");
QTest::addColumn<int>("selection1Start");
QTest::addColumn<int>("selection1End");
QTest::addColumn<int>("selection2Start");
QTest::addColumn<int>("selection2End");
// () contains the text selected by the cursor.
// <> contains the actual selection.
// ^ is the revised cursor position.
// {} contains the revised selection.
QTest::newRow("the {<quick( bro)wn> f^ox} jumped|ltr")
<< standard[0]
<< 9 << 13 << 17
<< 4 << 15
<< 4 << 19;
QTest::newRow("the quick<( {bro)wn> f^ox} jumped|rtl")
<< standard[0]
<< 13 << 9 << 17
<< 9 << 15
<< 10 << 19;
QTest::newRow("the {<quick( bro)wn> ^}fox jumped|ltr")
<< standard[0]
<< 9 << 13 << 16
<< 4 << 15
<< 4 << 16;
QTest::newRow("the quick<( {bro)wn> ^}fox jumped|rtl")
<< standard[0]
<< 13 << 9 << 16
<< 9 << 15
<< 10 << 16;
QTest::newRow("the {<quick( bro)wn^>} fox jumped|ltr")
<< standard[0]
<< 9 << 13 << 15
<< 4 << 15
<< 4 << 15;
QTest::newRow("the quick<( {bro)wn^>} f^ox jumped|rtl")
<< standard[0]
<< 13 << 9 << 15
<< 9 << 15
<< 10 << 15;
QTest::newRow("the {<quick() ^}bro)wn> fox|ltr")
<< standard[0]
<< 9 << 13 << 10
<< 4 << 15
<< 4 << 10;
QTest::newRow("the quick<( {^bro)wn>} fox|rtl")
<< standard[0]
<< 13 << 9 << 10
<< 9 << 15
<< 10 << 15;
QTest::newRow("the {<quick^}( bro)wn> fox|ltr")
<< standard[0]
<< 9 << 13 << 9
<< 4 << 15
<< 4 << 9;
QTest::newRow("the quick{<(^ bro)wn>} fox|rtl")