aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorShawn Rutledge <shawn.rutledge@qt.io>2022-02-24 09:00:48 +0100
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2022-07-16 14:05:15 +0000
commitbaa395864555e113c4d7d51a11a4934c792150db (patch)
tree808fe11db1764108727d981398c20d4d0b138f6d /tests
parente97bd5dcc695136ec9020fab3983bf4811323031 (diff)
TextInput/Field: selectByMouse default=true, but not on touchscreens
When you drag a finger across a TextInput or TextField, it should not select text. - your finger probably covers several characters, so you can't see where you're selecting until afterwards - if the item is in a Flickable, flicking by touch should be prioritized - if flicking happens, the text cursor should not move; but to avoid losing too much functionality, we allow it to move on release, if the TextInput or TextField gets the release (i.e. if it still has the exclusive grab) - TextField's pressed, pressAndHold and released signals continue to behave the same with touch as with mouse So now we distinguish mouse events that are synthesized from non-mouse devices and avoid mouse-like behaviors as described above, but there is no behavior change if the event comes from an actual mouse or touchpad. Since most users want selecting text by mouse to "just work", and an actual mouse is precise enough to do so, and dragging a Flickable with the mouse is unintuitive (since most UIs don't allow it and most mice have wheels), selectByMouse now defaults to true, and has the stricter meaning that its name implies. To select text on a touchscreen, the end-user needs to rely on text-selection handles, which are provided on touch-centric mobile platforms, and could also be implemented from scratch if someone builds a custom text field using TextInput. [ChangeLog][QtQuick][TextInput] The selectByMouse property is now enabled by default, but no longer enables selecting by dragging your finger across text on a touchscreen. Platforms that are optimized for touchscreens normally use special text-selection handles, which interact with Qt via QInputMethod. You can opt out of the behavior change by using an import version < 6.4. [ChangeLog][Controls][TextField] The selectByMouse property is now enabled by default, but no longer enables selecting by dragging your finger across text on a touchscreen. Platforms that are optimized for touchscreens normally use special text-selection handles, which interact with Qt via QInputMethod. You can opt out of the behavior change by using an import version < 6.4. Task-number: QTBUG-10684 Task-number: QTBUG-38934 Task-number: QTBUG-101205 Change-Id: I6d3158dd48896a0bed37cbc0b2da01d313a499f8 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io> (cherry picked from commit 650342de792e0ab37ce8bac8ccde21ab9b96b2c9) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/quick/qquicktextinput/data/mouseselection_old_default.qml (renamed from tests/auto/quick/qquicktextinput/data/mouseselection_true.qml)1
-rw-r--r--tests/auto/quick/qquicktextinput/data/mouseselectionmode_default.qml3
-rw-r--r--tests/auto/quick/qquicktextinput/data/twoInAColumn.qml14
-rw-r--r--tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp103
-rw-r--r--tests/auto/quickcontrols2/controls/data/tst_textfield.qml45
5 files changed, 159 insertions, 7 deletions
diff --git a/tests/auto/quick/qquicktextinput/data/mouseselection_true.qml b/tests/auto/quick/qquicktextinput/data/mouseselection_old_default.qml
index 974041b04a..42ab4931ea 100644
--- a/tests/auto/quick/qquicktextinput/data/mouseselection_true.qml
+++ b/tests/auto/quick/qquicktextinput/data/mouseselection_old_default.qml
@@ -3,5 +3,4 @@ import QtQuick 2.0
TextInput {
focus: true
text: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- selectByMouse: true
}
diff --git a/tests/auto/quick/qquicktextinput/data/mouseselectionmode_default.qml b/tests/auto/quick/qquicktextinput/data/mouseselectionmode_default.qml
index 974041b04a..ad19fa8c2a 100644
--- a/tests/auto/quick/qquicktextinput/data/mouseselectionmode_default.qml
+++ b/tests/auto/quick/qquicktextinput/data/mouseselectionmode_default.qml
@@ -1,7 +1,6 @@
-import QtQuick 2.0
+import QtQuick
TextInput {
focus: true
text: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- selectByMouse: true
}
diff --git a/tests/auto/quick/qquicktextinput/data/twoInAColumn.qml b/tests/auto/quick/qquicktextinput/data/twoInAColumn.qml
new file mode 100644
index 0000000000..dbc70afe4b
--- /dev/null
+++ b/tests/auto/quick/qquicktextinput/data/twoInAColumn.qml
@@ -0,0 +1,14 @@
+import QtQuick
+import QtQuick.Layouts
+
+ColumnLayout {
+ height: 100
+ TextInput {
+ objectName: "top"
+ text: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ }
+ TextInput {
+ objectName: "bottom"
+ text: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ }
+}
diff --git a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp
index ad9bd7a501..54f650f86e 100644
--- a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp
+++ b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp
@@ -4,6 +4,7 @@
#include <QtTest/QSignalSpy>
#include <QtQuickTestUtils/private/qmlutils_p.h>
#include <QtQuickTestUtils/private/testhttpserver_p.h>
+#include <QtQuickTestUtils/private/viewtestutils_p.h>
#include <private/qinputmethod_p.h>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcomponent.h>
@@ -13,6 +14,8 @@
#include <QtGui/qguiapplication.h>
#include <QtGui/qstylehints.h>
#include <QtGui/qvalidator.h>
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/private/qpointingdevice_p.h>
#include <QInputMethod>
#include <private/qquicktextinput_p.h>
#include <private/qquicktextinput_p_p.h>
@@ -197,15 +200,22 @@ private slots:
void checkCursorDelegateWhenPaddingChanged();
void focusReason();
+
+ void touchscreenDoesNotSelect_data();
+ void touchscreenDoesNotSelect();
+ void touchscreenSetsFocusAndMovesCursor();
+
private:
void simulateKeys(QWindow *window, const QList<Key> &keys);
#if QT_CONFIG(shortcut)
void simulateKeys(QWindow *window, const QKeySequence &sequence);
#endif
+ static bool hasWindowActivation();
QQmlEngine engine;
QStringList standard;
QStringList colorStrings;
+ QScopedPointer<QPointingDevice> touchscreen = QScopedPointer<QPointingDevice>(QTest::createTouchDevice());
};
typedef QList<int> IntList;
@@ -226,6 +236,11 @@ void tst_qquicktextinput::simulateKeys(QWindow *window, const QList<Key> &keys)
}
}
+bool tst_qquicktextinput::hasWindowActivation()
+{
+ return (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation));
+}
+
#if QT_CONFIG(shortcut)
void tst_qquicktextinput::simulateKeys(QWindow *window, const QKeySequence &sequence)
@@ -1253,7 +1268,7 @@ void tst_qquicktextinput::moveCursorSelectionSequence()
void tst_qquicktextinput::dragMouseSelection()
{
- QString qmlfile = testFile("mouseselection_true.qml");
+ QString qmlfile = testFile("mouseselectionmode_default.qml");
QQuickView window(QUrl::fromLocalFile(qmlfile));
@@ -1264,6 +1279,7 @@ void tst_qquicktextinput::dragMouseSelection()
QVERIFY(window.rootObject() != nullptr);
QQuickTextInput *textInputObject = qobject_cast<QQuickTextInput *>(window.rootObject());
QVERIFY(textInputObject != nullptr);
+ textInputObject->setSelectByMouse(true);
// press-and-drag-and-release from x1 to x2
int x1 = 10;
@@ -2744,7 +2760,7 @@ void tst_qquicktextinput::middleClickPaste()
if (!PlatformQuirks::isClipboardAvailable())
QSKIP("This machine doesn't support the clipboard");
- QQuickView window(testFileUrl("mouseselection_true.qml"));
+ QQuickView window(testFileUrl("mouseselectionmode_default.qml"));
window.show();
window.requestActivate();
@@ -2753,6 +2769,7 @@ void tst_qquicktextinput::middleClickPaste()
QVERIFY(window.rootObject() != nullptr);
QQuickTextInput *textInputObject = qobject_cast<QQuickTextInput *>(window.rootObject());
QVERIFY(textInputObject != nullptr);
+ textInputObject->setSelectByMouse(true);
textInputObject->setFocus(true);
@@ -7091,6 +7108,88 @@ void tst_qquicktextinput::focusReason()
QCOMPARE(eventFilter.lastFocusReason[first], Qt::TabFocusReason);
}
+void tst_qquicktextinput::touchscreenDoesNotSelect_data()
+{
+ QTest::addColumn<QUrl>("src");
+ QTest::addColumn<bool>("expectDefaultSelectByMouse");
+ QTest::addColumn<bool>("overrideSelectByMouseFalse");
+ QTest::newRow("new default") << testFileUrl("mouseselectionmode_default.qml") << true << false;
+ QTest::newRow("new override") << testFileUrl("mouseselectionmode_default.qml") << true << true;
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
+ QTest::newRow("old default") << testFileUrl("mouseselection_old_default.qml") << false << false;
+#endif
+}
+
+void tst_qquicktextinput::touchscreenDoesNotSelect()
+{
+ QFETCH(QUrl, src);
+ QFETCH(bool, expectDefaultSelectByMouse);
+ QFETCH(bool, overrideSelectByMouseFalse);
+
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, src));
+
+ QQuickTextInput *textInputObject = qobject_cast<QQuickTextInput *>(window.rootObject());
+ QVERIFY(textInputObject);
+ QCOMPARE(textInputObject->selectByMouse(), expectDefaultSelectByMouse);
+ if (overrideSelectByMouseFalse)
+ textInputObject->setSelectByMouse(overrideSelectByMouseFalse);
+
+ // press-drag-and-release from x1 to x2
+ int x1 = 10;
+ int x2 = 70;
+ int y = textInputObject->height() / 2;
+ QTest::touchEvent(&window, touchscreen.data()).press(0, QPoint(x1,y), &window);
+ QTest::touchEvent(&window, touchscreen.data()).move(0, QPoint(x2,y), &window);
+ QTest::touchEvent(&window, touchscreen.data()).release(0, QPoint(x2,y), &window);
+ QQuickTouchUtils::flush(&window);
+ QVERIFY(textInputObject->selectedText().isEmpty());
+}
+
+void tst_qquicktextinput::touchscreenSetsFocusAndMovesCursor()
+{
+ if (!hasWindowActivation())
+ QSKIP("Window activation is not supported");
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("twoInAColumn.qml")));
+ window.requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(&window));
+
+ QQuickTextInput *top = window.rootObject()->findChild<QQuickTextInput*>("top");
+ QVERIFY(top);
+ QQuickTextInput *bottom = window.rootObject()->findChild<QQuickTextInput*>("bottom");
+ QVERIFY(bottom);
+
+ // tap the bottom field
+ int x1 = 10;
+ int y = bottom->position().y() + bottom->height() / 2;
+ QTest::touchEvent(&window, touchscreen.data()).press(0, QPoint(x1,y), &window);
+ QQuickTouchUtils::flush(&window);
+ QCOMPARE(qApp->focusObject(), bottom);
+ // text cursor is at the end by default, on press
+ const auto len = bottom->text().length();
+ QCOMPARE(bottom->cursorPosition(), len);
+ // so typing a character appends it
+ QVERIFY(!bottom->text().endsWith('q'));
+ QTest::keyClick(&window, Qt::Key_Q);
+ QVERIFY(bottom->text().endsWith('q'));
+ QCOMPARE(bottom->text().length(), len + 1);
+ QTest::touchEvent(&window, touchscreen.data()).release(0, QPoint(x1,y), &window);
+ QQuickTouchUtils::flush(&window);
+ // the cursor gets moved on release, as long as TextInput's grab wasn't stolen (e.g. by Flickable)
+ QVERIFY(bottom->cursorPosition() < 5);
+
+ // press-drag-and-release from x1 to x2 on the top field
+ int x2 = 70;
+ y = top->position().y() + top->height() / 2;
+ QTest::touchEvent(&window, touchscreen.data()).press(0, QPoint(x1,y), &window);
+ QTest::touchEvent(&window, touchscreen.data()).move(0, QPoint(x2,y), &window);
+ QTest::touchEvent(&window, touchscreen.data()).release(0, QPoint(x2,y), &window);
+ QQuickTouchUtils::flush(&window);
+ QCOMPARE(qApp->focusObject(), top);
+ QVERIFY(top->selectedText().isEmpty());
+}
+
QTEST_MAIN(tst_qquicktextinput)
#include "tst_qquicktextinput.moc"
diff --git a/tests/auto/quickcontrols2/controls/data/tst_textfield.qml b/tests/auto/quickcontrols2/controls/data/tst_textfield.qml
index 09669a8df2..ecda6c25b5 100644
--- a/tests/auto/quickcontrols2/controls/data/tst_textfield.qml
+++ b/tests/auto/quickcontrols2/controls/data/tst_textfield.qml
@@ -394,7 +394,7 @@ TestCase {
}
function test_multiClick() {
- var control = createTemporaryObject(textField, testCase, {text: "Qt Quick Controls 2 TextArea", selectByMouse: true})
+ var control = createTemporaryObject(textField, testCase, {text: "Qt Quick Controls 2 TextArea"})
verify(control)
waitForRendering(control)
@@ -412,7 +412,7 @@ TestCase {
// QTBUG-64048
function test_rightClick() {
- var control = createTemporaryObject(textField, testCase, {text: "TextField", selectByMouse: true})
+ var control = createTemporaryObject(textField, testCase, {text: "TextField"})
verify(control)
control.selectAll()
@@ -425,6 +425,47 @@ TestCase {
compare(control.selectedText, "")
}
+ function test_mouseSelect() {
+ var control = createTemporaryObject(textField, testCase, {text: "Text", width: parent.width})
+ verify(control)
+ verify(control.selectByMouse) // true by default since 6.4
+ var pressSpy = signalSpy.createObject(control, {target: control, signalName: "pressed"})
+
+ const y = control.height / 2
+ mousePress(control, 0, y, Qt.LeftButton)
+ tryCompare(pressSpy, "count", 1)
+ mouseMove(control, control.implicitWidth, y, 0, Qt.LeftButton)
+ mouseRelease(control, control.implicitWidth, y, Qt.LeftButton)
+ tryVerify(function() { return control.selectedText.length > 1 }) // ideally the whole 4-letter word
+ }
+
+ function test_noTouchSelect() {
+ var control = createTemporaryObject(textField, testCase, {text: "Text"})
+ verify(control)
+ verify(control.selectByMouse) // true by default since 6.4
+
+ var touch = touchEvent(control)
+ const y = control.height / 2
+ touch.press(0, control, 0, y).commit()
+ touch.move(0, control, control.implicitWidth, 0).commit()
+ touch.release(0, control)
+ compare(control.selectedText, "")
+ }
+
+ function test_aaTouchPressAndHold() {
+ var control = createTemporaryObject(textField, testCase, {text: "Text"})
+ verify(control)
+ verify(control.selectByMouse) // true by default since 6.4
+ var pressSpy = signalSpy.createObject(control, {target: control, signalName: "pressed"})
+ var pressAndHoldSpy = signalSpy.createObject(control, {target: control, signalName: "pressAndHold"})
+
+ var touch = touchEvent(control)
+ touch.press(0, control).commit()
+ tryCompare(pressSpy, "count", 1)
+ tryCompare(pressAndHoldSpy, "count", 1)
+ touch.release(0, control).commit()
+ }
+
// QTBUG-66260
function test_placeholderTextColor() {
var control = createTemporaryObject(textField, testCase)