diff options
author | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2018-11-01 01:00:14 +0100 |
---|---|---|
committer | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2018-11-01 01:00:14 +0100 |
commit | 1a0b06bca7e6e23aede9dc624c7e4037cf486105 (patch) | |
tree | 199ea84d1c3410ef29414774dab1f07f099af6a3 | |
parent | 3ed8744d24032fdaa9c84f32f918a3027cb0420f (diff) | |
parent | 2609429d7afc263ab8e44864b0f42f1c8356eda8 (diff) |
Merge remote-tracking branch 'origin/5.12' into dev
Change-Id: I7a2b9bdb69512b2d52050d829b1b65f4fcd9d99d
21 files changed, 340 insertions, 53 deletions
diff --git a/src/imports/layouts/qquicklayout.cpp b/src/imports/layouts/qquicklayout.cpp index cc206bcb95..d90eae5f80 100644 --- a/src/imports/layouts/qquicklayout.cpp +++ b/src/imports/layouts/qquicklayout.cpp @@ -74,10 +74,14 @@ false, the item's size will be fixed to its preferred size. Otherwise, it will grow or shrink between its minimum and maximum size as the layout is resized. - \note It is not recommended to have bindings to the x, y, width, or height properties of items - in a layout, since this would conflict with the goals of Layout, and can also cause binding - loops. - + \note Do not bind to the x, y, width, or height properties of items in a layout, + as this would conflict with the goals of Layout, and can also cause binding loops. + The width and height properties are used by the layout engine to store the current + size of items as calculated from the minimum/preferred/maximum attached properties, + and can be ovewritten each time the items are laid out. Use + \l {Layout::preferredWidth}{Layout.preferredWidth} and + \l {Layout::preferredHeight}{Layout.preferredHeight}, or \l {Item::}{implicitWidth} + and \l {Item::}{implicitHeight} to specify the preferred size of items. \sa GridLayout \sa RowLayout diff --git a/src/imports/settings/qqmlsettings.cpp b/src/imports/settings/qqmlsettings.cpp index 6b3904909a..310ef62d9f 100644 --- a/src/imports/settings/qqmlsettings.cpp +++ b/src/imports/settings/qqmlsettings.cpp @@ -39,10 +39,12 @@ #include "qqmlsettings_p.h" #include <qcoreevent.h> +#include <qcoreapplication.h> #include <qloggingcategory.h> #include <qsettings.h> #include <qpointer.h> #include <qjsvalue.h> +#include <qqmlinfo.h> #include <qdebug.h> #include <qhash.h> @@ -271,6 +273,26 @@ QSettings *QQmlSettingsPrivate::instance() const if (!settings) { QQmlSettings *q = const_cast<QQmlSettings*>(q_func()); settings = fileName.isEmpty() ? new QSettings(q) : new QSettings(fileName, QSettings::IniFormat, q); + if (settings->status() != QSettings::NoError) { + // TODO: can't print out the enum due to the following error: + // error: C2666: 'QQmlInfo::operator <<': 15 overloads have similar conversions + qmlWarning(q) << "Failed to initialize QSettings instance. Status code is: " << int(settings->status()); + + if (settings->status() == QSettings::AccessError) { + QVector<QString> missingIdentifiers; + if (QCoreApplication::organizationName().isEmpty()) + missingIdentifiers.append(QLatin1String("organizationName")); + if (QCoreApplication::organizationDomain().isEmpty()) + missingIdentifiers.append(QLatin1String("organizationDomain")); + if (QCoreApplication::applicationName().isEmpty()) + missingIdentifiers.append(QLatin1String("applicationName")); + + if (!missingIdentifiers.isEmpty()) + qmlWarning(q) << "The following application identifiers have not been set: " << missingIdentifiers; + } + return settings; + } + if (!category.isEmpty()) settings->beginGroup(category); if (initialized) diff --git a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc index 31650db7c0..2bb1fcac61 100644 --- a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc +++ b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc @@ -462,6 +462,8 @@ Unlike an ordinary property, an alias has the following restrictions: \li The \e {alias reference} is not optional, unlike the optional default value for an ordinary property; the alias reference must be provided when the alias is first declared. +\li It cannot refer to \l {Attached Properties and Attached Signal Handlers} + {attached properties}. \li It cannot refer to grouped properties; the following code will not work: \code property alias color: rectangle.border.color diff --git a/src/qml/jsruntime/qv4promiseobject_p.h b/src/qml/jsruntime/qv4promiseobject_p.h index 80f7183074..bce59b19a7 100644 --- a/src/qml/jsruntime/qv4promiseobject_p.h +++ b/src/qml/jsruntime/qv4promiseobject_p.h @@ -39,6 +39,17 @@ #ifndef QV4PROMISEOBJECT_H #define QV4PROMISEOBJECT_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include "qv4object_p.h" #include "qv4functionobject_p.h" diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index a67c5c4a2b..5ed3cc5d6a 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -1132,22 +1132,23 @@ class QQmlComponentIncubator : public QQmlIncubator public: QQmlComponentIncubator(QV4::Heap::QmlIncubatorObject *inc, IncubationMode mode) : QQmlIncubator(mode) - , incubatorObject(inc) - {} + { + incubatorObject.set(inc->internalClass->engine, inc); + } void statusChanged(Status s) override { - QV4::Scope scope(incubatorObject->internalClass->engine); - QV4::Scoped<QV4::QmlIncubatorObject> i(scope, incubatorObject); + QV4::Scope scope(incubatorObject.engine()); + QV4::Scoped<QV4::QmlIncubatorObject> i(scope, incubatorObject.as<QV4::QmlIncubatorObject>()); i->statusChanged(s); } void setInitialState(QObject *o) override { - QV4::Scope scope(incubatorObject->internalClass->engine); - QV4::Scoped<QV4::QmlIncubatorObject> i(scope, incubatorObject); + QV4::Scope scope(incubatorObject.engine()); + QV4::Scoped<QV4::QmlIncubatorObject> i(scope, incubatorObject.as<QV4::QmlIncubatorObject>()); i->setInitialState(o); } - QV4::Heap::QmlIncubatorObject *incubatorObject; + QV4::PersistentValue incubatorObject; // keep a strong internal reference while incubating }; @@ -1571,6 +1572,9 @@ void QV4::QmlIncubatorObject::statusChanged(QQmlIncubator::Status s) QQmlEnginePrivate::warning(QQmlEnginePrivate::get(scope.engine->qmlEngine()), error); } } + + if (s != QQmlIncubator::Loading) + d()->incubator->incubatorObject.clear(); } #undef INITIALPROPERTIES_SOURCE diff --git a/src/quick/accessible/qaccessiblequickitem.cpp b/src/quick/accessible/qaccessiblequickitem.cpp index 87e581384b..98e7663c96 100644 --- a/src/quick/accessible/qaccessiblequickitem.cpp +++ b/src/quick/accessible/qaccessiblequickitem.cpp @@ -205,14 +205,16 @@ QAccessible::Role QAccessibleQuickItem::role() const // Workaround for setAccessibleRole() not working for // Text items. Text items are special since they are defined // entirely from C++ (setting the role from QML works.) - if (qobject_cast<QQuickText*>(const_cast<QQuickItem *>(item()))) - return QAccessible::StaticText; QAccessible::Role role = QAccessible::NoRole; if (item()) role = QQuickItemPrivate::get(item())->accessibleRole(); - if (role == QAccessible::NoRole) - role = QAccessible::Client; + if (role == QAccessible::NoRole) { + if (qobject_cast<QQuickText*>(const_cast<QQuickItem *>(item()))) + role = QAccessible::StaticText; + else + role = QAccessible::Client; + } return role; } diff --git a/src/quick/items/qquickevents_p_p.h b/src/quick/items/qquickevents_p_p.h index f3ce04d11e..d1a8bbd901 100644 --- a/src/quick/items/qquickevents_p_p.h +++ b/src/quick/items/qquickevents_p_p.h @@ -450,6 +450,8 @@ protected: Qt::MouseButton m_button = Qt::NoButton; Qt::MouseButtons m_pressedButtons; + friend class QQuickWindowPrivate; + Q_DISABLE_COPY(QQuickPointerEvent) }; diff --git a/src/quick/items/qquickflickable_p.h b/src/quick/items/qquickflickable_p.h index 57cc2533a0..7e9b18e101 100644 --- a/src/quick/items/qquickflickable_p.h +++ b/src/quick/items/qquickflickable_p.h @@ -267,10 +267,11 @@ Q_SIGNALS: Q_REVISION(9) void horizontalOvershootChanged(); Q_REVISION(9) void verticalOvershootChanged(); - Q_REVISION(12) void atXEndChanged(); - Q_REVISION(12) void atYEndChanged(); - Q_REVISION(12) void atXBeginningChanged(); - Q_REVISION(12) void atYBeginningChanged(); + // The next four signals should be marked as Q_REVISION(12). See QTBUG-71243 + void atXEndChanged(); + void atYEndChanged(); + void atXBeginningChanged(); + void atYBeginningChanged(); protected: bool childMouseEventFilter(QQuickItem *, QEvent *) override; diff --git a/src/quick/items/qquicktext_p.h b/src/quick/items/qquicktext_p.h index f4e7fa7046..1af60051fb 100644 --- a/src/quick/items/qquicktext_p.h +++ b/src/quick/items/qquicktext_p.h @@ -272,8 +272,10 @@ Q_SIGNALS: void textFormatChanged(QQuickText::TextFormat textFormat); void elideModeChanged(QQuickText::TextElideMode mode); void contentSizeChanged(); - Q_REVISION(12) void contentWidthChanged(qreal contentWidth); - Q_REVISION(12) void contentHeightChanged(qreal contentHeight); + // The next two signals should be marked as Q_REVISION(12). See QTBUG-71247 + void contentWidthChanged(qreal contentWidth); + void contentHeightChanged(qreal contentHeight); + void lineHeightChanged(qreal lineHeight); void lineHeightModeChanged(LineHeightMode mode); void fontSizeModeChanged(); diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index d27ee54c89..4f14eedd39 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -2548,6 +2548,10 @@ bool QQuickWindowPrivate::deliverPressOrReleaseEvent(QQuickPointerEvent *event, } for (QQuickItem *item : targetItems) { + if (!event->m_event) { + qWarning("event went missing during delivery! (nested sendEvent() is not allowed)"); + break; + } hasFiltered.clear(); if (!handlersOnly && sendFilteredPointerEvent(event, item)) { if (event->isAccepted()) { @@ -2562,6 +2566,10 @@ bool QQuickWindowPrivate::deliverPressOrReleaseEvent(QQuickPointerEvent *event, // nor to any item which already had a chance to filter. if (skipDelivery.contains(item)) continue; + if (!event->m_event) { + qWarning("event went missing during delivery! (nested sendEvent() is not allowed)"); + break; + } deliverMatchingPointsToItem(item, event, handlersOnly); if (event->allPointsAccepted()) handlersOnly = true; diff --git a/src/quick/scenegraph/qsgbasicinternalimagenode.cpp b/src/quick/scenegraph/qsgbasicinternalimagenode.cpp index 53271af9ab..03b48b4b8a 100644 --- a/src/quick/scenegraph/qsgbasicinternalimagenode.cpp +++ b/src/quick/scenegraph/qsgbasicinternalimagenode.cpp @@ -230,6 +230,9 @@ QSGGeometry *QSGBasicInternalImageNode::updateGeometry(const QRectF &targetRect, ++vCells; if (innerTargetRect.bottom() != targetRect.bottom()) ++vCells; + if (hCells * vCells * 4 >= 0x10000) + qWarning("QTBUG-58924 - Too many tiles in QSGInternalImageNode, rendering will be partially missing."); + QVarLengthArray<X, 32> xData(2 * hCells); QVarLengthArray<Y, 32> yData(2 * vCells); X *xs = xData.data(); diff --git a/src/quick/util/qquickstategroup.cpp b/src/quick/util/qquickstategroup.cpp index 3d8c5e0507..d8daec2f07 100644 --- a/src/quick/util/qquickstategroup.cpp +++ b/src/quick/util/qquickstategroup.cpp @@ -302,7 +302,8 @@ void QQuickStateGroup::componentComplete() Q_D(QQuickStateGroup); d->componentComplete = true; - QSet<QString> names; + QVarLengthArray<QString, 4> names; + names.reserve(d->states.count()); for (int ii = 0; ii < d->states.count(); ++ii) { QQuickState *state = d->states.at(ii); if (!state->isNamed()) @@ -312,7 +313,7 @@ void QQuickStateGroup::componentComplete() if (names.contains(stateName)) { qmlWarning(state->parent()) << "Found duplicate state name: " << stateName; } else { - names << stateName; + names.append(std::move(stateName)); } } diff --git a/tests/auto/qml/qqmlincubator/data/garbageCollection.qml b/tests/auto/qml/qqmlincubator/data/garbageCollection.qml new file mode 100644 index 0000000000..6866a02a00 --- /dev/null +++ b/tests/auto/qml/qqmlincubator/data/garbageCollection.qml @@ -0,0 +1,19 @@ +import QtQuick 2.0 + +QtObject { + id: root + + property var incubator + + function getAndClearIncubator() { + var result = incubator + incubator = null + return result + } + + Component.onCompleted: { + var c = Qt.createComponent("statusChanged.qml"); // use existing simple type for convenience + var incubator = c.incubateObject(root); + incubator.onStatusChanged = function(status) { if (status === 1) root.incubator = incubator } + } +} diff --git a/tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp b/tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp index 8f0e04e12e..8e25079703 100644 --- a/tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp +++ b/tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp @@ -39,6 +39,7 @@ #include <QQmlComponent> #include <QQmlIncubator> #include "../../shared/util.h" +#include <private/qjsvalue_p.h> #include <private/qqmlincubator_p.h> #include <private/qqmlobjectcreator_p.h> @@ -68,6 +69,7 @@ private slots: void chainedAsynchronousClear(); void selfDelete(); void contextDelete(); + void garbageCollection(); private: QQmlIncubationController controller; @@ -1144,6 +1146,34 @@ void tst_qqmlincubator::contextDelete() } } +// QTBUG-53111 +void tst_qqmlincubator::garbageCollection() +{ + QQmlComponent component(&engine, testFileUrl("garbageCollection.qml")); + QScopedPointer<QObject> obj(component.create()); + + engine.collectGarbage(); + + bool b = true; + controller.incubateWhile(&b); + + // verify incubation completed (the incubator was not prematurely collected) + QVariant incubatorVariant; + QMetaObject::invokeMethod(obj.data(), "getAndClearIncubator", Q_RETURN_ARG(QVariant, incubatorVariant)); + QJSValue strongRef = incubatorVariant.value<QJSValue>(); + QVERIFY(!strongRef.isNull() && !strongRef.isUndefined()); + + // turn the last strong reference to the incubator into a weak one and collect + QV4::WeakValue weakIncubatorRef; + weakIncubatorRef.set(QQmlEnginePrivate::getV4Engine(&engine), *QJSValuePrivate::getValue(&strongRef)); + strongRef = QJSValue(); + incubatorVariant.clear(); + + // verify incubator is correctly collected now that incubation is complete and all references are gone + engine.collectGarbage(); + QVERIFY(weakIncubatorRef.isNullOrUndefined()); +} + QTEST_MAIN(tst_qqmlincubator) #include "tst_qqmlincubator.moc" diff --git a/tests/auto/qml/qqmlsettings/tst_qqmlsettings.cpp b/tests/auto/qml/qqmlsettings/tst_qqmlsettings.cpp index b353d23539..b0be799bd5 100644 --- a/tests/auto/qml/qqmlsettings/tst_qqmlsettings.cpp +++ b/tests/auto/qml/qqmlsettings/tst_qqmlsettings.cpp @@ -53,6 +53,7 @@ private slots: void categories(); void siblings(); void initial(); + void noApplicationIdentifiersSet(); }; // ### Replace keyValueMap("foo", "bar") with QVariantMap({{"foo", "bar"}}) @@ -147,10 +148,6 @@ void tst_QQmlSettings::initTestCase() { QQmlDataTest::initTestCase(); - QCoreApplication::setApplicationName("tst_QQmlSettings"); - QCoreApplication::setOrganizationName("QtProject"); - QCoreApplication::setOrganizationDomain("qt-project.org"); - qmlRegisterType<CppObject>("Qt.test", 1, 0, "CppObject"); } @@ -158,6 +155,10 @@ void tst_QQmlSettings::init() { QSettings settings; settings.clear(); + + QCoreApplication::setApplicationName("tst_QQmlSettings"); + QCoreApplication::setOrganizationName("QtProject"); + QCoreApplication::setOrganizationDomain("qt-project.org"); } void tst_QQmlSettings::cleanup() @@ -481,6 +482,31 @@ void tst_QQmlSettings::initial() QCOMPARE(settings->property("value").toString(), QStringLiteral("initial")); } +void tst_QQmlSettings::noApplicationIdentifiersSet() +{ +#ifdef Q_OS_MACOS + QSKIP("macOS doesn't complain about empty application identifiers"); +#endif + + QCoreApplication::setApplicationName(QString()); + QCoreApplication::setOrganizationName(QString()); + QCoreApplication::setOrganizationDomain(QString()); + + QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*QML Settings: Failed to initialize QSettings instance. Status code is: 1")); + // Can't set an empty applicationName because QCoreApplication won't allow it, which is why it's not listed here. + QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*QML Settings: The following application identifiers have not been set: QVector\\(\"organizationName\", \"organizationDomain\"\\)")); + + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("basic.qml")); + QScopedPointer<QObject> root(component.create()); + QVERIFY(root.data()); + // The value of the QML property will be true because it defaults to it... + QVERIFY(root->property("success").toBool()); + QSettings settings; + // ... but the settings' value should be false because it was never loaded. + QVERIFY(!settings.value("success").toBool()); +} + QTEST_MAIN(tst_QQmlSettings) #include "tst_qqmlsettings.moc" diff --git a/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp b/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp index 0ee78fae54..1bfeb94161 100644 --- a/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp +++ b/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp @@ -42,9 +42,11 @@ #include <QtQml/qqmlengine.h> #include <QtQml/qqmlproperty.h> #include <QtQuick/private/qquickaccessibleattached_p.h> +#include <QtQuick/private/qquicklistview_p.h> +#include <QtQuick/private/qquicktext_p.h> #include "../../shared/util.h" - +#include "../shared/visualtestutil.h" #define EXPECT(cond) \ do { \ @@ -224,6 +226,72 @@ void tst_QQuickAccessible::quickAttachedProperties() } delete object; } + + // Check overriding of attached role for Text + { + QQmlEngine engine; + QQmlComponent component(&engine); + component.setData("import QtQuick 2.0\nText {\n" + "Accessible.role: Accessible.Button\n" + "Accessible.name: \"TextButton\"\n" + "Accessible.description: \"Text Button\"\n" + "}", QUrl()); + QObject *object = component.create(); + QVERIFY(object != nullptr); + + QObject *attachedObject = QQuickAccessibleAttached::attachedProperties(object); + QVERIFY(attachedObject); + if (attachedObject) { + QVariant p = attachedObject->property("role"); + QCOMPARE(p.isNull(), false); + QCOMPARE(p.toInt(), int(QAccessible::PushButton)); + p = attachedObject->property("name"); + QCOMPARE(p.isNull(), false); + QCOMPARE(p.toString(), QLatin1String("TextButton")); + p = attachedObject->property("description"); + QCOMPARE(p.isNull(), false); + QCOMPARE(p.toString(), QLatin1String("Text Button")); + } + delete object; + } + // Check overriding of attached role for Text + { + QQmlEngine engine; + QQmlComponent component(&engine); + component.setData("import QtQuick 2.0\nListView {\n" + "id: list\n" + "model: 5\n" + "delegate: Text {\n" + "objectName: \"acc_text\"\n" + "Accessible.role: Accessible.Button\n" + "Accessible.name: \"TextButton\"\n" + "Accessible.description: \"Text Button\"\n" + "}\n" + "}", QUrl()); + QObject *object = component.create(); + QVERIFY(object != nullptr); + + QQuickListView *listview = qobject_cast<QQuickListView *>(object); + QVERIFY(listview != nullptr); + QQuickItem *contentItem = listview->contentItem(); + QQuickText *childItem = QQuickVisualTestUtil::findItem<QQuickText>(contentItem, "acc_text"); + QVERIFY(childItem != nullptr); + + QObject *attachedObject = QQuickAccessibleAttached::attachedProperties(childItem); + QVERIFY(attachedObject); + if (attachedObject) { + QVariant p = attachedObject->property("role"); + QCOMPARE(p.isNull(), false); + QCOMPARE(p.toInt(), int(QAccessible::PushButton)); + p = attachedObject->property("name"); + QCOMPARE(p.isNull(), false); + QCOMPARE(p.toString(), QLatin1String("TextButton")); + p = attachedObject->property("description"); + QCOMPARE(p.isNull(), false); + QCOMPARE(p.toString(), QLatin1String("Text Button")); + } + delete object; + } QTestAccessibility::clearEvents(); } diff --git a/tests/auto/quick/qquickmousearea/data/nestedSendEvent.qml b/tests/auto/quick/qquickmousearea/data/nestedSendEvent.qml new file mode 100644 index 0000000000..908a43b04e --- /dev/null +++ b/tests/auto/quick/qquickmousearea/data/nestedSendEvent.qml @@ -0,0 +1,49 @@ +import QtQuick 2.11 +import QtQuick.Window 2.11 +import Test 1.0 + +Window { + id: window + visible: true + width: 200 + height: 200 + + property EventSender sender: EventSender { } + + Item { + width: 200 + height: 200 + + MouseArea { + anchors.fill: parent + } + + Item { + width: 200 + height: 200 + + Rectangle { + width: 200 + height: 100 + color: "red" + + MouseArea { + anchors.fill: parent + onPressed: sender.sendMouseClick(window, 50, 50) + } + } + + Rectangle { + y: 100 + width: 200 + height: 100 + color: "yellow" + + MouseArea { + anchors.fill: parent + onPressed: sender.sendMouseClick(window, 50, 50) + } + } + } + } +} diff --git a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp index aa379e834e..558ca2e759 100644 --- a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp +++ b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp @@ -98,6 +98,22 @@ private: qreal m_radius; }; +class EventSender : public QObject { + Q_OBJECT + +public: + Q_INVOKABLE void sendMouseClick(QObject* obj ,qreal x , qreal y) { + { + QMouseEvent event(QEvent::MouseButtonPress, QPointF(x , y), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); + qApp->sendEvent(obj, &event); + } + { + QMouseEvent event(QEvent::MouseButtonRelease, QPointF(x , y), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); + qApp->sendEvent(obj, &event); + } + } +}; + class tst_QQuickMouseArea: public QQmlDataTest { Q_OBJECT @@ -106,6 +122,7 @@ public: : device(nullptr) { qmlRegisterType<CircleMask>("Test", 1, 0, "CircleMask"); + qmlRegisterType<EventSender>("Test", 1, 0, "EventSender"); } private slots: @@ -165,6 +182,7 @@ private slots: void pressOneAndTapAnother_data(); void pressOneAndTapAnother(); void mask(); + void nestedEventDelivery(); private: int startDragDistance() const { @@ -2298,6 +2316,21 @@ void tst_QQuickMouseArea::mask() QCOMPARE(window.rootObject()->property("clicked").toInt(), 1); } +void tst_QQuickMouseArea::nestedEventDelivery() // QTBUG-70898 +{ + QQmlEngine engine; + QQmlComponent c(&engine, testFileUrl("nestedSendEvent.qml")); + QScopedPointer<QQuickWindow> window(qmlobject_cast<QQuickWindow *>(c.create())); + QVERIFY(window.data()); + + // Click each MouseArea and verify that it doesn't crash + QByteArray message = "event went missing during delivery! (nested sendEvent() is not allowed)"; + QTest::ignoreMessage(QtWarningMsg, message); + QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(50,50)); + QTest::ignoreMessage(QtWarningMsg, message); // twice though, actually + QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(50,150)); +} + QTEST_MAIN(tst_QQuickMouseArea) #include "tst_qquickmousearea.moc" diff --git a/tests/auto/quick/qquickstates/data/duplicateStateName.qml b/tests/auto/quick/qquickstates/data/duplicateStateName.qml new file mode 100644 index 0000000000..7bfafbef1b --- /dev/null +++ b/tests/auto/quick/qquickstates/data/duplicateStateName.qml @@ -0,0 +1,13 @@ +import QtQuick 2.0 + +Rectangle { + property bool condition1: false + property bool condition2: false + property bool condition3: false + + states: [ + State { name: "state1"; when: condition1 }, + State { name: "state2"; when: condition2 }, + State { name: "state1"; when: condition3 } + ] +} diff --git a/tests/auto/quick/qquickstates/tst_qquickstates.cpp b/tests/auto/quick/qquickstates/tst_qquickstates.cpp index 073fe33e20..50554f6333 100644 --- a/tests/auto/quick/qquickstates/tst_qquickstates.cpp +++ b/tests/auto/quick/qquickstates/tst_qquickstates.cpp @@ -137,6 +137,7 @@ private slots: void revertListBug(); void QTBUG_38492(); void revertListMemoryLeak(); + void duplicateStateName(); }; void tst_qquickstates::initTestCase() @@ -1654,6 +1655,17 @@ void tst_qquickstates::revertListMemoryLeak() QVERIFY(bindingPtr->ref == 1); } +void tst_qquickstates::duplicateStateName() +{ + QQmlEngine engine; + + QQmlComponent c(&engine, testFileUrl("duplicateStateName.qml")); + QTest::ignoreMessage(QtWarningMsg, fullDataPath("duplicateStateName.qml") + ":3:1: QML Rectangle: Found duplicate state name: state1"); + QScopedPointer<QQuickItem> item(qobject_cast<QQuickItem *>(c.create())); + QVERIFY(!item.isNull()); +} + + QTEST_MAIN(tst_qquickstates) #include "tst_qquickstates.moc" diff --git a/tools/qmlplugindump/main.cpp b/tools/qmlplugindump/main.cpp index e7523ec269..7ab42e9a26 100644 --- a/tools/qmlplugindump/main.cpp +++ b/tools/qmlplugindump/main.cpp @@ -66,9 +66,6 @@ #include <QtGui/private/qsimulatorconnection_p.h> #endif -#ifdef Q_OS_UNIX -#include <signal.h> -#endif #ifdef Q_OS_WIN # if !defined(Q_CC_MINGW) # include <crtdbg.h> @@ -750,17 +747,6 @@ enum ExitCode { EXIT_IMPORTERROR = 3 }; -#ifdef Q_OS_UNIX -Q_NORETURN void sigSegvHandler(int) { - fprintf(stderr, "Error: SEGV\n"); - if (!currentProperty.isEmpty()) - fprintf(stderr, "While processing the property '%s', which probably has uninitialized data.\n", currentProperty.toLatin1().constData()); - if (!inObjectInstantiation.isEmpty()) - fprintf(stderr, "While instantiating the object '%s'.\n", inObjectInstantiation.toLatin1().constData()); - exit(EXIT_SEGV); -} -#endif - void printUsage(const QString &appName) { std::cerr << qPrintable(QString( @@ -985,17 +971,6 @@ int main(int argc, char *argv[]) #endif // Q_OS_WIN && !Q_CC_MINGW // The default message handler might not print to console on some systems. Enforce this. qInstallMessageHandler(printDebugMessage); -#ifdef Q_OS_UNIX - // qmldump may crash, but we don't want any crash handlers to pop up - // therefore we intercept the segfault and just exit() ourselves - struct sigaction sigAction; - - sigemptyset(&sigAction.sa_mask); - sigAction.sa_handler = &sigSegvHandler; - sigAction.sa_flags = 0; - - sigaction(SIGSEGV, &sigAction, nullptr); -#endif #ifdef QT_SIMULATOR // Running this application would bring up the Qt Simulator (since it links Qt GUI), avoid that! |