diff options
author | Shawn Rutledge <shawn.rutledge@qt.io> | 2022-01-06 17:12:36 +0100 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2022-01-07 23:29:03 +0000 |
commit | e35b06219d5456c8ce7c96931f7c627a480c56db (patch) | |
tree | b340e9f23a1d49bdb113e21e231d6d7b44640d7e | |
parent | 9c8e32a575c2ba415090a11e05a204d4b5e8f0b3 (diff) |
Don't crash when pasting text into TextArea
If QQuickTextAreaPrivate::ensureCursorVisible() calls
QQuickFlickable::setContentY() while the Flickable does not yet know the
extents of its new content, it caused a crash when
QQuickScrollBarPrivate::visualArea() called qBound(0, 1, -something).
We need to wait until Flickable knows it can scroll that far. It turns
out ensureCursorVisible() is called several times anyway, so it's OK to
skip the calls that would ask the Flickable to scroll out-of-bounds.
Task-number: QTBUG-99582
Change-Id: Ifb374a81591df49d3c571f55cb3076a78a808918
Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
(cherry picked from commit 924b2d5d47a33d11999a8edbfe6960e9593038ec)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r-- | src/qmltest/quicktestutil.cpp | 13 | ||||
-rw-r--r-- | src/qmltest/quicktestutil_p.h | 2 | ||||
-rw-r--r-- | src/quicktemplates2/qquicktextarea.cpp | 2 | ||||
-rw-r--r-- | tests/auto/quickcontrols2/controls/data/tst_textarea.qml | 33 |
4 files changed, 49 insertions, 1 deletions
diff --git a/src/qmltest/quicktestutil.cpp b/src/qmltest/quicktestutil.cpp index 994c66845b..25863c3842 100644 --- a/src/qmltest/quicktestutil.cpp +++ b/src/qmltest/quicktestutil.cpp @@ -47,6 +47,7 @@ #include <QtQml/private/qjsvalue_p.h> #include <QtGui/qguiapplication.h> +#include <QtGui/qclipboard.h> #include <QtGui/qstylehints.h> #include <QtQml/qqmlengine.h> @@ -62,6 +63,18 @@ int QuickTestUtil::dragThreshold() const return QGuiApplication::styleHints()->startDragDistance(); } +void QuickTestUtil::populateClipboardText(int lineCount) +{ +#if QT_CONFIG(clipboard) + QString fmt(u"%1 bottles of beer on the wall, %1 bottles of beer; " + "take one down, pass it around, %2 bottles of beer on the wall."_qs); + QStringList lines; + for (int i = lineCount; i > 0; --i) + lines << fmt.arg(i).arg(i - 1); + QGuiApplication::clipboard()->setText(lines.join(u'\n')); +#endif +} + QJSValue QuickTestUtil::typeName(const QVariant &v) const { QString name = QString::fromUtf8(v.typeName()); diff --git a/src/qmltest/quicktestutil_p.h b/src/qmltest/quicktestutil_p.h index 1cf2a6f356..fae904b84c 100644 --- a/src/qmltest/quicktestutil_p.h +++ b/src/qmltest/quicktestutil_p.h @@ -73,6 +73,8 @@ public: bool printAvailableFunctions() const; int dragThreshold() const; + Q_INVOKABLE void populateClipboardText(int lineCount); + Q_SIGNALS: void printAvailableFunctionsChanged(); void dragThresholdChanged(); diff --git a/src/quicktemplates2/qquicktextarea.cpp b/src/quicktemplates2/qquicktextarea.cpp index 6ba0474073..c2c2a91cb4 100644 --- a/src/quicktemplates2/qquicktextarea.cpp +++ b/src/quicktemplates2/qquicktextarea.cpp @@ -383,7 +383,7 @@ void QQuickTextAreaPrivate::ensureCursorVisible() flickable->setContentY(cr.top() - tp); } else { const qreal bp = q->bottomPadding(); - if (cr.bottom() >= cy + tp + h - bp) + if (cr.bottom() >= cy + tp + h - bp && cr.bottom() <= flickable->contentHeight()) flickable->setContentY(cr.bottom() - h + bp); } } diff --git a/tests/auto/quickcontrols2/controls/data/tst_textarea.qml b/tests/auto/quickcontrols2/controls/data/tst_textarea.qml index 5fcc4773dc..e4ae3713f3 100644 --- a/tests/auto/quickcontrols2/controls/data/tst_textarea.qml +++ b/tests/auto/quickcontrols2/controls/data/tst_textarea.qml @@ -88,6 +88,16 @@ TestCase { } Component { + id: flickableWithScrollBar + Flickable { + width: 200 + height: 200 + TextArea.flickable: TextArea { } + ScrollBar.vertical: ScrollBar { } + } + } + + Component { id: signalSpy SignalSpy { } } @@ -101,6 +111,10 @@ TestCase { id: defaultFontMetrics } + TestUtil { + id: util + } + function test_creation() { var control = createTemporaryObject(textArea, testCase) verify(control) @@ -351,6 +365,25 @@ TestCase { compare(textArea.background.height, flickable.height) } + function test_scrollable_paste_large() { + var control = createTemporaryObject(flickableWithScrollBar, testCase) + verify(control) + + var textArea = control.TextArea.flickable + verify(textArea) + + if (typeof(textArea.paste) !== "function") + skip("Clipboard is not supported on this platform.") + + util.populateClipboardText(100) + waitForRendering(control) + // don't crash (QTBUG-99582) + textArea.paste() + // verify that the cursor moved to the bottom after pasting, and we scrolled down to show it + tryVerify(function() { return textArea.cursorRectangle.y > 1000 }); // maybe > 2000, depending on font size + tryVerify(function() { return control.contentY > textArea.cursorRectangle.y - control.height }) + } + function test_warning() { ignoreWarning(/QML TestCase: TextArea must be attached to a Flickable/) testCase.TextArea.flickable = null |