diff options
author | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2019-05-16 01:00:46 +0200 |
---|---|---|
committer | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2019-05-16 01:00:46 +0200 |
commit | 039071ea5e93d93deb0103e7c9488198dcce55d6 (patch) | |
tree | c4cfcf20ed1f836e9c958b2835c84a2b28915e3b | |
parent | 9b36512b9453f429644b0c388d381f7a2fc0f825 (diff) | |
parent | 56fbc277a1acc49d9ead4c89edd250a021ef2a01 (diff) |
Merge remote-tracking branch 'origin/5.12' into 5.13
Change-Id: Ia93dc734ce25b3134b0f905f473a0c30777ceaf1
-rw-r--r-- | src/qml/doc/src/qmllanguageref/typesystem/basictypes.qdoc | 4 | ||||
-rw-r--r-- | src/quick/doc/snippets/pointerHandlers/tapHandlerOnTapped.qml | 64 | ||||
-rw-r--r-- | src/quick/handlers/qquicktaphandler.cpp | 27 | ||||
-rw-r--r-- | src/quick/items/qquickaccessibleattached.cpp | 43 | ||||
-rw-r--r-- | src/quick/items/qquickaccessibleattached_p.h | 38 | ||||
-rw-r--r-- | src/quick/items/qquicktextedit.cpp | 19 | ||||
-rw-r--r-- | src/quick/items/qquicktextedit_p.h | 1 | ||||
-rw-r--r-- | src/quick/items/qquicktextedit_p_p.h | 1 | ||||
-rw-r--r-- | src/quick/items/qquickwindow.cpp | 42 | ||||
-rw-r--r-- | src/quick/items/qquickwindow_p.h | 3 | ||||
-rw-r--r-- | tests/auto/qml/qqmlengine/data/CachedGetterLookup.qml | 20 | ||||
-rw-r--r-- | tests/auto/qml/qqmlengine/tst_qqmlengine.cpp | 11 | ||||
-rw-r--r-- | tests/auto/quick/qquickaccessible/data/text.qml | 11 | ||||
-rw-r--r-- | tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp | 26 | ||||
-rw-r--r-- | tests/auto/quick/qquicktextedit/qquicktextedit.pro | 1 | ||||
-rw-r--r-- | tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp | 56 | ||||
-rw-r--r-- | tests/auto/quick/qquickwindow/tst_qquickwindow.cpp | 56 |
17 files changed, 364 insertions, 59 deletions
diff --git a/src/qml/doc/src/qmllanguageref/typesystem/basictypes.qdoc b/src/qml/doc/src/qmllanguageref/typesystem/basictypes.qdoc index c4c1b61693..5144fe219e 100644 --- a/src/qml/doc/src/qmllanguageref/typesystem/basictypes.qdoc +++ b/src/qml/doc/src/qmllanguageref/typesystem/basictypes.qdoc @@ -44,6 +44,10 @@ Basic types can be used to refer to: \li A value that contains a simple set of property-value pairs (e.g. \l size refers to a value with \c width and \c height attributes) \endlist +When a variable or property holds a basic type and it is assigned to another +variable or property, then a copy of the value is made. In JavaScript, this +value is called a primitive value. + \sa {qtqml-typesystem-topic.html}{The QML Type System} diff --git a/src/quick/doc/snippets/pointerHandlers/tapHandlerOnTapped.qml b/src/quick/doc/snippets/pointerHandlers/tapHandlerOnTapped.qml new file mode 100644 index 0000000000..f556c238da --- /dev/null +++ b/src/quick/doc/snippets/pointerHandlers/tapHandlerOnTapped.qml @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +//![0] +import QtQuick 2.12 + +Rectangle { + width: 100 + height: 100 + + TapHandler { + acceptedButtons: Qt.LeftButton | Qt.RightButton + onTapped: console.log("tapped", eventPoint.event.device.name, + "button", eventPoint.event.button, + "@", eventPoint.scenePosition) + } +} +//![0] diff --git a/src/quick/handlers/qquicktaphandler.cpp b/src/quick/handlers/qquicktaphandler.cpp index 081645da71..40a4813527 100644 --- a/src/quick/handlers/qquicktaphandler.cpp +++ b/src/quick/handlers/qquicktaphandler.cpp @@ -381,35 +381,50 @@ void QQuickTapHandler::updateTimeHeld() */ /*! - \qmlsignal QtQuick::TapHandler::tapped + \qmlsignal QtQuick::TapHandler::tapped(EventPoint eventPoint) This signal is emitted each time the \c parent Item is tapped. That is, if you press and release a touchpoint or button within a time period less than \l longPressThreshold, while any movement does not exceed the drag threshold, then the \c tapped signal will be emitted at the time - of release. + of release. The \c eventPoint signal parameter contains information + from the release event about the point that was tapped: + + \snippet pointerHandlers/tapHandlerOnTapped.qml 0 + + \note At the time this signal is emitted, \l point has been reset + (all coordinates are \c 0). */ /*! - \qmlsignal QtQuick::TapHandler::singleTapped + \qmlsignal QtQuick::TapHandler::singleTapped(EventPoint eventPoint) \since 5.11 This signal is emitted when the \c parent Item is tapped once. After an amount of time greater than QStyleHints::mouseDoubleClickInterval, it can be tapped again; but if the time until the next tap is less, - \l tapCount will increase. + \l tapCount will increase. The \c eventPoint signal parameter contains + information from the release event about the point that was tapped. + + \note At the time this signal is emitted, \l point has been reset + (all coordinates are \c 0). */ /*! - \qmlsignal QtQuick::TapHandler::doubleTapped + \qmlsignal QtQuick::TapHandler::doubleTapped(EventPoint eventPoint) \since 5.11 This signal is emitted when the \c parent Item is tapped twice within a short span of time (QStyleHints::mouseDoubleClickInterval) and distance (QPlatformTheme::MouseDoubleClickDistance or QPlatformTheme::TouchDoubleTapDistance). This signal always occurs after - \l singleTapped, \l tapped, and \l tapCountChanged. + \l singleTapped, \l tapped, and \l tapCountChanged. The \c eventPoint + signal parameter contains information from the release event about the + point that was tapped. + + \note At the time this signal is emitted, \l point has been reset + (all coordinates are \c 0). */ /*! diff --git a/src/quick/items/qquickaccessibleattached.cpp b/src/quick/items/qquickaccessibleattached.cpp index 0168c3160c..c150e4efa2 100644 --- a/src/quick/items/qquickaccessibleattached.cpp +++ b/src/quick/items/qquickaccessibleattached.cpp @@ -390,6 +390,49 @@ QQuickAccessibleAttached::~QQuickAccessibleAttached() { } +void QQuickAccessibleAttached::setRole(QAccessible::Role role) +{ + if (role != m_role) { + m_role = role; + Q_EMIT roleChanged(); + // There is no way to signify role changes at the moment. + // QAccessible::updateAccessibility(parent(), 0, QAccessible::); + + switch (role) { + case QAccessible::CheckBox: + case QAccessible::RadioButton: + if (!m_stateExplicitlySet.focusable) + m_state.focusable = true; + if (!m_stateExplicitlySet.checkable) + m_state.checkable = true; + break; + case QAccessible::Button: + case QAccessible::MenuItem: + case QAccessible::PageTab: + case QAccessible::SpinBox: + case QAccessible::ComboBox: + case QAccessible::Terminal: + case QAccessible::ScrollBar: + if (!m_stateExplicitlySet.focusable) + m_state.focusable = true; + break; + case QAccessible::EditableText: + if (!m_stateExplicitlySet.editable) + m_state.editable = true; + if (!m_stateExplicitlySet.focusable) + m_state.focusable = true; + break; + case QAccessible::StaticText: + if (!m_stateExplicitlySet.readOnly) { + m_state.readOnly = true; + } + break; + default: + break; + } + } +} + QQuickAccessibleAttached *QQuickAccessibleAttached::qmlAttachedProperties(QObject *obj) { return new QQuickAccessibleAttached(obj); diff --git a/src/quick/items/qquickaccessibleattached_p.h b/src/quick/items/qquickaccessibleattached_p.h index e292c280df..f4194ef13d 100644 --- a/src/quick/items/qquickaccessibleattached_p.h +++ b/src/quick/items/qquickaccessibleattached_p.h @@ -69,6 +69,7 @@ QT_BEGIN_NAMESPACE bool P() const { return m_state.P ; } \ void set_ ## P(bool arg) \ { \ + m_stateExplicitlySet.P = true; \ if (m_state.P == arg) \ return; \ m_state.P = arg; \ @@ -111,41 +112,7 @@ public: ~QQuickAccessibleAttached(); QAccessible::Role role() const { return m_role; } - void setRole(QAccessible::Role role) - { - if (role != m_role) { - m_role = role; - Q_EMIT roleChanged(); - // There is no way to signify role changes at the moment. - // QAccessible::updateAccessibility(parent(), 0, QAccessible::); - - switch (role) { - case QAccessible::CheckBox: - case QAccessible::RadioButton: - m_state.focusable = true; - m_state.checkable = true; - break; - case QAccessible::Button: - case QAccessible::MenuItem: - case QAccessible::PageTab: - case QAccessible::SpinBox: - case QAccessible::ComboBox: - case QAccessible::Terminal: - case QAccessible::ScrollBar: - m_state.focusable = true; - break; - case QAccessible::EditableText: - m_state.editable = true; - m_state.focusable = true; - break; - case QAccessible::StaticText: - m_state.readOnly = true; - break; - default: - break; - } - } - } + void setRole(QAccessible::Role role); QString name() const { if (m_state.passwordEdit) return QString(); @@ -247,6 +214,7 @@ private: QAccessible::Role m_role; QAccessible::State m_state; + QAccessible::State m_stateExplicitlySet; QString m_name; QString m_description; diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp index 6b4b118eb7..b299e7c92f 100644 --- a/src/quick/items/qquicktextedit.cpp +++ b/src/quick/items/qquicktextedit.cpp @@ -2298,7 +2298,6 @@ void QQuickTextEditPrivate::init() qmlobject_connect(control, QQuickTextControl, SIGNAL(cursorPositionChanged()), q, QQuickTextEdit, SIGNAL(cursorPositionChanged())); qmlobject_connect(control, QQuickTextControl, SIGNAL(cursorRectangleChanged()), q, QQuickTextEdit, SLOT(moveCursorDelegate())); qmlobject_connect(control, QQuickTextControl, SIGNAL(linkActivated(QString)), q, QQuickTextEdit, SIGNAL(linkActivated(QString))); - qmlobject_connect(control, QQuickTextControl, SIGNAL(linkHovered(QString)), q, QQuickTextEdit, SIGNAL(linkHovered(QString))); qmlobject_connect(control, QQuickTextControl, SIGNAL(overwriteModeChanged(bool)), q, QQuickTextEdit, SIGNAL(overwriteModeChanged(bool))); qmlobject_connect(control, QQuickTextControl, SIGNAL(textChanged()), q, QQuickTextEdit, SLOT(q_textChanged())); qmlobject_connect(control, QQuickTextControl, SIGNAL(preeditTextChanged()), q, QQuickTextEdit, SIGNAL(preeditTextChanged())); @@ -2310,6 +2309,7 @@ void QQuickTextEditPrivate::init() qmlobject_connect(document, QQuickTextDocumentWithImageResources, SIGNAL(imagesLoaded()), q, QQuickTextEdit, SLOT(updateSize())); QObject::connect(document, &QQuickTextDocumentWithImageResources::contentsChange, q, &QQuickTextEdit::q_contentsChange); QObject::connect(document->documentLayout(), &QAbstractTextDocumentLayout::updateBlock, q, &QQuickTextEdit::invalidateBlock); + QObject::connect(control, &QQuickTextControl::linkHovered, q, &QQuickTextEdit::q_linkHovered); document->setDefaultFont(font); document->setDocumentMargin(textMargin); @@ -2317,6 +2317,9 @@ void QQuickTextEditPrivate::init() document->setUndoRedoEnabled(true); updateDefaultTextOption(); q->updateSize(); +#if QT_CONFIG(cursor) + q->setCursor(Qt::IBeamCursor); +#endif } void QQuickTextEditPrivate::resetInputMethod() @@ -2584,6 +2587,20 @@ void QQuickTextEdit::updateCursor() } } +void QQuickTextEdit::q_linkHovered(const QString &link) +{ + Q_D(QQuickTextEdit); + emit linkHovered(link); +#if QT_CONFIG(cursor) + if (link.isEmpty()) { + setCursor(d->cursorToRestoreAfterHover); + } else if (cursor().shape() != Qt::PointingHandCursor) { + d->cursorToRestoreAfterHover = cursor().shape(); + setCursor(Qt::PointingHandCursor); + } +#endif +} + void QQuickTextEdit::q_updateAlignment() { Q_D(QQuickTextEdit); diff --git a/src/quick/items/qquicktextedit_p.h b/src/quick/items/qquicktextedit_p.h index 7a847ffeae..259a614d6b 100644 --- a/src/quick/items/qquicktextedit_p.h +++ b/src/quick/items/qquicktextedit_p.h @@ -374,6 +374,7 @@ private Q_SLOTS: void updateWholeDocument(); void invalidateBlock(const QTextBlock &block); void updateCursor(); + void q_linkHovered(const QString &link); void q_updateAlignment(); void updateSize(); void triggerPreprocess(); diff --git a/src/quick/items/qquicktextedit_p_p.h b/src/quick/items/qquicktextedit_p_p.h index 46d3d5ff6b..389ce3175c 100644 --- a/src/quick/items/qquicktextedit_p_p.h +++ b/src/quick/items/qquicktextedit_p_p.h @@ -207,6 +207,7 @@ public: Qt::InputMethodHints inputMethodHints; #endif UpdateType updateType; + Qt::CursorShape cursorToRestoreAfterHover = Qt::IBeamCursor; bool dirty : 1; bool richText : 1; diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index f3a2b07620..5dcd101462 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -64,6 +64,7 @@ #include <QtGui/qpainter.h> #include <QtGui/qevent.h> #include <QtGui/qmatrix4x4.h> +#include <QtGui/qpa/qplatformtheme.h> #include <QtCore/qvarlengtharray.h> #include <QtCore/qabstractanimation.h> #include <QtCore/QLibraryInfo> @@ -632,25 +633,28 @@ static QMouseEvent *touchToMouseEvent(QEvent::Type type, const QTouchEvent::Touc return me; } -bool QQuickWindowPrivate::checkIfDoubleClicked(ulong newPressEventTimestamp) +bool QQuickWindowPrivate::checkIfDoubleTapped(ulong newPressEventTimestamp, QPoint newPressPos) { - bool doubleClicked; + bool doubleClicked = false; + + if (touchMousePressTimestamp > 0) { + QPoint distanceBetweenPresses = newPressPos - touchMousePressPos; + const int doubleTapDistance = QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::TouchDoubleTapDistance).toInt(); + doubleClicked = (qAbs(distanceBetweenPresses.x()) <= doubleTapDistance) && (qAbs(distanceBetweenPresses.y()) <= doubleTapDistance); - if (touchMousePressTimestamp == 0) { - // just initialize the variable - touchMousePressTimestamp = newPressEventTimestamp; - doubleClicked = false; - } else { - ulong timeBetweenPresses = newPressEventTimestamp - touchMousePressTimestamp; - ulong doubleClickInterval = static_cast<ulong>(QGuiApplication::styleHints()-> - mouseDoubleClickInterval()); - doubleClicked = timeBetweenPresses < doubleClickInterval; if (doubleClicked) { - touchMousePressTimestamp = 0; - } else { - touchMousePressTimestamp = newPressEventTimestamp; + ulong timeBetweenPresses = newPressEventTimestamp - touchMousePressTimestamp; + ulong doubleClickInterval = static_cast<ulong>(QGuiApplication::styleHints()-> + mouseDoubleClickInterval()); + doubleClicked = timeBetweenPresses < doubleClickInterval; } } + if (doubleClicked) { + touchMousePressTimestamp = 0; + } else { + touchMousePressTimestamp = newPressEventTimestamp; + touchMousePressPos = newPressPos; + } return doubleClicked; } @@ -707,7 +711,9 @@ bool QQuickWindowPrivate::deliverTouchAsMouse(QQuickItem *item, QQuickPointerEve if (auto pointerEventPoint = pointerEvent->pointById(p.id())) pointerEventPoint->setGrabberItem(item); - if (checkIfDoubleClicked(event->timestamp())) { + if (checkIfDoubleTapped(event->timestamp(), p.screenPos().toPoint())) { + // since we synth the mouse event from from touch, we respect the + // QPlatformTheme::TouchDoubleTapDistance instead of QPlatformTheme::MouseDoubleClickDistance QScopedPointer<QMouseEvent> mouseDoubleClick(touchToMouseEvent(QEvent::MouseButtonDblClick, p, event.data(), item, false)); QCoreApplication::sendEvent(item, mouseDoubleClick.data()); event->setAccepted(mouseDoubleClick->isAccepted()); @@ -722,6 +728,12 @@ bool QQuickWindowPrivate::deliverTouchAsMouse(QQuickItem *item, QQuickPointerEve // Touch point was there before and moved } else if (touchMouseDevice == device && p.id() == touchMouseId) { if (p.state() & Qt::TouchPointMoved) { + if (touchMousePressTimestamp != 0) { + const int doubleTapDistance = QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::TouchDoubleTapDistance).toInt(); + const QPoint moveDelta = p.screenPos().toPoint() - touchMousePressPos; + if (moveDelta.x() >= doubleTapDistance || moveDelta.y() >= doubleTapDistance) + touchMousePressTimestamp = 0; // Got dragged too far, dismiss the double tap + } if (QQuickItem *mouseGrabberItem = q->mouseGrabberItem()) { QScopedPointer<QMouseEvent> me(touchToMouseEvent(QEvent::MouseMove, p, event.data(), mouseGrabberItem, false)); QCoreApplication::sendEvent(item, me.data()); diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h index 5a3807b24f..63760a3b68 100644 --- a/src/quick/items/qquickwindow_p.h +++ b/src/quick/items/qquickwindow_p.h @@ -135,8 +135,9 @@ public: #endif int touchMouseId; QQuickPointerDevice *touchMouseDevice; - bool checkIfDoubleClicked(ulong newPressEventTimestamp); + bool checkIfDoubleTapped(ulong newPressEventTimestamp, QPoint newPressPos); ulong touchMousePressTimestamp; + QPoint touchMousePressPos; // in screen coordiantes void cancelTouchMouseSynthesis(); // Mouse positions are saved in widget coordinates diff --git a/tests/auto/qml/qqmlengine/data/CachedGetterLookup.qml b/tests/auto/qml/qqmlengine/data/CachedGetterLookup.qml new file mode 100644 index 0000000000..1a2a7ff341 --- /dev/null +++ b/tests/auto/qml/qqmlengine/data/CachedGetterLookup.qml @@ -0,0 +1,20 @@ +import QtQuick 2.12 + +QtObject { + Component.onCompleted: { + // create getter + var getFoo = function(o) { return o.foo; } + + // create two diffrent shapes for x,y + var x = { foo:1 , bar:2 } + var y = { bar:2 , foo:1 } + + // initialize inline cache with getFoo + getFoo(x); + getFoo(y); + + // hit getter lookup with string "crash" + getFoo('crash'); + } +} + diff --git a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp index b9cb6b70d2..0cb6753020 100644 --- a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp +++ b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp @@ -81,6 +81,7 @@ private slots: void cppSignalAndEval(); void singletonInstance(); void aggressiveGc(); + void cachedGetterLookup_qtbug_75335(); public slots: QObject *createAQObjectForOwnershipTest () @@ -1056,6 +1057,16 @@ void tst_qqmlengine::aggressiveGc() qputenv("QV4_MM_AGGRESSIVE_GC", origAggressiveGc); } +void tst_qqmlengine::cachedGetterLookup_qtbug_75335() +{ + QQmlEngine engine; + const QUrl testUrl = testFileUrl("CachedGetterLookup.qml"); + QQmlComponent component(&engine, testUrl); + QVERIFY(component.isReady()); + QScopedPointer<QObject> object(component.create()); + QVERIFY(object != nullptr); +} + QTEST_MAIN(tst_qqmlengine) #include "tst_qqmlengine.moc" diff --git a/tests/auto/quick/qquickaccessible/data/text.qml b/tests/auto/quick/qquickaccessible/data/text.qml index 88f292a61f..6daeacfd81 100644 --- a/tests/auto/quick/qquickaccessible/data/text.qml +++ b/tests/auto/quick/qquickaccessible/data/text.qml @@ -46,4 +46,15 @@ Item { text: "A multi-line text edit\nTesting Accessibility." Accessible.role: Accessible.EditableText } + + Text { + x: 100 + y: 160 + width: 100 + height: 40 + text : "Hello 3" + Accessible.name: text + Accessible.description: "description" + } + } diff --git a/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp b/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp index 243d87f212..c5fdb6c1b9 100644 --- a/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp +++ b/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp @@ -312,7 +312,7 @@ void tst_QQuickAccessible::basicPropertiesTest() QAccessibleInterface *item = iface->child(0); QVERIFY(item); - QCOMPARE(item->childCount(), 4); + QCOMPARE(item->childCount(), 5); QCOMPARE(item->rect().size(), QSize(400, 400)); QCOMPARE(item->role(), QAccessible::Client); QCOMPARE(iface->indexOfChild(item), 0); @@ -382,6 +382,30 @@ void tst_QQuickAccessible::basicPropertiesTest() QEXPECT_FAIL("", "multi line is not implemented", Continue); QCOMPARE(textInput->state().multiLine, 1); + // Text "Hello 3" + QAccessibleInterface *text3 = item->child(4); + QVERIFY(text3); + QCOMPARE(text3->childCount(), 0); + QCOMPARE(text3->text(QAccessible::Name), QLatin1String("Hello 3")); + QCOMPARE(text3->role(), QAccessible::StaticText); + QCOMPARE(item->indexOfChild(text3), 4); + QCOMPARE(text3->state().editable, 0); + QCOMPARE(text3->state().readOnly, 0); + // test implicit state values due to role change + QQuickAccessibleAttached *attached = QQuickAccessibleAttached::attachedProperties(text3->object()); + attached->setRole(QAccessible::StaticText); + QCOMPARE(text3->role(), QAccessible::StaticText); + QCOMPARE(text3->state().readOnly, 1); + + // see if implicit changes back + attached->setRole(QAccessible::EditableText); + QEXPECT_FAIL("", "EditableText does not implicitly set readOnly to false", Continue); + QCOMPARE(text3->state().readOnly, 0); + // explicitly set state + attached->set_readOnly(false); + attached->setRole(QAccessible::StaticText); + QCOMPARE(text3->state().readOnly, 0); + delete window; QTestAccessibility::clearEvents(); } diff --git a/tests/auto/quick/qquicktextedit/qquicktextedit.pro b/tests/auto/quick/qquicktextedit/qquicktextedit.pro index ea6e8bc60d..576e25d092 100644 --- a/tests/auto/quick/qquicktextedit/qquicktextedit.pro +++ b/tests/auto/quick/qquicktextedit/qquicktextedit.pro @@ -8,6 +8,7 @@ SOURCES += tst_qquicktextedit.cpp \ HEADERS += ../../shared/testhttpserver.h include (../../shared/util.pri) +include (../shared/util.pri) TESTDATA = data/* diff --git a/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp b/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp index ce2a8eb257..33a6b829bc 100644 --- a/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp +++ b/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp @@ -49,6 +49,7 @@ #include <QMimeData> #include <private/qquicktextcontrol_p.h> #include "../../shared/util.h" +#include "../shared/viewtestutil.h" #include "../../shared/platformquirks.h" #include "../../shared/platforminputcontext.h" #include <private/qinputmethod_p.h> @@ -63,6 +64,11 @@ Q_DECLARE_METATYPE(QQuickTextEdit::SelectionMode) Q_DECLARE_METATYPE(Qt::Key) DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD) +static bool isPlatformWayland() +{ + return !QGuiApplication::platformName().compare(QLatin1String("wayland"), Qt::CaseInsensitive); +} + QString createExpectedFileIfNotFound(const QString& filebasename, const QImage& actual) { // XXX This will be replaced by some clever persistent platform image store. @@ -133,6 +139,7 @@ private slots: void positionAt_data(); void positionAt(); + void linkHover(); void linkInteraction(); void cursorDelegate_data(); @@ -2536,10 +2543,59 @@ void tst_qquicktextedit::positionAt() QVERIFY(texteditObject->positionAt(x0 / 2, y1) > 0); } +#if QT_CONFIG(cursor) +void tst_qquicktextedit::linkHover() +{ + if (isPlatformWayland()) + QSKIP("Wayland: QCursor::setPos() doesn't work."); + + QQuickView window(testFileUrl("linkInteraction.qml")); + window.setFlag(Qt::FramelessWindowHint); + QVERIFY(window.rootObject() != nullptr); + QQuickViewTestUtil::centerOnScreen(&window); + QQuickViewTestUtil::moveMouseAway(&window); + window.show(); + window.requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(&window)); + QQuickTextEdit *texteditObject = qobject_cast<QQuickTextEdit *>(window.rootObject()); + QVERIFY(texteditObject != nullptr); + + QSignalSpy hover(texteditObject, SIGNAL(linkHovered(QString))); + + const QString link("http://example.com/"); + const QPoint linkPos = window.mapToGlobal(texteditObject->positionToRectangle(7).center().toPoint()); + const QPoint textPos = window.mapToGlobal(texteditObject->positionToRectangle(2).center().toPoint()); + + QCursor::setPos(linkPos); + QTRY_COMPARE(hover.count(), 1); + QCOMPARE(window.cursor().shape(), Qt::PointingHandCursor); + QCOMPARE(hover.last()[0].toString(), link); + + QCursor::setPos(textPos); + QTRY_COMPARE(hover.count(), 2); + QCOMPARE(window.cursor().shape(), Qt::IBeamCursor); + QCOMPARE(hover.last()[0].toString(), QString()); + + texteditObject->setCursor(Qt::OpenHandCursor); + + QCursor::setPos(linkPos); + QTRY_COMPARE(hover.count(), 3); + QCOMPARE(window.cursor().shape(), Qt::PointingHandCursor); + QCOMPARE(hover.last()[0].toString(), link); + + QCursor::setPos(textPos); + QTRY_COMPARE(hover.count(), 4); + QCOMPARE(window.cursor().shape(), Qt::OpenHandCursor); + QCOMPARE(hover.last()[0].toString(), QString()); +} +#endif + void tst_qquicktextedit::linkInteraction() { QQuickView window(testFileUrl("linkInteraction.qml")); QVERIFY(window.rootObject() != nullptr); + QQuickViewTestUtil::centerOnScreen(&window); + QQuickViewTestUtil::moveMouseAway(&window); window.show(); window.requestActivate(); QVERIFY(QTest::qWaitForWindowActive(&window)); diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp index 4cf7fa7119..f08b9207d1 100644 --- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp +++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp @@ -353,6 +353,11 @@ protected: m_mouseEvents << *event; } + void mouseDoubleClickEvent(QMouseEvent *event) override { + qCDebug(lcTests) << event; + m_mouseEvents << *event; + } + public: QList<QMouseEvent> m_mouseEvents; QList<QTouchEvent> m_touchEvents; @@ -401,6 +406,8 @@ private slots: void mouseFromTouch_basic(); void synthMouseFromTouch_data(); void synthMouseFromTouch(); + void synthMouseDoubleClickFromTouch_data(); + void synthMouseDoubleClickFromTouch(); void clearWindow(); @@ -1241,6 +1248,55 @@ void tst_qquickwindow::synthMouseFromTouch() QCOMPARE(ev.source(), Qt::MouseEventSynthesizedByQt); } +void tst_qquickwindow::synthMouseDoubleClickFromTouch_data() +{ + QTest::addColumn<QPoint>("movement"); + QTest::addColumn<QPoint>("distanceBetweenPresses"); + QTest::addColumn<bool>("expectedSynthesizedDoubleClickEvent"); + + QTest::newRow("normal") << QPoint(0, 0) << QPoint(0, 0) << true; + QTest::newRow("with 1 pixel wiggle") << QPoint(1, 1) << QPoint(1, 1) << true; + QTest::newRow("too much distance to second tap") << QPoint(0, 0) << QPoint(50, 0) << false; + QTest::newRow("too much drag") << QPoint(50, 0) << QPoint(0, 0) << false; + QTest::newRow("too much drag and too much distance to second tap") << QPoint(50, 0) << QPoint(50, 0) << false; +} + +void tst_qquickwindow::synthMouseDoubleClickFromTouch() +{ + QFETCH(QPoint, movement); + QFETCH(QPoint, distanceBetweenPresses); + QFETCH(bool, expectedSynthesizedDoubleClickEvent); + + QCoreApplication::setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, true); + QScopedPointer<MouseRecordingWindow> window(new MouseRecordingWindow); + QScopedPointer<MouseRecordingItem> item(new MouseRecordingItem(false, nullptr)); + item->setParentItem(window->contentItem()); + window->resize(250, 250); + window->setPosition(100, 100); + window->setTitle(QTest::currentTestFunction()); + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window.data())); + QTest::qWait(100); + + QPoint p1 = item->mapToScene(item->clipRect().center()).toPoint(); + QTest::touchEvent(window.data(), touchDevice).press(0, p1, window.data()); + QTest::touchEvent(window.data(), touchDevice).move(0, p1 + movement, window.data()); + QTest::touchEvent(window.data(), touchDevice).release(0, p1 + movement, window.data()); + + QPoint p2 = p1 + distanceBetweenPresses; + QTest::touchEvent(window.data(), touchDevice).press(1, p2, window.data()); + QTest::touchEvent(window.data(), touchDevice).move(1, p2 + movement, window.data()); + QTest::touchEvent(window.data(), touchDevice).release(1, p2 + movement, window.data()); + + const int eventCount = item->m_mouseEvents.count(); + QVERIFY(eventCount >= 2); + + const int nDoubleClicks = std::count_if(item->m_mouseEvents.constBegin(), item->m_mouseEvents.constEnd(), [](const QMouseEvent &ev) { return (ev.type() == QEvent::MouseButtonDblClick); } ); + const bool foundDoubleClick = (nDoubleClicks == 1); + QCOMPARE(foundDoubleClick, expectedSynthesizedDoubleClickEvent); + +} + void tst_qquickwindow::clearWindow() { QQuickWindow *window = new QQuickWindow; |