From a82b1b278ace7a500f95473f2a873923d2d4e60a Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Wed, 29 Jan 2020 10:13:08 +0100 Subject: QQuickFlickable: fix division by zero The issue could be seen when enabling exceptions and running the following QML code: Flickable { id: flickable anchors.fill: parent contentWidth: 1000 contentHeight: 1000 Text { text: flickable.visibleArea.xPosition } } Change-Id: I615f9f9dc84903fb3a902f416a55e3ce3fece64c Fixes: QTBUG-81098 Reviewed-by: Ulf Hermann --- src/quick/items/qquickflickable.cpp | 19 ++++++++--- .../qquickflickable/data/visibleAreaBinding.qml | 38 ++++++++++++++++++++++ .../quick/qquickflickable/tst_qquickflickable.cpp | 11 +++++++ 3 files changed, 64 insertions(+), 4 deletions(-) create mode 100644 tests/auto/quick/qquickflickable/data/visibleAreaBinding.qml diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp index d9ec7de611..52f7c29aa4 100644 --- a/src/quick/items/qquickflickable.cpp +++ b/src/quick/items/qquickflickable.cpp @@ -128,8 +128,13 @@ void QQuickFlickableVisibleArea::updateVisible() // Vertical const qreal viewheight = flickable->height(); const qreal maxyextent = -flickable->maxYExtent() + flickable->minYExtent(); - qreal pagePos = (-p->vData.move.value() + flickable->minYExtent()) / (maxyextent + viewheight); - qreal pageSize = viewheight / (maxyextent + viewheight); + const qreal maxYBounds = maxyextent + viewheight; + qreal pagePos = 0; + qreal pageSize = 0; + if (!qFuzzyIsNull(maxYBounds)) { + pagePos = (-p->vData.move.value() + flickable->minYExtent()) / maxYBounds; + pageSize = viewheight / maxYBounds; + } if (pageSize != m_heightRatio) { m_heightRatio = pageSize; @@ -143,8 +148,14 @@ void QQuickFlickableVisibleArea::updateVisible() // Horizontal const qreal viewwidth = flickable->width(); const qreal maxxextent = -flickable->maxXExtent() + flickable->minXExtent(); - pagePos = (-p->hData.move.value() + flickable->minXExtent()) / (maxxextent + viewwidth); - pageSize = viewwidth / (maxxextent + viewwidth); + const qreal maxXBounds = maxxextent + viewwidth; + if (!qFuzzyIsNull(maxXBounds)) { + pagePos = (-p->hData.move.value() + flickable->minXExtent()) / maxXBounds; + pageSize = viewwidth / maxXBounds; + } else { + pagePos = 0; + pageSize = 0; + } if (pageSize != m_widthRatio) { m_widthRatio = pageSize; diff --git a/tests/auto/quick/qquickflickable/data/visibleAreaBinding.qml b/tests/auto/quick/qquickflickable/data/visibleAreaBinding.qml new file mode 100644 index 0000000000..6f7bc89793 --- /dev/null +++ b/tests/auto/quick/qquickflickable/data/visibleAreaBinding.qml @@ -0,0 +1,38 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.14 + +Flickable { + id: flickable + // Deliberately has no size set. + + Text { + text: flickable.visibleArea.xPosition + } +} diff --git a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp index c104eecbcd..da4bf5dae3 100644 --- a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp +++ b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp @@ -205,6 +205,7 @@ private slots: void overshoot_reentrant(); void synchronousDrag_data(); void synchronousDrag(); + void visibleAreaBinding(); private: void flickWithTouch(QQuickWindow *window, const QPoint &from, const QPoint &to); @@ -2541,6 +2542,16 @@ void tst_qquickflickable::synchronousDrag() QTest::touchEvent(window, touchDevice).release(0, p5, window); } +// QTBUG-81098: tests that a binding to visibleArea doesn't result +// in a division-by-zero exception (when exceptions are enabled). +void tst_qquickflickable::visibleAreaBinding() +{ + QScopedPointer window(new QQuickView); + window->setSource(testFileUrl("visibleAreaBinding.qml")); + QTRY_COMPARE(window->status(), QQuickView::Ready); + // Shouldn't crash. +} + QTEST_MAIN(tst_qquickflickable) #include "tst_qquickflickable.moc" -- cgit v1.2.3 From 228f854ff99719d4c8151a3b52612e74f649f2b8 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 13 Jan 2020 18:36:13 +0100 Subject: Get rid of global gadgetPtr in QQmlValueType We should not keep user-created objects in global data structures. This is inherently thread-unsafe and crashes when the user passes static data and later unloads the same. Instead we keep the cached gadgetPtr wrapper objects in the engine now. Fixes: QTBUG-79553 Change-Id: I24ac3e84b572831d1d70b61b8a6001338579e284 Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlengine_p.h | 16 ++++ src/qml/qml/qqmlobjectcreator.cpp | 4 +- src/qml/qml/qqmlproperty.cpp | 38 ++++++--- src/qml/qml/qqmlvaluetype.cpp | 92 +++++++++++++--------- src/qml/qml/qqmlvaluetype_p.h | 49 +++++++++--- src/qml/qml/qqmlvmemetaobject.cpp | 12 +-- .../designer/qquickdesignersupportproperties.cpp | 8 +- 7 files changed, 150 insertions(+), 69 deletions(-) diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h index 385ae02ce5..502e2ed3d9 100644 --- a/src/qml/qml/qqmlengine_p.h +++ b/src/qml/qml/qqmlengine_p.h @@ -263,8 +263,24 @@ public: mutable QMutex networkAccessManagerMutex; + QQmlGadgetPtrWrapper *valueTypeInstance(int typeIndex) + { + auto it = cachedValueTypeInstances.find(typeIndex); + if (it != cachedValueTypeInstances.end()) + return *it; + + if (QQmlValueType *valueType = QQmlValueTypeFactory::valueType(typeIndex)) { + QQmlGadgetPtrWrapper *instance = new QQmlGadgetPtrWrapper(valueType, q_func()); + cachedValueTypeInstances.insert(typeIndex, instance); + return instance; + } + + return nullptr; + } + private: QHash singletonInstances; + QHash cachedValueTypeInstances; // These members must be protected by a QQmlEnginePrivate::Locker as they are required by // the threaded loader. Only access them through their respective accessor methods. diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index a4270628e8..836d27f245 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -871,12 +871,12 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper if (stringAt(obj->inheritedTypeNameIndex).isEmpty()) { QObject *groupObject = nullptr; - QQmlValueType *valueType = nullptr; + QQmlGadgetPtrWrapper *valueType = nullptr; const QQmlPropertyData *valueTypeProperty = nullptr; QObject *bindingTarget = _bindingTarget; if (QQmlValueTypeFactory::isValueType(bindingProperty->propType())) { - valueType = QQmlValueTypeFactory::valueType(bindingProperty->propType()); + valueType = QQmlGadgetPtrWrapper::instance(engine, bindingProperty->propType()); if (!valueType) { recordError(binding->location, tr("Cannot set properties on %1 as it is null").arg(stringAt(binding->propertyNameIndex))); return false; diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp index f5aae8f462..d191d07258 100644 --- a/src/qml/qml/qqmlproperty.cpp +++ b/src/qml/qml/qqmlproperty.cpp @@ -1044,13 +1044,19 @@ QVariant QQmlProperty::read(const QObject *object, const QString &name, QQmlEngi QVariant QQmlPropertyPrivate::readValueProperty() { - if (isValueType()) { - - QQmlValueType *valueType = QQmlValueTypeFactory::valueType(core.propType()); - Q_ASSERT(valueType); - valueType->read(object, core.coreIndex()); - return valueType->metaObject()->property(valueTypeData.coreIndex()).read(valueType); + auto doRead = [&](QQmlGadgetPtrWrapper *wrapper) { + wrapper->read(object, core.coreIndex()); + return wrapper->property(valueTypeData.coreIndex()).read(wrapper); + }; + if (isValueType()) { + if (QQmlGadgetPtrWrapper *wrapper = QQmlGadgetPtrWrapper::instance(engine, core.propType())) + return doRead(wrapper); + if (QQmlValueType *valueType = QQmlValueTypeFactory::valueType(core.propType())) { + QQmlGadgetPtrWrapper wrapper(valueType, nullptr); + return doRead(&wrapper); + } + return QVariant(); } else if (core.isQList()) { QQmlListProperty prop; @@ -1183,10 +1189,22 @@ QQmlPropertyPrivate::writeValueProperty(QObject *object, bool rv = false; if (valueTypeData.isValid()) { - QQmlValueType *writeBack = QQmlValueTypeFactory::valueType(core.propType()); - writeBack->read(object, core.coreIndex()); - rv = write(writeBack, valueTypeData, value, context, flags); - writeBack->write(object, core.coreIndex(), flags); + auto doWrite = [&](QQmlGadgetPtrWrapper *wrapper) { + wrapper->read(object, core.coreIndex()); + rv = write(wrapper, valueTypeData, value, context, flags); + wrapper->write(object, core.coreIndex(), flags); + }; + + QQmlGadgetPtrWrapper *wrapper = context + ? QQmlGadgetPtrWrapper::instance(context->engine, core.propType()) + : nullptr; + if (wrapper) { + doWrite(wrapper); + } else if (QQmlValueType *valueType = QQmlValueTypeFactory::valueType(core.propType())) { + QQmlGadgetPtrWrapper wrapper(valueType, nullptr); + doWrite(&wrapper); + } + } else { rv = write(object, core, value, context, flags); } diff --git a/src/qml/qml/qqmlvaluetype.cpp b/src/qml/qml/qqmlvaluetype.cpp index a4737b3da9..a8fe4ec2c6 100644 --- a/src/qml/qml/qqmlvaluetype.cpp +++ b/src/qml/qml/qqmlvaluetype.cpp @@ -42,11 +42,11 @@ #include #include #include +#include #include #if QT_CONFIG(qml_itemmodel) #include #endif -#include QT_BEGIN_NAMESPACE @@ -214,61 +214,82 @@ void QQmlValueTypeFactory::registerValueTypes(const char *uri, int versionMajor, qmlRegisterValueTypeEnums(uri, versionMajor, versionMinor, "Easing"); } -QQmlValueType::QQmlValueType() : - _metaObject(nullptr), - gadgetPtr(nullptr), - metaType(QMetaType::UnknownType) +QQmlValueType::QQmlValueType(int typeId, const QMetaObject *gadgetMetaObject) + : metaType(typeId) { + QMetaObjectBuilder builder(gadgetMetaObject); + dynamicMetaObject = builder.toMetaObject(); + *static_cast(this) = *dynamicMetaObject; } -QQmlValueType::QQmlValueType(int typeId, const QMetaObject *gadgetMetaObject) - : gadgetPtr(QMetaType::create(typeId)) - , metaType(typeId) +QQmlValueType::~QQmlValueType() { - QObjectPrivate *op = QObjectPrivate::get(this); - Q_ASSERT(!op->metaObject); - op->metaObject = this; + ::free(dynamicMetaObject); +} - QMetaObjectBuilder builder(gadgetMetaObject); - _metaObject = builder.toMetaObject(); +QQmlGadgetPtrWrapper *QQmlGadgetPtrWrapper::instance(QQmlEngine *engine, int index) +{ + return engine ? QQmlEnginePrivate::get(engine)->valueTypeInstance(index) : nullptr; +} - *static_cast(this) = *_metaObject; +QQmlGadgetPtrWrapper::QQmlGadgetPtrWrapper(QQmlValueType *valueType, QObject *parent) + : QObject(parent), m_gadgetPtr(valueType->create()) +{ + QObjectPrivate *d = QObjectPrivate::get(this); + Q_ASSERT(!d->metaObject); + d->metaObject = valueType; } -QQmlValueType::~QQmlValueType() +QQmlGadgetPtrWrapper::~QQmlGadgetPtrWrapper() { - QObjectPrivate *op = QObjectPrivate::get(this); - Q_ASSERT(op->metaObject == nullptr || op->metaObject == this); - op->metaObject = nullptr; - ::free(const_cast(_metaObject)); - metaType.destroy(gadgetPtr); + QObjectPrivate *d = QObjectPrivate::get(this); + static_cast(d->metaObject)->destroy(m_gadgetPtr); + d->metaObject = nullptr; } -void QQmlValueType::read(QObject *obj, int idx) +void QQmlGadgetPtrWrapper::read(QObject *obj, int idx) { - void *a[] = { gadgetPtr, nullptr }; + Q_ASSERT(m_gadgetPtr); + void *a[] = { m_gadgetPtr, nullptr }; QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a); } -void QQmlValueType::write(QObject *obj, int idx, QQmlPropertyData::WriteFlags flags) +void QQmlGadgetPtrWrapper::write(QObject *obj, int idx, QQmlPropertyData::WriteFlags flags) { - Q_ASSERT(gadgetPtr); + Q_ASSERT(m_gadgetPtr); int status = -1; - void *a[] = { gadgetPtr, nullptr, &status, &flags }; + void *a[] = { m_gadgetPtr, nullptr, &status, &flags }; QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a); } -QVariant QQmlValueType::value() +QVariant QQmlGadgetPtrWrapper::value() +{ + Q_ASSERT(m_gadgetPtr); + return QVariant(metaTypeId(), m_gadgetPtr); +} + +void QQmlGadgetPtrWrapper::setValue(const QVariant &value) +{ + Q_ASSERT(m_gadgetPtr); + Q_ASSERT(metaTypeId() == value.userType()); + const QQmlValueType *type = valueType(); + type->destruct(m_gadgetPtr); + type->construct(m_gadgetPtr, value.constData()); +} + +int QQmlGadgetPtrWrapper::metaCall(QMetaObject::Call type, int id, void **argv) { - Q_ASSERT(gadgetPtr); - return QVariant(metaType.id(), gadgetPtr); + Q_ASSERT(m_gadgetPtr); + const QMetaObject *metaObject = valueType(); + QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(type, &metaObject, &id); + metaObject->d.static_metacall(static_cast(m_gadgetPtr), type, id, argv); + return id; } -void QQmlValueType::setValue(const QVariant &value) +const QQmlValueType *QQmlGadgetPtrWrapper::valueType() const { - Q_ASSERT(metaType.id() == value.userType()); - metaType.destruct(gadgetPtr); - metaType.construct(gadgetPtr, value.constData()); + const QObjectPrivate *d = QObjectPrivate::get(this); + return static_cast(d->metaObject); } QAbstractDynamicMetaObject *QQmlValueType::toDynamicMetaObject(QObject *) @@ -280,12 +301,9 @@ void QQmlValueType::objectDestroyed(QObject *) { } -int QQmlValueType::metaCall(QObject *, QMetaObject::Call type, int _id, void **argv) +int QQmlValueType::metaCall(QObject *object, QMetaObject::Call type, int _id, void **argv) { - const QMetaObject *mo = _metaObject; - QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(type, &mo, &_id); - mo->d.static_metacall(reinterpret_cast(gadgetPtr), type, _id, argv); - return _id; + return static_cast(object)->metaCall(type, _id, argv); } QString QQmlPointFValueType::toString() const diff --git a/src/qml/qml/qqmlvaluetype_p.h b/src/qml/qml/qqmlvaluetype_p.h index cf53b8cb4a..fec942fcbb 100644 --- a/src/qml/qml/qqmlvaluetype_p.h +++ b/src/qml/qml/qqmlvaluetype_p.h @@ -54,7 +54,9 @@ #include "qqml.h" #include "qqmlproperty.h" #include "qqmlproperty_p.h" + #include +#include #include #include @@ -63,16 +65,20 @@ QT_BEGIN_NAMESPACE -class Q_QML_PRIVATE_EXPORT QQmlValueType : public QObject, public QAbstractDynamicMetaObject +class Q_QML_PRIVATE_EXPORT QQmlValueType : public QAbstractDynamicMetaObject { public: - QQmlValueType(); + QQmlValueType() : metaType(QMetaType::UnknownType) {} QQmlValueType(int userType, const QMetaObject *metaObject); - ~QQmlValueType() override; - void read(QObject *, int); - void write(QObject *, int, QQmlPropertyData::WriteFlags flags); - QVariant value(); - void setValue(const QVariant &); + ~QQmlValueType(); + + void *create() const { return metaType.create(); } + void destroy(void *gadgetPtr) const { metaType.destroy(gadgetPtr); } + + void construct(void *gadgetPtr, const void *copy) const { metaType.construct(gadgetPtr, copy); } + void destruct(void *gadgetPtr) const { metaType.destruct(gadgetPtr); } + + int metaTypeId() const { return metaType.id(); } // ---- dynamic meta object data interface QAbstractDynamicMetaObject *toDynamicMetaObject(QObject *) override; @@ -80,12 +86,33 @@ public: int metaCall(QObject *obj, QMetaObject::Call type, int _id, void **argv) override; // ---- -private: - const QMetaObject *_metaObject; - void *gadgetPtr; - public: QMetaType metaType; + QMetaObject *dynamicMetaObject = nullptr; +}; + +class Q_QML_PRIVATE_EXPORT QQmlGadgetPtrWrapper : public QObject +{ + Q_OBJECT +public: + static QQmlGadgetPtrWrapper *instance(QQmlEngine *engine, int index); + + QQmlGadgetPtrWrapper(QQmlValueType *valueType, QObject *parent); + ~QQmlGadgetPtrWrapper(); + + void read(QObject *obj, int idx); + void write(QObject *obj, int idx, QQmlPropertyData::WriteFlags flags); + QVariant value(); + void setValue(const QVariant &value); + + int metaTypeId() const { return valueType()->metaTypeId(); } + int metaCall(QMetaObject::Call type, int id, void **argv); + QMetaProperty property(int index) { return valueType()->property(index); } + +private: + const QQmlValueType *valueType() const; + + void *m_gadgetPtr = nullptr; }; class Q_QML_PRIVATE_EXPORT QQmlValueTypeFactory diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp index 95e99206f0..69215b1304 100644 --- a/src/qml/qml/qqmlvmemetaobject.cpp +++ b/src/qml/qml/qqmlvmemetaobject.cpp @@ -241,11 +241,13 @@ bool QQmlInterceptorMetaObject::intercept(QMetaObject::Call c, int id, void **a) continue; const int valueIndex = vi->m_propertyIndex.valueTypeIndex(); - int type = QQmlData::get(object)->propertyCache->property(id)->propType(); + const QQmlData *data = QQmlData::get(object); + const int type = data->propertyCache->property(id)->propType(); if (type != QVariant::Invalid) { if (valueIndex != -1) { - QQmlValueType *valueType = QQmlValueTypeFactory::valueType(type); + QQmlGadgetPtrWrapper *valueType = QQmlGadgetPtrWrapper::instance( + data->context->engine, type); Q_ASSERT(valueType); // @@ -279,7 +281,7 @@ bool QQmlInterceptorMetaObject::intercept(QMetaObject::Call c, int id, void **a) // (7) Issue the interceptor call with the new component value. // - QMetaProperty valueProp = valueType->metaObject()->property(valueIndex); + QMetaProperty valueProp = valueType->property(valueIndex); QVariant newValue(type, a[0]); valueType->read(object, id); @@ -833,9 +835,9 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void * return -1; const QQmlPropertyData *pd = targetDData->propertyCache->property(coreIndex); // Value type property or deep alias - QQmlValueType *valueType = QQmlValueTypeFactory::valueType(pd->propType()); + QQmlGadgetPtrWrapper *valueType = QQmlGadgetPtrWrapper::instance( + ctxt->engine, pd->propType()); if (valueType) { - valueType->read(target, coreIndex); int rv = QMetaObject::metacall(valueType, c, valueTypePropertyIndex, a); diff --git a/src/quick/designer/qquickdesignersupportproperties.cpp b/src/quick/designer/qquickdesignersupportproperties.cpp index c746f55daa..335795acf1 100644 --- a/src/quick/designer/qquickdesignersupportproperties.cpp +++ b/src/quick/designer/qquickdesignersupportproperties.cpp @@ -155,8 +155,8 @@ QQuickDesignerSupport::PropertyNameList QQuickDesignerSupportProperties::propert baseName + QQuickDesignerSupport::PropertyName(metaProperty.name()) + '.', inspectedObjects)); } - } else if (QQmlValueTypeFactory::valueType(metaProperty.userType())) { - QQmlValueType *valueType = QQmlValueTypeFactory::valueType(metaProperty.userType()); + } else if (QQmlGadgetPtrWrapper *valueType + = QQmlGadgetPtrWrapper::instance(qmlEngine(object), metaProperty.userType())) { valueType->setValue(metaProperty.read(object)); propertyNameList.append(propertyNameListForWritableProperties(valueType, baseName + QQuickDesignerSupport::PropertyName(metaProperty.name()) @@ -223,8 +223,8 @@ QQuickDesignerSupport::PropertyNameList QQuickDesignerSupportProperties::allProp + QQuickDesignerSupport::PropertyName(metaProperty.name()) + '.', inspectedObjects)); } - } else if (QQmlValueTypeFactory::valueType(metaProperty.userType())) { - QQmlValueType *valueType = QQmlValueTypeFactory::valueType(metaProperty.userType()); + } else if (QQmlGadgetPtrWrapper *valueType + = QQmlGadgetPtrWrapper::instance(qmlEngine(object), metaProperty.userType())) { valueType->setValue(metaProperty.read(object)); propertyNameList.append(baseName + QQuickDesignerSupport::PropertyName(metaProperty.name())); propertyNameList.append(allPropertyNames(valueType, -- cgit v1.2.3 From 01660fbb67c39c74b2e1eeae1e3d1b97c8886cdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Arve=20S=C3=A6ther?= Date: Tue, 3 Dec 2019 11:52:55 +0100 Subject: Fix some ListView bugs related to snapping when it had a header Most bugs were related to the PullBackHeader header positining mode, for instance the old code did not take into consideration that for the PullBackHeader it was sometimes not sufficient to scroll the view. The header also had to be scrolled independently from the view: We achieve this by hooking on to the same timeline that is used for scrolling the view. (This way, both animations are synchronized, and they start and end at the same time). Change-Id: I75708c0fd8d4741032c04ad9ee144d7a49cf3359 Fixes: QTBUG-76362 Reviewed-by: Shawn Rutledge --- src/quick/items/qquicklistview.cpp | 168 +++++- .../quick/qquicklistview/data/headerSnapToItem.qml | 67 +++ .../quick/qquicklistview/tst_qquicklistview.cpp | 601 +++++++++++++++++++++ 3 files changed, 821 insertions(+), 15 deletions(-) create mode 100644 tests/auto/quick/qquicklistview/data/headerSnapToItem.qml diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp index 48bb70e597..ef601dcaec 100644 --- a/src/quick/items/qquicklistview.cpp +++ b/src/quick/items/qquicklistview.cpp @@ -138,6 +138,8 @@ public: bool flick(QQuickItemViewPrivate::AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize, QQuickTimeLineCallback::Callback fixupCallback, qreal velocity) override; + void fixupHeader(); + void fixupHeaderCompleted(); QQuickListView::Orientation orient; qreal visiblePos; qreal averageSize; @@ -166,6 +168,12 @@ public: QString nextSection; qreal overshootDist; + + qreal desiredViewportPosition; + qreal fixupHeaderPosition; + bool headerNeedsSeparateFixup : 1; + bool desiredHeaderVisible : 1; + bool correctFlick : 1; bool inFlickCorrection : 1; @@ -179,7 +187,9 @@ public: , highlightPosAnimator(nullptr), highlightWidthAnimator(nullptr), highlightHeightAnimator(nullptr) , highlightMoveVelocity(400), highlightResizeVelocity(400), highlightResizeDuration(-1) , sectionCriteria(nullptr), currentSectionItem(nullptr), nextSectionItem(nullptr) - , overshootDist(0.0), correctFlick(false), inFlickCorrection(false) + , overshootDist(0.0), desiredViewportPosition(0.0), fixupHeaderPosition(0.0) + , headerNeedsSeparateFixup(false), desiredHeaderVisible(false) + , correctFlick(false), inFlickCorrection(false) { highlightMoveDuration = -1; //override default value set in base class } @@ -1391,6 +1401,31 @@ void QQuickListViewPrivate::updateFooter() emit q->footerItemChanged(); } +void QQuickListViewPrivate::fixupHeaderCompleted() +{ + headerNeedsSeparateFixup = false; + QObjectPrivate::disconnect(&timeline, &QQuickTimeLine::updated, this, &QQuickListViewPrivate::fixupHeader); +} + +void QQuickListViewPrivate::fixupHeader() +{ + FxListItemSG *listItem = static_cast(header); + const bool fixingUp = (orient == QQuickListView::Vertical ? vData : hData).fixingUp; + if (fixingUp && headerPositioning == QQuickListView::PullBackHeader && visibleItems.count()) { + int fixupDura = timeline.duration(); + if (fixupDura < 0) + fixupDura = fixupDuration/2; + const int t = timeline.time(); + + const qreal progress = qreal(t)/fixupDura; + const qreal ultimateHeaderPosition = desiredHeaderVisible ? desiredViewportPosition : desiredViewportPosition - headerSize(); + const qreal headerPosition = fixupHeaderPosition * (1 - progress) + ultimateHeaderPosition * progress; + const qreal viewPos = isContentFlowReversed() ? -position() - size() : position(); + const qreal clampedPos = qBound(originPosition() - headerSize(), headerPosition, lastPosition() - size()); + listItem->setPosition(qBound(viewPos - headerSize(), clampedPos, viewPos)); + } +} + void QQuickListViewPrivate::updateHeader() { Q_Q(QQuickListView); @@ -1408,9 +1443,14 @@ void QQuickListViewPrivate::updateHeader() if (headerPositioning == QQuickListView::OverlayHeader) { listItem->setPosition(isContentFlowReversed() ? -position() - size() : position()); } else if (visibleItems.count()) { + const bool fixingUp = (orient == QQuickListView::Vertical ? vData : hData).fixingUp; if (headerPositioning == QQuickListView::PullBackHeader) { - qreal viewPos = isContentFlowReversed() ? -position() - size() : position(); - qreal clampedPos = qBound(originPosition() - headerSize(), listItem->position(), lastPosition() - headerSize() - size()); + qreal headerPosition = listItem->position(); + const qreal viewPos = isContentFlowReversed() ? -position() - size() : position(); + // Make sure the header is not shown if we absolutely do not have any plans to show it + if (fixingUp && !headerNeedsSeparateFixup) + headerPosition = viewPos - headerSize(); + qreal clampedPos = qBound(originPosition() - headerSize(), headerPosition, lastPosition() - size()); listItem->setPosition(qBound(viewPos - headerSize(), clampedPos, viewPos)); } else { qreal startPos = originPosition(); @@ -1528,13 +1568,46 @@ void QQuickListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExte bias = -bias; tempPosition -= bias; } - FxViewItem *topItem = snapItemAt(tempPosition+highlightRangeStart); + + qreal snapOffset = 0; + qreal overlayHeaderOffset = 0; + bool isHeaderWithinBounds = false; + if (header) { + qreal visiblePartOfHeader = header->position() + header->size() - tempPosition; + isHeaderWithinBounds = visiblePartOfHeader > 0; + switch (headerPositioning) { + case QQuickListView::OverlayHeader: + snapOffset = header->size(); + overlayHeaderOffset = header->size(); + break; + case QQuickListView::InlineHeader: + if (isHeaderWithinBounds && tempPosition < originPosition()) + // For the inline header, we want to snap to the first item + // if we're more than halfway down the inline header. + // So if we look for an item halfway down of the header + snapOffset = header->size() / 2; + break; + case QQuickListView::PullBackHeader: + desiredHeaderVisible = visiblePartOfHeader > header->size()/2; + if (qFuzzyCompare(header->position(), tempPosition)) { + // header was pulled down; make sure it remains visible and snap items to bottom of header + snapOffset = header->size(); + } else if (desiredHeaderVisible) { + // More than 50% of the header is shown. Show it fully. + // Scroll the view so the next item snaps to the header. + snapOffset = header->size(); + overlayHeaderOffset = header->size(); + } + break; + } + } + FxViewItem *topItem = snapItemAt(tempPosition + snapOffset + highlightRangeStart); if (strictHighlightRange && currentItem && (!topItem || (topItem->index != currentIndex && fixupMode == Immediate))) { // StrictlyEnforceRange always keeps an item in range updateHighlight(); topItem = currentItem; } - FxViewItem *bottomItem = snapItemAt(tempPosition+highlightRangeEnd); + FxViewItem *bottomItem = snapItemAt(tempPosition + snapOffset + highlightRangeEnd); if (strictHighlightRange && currentItem && (!bottomItem || (bottomItem->index != currentIndex && fixupMode == Immediate))) { // StrictlyEnforceRange always keeps an item in range updateHighlight(); @@ -1542,27 +1615,92 @@ void QQuickListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExte } qreal pos; bool isInBounds = -position() > maxExtent && -position() <= minExtent; - if (topItem && (isInBounds || strictHighlightRange)) { - if (topItem->index == 0 && header && tempPosition+highlightRangeStart < header->position()+header->size()/2 && !strictHighlightRange) { - pos = isContentFlowReversed() ? - header->position() + highlightRangeStart - size() : header->position() - highlightRangeStart; + + if (header && !topItem && isInBounds) { + // We are trying to pull back further than needed + switch (headerPositioning) { + case QQuickListView::OverlayHeader: + pos = startPosition() - overlayHeaderOffset; + break; + case QQuickListView::InlineHeader: + pos = isContentFlowReversed() ? header->size() - size() : header->position(); + break; + case QQuickListView::PullBackHeader: + pos = isContentFlowReversed() ? -size() : startPosition(); + break; + } + } else if (topItem && (isInBounds || strictHighlightRange)) { + if (topItem->index == 0 && header && !hasStickyHeader() && tempPosition+highlightRangeStart < header->position()+header->size()/2 && !strictHighlightRange) { + pos = isContentFlowReversed() ? -header->position() + highlightRangeStart - size() : (header->position() - highlightRangeStart + header->size()); } else { - if (isContentFlowReversed()) - pos = qMax(qMin(-static_cast(topItem)->itemPosition() + highlightRangeStart - size(), -maxExtent), -minExtent); - else - pos = qMax(qMin(static_cast(topItem)->itemPosition() - highlightRangeStart, -maxExtent), -minExtent); + if (header && headerPositioning == QQuickListView::PullBackHeader) { + // We pulled down the header. If it isn't pulled all way down, we need to snap + // the header. + if (qFuzzyCompare(tempPosition, header->position())) { + // It is pulled all way down. Scroll-snap the content, but not the header. + if (isContentFlowReversed()) + pos = -static_cast(topItem)->itemPosition() + highlightRangeStart - size() + snapOffset; + else + pos = static_cast(topItem)->itemPosition() - highlightRangeStart - snapOffset; + } else { + // Header is not pulled all way down, make it completely visible or hide it. + // Depends on how much of the header is visible. + if (desiredHeaderVisible) { + // More than half of the header is visible - show it. + // Scroll so that the topItem is aligned to a fully visible header + if (isContentFlowReversed()) + pos = -static_cast(topItem)->itemPosition() + highlightRangeStart - size() + headerSize(); + else + pos = static_cast(topItem)->itemPosition() - highlightRangeStart - headerSize(); + } else { + // Less than half is visible - hide the header. Scroll so + // that the topItem is aligned to the top of the view + if (isContentFlowReversed()) + pos = -static_cast(topItem)->itemPosition() + highlightRangeStart - size(); + else + pos = static_cast(topItem)->itemPosition() - highlightRangeStart; + } + } + + headerNeedsSeparateFixup = isHeaderWithinBounds || desiredHeaderVisible; + if (headerNeedsSeparateFixup) { + // We need to animate the header independently if it starts visible or should end as visible, + // since the header should not necessarily follow the content. + // Store the desired viewport position. + // Also store the header position so we know where to animate the header from (fixupHeaderPosition). + // We deduce the desired header position from the desiredViewportPosition variable. + pos = qBound(-minExtent, pos, -maxExtent); + desiredViewportPosition = isContentFlowReversed() ? -pos - size() : pos; + + FxListItemSG *headerItem = static_cast(header); + fixupHeaderPosition = headerItem->position(); + + // follow the same fixup timeline + QObjectPrivate::connect(&timeline, &QQuickTimeLine::updated, this, &QQuickListViewPrivate::fixupHeader); + QObjectPrivate::connect(&timeline, &QQuickTimeLine::completed, this, &QQuickListViewPrivate::fixupHeaderCompleted); + } + } else if (isContentFlowReversed()) { + pos = -static_cast(topItem)->itemPosition() + highlightRangeStart - size() + overlayHeaderOffset; + } else { + pos = static_cast(topItem)->itemPosition() - highlightRangeStart - overlayHeaderOffset; + } } } else if (bottomItem && isInBounds) { if (isContentFlowReversed()) - pos = qMax(qMin(-static_cast(bottomItem)->itemPosition() + highlightRangeEnd - size(), -maxExtent), -minExtent); + pos = -static_cast(bottomItem)->itemPosition() + highlightRangeEnd - size() + overlayHeaderOffset; else - pos = qMax(qMin(static_cast(bottomItem)->itemPosition() - highlightRangeEnd, -maxExtent), -minExtent); + pos = static_cast(bottomItem)->itemPosition() - highlightRangeEnd - overlayHeaderOffset; } else { QQuickItemViewPrivate::fixup(data, minExtent, maxExtent); return; } + pos = qBound(-minExtent, pos, -maxExtent); qreal dist = qAbs(data.move + pos); - if (dist > 0) { + if (dist >= 0) { + // Even if dist == 0 we still start the timeline, because we use the same timeline for + // moving the header. And we might need to move the header while the content does not + // need moving timeline.reset(data.move); if (fixupMode != Immediate) { timeline.move(data.move, -pos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2); diff --git a/tests/auto/quick/qquicklistview/data/headerSnapToItem.qml b/tests/auto/quick/qquicklistview/data/headerSnapToItem.qml new file mode 100644 index 0000000000..1e5a811630 --- /dev/null +++ b/tests/auto/quick/qquicklistview/data/headerSnapToItem.qml @@ -0,0 +1,67 @@ +import QtQuick 2.12 + +Rectangle { + + width: 240 + height: 320 + color: "#ffffff" + + Component { + id: myDelegate + Rectangle { + id: wrapper + objectName: "wrapper" + width: list.orientation == ListView.Vertical ? 240 : 20 + height: list.orientation == ListView.Vertical ? 20 : 240 + border.width: 1 + border.color: "black" + Text { + text: index + ":" + (list.orientation == ListView.Vertical ? parent.y : parent.x).toFixed(0) + } + color: ListView.isCurrentItem ? "lightsteelblue" : "white" + } + } + + ListView { + id: list + objectName: "list" + focus: true + width: 240 + height: 200 + clip: true + snapMode: ListView.SnapToItem + headerPositioning: ListView.OverlayHeader + model: 30 + delegate: myDelegate + orientation: ListView.Vertical + verticalLayoutDirection: ListView.BottomToTop + + header: Rectangle { + width: list.orientation == Qt.Vertical ? 240 : 30 + height: list.orientation == Qt.Vertical ? 30 : 240 + objectName: "header"; + color: "green" + z: 11 + Text { + anchors.centerIn: parent + text: "header " + (list.orientation == ListView.Vertical ? parent.y : parent.x).toFixed(1) + } + } + } + + Rectangle { + color: "red" + opacity: 0.5 + width: txt.implicitWidth + 50 + height: txt.implicitHeight + anchors.bottom: parent.bottom + anchors.right: parent.right + + Text { + id: txt + anchors.centerIn: parent + text: "header position: " + (list.orientation == ListView.Vertical ? list.headerItem.y : list.headerItem.x).toFixed(1) + + "\ncontent position: " + (list.orientation == ListView.Vertical ? list.contentY : list.contentX).toFixed(1) + } + } +} diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp index 3687c9416e..20d71aa0d7 100644 --- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp +++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -183,6 +184,8 @@ private slots: void creationContext(); void snapToItem_data(); void snapToItem(); + void headerSnapToItem_data(); + void headerSnapToItem(); void snapToItemWithSpacing_QTBUG_59852(); void snapOneItemResize_QTBUG_43555(); void snapOneItem_data(); @@ -5395,6 +5398,604 @@ void tst_QQuickListView::snapToItemWithSpacing_QTBUG_59852() releaseView(window); } +static void drag_helper(QWindow *window, QPoint *startPos, const QPoint &delta) +{ + QPoint pos = *startPos; + int dragDistance = delta.manhattanLength(); + Q_ASSERT(qAbs(delta.x()) >= 1 || qAbs(delta.y()) >= 1); + + const int stepSize = 8; + QPoint unitVector(0, 0); + if (delta.x()) + unitVector.setX(qBound(-1, delta.x(), 1)); + if (delta.y()) + unitVector.setY(qBound(-1, delta.y(), 1)); + QPoint dragStepSize = unitVector * stepSize; + int nDragSteps = qAbs(dragDistance/stepSize); + + for (int i = 0 ; i < nDragSteps; ++i) { + QTest::mouseMove(window, pos); + pos += dragStepSize; + } + // Move to the final position + pos = *startPos + delta; + QTest::mouseMove(window, pos); + *startPos = pos; +} + +static void dragtwice(QWindow *window, QPoint *startPos, const QPoint &delta1, const QPoint &delta2) +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QPoint &pos = *startPos; + QPoint unitVector(0, 0); + if (delta1.x()) + unitVector.setX(qBound(-1, delta1.x(), 1)); + if (delta1.y()) + unitVector.setY(qBound(-1, delta1.y(), 1)); + + // go just beyond the drag theshold + drag_helper(window, &pos, unitVector * (dragThreshold + 1)); + drag_helper(window, &pos, unitVector); + + // next drag will actually scroll the listview + if (delta1.manhattanLength() >= 1) + drag_helper(window, &pos, delta1); + if (delta2.manhattanLength() >= 1) + drag_helper(window, &pos, delta2); +} + +struct MyListView : public QQuickListView{ + qreal contentPosition() const + { + return (orientation() == QQuickListView::Horizontal ? contentX(): contentY()); + } + + qreal headerPosition() const + { + return (orientation() == QQuickListView::Horizontal ? headerItem()->x() : headerItem()->y()); + } +}; + +void tst_QQuickListView::headerSnapToItem() +{ + QFETCH(QQuickItemView::LayoutDirection, layoutDirection); + QFETCH(QQuickListView::HeaderPositioning, headerPositioning); + QFETCH(int, firstDragDistance); + QFETCH(int, secondDragDistance); + QFETCH(int, expectedContentPosition); + QFETCH(int, expectedHeaderPosition); + + QQuickView *window = getView(); + window->setSource(testFileUrl("headerSnapToItem.qml")); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + + MyListView *listview = static_cast(findItem(window->rootObject(), "list")); + QVERIFY(listview != nullptr); + + const bool horizontal = layoutDirection < QQuickItemView::VerticalTopToBottom; + listview->setOrientation(horizontal ? QQuickListView::Horizontal : QQuickListView::Vertical); + + if (horizontal) + listview->setLayoutDirection(static_cast(layoutDirection)); + else + listview->setVerticalLayoutDirection(static_cast(layoutDirection)); + + listview->setHeaderPositioning(headerPositioning); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); + + QQuickItem *contentItem = listview->contentItem(); + QVERIFY(contentItem != nullptr); + QQuickItem *header = findItem(contentItem, "header"); + QVERIFY(header != nullptr); + QCOMPARE(header, listview->headerItem()); + + QPoint startPos = (QPointF(listview->width(), listview->height())/2).toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, startPos, 200); + + QPoint firstDragDelta(0, firstDragDistance); + QPoint secondDragDelta = QPoint(0, secondDragDistance); + if (horizontal) { + firstDragDelta = firstDragDelta.transposed(); + secondDragDelta = secondDragDelta.transposed(); + } + + dragtwice(window, &startPos, firstDragDelta, secondDragDelta); + + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, startPos, 200); // Wait 200 ms before we release to avoid trigger a flick + + // wait for the "fixup" animation to finish + QTest::qWaitFor([&]() + { return !listview->isMoving();} + ); + + QCOMPARE(listview->contentPosition(), expectedContentPosition); + QCOMPARE(listview->headerPosition(), expectedHeaderPosition); +} + +void tst_QQuickListView::headerSnapToItem_data() +{ + QTest::addColumn("layoutDirection"); + QTest::addColumn("headerPositioning"); + QTest::addColumn("firstDragDistance"); + QTest::addColumn("secondDragDistance"); + QTest::addColumn("expectedContentPosition"); + QTest::addColumn("expectedHeaderPosition"); + + // -------------------- + // InlineHeader TopToBottom + QTest::newRow("InlineHeader TopToBottom -10") << QQuickItemView::VerticalTopToBottom + << QQuickListView::InlineHeader + << -10 << 0 + << -30 << -30; + + QTest::newRow("InlineHeader TopToBottom -14") << QQuickItemView::VerticalTopToBottom + << QQuickListView::InlineHeader + << -14 << 0 + << -30 << -30; + + QTest::newRow("InlineHeader TopToBottom -16") << QQuickItemView::VerticalTopToBottom + << QQuickListView::InlineHeader + << -16 << 0 + << 0 << -30; + + QTest::newRow("InlineHeader TopToBottom -30") << QQuickItemView::VerticalTopToBottom + << QQuickListView::InlineHeader + << -30 << 0 + << 0 << -30; + + QTest::newRow("InlineHeader TopToBottom -39") << QQuickItemView::VerticalTopToBottom + << QQuickListView::InlineHeader + << -39 << 0 + << 0 << -30; + + QTest::newRow("InlineHeader TopToBottom -41") << QQuickItemView::VerticalTopToBottom + << QQuickListView::InlineHeader + << -41 << 0 + << 20 << -30; + + QTest::newRow("InlineHeader TopToBottom -65+10") << QQuickItemView::VerticalTopToBottom + << QQuickListView::InlineHeader + << -65 << 10 + << 20 << -30; + + // -------------------- + // InlineHeader BottomToTop + QTest::newRow("InlineHeader BottomToTop +10") << QQuickItemView::VerticalBottomToTop + << QQuickListView::InlineHeader + << 10 << 0 + << -170 << 0; + + QTest::newRow("InlineHeader BottomToTop +14") << QQuickItemView::VerticalBottomToTop + << QQuickListView::InlineHeader + << 14 << 0 + << -170 << 0; + + QTest::newRow("InlineHeader BottomToTop +16") << QQuickItemView::VerticalBottomToTop + << QQuickListView::InlineHeader + << 16 << 0 + << -200 << 0; + + QTest::newRow("InlineHeader BottomToTop +30") << QQuickItemView::VerticalBottomToTop + << QQuickListView::InlineHeader + << 30 << 0 + << -200 << 0; + + QTest::newRow("InlineHeader BottomToTop +39") << QQuickItemView::VerticalBottomToTop + << QQuickListView::InlineHeader + << 39 << 0 + << -200 << 0; + + QTest::newRow("InlineHeader BottomToTop +41") << QQuickItemView::VerticalBottomToTop + << QQuickListView::InlineHeader + << 41 << 0 + << -220 << 0; + + QTest::newRow("InlineHeader BottomToTop +65-10") << QQuickItemView::VerticalBottomToTop + << QQuickListView::InlineHeader + << 65 << -10 + << -220 << 0; + + // -------------------- + // InlineHeader LeftToRight + QTest::newRow("InlineHeader LeftToRight -10") << QQuickItemView::LeftToRight + << QQuickListView::InlineHeader + << -10 << 0 + << -30 << -30; + + QTest::newRow("InlineHeader LeftToRight -14") << QQuickItemView::LeftToRight + << QQuickListView::InlineHeader + << -14 << 0 + << -30 << -30; + + QTest::newRow("InlineHeader LeftToRight -16") << QQuickItemView::LeftToRight + << QQuickListView::InlineHeader + << -16 << 0 + << 0 << -30; + + QTest::newRow("InlineHeader LeftToRight -30") << QQuickItemView::LeftToRight + << QQuickListView::InlineHeader + << -30 << 0 + << 0 << -30; + + QTest::newRow("InlineHeader LeftToRight -39") << QQuickItemView::LeftToRight + << QQuickListView::InlineHeader + << -39 << 0 + << 0 << -30; + + QTest::newRow("InlineHeader LeftToRight -41") << QQuickItemView::LeftToRight + << QQuickListView::InlineHeader + << -41 << 0 + << 20 << -30; + + QTest::newRow("InlineHeader LeftToRight -65+10") << QQuickItemView::LeftToRight + << QQuickListView::InlineHeader + << -65 << 10 + << 20 << -30; + + // -------------------- + // InlineHeader RightToLeft + QTest::newRow("InlineHeader RightToLeft +10") << QQuickItemView::RightToLeft + << QQuickListView::InlineHeader + << 10 << 0 + << -210 << 0; + + QTest::newRow("InlineHeader RightToLeft +14") << QQuickItemView::RightToLeft + << QQuickListView::InlineHeader + << 14 << 0 + << -210 << 0; + + QTest::newRow("InlineHeader RightToLeft +16") << QQuickItemView::RightToLeft + << QQuickListView::InlineHeader + << 16 << 0 + << -240 << 0; + + QTest::newRow("InlineHeader RightToLeft +30") << QQuickItemView::RightToLeft + << QQuickListView::InlineHeader + << 30 << 0 + << -240 << 0; + + QTest::newRow("InlineHeader RightToLeft +39") << QQuickItemView::RightToLeft + << QQuickListView::InlineHeader + << 39 << 0 + << -240 << 0; + + QTest::newRow("InlineHeader RightToLeft +41") << QQuickItemView::RightToLeft + << QQuickListView::InlineHeader + << 41 << 0 + << -260 << 0; + + QTest::newRow("InlineHeader RightToLeft +65-10") << QQuickItemView::RightToLeft + << QQuickListView::InlineHeader + << 65 << -10 + << -260 << 0; + + // -------------------- + // OverlayHeader TopToBottom + QTest::newRow("OverlayHeader TopToBottom +9") << QQuickItemView::VerticalTopToBottom + << QQuickListView::OverlayHeader + << 9 << 0 + << -30 << -30; + + QTest::newRow("OverlayHeader TopToBottom -9") << QQuickItemView::VerticalTopToBottom + << QQuickListView::OverlayHeader + << -9 << 0 + << -30 << -30; + + QTest::newRow("OverlayHeader TopToBottom -11") << QQuickItemView::VerticalTopToBottom + << QQuickListView::OverlayHeader + << -11 << 0 + << -10 << -10; + + QTest::newRow("OverlayHeader TopToBottom -29") << QQuickItemView::VerticalTopToBottom + << QQuickListView::OverlayHeader + << -29 << 0 + << -10 << -10; + + QTest::newRow("OverlayHeader TopToBottom -31") << QQuickItemView::VerticalTopToBottom + << QQuickListView::OverlayHeader + << -31 << 0 + << 10 << 10; + + // -------------------- + // OverlayHeader BottomToTop + QTest::newRow("OverlayHeader BottomToTop -9") << QQuickItemView::VerticalBottomToTop + << QQuickListView::OverlayHeader + << -9 << 0 + << -170 << 0; + + QTest::newRow("OverlayHeader BottomToTop +9") << QQuickItemView::VerticalBottomToTop + << QQuickListView::OverlayHeader + << 9 << 0 + << -170 << 0; + + QTest::newRow("OverlayHeader BottomToTop +11") << QQuickItemView::VerticalBottomToTop + << QQuickListView::OverlayHeader + << 11 << 0 + << -190 << -20; + + QTest::newRow("OverlayHeader BottomToTop +29") << QQuickItemView::VerticalBottomToTop + << QQuickListView::OverlayHeader + << 29 << 0 + << -190 << -20; + + QTest::newRow("OverlayHeader BottomToTop +31") << QQuickItemView::VerticalBottomToTop + << QQuickListView::OverlayHeader + << 31 << 0 + << -210 << -40; + + // -------------------- + // OverlayHeader LeftToRight + QTest::newRow("OverlayHeader LeftToRight +9") << QQuickItemView::LeftToRight + << QQuickListView::OverlayHeader + << 9 << 0 + << -30 << -30; + + QTest::newRow("OverlayHeader LeftToRight -9") << QQuickItemView::LeftToRight + << QQuickListView::OverlayHeader + << -9 << 0 + << -30 << -30; + + QTest::newRow("OverlayHeader LeftToRight -11") << QQuickItemView::LeftToRight + << QQuickListView::OverlayHeader + << -11 << 0 + << -10 << -10; + + QTest::newRow("OverlayHeader LeftToRight -29") << QQuickItemView::LeftToRight + << QQuickListView::OverlayHeader + << -29 << 0 + << -10 << -10; + + QTest::newRow("OverlayHeader LeftToRight -31") << QQuickItemView::LeftToRight + << QQuickListView::OverlayHeader + << -31 << 0 + << 10 << 10; + + // -------------------- + // OverlayHeader RightToLeft + QTest::newRow("OverlayHeader RightToLeft -9") << QQuickItemView::RightToLeft + << QQuickListView::OverlayHeader + << -9 << 0 + << -210 << 0; + + QTest::newRow("OverlayHeader RightToLeft +9") << QQuickItemView::RightToLeft + << QQuickListView::OverlayHeader + << 9 << 0 + << -210 << 0; + + QTest::newRow("OverlayHeader RightToLeft +11") << QQuickItemView::RightToLeft + << QQuickListView::OverlayHeader + << 11 << 0 + << -230 << -20; + + QTest::newRow("OverlayHeader RightToLeft +29") << QQuickItemView::RightToLeft + << QQuickListView::OverlayHeader + << 29 << 0 + << -230 << -20; + + QTest::newRow("OverlayHeader RightToLeft +31") << QQuickItemView::RightToLeft + << QQuickListView::OverlayHeader + << 31 << 0 + << -250 << -40; + + // -------------------- + // PullbackHeader TopToBottom + QTest::newRow("PullbackHeader TopToBottom -2") << QQuickItemView::VerticalTopToBottom + << QQuickListView::PullBackHeader + << -2 << 0 + << -30 << -30; + + QTest::newRow("PullbackHeader TopToBottom -10") << QQuickItemView::VerticalTopToBottom + << QQuickListView::PullBackHeader + << -10 << 0 + << -30 << -30; + + QTest::newRow("PullbackHeader TopToBottom -11") << QQuickItemView::VerticalTopToBottom + << QQuickListView::PullBackHeader + << -11 << 0 + << -10 << -10; + + QTest::newRow("PullbackHeader TopToBottom -14") << QQuickItemView::VerticalTopToBottom + << QQuickListView::PullBackHeader + << -14 << 0 + << -10 << -10; + + QTest::newRow("PullbackHeader TopToBottom -16") << QQuickItemView::VerticalTopToBottom + << QQuickListView::PullBackHeader + << -16 << 0 + << 0 << -30; + + QTest::newRow("PullbackHeader TopToBottom -20") << QQuickItemView::VerticalTopToBottom + << QQuickListView::PullBackHeader + << -20 << 0 + << 0 << -30; + + QTest::newRow("PullbackHeader TopToBottom -65+10") << QQuickItemView::VerticalTopToBottom + << QQuickListView::PullBackHeader + << -65 << 10 + << 20 << -10; + + QTest::newRow("PullbackHeader TopToBottom -65+20") << QQuickItemView::VerticalTopToBottom + << QQuickListView::PullBackHeader + << -65 << 20 + << 10 << 10; + + // Should move header even if contentY doesn't move (its aligned with top) + QTest::newRow("PullbackHeader TopToBottom -55+5") << QQuickItemView::VerticalTopToBottom + << QQuickListView::PullBackHeader + << -55 << 5 + << 20 << -10; + + // Should move header even if contentY doesn't move (it's aligned with header) + QTest::newRow("PullbackHeader TopToBottom -76+16") << QQuickItemView::VerticalTopToBottom + << QQuickListView::PullBackHeader + << -76 << 16 + << 30 << 30; + + // -------------------- + // PullbackHeader BottomToTop + QTest::newRow("PullbackHeader BottomToTop +2") << QQuickItemView::VerticalBottomToTop + << QQuickListView::PullBackHeader + << +2 << 0 + << -170 << 0; + + QTest::newRow("PullbackHeader BottomToTop +9") << QQuickItemView::VerticalBottomToTop + << QQuickListView::PullBackHeader + << +9 << 0 + << -170 << 0; + + QTest::newRow("PullbackHeader BottomToTop +11") << QQuickItemView::VerticalBottomToTop + << QQuickListView::PullBackHeader + << +11 << 0 + << -190 << -20; + + QTest::newRow("PullbackHeader BottomToTop +14") << QQuickItemView::VerticalBottomToTop + << QQuickListView::PullBackHeader + << +14 << 0 + << -190 << -20; + + QTest::newRow("PullbackHeader BottomToTop +16") << QQuickItemView::VerticalBottomToTop + << QQuickListView::PullBackHeader + << +16 << 0 + << -200 << 0; + + QTest::newRow("PullbackHeader BottomToTop +20") << QQuickItemView::VerticalBottomToTop + << QQuickListView::PullBackHeader + << +20 << 0 + << -200 << 0; + + QTest::newRow("PullbackHeader BottomToTop +65-10") << QQuickItemView::VerticalBottomToTop + << QQuickListView::PullBackHeader + << +65 << -10 + << -220 << -20; + + QTest::newRow("PullbackHeader BottomToTop +65-20") << QQuickItemView::VerticalBottomToTop + << QQuickListView::PullBackHeader + << +65 << -20 + << -210 << -40; + + // Should move header even if contentY doesn't move (it's aligned with top) + QTest::newRow("PullbackHeader BottomToTop +55-5") << QQuickItemView::VerticalBottomToTop + << QQuickListView::PullBackHeader + << 55 << -5 + << -220 << -20; + + // Should move header even if contentY doesn't move (it's aligned with header) + QTest::newRow("PullbackHeader BottomToTop +76-16") << QQuickItemView::VerticalBottomToTop + << QQuickListView::PullBackHeader + << 76 << -16 + << -230 << -60; + + // -------------------- + // PullbackHeader LeftToRight + QTest::newRow("PullbackHeader LeftToRight -2") << QQuickItemView::LeftToRight + << QQuickListView::PullBackHeader + << -2 << 0 + << -30 << -30; + + QTest::newRow("PullbackHeader LeftToRight -10") << QQuickItemView::LeftToRight + << QQuickListView::PullBackHeader + << -10 << 0 + << -30 << -30; + + QTest::newRow("PullbackHeader LeftToRight -11") << QQuickItemView::LeftToRight + << QQuickListView::PullBackHeader + << -11 << 0 + << -10 << -10; + + QTest::newRow("PullbackHeader LeftToRight -14") << QQuickItemView::LeftToRight + << QQuickListView::PullBackHeader + << -14 << 0 + << -10 << -10; + + QTest::newRow("PullbackHeader LeftToRight -16") << QQuickItemView::LeftToRight + << QQuickListView::PullBackHeader + << -16 << 0 + << 0 << -30; + + QTest::newRow("PullbackHeader LeftToRight -20") << QQuickItemView::LeftToRight + << QQuickListView::PullBackHeader + << -20 << 0 + << 0 << -30; + + QTest::newRow("PullbackHeader LeftToRight -65+10") << QQuickItemView::LeftToRight + << QQuickListView::PullBackHeader + << -65 << 10 + << 20 << -10; + + QTest::newRow("PullbackHeader LeftToRight -65+20") << QQuickItemView::LeftToRight + << QQuickListView::PullBackHeader + << -65 << 20 + << 10 << 10; + + // Should move header even if contentX doesn't move (its aligned with top) + QTest::newRow("PullbackHeader LeftToRight -55+5") << QQuickItemView::LeftToRight + << QQuickListView::PullBackHeader + << -55 << 5 + << 20 << -10; + + // Should move header even if contentX doesn't move (it's aligned with header) + QTest::newRow("PullbackHeader LeftToRight -76+16") << QQuickItemView::LeftToRight + << QQuickListView::PullBackHeader + << -76 << 16 + << 30 << 30; + + // -------------------- + // PullbackHeader RightToLeft + QTest::newRow("PullbackHeader RightToLeft +2") << QQuickItemView::RightToLeft + << QQuickListView::PullBackHeader + << +2 << 0 + << -210 << 0; + + QTest::newRow("PullbackHeader RightToLeft +9") << QQuickItemView::RightToLeft + << QQuickListView::PullBackHeader + << +9 << 0 + << -210 << 0; + + QTest::newRow("PullbackHeader RightToLeft +11") << QQuickItemView::RightToLeft + << QQuickListView::PullBackHeader + << +11 << 0 + << -230 << -20; + + QTest::newRow("PullbackHeader RightToLeft +14") << QQuickItemView::RightToLeft + << QQuickListView::PullBackHeader + << +14 << 0 + << -230 << -20; + + QTest::newRow("PullbackHeader RightToLeft +16") << QQuickItemView::RightToLeft + << QQuickListView::PullBackHeader + << +16 << 0 + << -240 << 0; + + QTest::newRow("PullbackHeader RightToLeft +20") << QQuickItemView::RightToLeft + << QQuickListView::PullBackHeader + << +20 << 0 + << -240 << 0; + + QTest::newRow("PullbackHeader RightToLeft +65-10") << QQuickItemView::RightToLeft + << QQuickListView::PullBackHeader + << +65 << -10 + << -260 << -20; + + QTest::newRow("PullbackHeader RightToLeft +65-20") << QQuickItemView::RightToLeft + << QQuickListView::PullBackHeader + << +65 << -20 + << -250 << -40; + + // Should move header even if contentX doesn't move (it's aligned with top) + QTest::newRow("PullbackHeader RightToLeft +55-5") << QQuickItemView::RightToLeft + << QQuickListView::PullBackHeader + << 55 << -5 + << -260 << -20; + + // Should move header even if contentX doesn't move (it's aligned with header) + QTest::newRow("PullbackHeader RightToLeft +76-16") << QQuickItemView::RightToLeft + << QQuickListView::PullBackHeader + << 76 << -16 + << -270 << -60; + +} + void tst_QQuickListView::snapOneItemResize_QTBUG_43555() { QScopedPointer window(createView()); -- cgit v1.2.3 From 38e6b511e9a5215ef0e8b3217fb51b5f8fbaa62d Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Thu, 30 Jan 2020 15:34:28 +0100 Subject: Run qtEnsurePluginResourcesCpp() from qtquickcompiler.prf This was missed when factoring out the resources flattening. Fixes: QTBUG-81699 Fixes: QTBUG-81713 Change-Id: I6ee42c0b91aaa57c593b218eb52359205098e5c6 Reviewed-by: Simon Hausmann --- tools/qmlcachegen/qtquickcompiler.prf | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/qmlcachegen/qtquickcompiler.prf b/tools/qmlcachegen/qtquickcompiler.prf index 77906b19a6..17f1cb5a79 100644 --- a/tools/qmlcachegen/qtquickcompiler.prf +++ b/tools/qmlcachegen/qtquickcompiler.prf @@ -33,6 +33,7 @@ defineTest(qtQuickSkippedResourceFile) { # Flatten RESOURCES that may contain individual files or objects load(resources_functions) qtFlattenResources() +qtEnsurePluginResourcesCpp() NEWRESOURCES = QMLCACHE_RESOURCE_FILES = -- cgit v1.2.3 From 41893b00fac8e1b18589694a35c20cf5251282fe Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Fri, 31 Jan 2020 09:43:35 +0100 Subject: Fix static builds due to name clashes When QtQuick and QtQuickParticles was linked into the same application then there was a name clash, so the classes in QtQuickParticles are renamed to avoid this clash. Change-Id: I8c2144ba7ad5838c95077a370ef400bd706fce8a Reviewed-by: Laszlo Agocs --- src/particles/qquickimageparticle.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/particles/qquickimageparticle.cpp b/src/particles/qquickimageparticle.cpp index 4ce8186c7c..c6fe2f516d 100644 --- a/src/particles/qquickimageparticle.cpp +++ b/src/particles/qquickimageparticle.cpp @@ -1,4 +1,4 @@ -/**************************************************************************** +/**************************************************************************** ** ** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ @@ -389,10 +389,10 @@ private: QSGMaterialType DeformableMaterial::m_type; -class SpriteMaterialShader : public QSGMaterialShader +class ParticleSpriteMaterialShader : public QSGMaterialShader { public: - SpriteMaterialShader() + ParticleSpriteMaterialShader() { QSGShaderSourceBuilder builder; const bool isES = QOpenGLContext::currentContext()->isOpenGLES(); @@ -478,10 +478,10 @@ public: QOpenGLFunctions* glFuncs; }; -class SpriteMaterialRhiShader : public QSGMaterialRhiShader +class ParticleSpriteMaterialRhiShader : public QSGMaterialRhiShader { public: - SpriteMaterialRhiShader() + ParticleSpriteMaterialRhiShader() { setShaderFileName(VertexStage, QStringLiteral(":/particles/shaders_ng/imageparticle_sprite.vert.qsb")); setShaderFileName(FragmentStage, QStringLiteral(":/particles/shaders_ng/imageparticle_sprite.frag.qsb")); @@ -544,9 +544,9 @@ public: SpriteMaterial() { setFlag(SupportsRhiShader, true); } QSGMaterialShader *createShader() const override { if (flags().testFlag(RhiShaderWanted)) - return new SpriteMaterialRhiShader; + return new ParticleSpriteMaterialRhiShader; else - return new SpriteMaterialShader; + return new ParticleSpriteMaterialShader; } QSGMaterialType *type() const override { return &m_type; } -- cgit v1.2.3 From ecdb4ed275a0869dc668d73d774735575d43a0a3 Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Thu, 2 Jan 2020 14:42:12 +0100 Subject: Enable conversion from QJSValues containing arrays to container types We started to convert containers to QJSValues, so that we could use them as JavaScript arrays. Unfortunately, this would then lead to a type missmatch when those same values where to be stored in a property of the container type. This commit fixes this by converting them back to the original type. Fixes: QTBUG-80916 Change-Id: I30a3b03e17c34b171d4a6881dfd7801c13e94d80 Reviewed-by: Ulf Hermann --- src/qml/jsruntime/qv4engine.cpp | 25 +++++++++++++++++++- .../data/sequenceConversion.write.error.qml | 2 +- .../auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 9 ++++---- .../qml/qqmllanguage/data/arrayToContainer.qml | 7 ++++++ tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp | 27 ++++++++++++++++++++++ 5 files changed, 63 insertions(+), 7 deletions(-) create mode 100644 tests/auto/qml/qqmllanguage/data/arrayToContainer.qml diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index c81661033a..81f55673cd 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -1508,12 +1508,35 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int return QVariant::fromValue(QV4::JsonObject::toJsonArray(a)); } + QVariant retn; #if QT_CONFIG(qml_sequence_object) bool succeeded = false; - QVariant retn = QV4::SequencePrototype::toVariant(value, typeHint, &succeeded); + retn = QV4::SequencePrototype::toVariant(value, typeHint, &succeeded); if (succeeded) return retn; #endif + retn = QVariant(typeHint, QMetaType::create(typeHint)); + auto retnAsIterable = retn.value(); + if (retnAsIterable._iteratorCapabilities & QtMetaTypePrivate::ContainerIsAppendable) { + auto const length = a->getLength(); + QV4::ScopedValue arrayValue(scope); + for (qint64 i = 0; i < length; ++i) { + arrayValue = a->get(i); + QVariant asVariant = toVariant(e, arrayValue, retnAsIterable._metaType_id, false, visitedObjects); + auto originalType = asVariant.userType(); + bool couldConvert = asVariant.convert(retnAsIterable._metaType_id); + if (!couldConvert) { + qWarning() << QLatin1String("Could not convert array value at position %1 from %2 to %3") + .arg(QString::number(i), + QMetaType::typeName(originalType), + QMetaType::typeName(retnAsIterable._metaType_id)); + // create default constructed value + asVariant = QVariant(retnAsIterable._metaType_id, nullptr); + } + retnAsIterable.append(asVariant.constData()); + } + return retn; + } } if (value.isUndefined()) diff --git a/tests/auto/qml/qqmlecmascript/data/sequenceConversion.write.error.qml b/tests/auto/qml/qqmlecmascript/data/sequenceConversion.write.error.qml index 75beafd1ee..c2c8c1b52b 100644 --- a/tests/auto/qml/qqmlecmascript/data/sequenceConversion.write.error.qml +++ b/tests/auto/qml/qqmlecmascript/data/sequenceConversion.write.error.qml @@ -12,7 +12,7 @@ Item { function performTest() { // we have NOT registered QList as a type - var pointList = [ Qt.point(7,7), Qt.point(8,8), Qt.point(9,9) ]; + var pointList = [ Qt.point(7,7), "hello world", Qt.point(8,8), Qt.point(9,9) ]; msco.pointListProperty = pointList; // error. } } diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index 370ef5f065..26232ac1a3 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -5792,13 +5792,12 @@ void tst_qqmlecmascript::sequenceConversionWrite() MySequenceConversionObject *seq = object->findChild("msco"); QVERIFY(seq != nullptr); - // we haven't registered QList as a sequence type, so writing shouldn't work. - QString warningOne = qmlFile.toString() + QLatin1String(":16: Error: Cannot assign QJSValue to QList"); - QTest::ignoreMessage(QtWarningMsg, warningOne.toLatin1().constData()); - + // Behavior change in 5.14: due to added auto-magical conversions, it is possible to assign to + // QList, even though it is not a registered sequence type + QTest::ignoreMessage(QtMsgType::QtWarningMsg, QRegularExpression("Could not convert array value at position 1 from QString to QPoint")); QMetaObject::invokeMethod(object, "performTest"); - QList pointList; pointList << QPoint(1, 2) << QPoint(3, 4) << QPoint(5, 6); // original values, shouldn't have changed + QList pointList; pointList << QPoint(7, 7) << QPoint(0,0) << QPoint(8, 8) << QPoint(9, 9); // original values, shouldn't have changed QCOMPARE(seq->pointListProperty(), pointList); delete object; diff --git a/tests/auto/qml/qqmllanguage/data/arrayToContainer.qml b/tests/auto/qml/qqmllanguage/data/arrayToContainer.qml new file mode 100644 index 0000000000..ee400eb41f --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/arrayToContainer.qml @@ -0,0 +1,7 @@ +import QtQml 2.14 +import qt.test 1.0 + +TestItem { + property var vector + positions: vector +} diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index fae74f1f25..4a8ce77f92 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -303,6 +303,8 @@ private slots: void typeWrapperToVariant(); + void arrayToContainer(); + private: QQmlEngine engine; QStringList defaultImportPathList; @@ -5238,6 +5240,31 @@ void tst_qqmllanguage::typeWrapperToVariant() QVERIFY(target); } +class TestItem : public QObject +{ + Q_OBJECT + Q_PROPERTY( QVector positions MEMBER m_points ) + +public: + TestItem() = default; + QVector< QPointF > m_points; +}; + + +Q_DECLARE_METATYPE(QVector); +void tst_qqmllanguage::arrayToContainer() +{ + QQmlEngine engine; + qmlRegisterType("qt.test", 1, 0, "TestItem"); + QVector points { QPointF (2.0, 3.0) }; + engine.rootContext()->setContextProperty("test", QVariant::fromValue(points)); + QQmlComponent component(&engine, testFileUrl("arrayToContainer.qml")); + VERIFY_ERRORS(0); + QScopedPointer root(qobject_cast(component.createWithInitialProperties( {{"vector", QVariant::fromValue(points)}} ))); + QVERIFY(root); + QCOMPARE(root->m_points.at(0), QPointF (2.0, 3.0) ); +} + QTEST_MAIN(tst_qqmllanguage) #include "tst_qqmllanguage.moc" -- cgit v1.2.3 From 8c07f998d7e9e9d30a2cc0c4999bb9675f8c70b3 Mon Sep 17 00:00:00 2001 From: Alexandru Croitor Date: Sun, 2 Feb 2020 13:41:30 +0100 Subject: Bump version Change-Id: Ia529cc8612d8fd4566c11aa01f89131ead7ac863 --- .qmake.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.qmake.conf b/.qmake.conf index 6d3b37fbad..4b9929245c 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -4,4 +4,4 @@ CONFIG += warning_clean DEFINES += QT_NO_LINKED_LIST DEFINES += QT_NO_JAVA_STYLE_ITERATORS -MODULE_VERSION = 5.14.1 +MODULE_VERSION = 5.14.2 -- cgit v1.2.3 From f572ea346cb50e783d636a56daea0b8d50f6df7e Mon Sep 17 00:00:00 2001 From: Joni Poikelin Date: Mon, 26 Aug 2019 15:35:50 +0300 Subject: Doc: Remove outdated note The behavior described in the note does not apply to Qt 5. Change-Id: Ia4d45ca35d095d6cdc193f276bd52c7ad403b82f Reviewed-by: Paul Wicking --- src/quick/items/qquickshadereffectsource.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/quick/items/qquickshadereffectsource.cpp b/src/quick/items/qquickshadereffectsource.cpp index f9f3e5cfa3..b298ed74da 100644 --- a/src/quick/items/qquickshadereffectsource.cpp +++ b/src/quick/items/qquickshadereffectsource.cpp @@ -161,10 +161,6 @@ public: \l sourceItem while still handling input. For this, you can use the \l hideSource property. - \note If \l sourceItem is a \l Rectangle with border, by default half the - border width falls outside the texture. To get the whole border, you can - extend the \l sourceRect. - \note The ShaderEffectSource relies on FBO multisampling support to antialias edges. If the underlying hardware does not support this, which is the case for most embedded graphics chips, edges rendered -- cgit v1.2.3 From 793ba7c0272725a377c1e27e69e84f3abadcbcf5 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 3 Feb 2020 12:37:54 +0100 Subject: Blacklist tst_qquickmousearea::nestedStopAtBounds on opensuse 15.0 This partially reverts commit 51e02fdc02c3cc2dbf9d2ba0b3fb709a6cd4e32e. Task-number: QTBUG-78153 Change-Id: I421fdc3acefd11cabfc192eb06c3cd92c0e76149 Reviewed-by: Fabian Kosmale Reviewed-by: Shawn Rutledge --- tests/auto/quick/qquickmousearea/BLACKLIST | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 tests/auto/quick/qquickmousearea/BLACKLIST diff --git a/tests/auto/quick/qquickmousearea/BLACKLIST b/tests/auto/quick/qquickmousearea/BLACKLIST new file mode 100644 index 0000000000..f2cb00225b --- /dev/null +++ b/tests/auto/quick/qquickmousearea/BLACKLIST @@ -0,0 +1,4 @@ +# QTBUG-78153 +[nestedStopAtBounds] +opensuse-leap + -- cgit v1.2.3 From 4e15f2135cdbefd9999a17d4e4fff5ea93679fac Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 3 Feb 2020 09:47:32 +0100 Subject: Clarify the Binding.restoreMode warning message Specify that you need to import QtQml 2.14 and where. Fixes: QTBUG-81787 Change-Id: Ia8e7fb3229971294cbade2791075dcd0b5943fae Reviewed-by: Fabian Kosmale Reviewed-by: Simon Hausmann Reviewed-by: Mitch Curtis --- src/qml/types/qqmlbind.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/qml/types/qqmlbind.cpp b/src/qml/types/qqmlbind.cpp index 921d60caa1..02c3b71806 100644 --- a/src/qml/types/qqmlbind.cpp +++ b/src/qml/types/qqmlbind.cpp @@ -484,9 +484,11 @@ void QQmlBind::eval() d->clearPrev(); } else if (!d->restoreModeExplicit) { qmlWarning(this) - << "Not restoring previous value because restoreMode has not been set." - << "This behavior is deprecated." - << "In Qt < 6.0 the default is Binding.RestoreBinding." + << "Not restoring previous value because restoreMode has not been set.\n" + << "This behavior is deprecated.\n" + << "You have to import QtQml 2.14 after any QtQuick imports and set\n" + << "the restoreMode of the binding to fix this warning.\n" + << "In Qt < 6.0 the default is Binding.RestoreBinding.\n" << "In Qt >= 6.0 the default is Binding.RestoreBindingOrValue."; } } else if (d->prevIsVariant) { @@ -495,10 +497,12 @@ void QQmlBind::eval() d->clearPrev(); } else if (!d->restoreModeExplicit) { qmlWarning(this) - << "Not restoring previous value because restoreMode has not been set." - << "This behavior is deprecated." - << "In Qt < 6.0 the default is Binding.RestoreBinding." - << "In Qt >= 6.0 the default is Binding.RestoreBindingOrValue."; + << "Not restoring previous value because restoreMode has not been set.\n" + << "This behavior is deprecated.\n" + << "You have to import QtQml 2.14 after any QtQuick imports and set\n" + << "the restoreMode of the binding to fix this warning.\n" + << "In Qt < 6.0 the default is Binding.RestoreBinding.\n" + << "In Qt >= 6.0 the default is Binding.RestoreBindingOrValue.\n"; } } return; -- cgit v1.2.3 From 6e111f96e307501ec02a620fa3124fd3ce9c9193 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Thu, 30 Jan 2020 15:43:57 +0100 Subject: Add support for file selectors to qml tool This allows defining file selectors using a command-line option. [ChangeLog][QtQml][qml] The QML Runtime tool --selector option now allows defining a custom QQmlFileSelector. Change-Id: I1be5efd273b2f387df72b1d5057f7281e5c0c156 Reviewed-by: Shawn Rutledge --- tools/qml/main.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tools/qml/main.cpp b/tools/qml/main.cpp index 4c613e4ab4..9f5aacb1dd 100644 --- a/tools/qml/main.cpp +++ b/tools/qml/main.cpp @@ -59,6 +59,7 @@ #include #include #include +#include #include #include @@ -511,6 +512,9 @@ int main(int argc, char *argv[]) "Backend is one of: default, vulkan, metal, d3d11, gl"), QStringLiteral("backend")); parser.addOption(rhiOption); + QCommandLineOption selectorOption(QStringLiteral("S"), QCoreApplication::translate("main", + "Add selector to the list of QQmlFileSelectors."), QStringLiteral("selector")); + parser.addOption(selectorOption); // Positional arguments parser.addPositionalArgument("files", @@ -550,6 +554,15 @@ int main(int argc, char *argv[]) #endif for (const QString &importPath : parser.values(importOption)) e.addImportPath(importPath); + + QStringList customSelectors; + for (const QString &selector : parser.values(selectorOption)) + customSelectors.append(selector); + if (!customSelectors.isEmpty()) { + QQmlFileSelector *selector = QQmlFileSelector::get(&e); + selector->setExtraSelectors(customSelectors); + } + files << parser.values(qmlFileOption); if (parser.isSet(configOption)) confFile = parser.value(configOption); -- cgit v1.2.3 From ac46c9f6ce9ef757e0ccba8a283cb0efabaef56e Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Fri, 31 Jan 2020 16:05:52 +0100 Subject: Synthetically reference type registration functions Add unused volatile pointers to the type registration functions in each import plugin. We need to do this in order to prevent the linker from optimizing the registration away. There are two ways for this to happen: When linking statically, the linker will examine the referenced symbols on a per-object base and leave out all unreferenced objects. When linking dynamically, the linker may do the same on a per-library base and drop any unreferenced libraries from the dependencies. Forcing a reference to the type registration function prevents both. The volatile technique allows us to remove the previous qCDebug() hack. Having an unused volatile auto variable should only result in a single memory read as runtime overhead. The qCDebug() technique would generate a read and a block of mostly dead code (as no one would ever use that logging category). Fixes: QTBUG-81622 Change-Id: I255667276dfd355b19baa17b1aad3db406bf1954 Reviewed-by: Fabian Kosmale --- src/imports/folderlistmodel/plugin.cpp | 9 ++++++++- src/imports/labsanimation/plugin.cpp | 8 +++++++- src/imports/labsmodels/plugin.cpp | 8 +++++++- src/imports/layouts/plugin.cpp | 4 ++++ src/imports/localstorage/plugin.cpp | 4 ++++ src/imports/models/plugin.cpp | 17 +++-------------- src/imports/particles/plugin.cpp | 7 ++++++- src/imports/qtqml/plugin.cpp | 17 ++++++++++++----- src/imports/qtquick2/plugin.cpp | 7 ++++++- src/imports/settings/plugin.cpp | 8 +++++++- src/imports/shapes/plugin.cpp | 2 ++ src/imports/sharedimage/plugin.cpp | 8 +++++++- src/imports/statemachine/plugin.cpp | 8 +++++++- src/imports/testlib/main.cpp | 8 +++++++- src/imports/wavefrontmesh/plugin.cpp | 4 ++++ src/imports/window/plugin.cpp | 8 +++++++- src/imports/workerscript/plugin.cpp | 17 +++-------------- src/particles/qtquickparticlesglobal_p.h | 2 ++ src/qml/qtqmlglobal_p.h | 2 ++ src/qmlmodels/qtqmlmodelsglobal_p.h | 2 ++ src/qmlworkerscript/qquickworkerscript_p.h | 2 +- src/qmlworkerscript/qtqmlworkerscriptglobal_p.h | 2 ++ src/quick/qtquickglobal_p.h | 2 ++ src/quickshapes/qquickshapesglobal_p.h | 1 + 24 files changed, 113 insertions(+), 44 deletions(-) diff --git a/src/imports/folderlistmodel/plugin.cpp b/src/imports/folderlistmodel/plugin.cpp index 28837655ef..7a38769b77 100644 --- a/src/imports/folderlistmodel/plugin.cpp +++ b/src/imports/folderlistmodel/plugin.cpp @@ -42,6 +42,8 @@ #include "qquickfolderlistmodel.h" +extern void qml_register_types_Qt_labs_folderlistmodel(); + QT_BEGIN_NAMESPACE //![class decl] @@ -51,7 +53,12 @@ class QmlFolderListModelPlugin : public QQmlExtensionPlugin Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: - QmlFolderListModelPlugin(QObject *parent = nullptr) : QQmlExtensionPlugin(parent) { } + QmlFolderListModelPlugin(QObject *parent = nullptr) : QQmlExtensionPlugin(parent) + { + volatile auto registration = &qml_register_types_Qt_labs_folderlistmodel; + Q_UNUSED(registration); + } + void registerTypes(const char *uri) override { Q_ASSERT(QLatin1String(uri) == QLatin1String("Qt.labs.folderlistmodel")); diff --git a/src/imports/labsanimation/plugin.cpp b/src/imports/labsanimation/plugin.cpp index bd732a6aba..9c985f0dcf 100644 --- a/src/imports/labsanimation/plugin.cpp +++ b/src/imports/labsanimation/plugin.cpp @@ -42,6 +42,8 @@ #include "qquickboundaryrule_p.h" +extern void qml_register_types_Qt_labs_animation(); + QT_BEGIN_NAMESPACE /*! @@ -66,7 +68,11 @@ class QtLabsAnimationPlugin : public QQmlEngineExtensionPlugin Q_OBJECT Q_PLUGIN_METADATA(IID QQmlEngineExtensionInterface_iid) public: - QtLabsAnimationPlugin(QObject *parent = nullptr) : QQmlEngineExtensionPlugin(parent) { } + QtLabsAnimationPlugin(QObject *parent = nullptr) : QQmlEngineExtensionPlugin(parent) + { + volatile auto registration = &qml_register_types_Qt_labs_animation; + Q_UNUSED(registration); + } }; //![class decl] diff --git a/src/imports/labsmodels/plugin.cpp b/src/imports/labsmodels/plugin.cpp index feb4f3ba0a..ab5e0023a6 100644 --- a/src/imports/labsmodels/plugin.cpp +++ b/src/imports/labsmodels/plugin.cpp @@ -50,6 +50,8 @@ #include "qqmldelegatecomponent_p.h" #endif +extern void qml_register_types_Qt_labs_qmlmodels(); + QT_BEGIN_NAMESPACE /*! @@ -74,7 +76,11 @@ class QtQmlLabsModelsPlugin : public QQmlEngineExtensionPlugin Q_OBJECT Q_PLUGIN_METADATA(IID QQmlEngineExtensionInterface_iid) public: - QtQmlLabsModelsPlugin(QObject *parent = nullptr) : QQmlEngineExtensionPlugin(parent) { } + QtQmlLabsModelsPlugin(QObject *parent = nullptr) : QQmlEngineExtensionPlugin(parent) + { + volatile auto registration = &qml_register_types_Qt_labs_qmlmodels; + Q_UNUSED(registration); + } }; //![class decl] diff --git a/src/imports/layouts/plugin.cpp b/src/imports/layouts/plugin.cpp index c302b79164..af270c1732 100644 --- a/src/imports/layouts/plugin.cpp +++ b/src/imports/layouts/plugin.cpp @@ -42,6 +42,8 @@ #include "qquicklinearlayout_p.h" #include "qquickstacklayout_p.h" +extern void qml_register_types_QtQuick_Layouts(); + QT_BEGIN_NAMESPACE //![class decl] @@ -52,6 +54,8 @@ class QtQuickLayoutsPlugin : public QQmlEngineExtensionPlugin public: QtQuickLayoutsPlugin(QObject *parent = nullptr) : QQmlEngineExtensionPlugin(parent) { + volatile auto registration = &qml_register_types_QtQuick_Layouts; + Q_UNUSED(registration); } }; //![class decl] diff --git a/src/imports/localstorage/plugin.cpp b/src/imports/localstorage/plugin.cpp index ae9f37784d..e488b3d43c 100644 --- a/src/imports/localstorage/plugin.cpp +++ b/src/imports/localstorage/plugin.cpp @@ -42,6 +42,8 @@ #include #include +extern void qml_register_types_QtQuick_LocalStorage(); + QT_BEGIN_NAMESPACE class QQmlLocalStoragePlugin : public QQmlEngineExtensionPlugin @@ -52,6 +54,8 @@ class QQmlLocalStoragePlugin : public QQmlEngineExtensionPlugin public: QQmlLocalStoragePlugin(QObject *parent = nullptr) : QQmlEngineExtensionPlugin(parent) { + volatile auto registration = &qml_register_types_QtQuick_LocalStorage; + Q_UNUSED(registration); } }; diff --git a/src/imports/models/plugin.cpp b/src/imports/models/plugin.cpp index 4aa9f27766..c15866cf05 100644 --- a/src/imports/models/plugin.cpp +++ b/src/imports/models/plugin.cpp @@ -37,17 +37,11 @@ ** ****************************************************************************/ -#include - +#include #include -#include - -#include QT_BEGIN_NAMESPACE -Q_LOGGING_CATEGORY(qmlModelsPlugin, "qt.qmlModelsPlugin") - /*! \qmlmodule QtQml.Models 2.\QtMinorVersion \title Qt QML Models QML Types @@ -92,13 +86,8 @@ class QtQmlModelsPlugin : public QQmlEngineExtensionPlugin public: QtQmlModelsPlugin(QObject *parent = nullptr) : QQmlEngineExtensionPlugin(parent) { - if (qmlModelsPlugin().isDebugEnabled()) { - // Superficial debug message that causes the dependency between QtQmlWorkerScript - // and the workerscript plugin to be retained. - // As qCDebug() can be a noop, retrieve the className in a separate step. - const QString className = QQmlObjectModel::staticMetaObject.className(); - qCDebug(qmlModelsPlugin) << "Loading QmlModels plugin:" << className; - } + volatile auto registration = &qml_register_types_QtQml_Models; + Q_UNUSED(registration); } }; //![class decl] diff --git a/src/imports/particles/plugin.cpp b/src/imports/particles/plugin.cpp index 4f319db9f1..6629a660af 100644 --- a/src/imports/particles/plugin.cpp +++ b/src/imports/particles/plugin.cpp @@ -50,7 +50,12 @@ class QtQuick2ParticlesPlugin : public QQmlExtensionPlugin Q_OBJECT Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: - QtQuick2ParticlesPlugin(QObject *parent = nullptr) : QQmlExtensionPlugin(parent) { } + QtQuick2ParticlesPlugin(QObject *parent = nullptr) : QQmlExtensionPlugin(parent) + { + volatile auto registration = &qml_register_types_QtQuick_Particles; + Q_UNUSED(registration); + } + void registerTypes(const char *uri) override { Q_UNUSED(uri); diff --git a/src/imports/qtqml/plugin.cpp b/src/imports/qtqml/plugin.cpp index 6891755446..854ef6d2e6 100644 --- a/src/imports/qtqml/plugin.cpp +++ b/src/imports/qtqml/plugin.cpp @@ -37,10 +37,8 @@ ** ****************************************************************************/ +#include #include -#include -#include -#include #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) #include @@ -71,7 +69,12 @@ class QtQmlPlugin : public QQmlExtensionPlugin Q_OBJECT Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: - QtQmlPlugin(QObject *parent = nullptr) : QQmlExtensionPlugin(parent) { } + QtQmlPlugin(QObject *parent = nullptr) : QQmlExtensionPlugin(parent) + { + volatile auto registration = &qml_register_types_QtQml; + Q_UNUSED(registration); + } + void registerTypes(const char *) override { QQmlModelsModule::registerQmlTypes(); } }; #else @@ -80,7 +83,11 @@ class QtQmlPlugin : public QQmlEngineExtensionPlugin Q_OBJECT Q_PLUGIN_METADATA(IID QQmlEngineExtensionInterface_iid) public: - QtQmlPlugin(QObject *parent = nullptr) : QQmlEngineExtensionPlugin(parent) {} + QtQmlPlugin(QObject *parent = nullptr) : QQmlEngineExtensionPlugin(parent) + { + volatile auto registration = &qml_register_types_QtQml; + Q_UNUSED(registration); + } }; #endif //![class decl] diff --git a/src/imports/qtquick2/plugin.cpp b/src/imports/qtquick2/plugin.cpp index 0832e22e5d..20bc4a3cc0 100644 --- a/src/imports/qtquick2/plugin.cpp +++ b/src/imports/qtquick2/plugin.cpp @@ -57,7 +57,12 @@ class QtQuick2Plugin : public QQmlExtensionPlugin Q_OBJECT Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: - QtQuick2Plugin(QObject *parent = nullptr) : QQmlExtensionPlugin(parent) { } + QtQuick2Plugin(QObject *parent = nullptr) : QQmlExtensionPlugin(parent) + { + volatile auto registration = &qml_register_types_QtQuick; + Q_UNUSED(registration); + } + void registerTypes(const char *uri) override { Q_ASSERT(QLatin1String(uri) == QLatin1String("QtQuick")); diff --git a/src/imports/settings/plugin.cpp b/src/imports/settings/plugin.cpp index 24ff43ea6f..e8e640412b 100644 --- a/src/imports/settings/plugin.cpp +++ b/src/imports/settings/plugin.cpp @@ -42,6 +42,8 @@ #include "qqmlsettings_p.h" +extern void qml_register_types_Qt_labs_settings(); + QT_BEGIN_NAMESPACE class QmlSettingsPlugin : public QQmlEngineExtensionPlugin @@ -50,7 +52,11 @@ class QmlSettingsPlugin : public QQmlEngineExtensionPlugin Q_PLUGIN_METADATA(IID QQmlEngineExtensionInterface_iid) public: - QmlSettingsPlugin(QObject *parent = nullptr) : QQmlEngineExtensionPlugin(parent) {} + QmlSettingsPlugin(QObject *parent = nullptr) : QQmlEngineExtensionPlugin(parent) + { + volatile auto registration = &qml_register_types_Qt_labs_settings; + Q_UNUSED(registration); + } }; QT_END_NAMESPACE diff --git a/src/imports/shapes/plugin.cpp b/src/imports/shapes/plugin.cpp index 3855a93fc7..48eecbd8f1 100644 --- a/src/imports/shapes/plugin.cpp +++ b/src/imports/shapes/plugin.cpp @@ -52,6 +52,8 @@ public: QmlShapesPlugin(QObject *parent = nullptr) : QQmlExtensionPlugin(parent) { + volatile auto registration = &qml_register_types_QtQuick_Shapes; + Q_UNUSED(registration); } void registerTypes(const char *uri) override diff --git a/src/imports/sharedimage/plugin.cpp b/src/imports/sharedimage/plugin.cpp index 237fa64c61..d7c2ef8d17 100644 --- a/src/imports/sharedimage/plugin.cpp +++ b/src/imports/sharedimage/plugin.cpp @@ -99,6 +99,8 @@ The shared image module does not provide any directly usable QML types. */ +extern void qml_register_types_Qt_labs_sharedimage(); + QT_BEGIN_NAMESPACE class QtQuickSharedImagePlugin : public QQmlEngineExtensionPlugin @@ -106,7 +108,11 @@ class QtQuickSharedImagePlugin : public QQmlEngineExtensionPlugin Q_OBJECT Q_PLUGIN_METADATA(IID QQmlEngineExtensionInterface_iid) public: - QtQuickSharedImagePlugin(QObject *parent = nullptr) : QQmlEngineExtensionPlugin(parent) {} + QtQuickSharedImagePlugin(QObject *parent = nullptr) : QQmlEngineExtensionPlugin(parent) + { + volatile auto registration = &qml_register_types_Qt_labs_sharedimage; + Q_UNUSED(registration); + } void initializeEngine(QQmlEngine *engine, const char *uri) override { diff --git a/src/imports/statemachine/plugin.cpp b/src/imports/statemachine/plugin.cpp index 4c991994f3..c370504029 100644 --- a/src/imports/statemachine/plugin.cpp +++ b/src/imports/statemachine/plugin.cpp @@ -48,6 +48,8 @@ #include #include +extern void qml_register_types_QtQml_StateMachine(); + QT_BEGIN_NAMESPACE class QtQmlStateMachinePlugin : public QQmlEngineExtensionPlugin @@ -56,7 +58,11 @@ class QtQmlStateMachinePlugin : public QQmlEngineExtensionPlugin Q_PLUGIN_METADATA(IID QQmlEngineExtensionInterface_iid) public: - QtQmlStateMachinePlugin(QObject *parent = nullptr) : QQmlEngineExtensionPlugin(parent) { } + QtQmlStateMachinePlugin(QObject *parent = nullptr) : QQmlEngineExtensionPlugin(parent) + { + volatile auto registration = &qml_register_types_QtQml_StateMachine; + Q_UNUSED(registration); + } }; QT_END_NAMESPACE diff --git a/src/imports/testlib/main.cpp b/src/imports/testlib/main.cpp index 1914c02dd0..83fc150e6c 100644 --- a/src/imports/testlib/main.cpp +++ b/src/imports/testlib/main.cpp @@ -50,6 +50,8 @@ QML_DECLARE_TYPE(QuickTestResult) QML_DECLARE_TYPE(QuickTestEvent) QML_DECLARE_TYPE(QuickTestUtil) +extern void qml_register_types_QtTest(); + QT_BEGIN_NAMESPACE class QTestQmlModule : public QQmlEngineExtensionPlugin @@ -58,7 +60,11 @@ class QTestQmlModule : public QQmlEngineExtensionPlugin Q_PLUGIN_METADATA(IID QQmlEngineExtensionInterface_iid) public: - QTestQmlModule(QObject *parent = nullptr) : QQmlEngineExtensionPlugin(parent) { } + QTestQmlModule(QObject *parent = nullptr) : QQmlEngineExtensionPlugin(parent) + { + volatile auto registration = &qml_register_types_QtTest; + Q_UNUSED(registration); + } }; QT_END_NAMESPACE diff --git a/src/imports/wavefrontmesh/plugin.cpp b/src/imports/wavefrontmesh/plugin.cpp index 9bb7a45b2f..eea0db19db 100644 --- a/src/imports/wavefrontmesh/plugin.cpp +++ b/src/imports/wavefrontmesh/plugin.cpp @@ -42,6 +42,8 @@ #include "qwavefrontmesh.h" +extern void qml_register_types_Qt_labs_wavefrontmesh(); + QT_BEGIN_NAMESPACE class QmlWavefrontMeshPlugin : public QQmlEngineExtensionPlugin @@ -52,6 +54,8 @@ public: QmlWavefrontMeshPlugin(QObject *parent = nullptr) : QQmlEngineExtensionPlugin(parent) { + volatile auto registration = &qml_register_types_Qt_labs_wavefrontmesh; + Q_UNUSED(registration); } }; diff --git a/src/imports/window/plugin.cpp b/src/imports/window/plugin.cpp index ec4f2c5d2a..5152fa02ec 100644 --- a/src/imports/window/plugin.cpp +++ b/src/imports/window/plugin.cpp @@ -41,6 +41,8 @@ #include "plugin.h" +extern void qml_register_types_QtQuick_Window(); + QT_BEGIN_NAMESPACE /*! @@ -64,7 +66,11 @@ class QtQuick2WindowPlugin : public QQmlEngineExtensionPlugin Q_OBJECT Q_PLUGIN_METADATA(IID QQmlEngineExtensionInterface_iid) public: - QtQuick2WindowPlugin(QObject *parent = nullptr) : QQmlEngineExtensionPlugin(parent) { } + QtQuick2WindowPlugin(QObject *parent = nullptr) : QQmlEngineExtensionPlugin(parent) + { + volatile auto registration = &qml_register_types_QtQuick_Window; + Q_UNUSED(registration); + } }; //![class decl] diff --git a/src/imports/workerscript/plugin.cpp b/src/imports/workerscript/plugin.cpp index 0961979c53..1323b17ef4 100644 --- a/src/imports/workerscript/plugin.cpp +++ b/src/imports/workerscript/plugin.cpp @@ -37,17 +37,11 @@ ** ****************************************************************************/ -#include - +#include #include -#include - -#include QT_BEGIN_NAMESPACE -Q_LOGGING_CATEGORY(workerScriptPlugin, "qt.workerScriptPlugin") - /*! \qmlmodule QtQml.WorkerScript 2.\QtMinorVersion \title Qt QML WorkerScript QML Types @@ -71,13 +65,8 @@ class QtQmlWorkerScriptPlugin : public QQmlEngineExtensionPlugin public: QtQmlWorkerScriptPlugin(QObject *parent = nullptr) : QQmlEngineExtensionPlugin(parent) { - if (workerScriptPlugin().isDebugEnabled()) { - // Superficial debug message that causes the dependency between QtQmlWorkerScript - // and the workerscript plugin to be retained. - // As qCDebug() can be a noop, retrieve the className in a separate step. - const QString className = QQuickWorkerScript::staticMetaObject.className(); - qCDebug(workerScriptPlugin) << "Loading WorkerScript plugin:" << className; - } + volatile auto registration = &qml_register_types_QtQml_WorkerScript; + Q_UNUSED(registration); } }; diff --git a/src/particles/qtquickparticlesglobal_p.h b/src/particles/qtquickparticlesglobal_p.h index d7647b3d97..927bc29050 100644 --- a/src/particles/qtquickparticlesglobal_p.h +++ b/src/particles/qtquickparticlesglobal_p.h @@ -65,4 +65,6 @@ # define Q_QUICKPARTICLES_PRIVATE_EXPORT #endif +void Q_QUICKPARTICLES_PRIVATE_EXPORT qml_register_types_QtQuick_Particles(); + #endif // QTQUICKPARTICLESGLOBAL_P_H diff --git a/src/qml/qtqmlglobal_p.h b/src/qml/qtqmlglobal_p.h index 9ca0cf2abe..a729729b67 100644 --- a/src/qml/qtqmlglobal_p.h +++ b/src/qml/qtqmlglobal_p.h @@ -60,6 +60,8 @@ #define Q_QML_PRIVATE_EXPORT Q_QML_EXPORT +void Q_QML_PRIVATE_EXPORT qml_register_types_QtQml(); + #if !defined(QT_QMLDEVTOOLS_LIB) && !defined(QT_BUILD_QMLDEVTOOLS_LIB) # define Q_QML_AUTOTEST_EXPORT Q_AUTOTEST_EXPORT #else diff --git a/src/qmlmodels/qtqmlmodelsglobal_p.h b/src/qmlmodels/qtqmlmodelsglobal_p.h index 145112c9c1..1a1157138d 100644 --- a/src/qmlmodels/qtqmlmodelsglobal_p.h +++ b/src/qmlmodels/qtqmlmodelsglobal_p.h @@ -58,4 +58,6 @@ #define Q_QMLMODELS_PRIVATE_EXPORT Q_QMLMODELS_EXPORT #define Q_QMLMODELS_AUTOTEST_EXPORT Q_AUTOTEST_EXPORT +void Q_QMLMODELS_PRIVATE_EXPORT qml_register_types_QtQml_Models(); + #endif // QTQMLMODELSGLOBAL_P_H diff --git a/src/qmlworkerscript/qquickworkerscript_p.h b/src/qmlworkerscript/qquickworkerscript_p.h index 03581089e0..22a205cfe4 100644 --- a/src/qmlworkerscript/qquickworkerscript_p.h +++ b/src/qmlworkerscript/qquickworkerscript_p.h @@ -84,7 +84,7 @@ private: }; class QQmlV4Function; -class Q_QMLWORKERSCRIPT_PRIVATE_EXPORT QQuickWorkerScript : public QObject, public QQmlParserStatus +class Q_AUTOTEST_EXPORT QQuickWorkerScript : public QObject, public QQmlParserStatus { Q_OBJECT Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) diff --git a/src/qmlworkerscript/qtqmlworkerscriptglobal_p.h b/src/qmlworkerscript/qtqmlworkerscriptglobal_p.h index 34236cd79e..c75d5f3129 100644 --- a/src/qmlworkerscript/qtqmlworkerscriptglobal_p.h +++ b/src/qmlworkerscript/qtqmlworkerscriptglobal_p.h @@ -57,4 +57,6 @@ #define Q_QMLWORKERSCRIPT_PRIVATE_EXPORT Q_QMLWORKERSCRIPT_EXPORT #define Q_QMLWORKERSCRIPT_AUTOTEST_EXPORT Q_AUTOTEST_EXPORT +void Q_QMLWORKERSCRIPT_PRIVATE_EXPORT qml_register_types_QtQml_WorkerScript(); + #endif // QTQMLWORKERSCRIPTGLOBAL_P_H diff --git a/src/quick/qtquickglobal_p.h b/src/quick/qtquickglobal_p.h index f6376a6d17..80e59563c7 100644 --- a/src/quick/qtquickglobal_p.h +++ b/src/quick/qtquickglobal_p.h @@ -61,6 +61,8 @@ #define Q_QUICK_PRIVATE_EXPORT Q_QUICK_EXPORT +void Q_QUICK_PRIVATE_EXPORT qml_register_types_QtQuick(); + QT_BEGIN_NAMESPACE void QQuick_initializeProviders(); diff --git a/src/quickshapes/qquickshapesglobal_p.h b/src/quickshapes/qquickshapesglobal_p.h index 2f559b45a0..40f6cfbdcf 100644 --- a/src/quickshapes/qquickshapesglobal_p.h +++ b/src/quickshapes/qquickshapesglobal_p.h @@ -59,5 +59,6 @@ QT_BEGIN_NAMESPACE QT_END_NAMESPACE +void Q_QUICKSHAPES_PRIVATE_EXPORT qml_register_types_QtQuick_Shapes(); #endif // QQUICKSHAPESGLOBAL_P_H -- cgit v1.2.3 From a8bc011d459a4d080815a2675f2a0413c8bf09d2 Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Tue, 4 Feb 2020 08:31:10 +0100 Subject: QV4: Handle value tyes in sameValue algorithm The sameValue(Zero) algorithm were implemented according to the JavaScript specification; however QML has the concept of value types. For those we need to check equality with the intrinsic isEqualTo method. This aligns sameValue(Zero) with strict equality in its treatment of value types. This fixes Array.includes for value types Fixes: QTBUG-81825 Change-Id: Idd3e09cbed94bca6ea44f5683610b87d184e432c Reviewed-by: Ulf Hermann --- src/qml/jsruntime/qv4value.cpp | 4 +++ .../auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 31 ++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/src/qml/jsruntime/qv4value.cpp b/src/qml/jsruntime/qv4value.cpp index d29b060b9e..3449603a8a 100644 --- a/src/qml/jsruntime/qv4value.cpp +++ b/src/qml/jsruntime/qv4value.cpp @@ -250,6 +250,8 @@ bool Value::sameValue(Value other) const { if (isDouble() && other.isInteger()) return other.int_32() ? (doubleValue() == double(other.int_32())) : (doubleValue() == 0 && !std::signbit(doubleValue())); + if (isManaged()) + return other.isManaged() && cast()->isEqualTo(other.cast()); return false; } @@ -269,6 +271,8 @@ bool Value::sameValueZero(Value other) const { return true; } } + if (isManaged()) + return other.isManaged() && cast()->isEqualTo(other.cast()); return false; } diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index ec0db16114..558647e17a 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -74,6 +74,7 @@ public: private slots: void initTestCase(); + void arrayIncludesValueType(); void assignBasicTypes(); void assignDate_data(); void assignDate(); @@ -414,6 +415,36 @@ void tst_qqmlecmascript::initTestCase() registerTypes(); } +void tst_qqmlecmascript::arrayIncludesValueType() +{ + QQmlEngine engine; + QQmlComponent component(&engine); + // It is vital that QtQuick is imported below else we get a warning about + // QQml_colorProvider and tst_qqmlecmascript::signalParameterTypes fails due + // to some static variable being initialized with the wrong value + component.setData(R"( + import QtQuick 2.15 + import QtQml 2.15 + QtObject { + id: root + property color r: Qt.rgba(1, 0, 0) + property color g: Qt.rgba(0, 1, 0) + property color b: Qt.rgba(0, 0, 1) + property var colors: [r, g, b] + property bool success: false + + Component.onCompleted: { + root.success = root.colors.includes(root.g) + } + } + )", QUrl("testData")); + QScopedPointer o(component.create()); + QVERIFY(o); + auto success = o->property("success"); + QVERIFY(success.isValid()); + QVERIFY(success.toBool()); +} + void tst_qqmlecmascript::assignBasicTypes() { QQmlEngine engine; -- cgit v1.2.3 From 9dccec88e3394d9d2dc52812d9607f0bfa01a2d2 Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Wed, 5 Feb 2020 08:50:37 +0100 Subject: Inline components: fix name resolution Inline components are an explicit component boundary, and therefore need some extra treatment. Change-Id: I03cc0d58f3565999f64675e8482ed3c3a325e8c0 Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlobjectcreator.cpp | 2 +- src/qml/qml/qqmlpropertyvalidator.cpp | 2 +- src/qml/qml/qqmltypecompiler.cpp | 6 +++++- tests/auto/qml/qqmllanguage/data/SimpleItem.qml | 5 +++++ .../qml/qqmllanguage/data/inlineComponentWithAlias.qml | 17 +++++++++++++++++ .../qml/qqmllanguage/data/inlineComponentWithId.qml | 14 ++++++++++++++ tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp | 3 +++ 7 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 tests/auto/qml/qqmllanguage/data/SimpleItem.qml create mode 100644 tests/auto/qml/qqmllanguage/data/inlineComponentWithAlias.qml create mode 100644 tests/auto/qml/qqmllanguage/data/inlineComponentWithId.qml diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 6cc2bf49c8..50e1918b6c 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -173,7 +173,7 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI context = new QQmlContextData; context->isInternal = true; context->imports = compilationUnit->typeNameCache; - context->initFromTypeCompilationUnit(compilationUnit, flags & CreationFlags::NormalObject ? subComponentIndex : -1); + context->initFromTypeCompilationUnit(compilationUnit, subComponentIndex); context->setParent(parentContext); if (!sharedState->rootContext) { diff --git a/src/qml/qml/qqmlpropertyvalidator.cpp b/src/qml/qml/qqmlpropertyvalidator.cpp index 8762dc328d..c897ac8751 100644 --- a/src/qml/qml/qqmlpropertyvalidator.cpp +++ b/src/qml/qml/qqmlpropertyvalidator.cpp @@ -104,7 +104,7 @@ QVector QQmlPropertyValidator::validateObject( validateObject(it->objectIndex, /* instantiatingBinding*/ nullptr); } - if (obj->flags & QV4::CompiledData::Object::IsComponent) { + if (obj->flags & QV4::CompiledData::Object::IsComponent && !(obj->flags & QV4::CompiledData::Object::IsInlineComponentRoot)) { Q_ASSERT(obj->nBindings == 1); const QV4::CompiledData::Binding *componentBinding = obj->bindingTable(); Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object); diff --git a/src/qml/qml/qqmltypecompiler.cpp b/src/qml/qml/qqmltypecompiler.cpp index 8d499bfe6a..d527fe0335 100644 --- a/src/qml/qml/qqmltypecompiler.cpp +++ b/src/qml/qml/qqmltypecompiler.cpp @@ -881,6 +881,10 @@ bool QQmlComponentAndAliasResolver::resolve() const int objCountWithoutSynthesizedComponents = qmlObjects->count(); for (int i = 0; i < objCountWithoutSynthesizedComponents; ++i) { QmlIR::Object *obj = qmlObjects->at(i); + if (obj->isInlineComponent) { + componentRoots.append(i); + continue; + } QQmlPropertyCache *cache = propertyCaches.at(i); if (obj->inheritedTypeNameIndex == 0 && !cache) continue; @@ -936,7 +940,7 @@ bool QQmlComponentAndAliasResolver::resolve() _objectsWithAliases.clear(); - if (!collectIdsAndAliases(rootBinding->value.objectIndex)) + if (!collectIdsAndAliases(component->isInlineComponent ? componentRoots.at(i) : rootBinding->value.objectIndex)) return false; component->namedObjectsInComponent.allocate(pool, _idToObjectIndex); diff --git a/tests/auto/qml/qqmllanguage/data/SimpleItem.qml b/tests/auto/qml/qqmllanguage/data/SimpleItem.qml new file mode 100644 index 0000000000..c7bce2bc78 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/SimpleItem.qml @@ -0,0 +1,5 @@ +import QtQuick 2.15 + +Item { + property int i: 42 +} diff --git a/tests/auto/qml/qqmllanguage/data/inlineComponentWithAlias.qml b/tests/auto/qml/qqmllanguage/data/inlineComponentWithAlias.qml new file mode 100644 index 0000000000..ab125e9323 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/inlineComponentWithAlias.qml @@ -0,0 +1,17 @@ +import QtQuick 2.15 + +Item { + id: root + component IC: SimpleItem { + width: i + Rectangle { + id: rect + color: "lime" + } + property alias color: rect.color + } + width: 200 + IC { + objectName: "icInstance" + } +} diff --git a/tests/auto/qml/qqmllanguage/data/inlineComponentWithId.qml b/tests/auto/qml/qqmllanguage/data/inlineComponentWithId.qml new file mode 100644 index 0000000000..c4093bad2f --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/inlineComponentWithId.qml @@ -0,0 +1,14 @@ +import QtQuick 2.15 + +Item { + id: root + component IC: SimpleItem { + id: root + width: root.i + property color color: "red" + } + width: 200 + IC { + objectName: "icInstance" + } +} diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index b4ad9bd7b3..5966831183 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -5547,6 +5547,9 @@ void tst_qqmllanguage::inlineComponent_data() QTest::newRow("Non-toplevel IC is found") << testFileUrl("inlineComponentUser5.qml") << QColorConstants::Svg::red << 24; QTest::newRow("Resolved in correct order") << testFileUrl("inlineComponentOrder.qml") << QColorConstants::Blue << 200; + + QTest::newRow("ID resolves correctly") << testFileUrl("inlineComponentWithId.qml") << QColorConstants::Svg::red << 42; + QTest::newRow("Alias resolves correctly") << testFileUrl("inlineComponentWithAlias.qml") << QColorConstants::Svg::lime << 42; } void tst_qqmllanguage::inlineComponentReferenceCycle_data() -- cgit v1.2.3 From 75ce6f3cd03362e6d763ae3bc21ab793a3675fce Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Wed, 29 Jan 2020 10:43:33 +0100 Subject: QQmlInstanceModel: refactor recycling signals to base class Now that QQmlDelegateModel has an API that handles reusing delegate items (*), we should also move the related signals inside it to be consistent. This will also remove the need to cast the model type in the views before connecting. This patch will also remove warnings that stems from QQuickListView trying to connect to the reuse signals when the model is not a QQmlDelegateModel. *: E.g: virtual ReleaseFlags release(QObject *object, ReusableFlag reusableFlag = NotReusable) = 0; Fixes: QTBUG-81257 Change-Id: Ia8a8f0d68e6ef7edc6c45b414121aaa77632bcd3 Reviewed-by: Mitch Curtis --- src/qmlmodels/qqmldelegatemodel_p.h | 2 -- src/qmlmodels/qqmlobjectmodel_p.h | 2 ++ src/qmlmodels/qqmltableinstancemodel_p.h | 4 ---- src/quick/items/qquicktableview.cpp | 20 +++++++------------- 4 files changed, 9 insertions(+), 19 deletions(-) diff --git a/src/qmlmodels/qqmldelegatemodel_p.h b/src/qmlmodels/qqmldelegatemodel_p.h index adb5f7008b..8aab4badca 100644 --- a/src/qmlmodels/qqmldelegatemodel_p.h +++ b/src/qmlmodels/qqmldelegatemodel_p.h @@ -144,8 +144,6 @@ Q_SIGNALS: void defaultGroupsChanged(); void rootIndexChanged(); void delegateChanged(); - void itemPooled(int index, QObject *object); - void itemReused(int index, QObject *object); private Q_SLOTS: void _q_itemsChanged(int index, int count, const QVector &roles); diff --git a/src/qmlmodels/qqmlobjectmodel_p.h b/src/qmlmodels/qqmlobjectmodel_p.h index 6c68e55012..7fb4f64676 100644 --- a/src/qmlmodels/qqmlobjectmodel_p.h +++ b/src/qmlmodels/qqmlobjectmodel_p.h @@ -104,6 +104,8 @@ Q_SIGNALS: void createdItem(int index, QObject *object); void initItem(int index, QObject *object); void destroyingItem(QObject *object); + void itemPooled(int index, QObject *object); + void itemReused(int index, QObject *object); protected: QQmlInstanceModel(QObjectPrivate &dd, QObject *parent = nullptr) diff --git a/src/qmlmodels/qqmltableinstancemodel_p.h b/src/qmlmodels/qqmltableinstancemodel_p.h index 661ea3a3aa..06d0db06aa 100644 --- a/src/qmlmodels/qqmltableinstancemodel_p.h +++ b/src/qmlmodels/qqmltableinstancemodel_p.h @@ -122,10 +122,6 @@ public: void setWatchedRoles(const QList &) override { Q_UNREACHABLE(); } int indexOf(QObject *, QObject *) const override { Q_UNREACHABLE(); return 0; } -Q_SIGNALS: - void itemPooled(int index, QObject *object); - void itemReused(int index, QObject *object); - private: QQmlComponent *resolveDelegate(int index); diff --git a/src/quick/items/qquicktableview.cpp b/src/quick/items/qquicktableview.cpp index 09d74d939e..403801b7ae 100644 --- a/src/quick/items/qquicktableview.cpp +++ b/src/quick/items/qquicktableview.cpp @@ -2349,14 +2349,11 @@ void QQuickTableViewPrivate::connectToModel() QObjectPrivate::connect(model, &QQmlInstanceModel::createdItem, this, &QQuickTableViewPrivate::itemCreatedCallback); QObjectPrivate::connect(model, &QQmlInstanceModel::initItem, this, &QQuickTableViewPrivate::initItemCallback); + QObjectPrivate::connect(model, &QQmlTableInstanceModel::itemPooled, this, &QQuickTableViewPrivate::itemPooledCallback); + QObjectPrivate::connect(model, &QQmlTableInstanceModel::itemReused, this, &QQuickTableViewPrivate::itemReusedCallback); - if (tableModel) { - const auto tm = tableModel.data(); - QObjectPrivate::connect(tm, &QQmlTableInstanceModel::itemPooled, this, &QQuickTableViewPrivate::itemPooledCallback); - QObjectPrivate::connect(tm, &QQmlTableInstanceModel::itemReused, this, &QQuickTableViewPrivate::itemReusedCallback); - // Connect atYEndChanged to a function that fetches data if more is available - QObjectPrivate::connect(q, &QQuickTableView::atYEndChanged, this, &QQuickTableViewPrivate::fetchMoreData); - } + // Connect atYEndChanged to a function that fetches data if more is available + QObjectPrivate::connect(q, &QQuickTableView::atYEndChanged, this, &QQuickTableViewPrivate::fetchMoreData); if (auto const aim = model->abstractItemModel()) { // When the model exposes a QAIM, we connect to it directly. This means that if the current model is @@ -2384,13 +2381,10 @@ void QQuickTableViewPrivate::disconnectFromModel() QObjectPrivate::disconnect(model, &QQmlInstanceModel::createdItem, this, &QQuickTableViewPrivate::itemCreatedCallback); QObjectPrivate::disconnect(model, &QQmlInstanceModel::initItem, this, &QQuickTableViewPrivate::initItemCallback); + QObjectPrivate::disconnect(model, &QQmlTableInstanceModel::itemPooled, this, &QQuickTableViewPrivate::itemPooledCallback); + QObjectPrivate::disconnect(model, &QQmlTableInstanceModel::itemReused, this, &QQuickTableViewPrivate::itemReusedCallback); - if (tableModel) { - const auto tm = tableModel.data(); - QObjectPrivate::disconnect(tm, &QQmlTableInstanceModel::itemPooled, this, &QQuickTableViewPrivate::itemPooledCallback); - QObjectPrivate::disconnect(tm, &QQmlTableInstanceModel::itemReused, this, &QQuickTableViewPrivate::itemReusedCallback); - QObjectPrivate::disconnect(q, &QQuickTableView::atYEndChanged, this, &QQuickTableViewPrivate::fetchMoreData); - } + QObjectPrivate::disconnect(q, &QQuickTableView::atYEndChanged, this, &QQuickTableViewPrivate::fetchMoreData); if (auto const aim = model->abstractItemModel()) { disconnect(aim, &QAbstractItemModel::rowsMoved, this, &QQuickTableViewPrivate::rowsMovedCallback); -- cgit v1.2.3 From 4975a33ba9aa357ba2bca93e292b1fbcfb34c24e Mon Sep 17 00:00:00 2001 From: Tim Jenssen Date: Fri, 24 Jan 2020 11:26:06 +0100 Subject: QmlDebug: add new debugtranslationservice Users were asking for having the possibility to see where the translated text will not fit in the reserved/available space. This is more a preparation patch to get the right connectors to change the visualization of findings or maybe log this to a file. Task-number: QDS-1463 Change-Id: Ic0a7a930141d6eeb79964e51c0a165c69888cf5d Reviewed-by: Ulf Hermann --- .../qmltooling/qmldbg_preview/qmldbg_preview.pro | 2 + .../qmldbg_preview/qqmldebugtranslationservice.cpp | 68 +++++++++++++++++ .../qmldbg_preview/qqmldebugtranslationservice.h | 87 ++++++++++++++++++++++ .../qmldbg_preview/qqmlpreviewservice.json | 2 +- .../qmldbg_preview/qqmlpreviewservicefactory.cpp | 8 +- .../qmltooling/qmldbg_server/qqmldebugserver.cpp | 5 ++ src/qml/debugger/qqmldebugserviceinterfaces.cpp | 1 + src/qml/debugger/qqmldebugserviceinterfaces_p.h | 21 ++++++ src/qml/qml/qqmlbinding.cpp | 9 +++ src/qmldebug/qmldebug.pro | 4 +- src/qmldebug/qqmldebugtranslationclient.cpp | 76 +++++++++++++++++++ src/qmldebug/qqmldebugtranslationclient_p.h | 81 ++++++++++++++++++++ src/quick/items/qquicktext.cpp | 7 ++ tests/auto/qml/debugger/debugger.pro | 1 + .../qqmldebugtranslationservice/data/test.qml | 41 ++++++++++ .../qqmldebugtranslationservice.pro | 12 +++ .../tst_qqmldebugtranslationservice.cpp | 80 ++++++++++++++++++++ 17 files changed, 502 insertions(+), 3 deletions(-) create mode 100644 src/plugins/qmltooling/qmldbg_preview/qqmldebugtranslationservice.cpp create mode 100644 src/plugins/qmltooling/qmldbg_preview/qqmldebugtranslationservice.h create mode 100644 src/qmldebug/qqmldebugtranslationclient.cpp create mode 100644 src/qmldebug/qqmldebugtranslationclient_p.h create mode 100644 tests/auto/qml/debugger/qqmldebugtranslationservice/data/test.qml create mode 100644 tests/auto/qml/debugger/qqmldebugtranslationservice/qqmldebugtranslationservice.pro create mode 100644 tests/auto/qml/debugger/qqmldebugtranslationservice/tst_qqmldebugtranslationservice.cpp diff --git a/src/plugins/qmltooling/qmldbg_preview/qmldbg_preview.pro b/src/plugins/qmltooling/qmldbg_preview/qmldbg_preview.pro index 08686a43e3..e1cbc393f7 100644 --- a/src/plugins/qmltooling/qmldbg_preview/qmldbg_preview.pro +++ b/src/plugins/qmltooling/qmldbg_preview/qmldbg_preview.pro @@ -3,6 +3,7 @@ QT += core-private qml-private packetprotocol-private network quick-private gui- TARGET = qmldbg_preview SOURCES += \ + $$PWD/qqmldebugtranslationservice.cpp \ $$PWD/qqmlpreviewblacklist.cpp \ $$PWD/qqmlpreviewfileengine.cpp \ $$PWD/qqmlpreviewfileloader.cpp \ @@ -12,6 +13,7 @@ SOURCES += \ $$PWD/qqmlpreviewservicefactory.cpp HEADERS += \ + $$PWD/qqmldebugtranslationservice.h \ $$PWD/qqmlpreviewblacklist.h \ $$PWD/qqmlpreviewfileengine.h \ $$PWD/qqmlpreviewfileloader.h \ diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmldebugtranslationservice.cpp b/src/plugins/qmltooling/qmldbg_preview/qqmldebugtranslationservice.cpp new file mode 100644 index 0000000000..1561777202 --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_preview/qqmldebugtranslationservice.cpp @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqmldebugtranslationservice.h" + +QT_BEGIN_NAMESPACE + +QQmlDebugTranslationServiceImpl::QQmlDebugTranslationServiceImpl(QObject *parent) : + QQmlDebugTranslationService(1, parent) +{ +} + +void QQmlDebugTranslationServiceImpl::messageReceived(const QByteArray &message) +{ + Q_UNUSED(message) +} + +QString QQmlDebugTranslationServiceImpl::foundElidedText(QObject *textObject, const QString &layoutText, const QString &elideText) +{ + Q_UNUSED(textObject) + Q_UNUSED(layoutText) + return elideText; +} + +void QQmlDebugTranslationServiceImpl::foundTranslationBinding(QQmlTranslationBinding *binding, QObject *scopeObject, QQmlContextData *contextData) +{ + Q_UNUSED(binding) + Q_UNUSED(scopeObject) + Q_UNUSED(contextData) +} + +QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmldebugtranslationservice.h b/src/plugins/qmltooling/qmldbg_preview/qqmldebugtranslationservice.h new file mode 100644 index 0000000000..a337a937a5 --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_preview/qqmldebugtranslationservice.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDEBUGMESSAGESERVICE_H +#define QDEBUGMESSAGESERVICE_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 + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QQmlDebugTranslationServicePrivate; + +class QQmlDebugTranslationServiceImpl : public QQmlDebugTranslationService +{ + Q_OBJECT +public: + //needs to be in sync with QQmlDebugTranslationClient in qqmldebugtranslationclient_p.h + enum Command { + ChangeLanguage, + ChangeWarningColor, + ChangeElidedTextWarningString, + SetDebugTranslationServiceLogFile, + EnableElidedTextWarning, + DisableElidedTextWarning, + TestAllLanguages + }; + QQmlDebugTranslationServiceImpl(QObject *parent = 0); + + QString foundElidedText(QObject *textObject, const QString &layoutText, const QString &elideText) override; + void foundTranslationBinding(QQmlTranslationBinding *binding, QObject *scopeObject, QQmlContextData *contextData) override; + void messageReceived(const QByteArray &message) override; +}; + +QT_END_NAMESPACE + +#endif // QDEBUGMESSAGESERVICE_H diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.json b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.json index d7e1ef1f10..5e148f8101 100644 --- a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.json +++ b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.json @@ -1,3 +1,3 @@ { - "Keys" : [ "QmlPreview" ] + "Keys" : [ "QmlPreview", "DebugTranslation" ] } diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservicefactory.cpp b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservicefactory.cpp index f0aa3226c8..6ff9805bbe 100644 --- a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservicefactory.cpp +++ b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservicefactory.cpp @@ -39,12 +39,18 @@ #include "qqmlpreviewservicefactory.h" #include "qqmlpreviewservice.h" +#include "qqmldebugtranslationservice.h" QT_BEGIN_NAMESPACE QQmlDebugService *QQmlPreviewServiceFactory::create(const QString &key) { - return key == QQmlPreviewServiceImpl::s_key ? new QQmlPreviewServiceImpl(this) : nullptr; + if (key == QQmlPreviewServiceImpl::s_key) + return new QQmlPreviewServiceImpl(this); + if (key == QQmlDebugTranslationServiceImpl::s_key) + return new QQmlDebugTranslationServiceImpl(this); + + return nullptr; } QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp b/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp index cc663cd6b3..33b6606b44 100644 --- a/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp +++ b/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp @@ -422,6 +422,11 @@ void QQmlDebugServerImpl::parseArguments() << tr("Sends qDebug() and similar messages over the QML debug\n" "\t\t connection. QtCreator uses this for showing debug\n" "\t\t messages in the debugger console.") << '\n' + << '\n' << QQmlDebugTranslationService::s_key << "\t- " + //: Please preserve the line breaks and formatting + << tr("helps to see if a translated text\n" + "\t\t will result in an elided text\n" + "\t\t in QML elements.") << '\n' << tr("Other services offered by qmltooling plugins that implement " "QQmlDebugServiceFactory and which can be found in the standard plugin " "paths will also be available and can be specified. If no \"services\" " diff --git a/src/qml/debugger/qqmldebugserviceinterfaces.cpp b/src/qml/debugger/qqmldebugserviceinterfaces.cpp index 76205c7760..3df1a21bda 100644 --- a/src/qml/debugger/qqmldebugserviceinterfaces.cpp +++ b/src/qml/debugger/qqmldebugserviceinterfaces.cpp @@ -48,6 +48,7 @@ const QString QQmlProfilerService::s_key = QStringLiteral("CanvasFrameRate"); const QString QDebugMessageService::s_key = QStringLiteral("DebugMessages"); const QString QQmlEngineControlService::s_key = QStringLiteral("EngineControl"); const QString QQmlNativeDebugService::s_key = QStringLiteral("NativeQmlDebugger"); +const QString QQmlDebugTranslationService::s_key = QStringLiteral("DebugTranslation"); QT_END_NAMESPACE diff --git a/src/qml/debugger/qqmldebugserviceinterfaces_p.h b/src/qml/debugger/qqmldebugserviceinterfaces_p.h index 01693aee24..644d9d6ba9 100644 --- a/src/qml/debugger/qqmldebugserviceinterfaces_p.h +++ b/src/qml/debugger/qqmldebugserviceinterfaces_p.h @@ -65,6 +65,7 @@ QT_BEGIN_NAMESPACE class QWindow; class QQuickWindow; +class QQmlTranslationBinding; #if !QT_CONFIG(qml_debug) @@ -103,6 +104,10 @@ public: class QDebugMessageService {}; class QQmlEngineControlService {}; class QQmlNativeDebugService {}; +class QQmlDebugTranslationService { + virtual QString foundElidedText(QObject *, const QString &, const QString &) {return {};} + virtual void foundTranslationBinding(QQmlTranslationBinding *, QObject *, QQmlContextData *) {} +}; #else @@ -162,6 +167,22 @@ protected: QQmlBoundSignal *nextSignal(QQmlBoundSignal *prev) { return prev->m_nextSignal; } }; +class Q_QML_PRIVATE_EXPORT QQmlDebugTranslationService : public QQmlDebugService +{ + Q_OBJECT +public: + static const QString s_key; + + virtual QString foundElidedText(QObject *qQuickTextObject, const QString &layoutText, const QString &elideText) = 0; + virtual void foundTranslationBinding(QQmlTranslationBinding *binding, QObject *scopeObject, QQmlContextData *contextData) = 0; +protected: + friend class QQmlDebugConnector; + + QQmlDebugTranslationService(float version, QObject *parent = nullptr) : + QQmlDebugService(s_key, version, parent) {} + +}; + class Q_QML_PRIVATE_EXPORT QQmlInspectorService : public QQmlDebugService { Q_OBJECT diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp index e14b00af22..b9566d5862 100644 --- a/src/qml/qml/qqmlbinding.cpp +++ b/src/qml/qml/qqmlbinding.cpp @@ -43,6 +43,10 @@ #include "qqmlcontext.h" #include "qqmlinfo.h" #include "qqmldata_p.h" + +#include +#include + #include #include #include @@ -392,6 +396,11 @@ QQmlBinding *QQmlBinding::createTranslationBinding(const QQmlRefPointerQQmlJavaScriptExpression::setContext(ctxt); b->setScopeObject(obj); + if (QQmlDebugTranslationService *service + = QQmlDebugConnector::service()) { + service->foundTranslationBinding(b, obj, ctxt); + } + return b; } diff --git a/src/qmldebug/qmldebug.pro b/src/qmldebug/qmldebug.pro index 94d300b765..ac3f3bf3bf 100644 --- a/src/qmldebug/qmldebug.pro +++ b/src/qmldebug/qmldebug.pro @@ -1,5 +1,5 @@ TARGET = QtQmlDebug -QT = core-private network packetprotocol-private +QT = core-private qml-private network packetprotocol-private CONFIG += static internal_module load(qt_module) @@ -8,6 +8,7 @@ SOURCES += \ qqmldebugclient.cpp \ qqmldebugconnection.cpp \ qqmldebugmessageclient.cpp \ + qqmldebugtranslationclient.cpp \ qqmlenginecontrolclient.cpp \ qqmlenginedebugclient.cpp \ qqmlinspectorclient.cpp \ @@ -24,6 +25,7 @@ HEADERS += \ qqmldebugclient_p_p.h \ qqmldebugconnection_p.h \ qqmldebugmessageclient_p.h \ + qqmldebugtranslationclient_p.h \ qqmlenginedebugclient_p.h \ qqmlenginedebugclient_p_p.h \ qqmlenginecontrolclient_p.h \ diff --git a/src/qmldebug/qqmldebugtranslationclient.cpp b/src/qmldebug/qqmldebugtranslationclient.cpp new file mode 100644 index 0000000000..1fd0748fa0 --- /dev/null +++ b/src/qmldebug/qqmldebugtranslationclient.cpp @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqmldebugtranslationclient_p.h" +#include "qqmldebugconnection_p.h" + +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +/*! + \class QQmlDebugTranslationClient + \internal + + \brief Client for the debug translation service + + The QQmlDebugTranslationClient can test if translated texts will fit. + */ + +QQmlDebugTranslationClient::QQmlDebugTranslationClient(QQmlDebugConnection *client) + : QQmlDebugClient(QLatin1String("DebugTranslation"), client) +{ +} + +void QQmlDebugTranslationClient::messageReceived(const QByteArray &data) +{ + Q_UNUSED(data); +} + +void QQmlDebugTranslationClient::triggerLanguage(const QUrl &url, const QString &locale) +{ + Q_UNUSED(url) + Q_UNUSED(locale) +} + +QT_END_NAMESPACE diff --git a/src/qmldebug/qqmldebugtranslationclient_p.h b/src/qmldebug/qqmldebugtranslationclient_p.h new file mode 100644 index 0000000000..3163759d9e --- /dev/null +++ b/src/qmldebug/qqmldebugtranslationclient_p.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QQMLDEBUGTRANSLATIONCLIENT_P_H +#define QQMLDEBUGTRANSLATIONCLIENT_P_H + +#include "qqmldebugclient_p.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. +// + +QT_BEGIN_NAMESPACE + +class QQmlDebugTranslationClient : public QQmlDebugClient +{ + Q_OBJECT + +public: + //needs to be in sync with QQmlDebugTranslationServiceImpl in qqmldebugtranslationservice.h + enum Command { + ChangeLanguage, + ChangeWarningColor, + ChangeElidedTextWarningString, + SetDebugTranslationServiceLogFile, + EnableElidedTextWarning, + DisableElidedTextWarning, + TestAllLanguages + }; + + explicit QQmlDebugTranslationClient(QQmlDebugConnection *client); + + virtual void messageReceived(const QByteArray &) override; + void triggerLanguage(const QUrl &url, const QString &locale); +}; + +QT_END_NAMESPACE + +#endif // QQMLDEBUGTRANSLATIONCLIENT_P_H diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp index c2980b792d..1c7f1ca6aa 100644 --- a/src/quick/items/qquicktext.cpp +++ b/src/quick/items/qquicktext.cpp @@ -40,6 +40,9 @@ #include "qquicktext_p.h" #include "qquicktext_p_p.h" +#include +#include + #include #include #include @@ -1146,6 +1149,10 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline) elideLayout->setFont(layout.font()); elideLayout->setTextOption(layout.textOption()); + if (QQmlDebugTranslationService *service + = QQmlDebugConnector::service()) { + elideText = service->foundElidedText(q, layoutText, elideText); + } elideLayout->setText(elideText); elideLayout->beginLayout(); diff --git a/tests/auto/qml/debugger/debugger.pro b/tests/auto/qml/debugger/debugger.pro index 5c328fbfcc..890e722aa3 100644 --- a/tests/auto/qml/debugger/debugger.pro +++ b/tests/auto/qml/debugger/debugger.pro @@ -4,6 +4,7 @@ SUBDIRS += qqmldebugjsserver PUBLICTESTS += \ qdebugmessageservice \ + qqmldebugtranslationservice \ qqmlenginedebugservice \ qqmldebugjs \ qqmlinspector \ diff --git a/tests/auto/qml/debugger/qqmldebugtranslationservice/data/test.qml b/tests/auto/qml/debugger/qqmldebugtranslationservice/data/test.qml new file mode 100644 index 0000000000..234496577a --- /dev/null +++ b/tests/auto/qml/debugger/qqmldebugtranslationservice/data/test.qml @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQuick.Controls 2.12 + +Item { + width: 360 + height: 360 + + Text { + text: qsTr("hello") + width: parent.width / 10 + elide: Text.ElideRight + } +} diff --git a/tests/auto/qml/debugger/qqmldebugtranslationservice/qqmldebugtranslationservice.pro b/tests/auto/qml/debugger/qqmldebugtranslationservice/qqmldebugtranslationservice.pro new file mode 100644 index 0000000000..32e60e306d --- /dev/null +++ b/tests/auto/qml/debugger/qqmldebugtranslationservice/qqmldebugtranslationservice.pro @@ -0,0 +1,12 @@ +CONFIG += testcase +TARGET = tst_qdebugtranslationservice +QT += network testlib gui-private core-private qmldebug-private +macos:CONFIG -= app_bundle + +SOURCES += tst_qqmldebugtranslationservice.cpp + +include(../shared/debugutil.pri) + +TESTDATA = data/* + +OTHER_FILES += data/test.qml diff --git a/tests/auto/qml/debugger/qqmldebugtranslationservice/tst_qqmldebugtranslationservice.cpp b/tests/auto/qml/debugger/qqmldebugtranslationservice/tst_qqmldebugtranslationservice.cpp new file mode 100644 index 0000000000..01ee805dee --- /dev/null +++ b/tests/auto/qml/debugger/qqmldebugtranslationservice/tst_qqmldebugtranslationservice.cpp @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//QQmlDebugTest +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +const char *QMLFILE = "test.qml"; + +class tst_QQmlDebugTranslationService : public QQmlDebugTest +{ + Q_OBJECT + +private slots: + void pluginConnection(); + +private: + QList createClients() override; + QPointer m_client; +}; + +QList tst_QQmlDebugTranslationService::createClients() +{ + m_client = new QQmlDebugTranslationClient(m_connection); + + QObject::connect(m_client, &QQmlDebugClient::stateChanged, m_client, [this](QQmlDebugClient::State newState) { + QCOMPARE(newState, m_client->state()); + }); + + return {m_client}; +} + +void tst_QQmlDebugTranslationService::pluginConnection() +{ + auto executable = QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qml"; + auto services = "DebugTranslation"; + auto extraArgs = testFile(QMLFILE); + auto block = true; + + auto result = QQmlDebugTest::connectTo(executable, services, extraArgs, block); + QCOMPARE(result, ConnectSuccess); +} + +QTEST_MAIN(tst_QQmlDebugTranslationService) + +#include "tst_qqmldebugtranslationservice.moc" -- cgit v1.2.3 From 6420ad91d30e0cc3c2b7500d7c4b4bf1fce7c771 Mon Sep 17 00:00:00 2001 From: Peter Varga Date: Wed, 15 Jan 2020 09:56:10 +0100 Subject: Fix QAccessibleQuickWindow::focusChild() to return focused descendant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Same as the focusChild fix for qtbase: a132e02540 Fix QAccessibleWidget::focusChild() to return focused descendant Task-number: QTBUG-78284 Change-Id: Ibc3e3287790ebc879513a5b1a739e3a919e1f038 Reviewed-by: Allan Sandfeld Jensen Reviewed-by: Jan Arve Sæther --- src/quick/accessible/qaccessiblequickview.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/quick/accessible/qaccessiblequickview.cpp b/src/quick/accessible/qaccessiblequickview.cpp index 41a02fc09c..b23b0316f5 100644 --- a/src/quick/accessible/qaccessiblequickview.cpp +++ b/src/quick/accessible/qaccessiblequickview.cpp @@ -84,8 +84,12 @@ QAccessibleInterface *QAccessibleQuickWindow::child(int index) const QAccessibleInterface *QAccessibleQuickWindow::focusChild() const { QObject *focusObject = window()->focusObject(); - if (focusObject) - return QAccessible::queryAccessibleInterface(focusObject); + if (focusObject) { + QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(focusObject); + if (!iface || iface == this || !iface->focusChild()) + return iface; + return iface->focusChild(); + } return nullptr; } -- cgit v1.2.3 From 6ba3dc8d489be0058d8ca6349ac19b0857247b17 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Tue, 4 Feb 2020 12:06:49 +0100 Subject: Models: Make sure we can use QList as required model We can use it as model passed via a context property as shown in the objectlistmodel example. We should also be able to pass it directly then. Change-Id: I55db74df969d8024553d9470f1afe4710e61b1bf Reviewed-by: Fabian Kosmale --- src/qmlmodels/qqmladaptormodel.cpp | 3 ++ src/qmlmodels/qqmladaptormodel_p.h | 5 +- src/qmlmodels/qqmllistaccessor.cpp | 6 +++ src/qmlmodels/qqmllistaccessor_p.h | 2 +- .../data/requiredObjectListModel.qml | 15 ++++++ .../quick/qquicklistview/tst_qquicklistview.cpp | 57 ++++++++++++++++++++++ 6 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 tests/auto/quick/qquicklistview/data/requiredObjectListModel.qml diff --git a/src/qmlmodels/qqmladaptormodel.cpp b/src/qmlmodels/qqmladaptormodel.cpp index 1f437a08c7..b4578db6c4 100644 --- a/src/qmlmodels/qqmladaptormodel.cpp +++ b/src/qmlmodels/qqmladaptormodel.cpp @@ -977,6 +977,9 @@ void QQmlAdaptorModel::setModel(const QVariant &variant, QObject *parent, QQmlEn } else if (list.type() == QQmlListAccessor::ListProperty) { setObject(static_cast(variant.constData())->object(), parent); accessors = new VDMObjectDelegateDataType; + } else if (list.type() == QQmlListAccessor::ObjectList) { + setObject(nullptr, parent); + accessors = new VDMObjectDelegateDataType; } else if (list.type() != QQmlListAccessor::Invalid && list.type() != QQmlListAccessor::Instance) { // Null QObject setObject(nullptr, parent); diff --git a/src/qmlmodels/qqmladaptormodel_p.h b/src/qmlmodels/qqmladaptormodel_p.h index ee4862f3b4..ba54c864c6 100644 --- a/src/qmlmodels/qqmladaptormodel_p.h +++ b/src/qmlmodels/qqmladaptormodel_p.h @@ -146,7 +146,10 @@ public: return accessors->createItem(*this, metaType, index, rowAt(index), columnAt(index)); } inline bool hasProxyObject() const { - return list.type() == QQmlListAccessor::Instance || list.type() == QQmlListAccessor::ListProperty; } + return list.type() == QQmlListAccessor::Instance + || list.type() == QQmlListAccessor::ListProperty + || list.type() == QQmlListAccessor::ObjectList; + } inline bool notify( const QList &items, diff --git a/src/qmlmodels/qqmllistaccessor.cpp b/src/qmlmodels/qqmllistaccessor.cpp index c450c616e7..69427df184 100644 --- a/src/qmlmodels/qqmllistaccessor.cpp +++ b/src/qmlmodels/qqmllistaccessor.cpp @@ -80,6 +80,8 @@ void QQmlListAccessor::setList(const QVariant &v, QQmlEngine *engine) m_type = StringList; } else if (d.userType() == QMetaType::QVariantList) { m_type = VariantList; + } else if (d.userType() == qMetaTypeId>()) { + m_type = ObjectList; } else if (d.canConvert(QMetaType::Int)) { // Here we have to check for an upper limit, because down the line code might (well, will) // allocate memory depending on the number of elements. The upper limit cannot be INT_MAX: @@ -120,6 +122,8 @@ int QQmlListAccessor::count() const return qvariant_cast(d).count(); case VariantList: return qvariant_cast(d).count(); + case ObjectList: + return qvariant_cast>(d).count(); case ListProperty: return ((const QQmlListReference *)d.constData())->count(); case Instance: @@ -140,6 +144,8 @@ QVariant QQmlListAccessor::at(int idx) const return QVariant::fromValue(qvariant_cast(d).at(idx)); case VariantList: return qvariant_cast(d).at(idx); + case ObjectList: + return QVariant::fromValue(qvariant_cast>(d).at(idx)); case ListProperty: return QVariant::fromValue(((const QQmlListReference *)d.constData())->at(idx)); case Instance: diff --git a/src/qmlmodels/qqmllistaccessor_p.h b/src/qmlmodels/qqmllistaccessor_p.h index bcd079adef..a57e4173e3 100644 --- a/src/qmlmodels/qqmllistaccessor_p.h +++ b/src/qmlmodels/qqmllistaccessor_p.h @@ -70,7 +70,7 @@ public: int count() const; QVariant at(int) const; - enum Type { Invalid, StringList, VariantList, ListProperty, Instance, Integer }; + enum Type { Invalid, StringList, VariantList, ObjectList, ListProperty, Instance, Integer }; Type type() const { return m_type; } private: diff --git a/tests/auto/quick/qquicklistview/data/requiredObjectListModel.qml b/tests/auto/quick/qquicklistview/data/requiredObjectListModel.qml new file mode 100644 index 0000000000..f6380ed5aa --- /dev/null +++ b/tests/auto/quick/qquicklistview/data/requiredObjectListModel.qml @@ -0,0 +1,15 @@ +import QtQuick 2.0 + +ListView { + width: 100 + height: 100 + required model + + delegate: Rectangle { + required color + required property string name + + height: 25 + width: 100 + } +} diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp index 45d16cc415..b141e235d5 100644 --- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp +++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -294,6 +295,8 @@ private slots: void moveObjectModelItemToAnotherObjectModel(); void changeModelAndDestroyTheOldOne(); + void requiredObjectListModel(); + private: template void items(const QUrl &source); template void changed(const QUrl &source); @@ -10032,6 +10035,60 @@ void tst_QQuickListView::changeModelAndDestroyTheOldOne() // QTBUG-80203 // no crash } +class DataObject : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString name READ name CONSTANT) + Q_PROPERTY(QString color READ color CONSTANT) + +public: + DataObject(QObject *parent = nullptr) : QObject(parent) {} + DataObject(const QString &name, const QString &color, QObject *parent = nullptr) + : QObject(parent), m_name(name), m_color(color) {} + + QString name() const { return m_name; } + QString color() const { return m_color; } + +private: + QString m_name; + QString m_color; +}; + +void tst_QQuickListView::requiredObjectListModel() +{ + QList dataList = { + new DataObject("Item 1", "red", this), + new DataObject("Item 2", "green", this), + new DataObject("Item 3", "blue", this), + new DataObject("Item 4", "yellow", this) + }; + + const auto deleter = qScopeGuard([&](){ qDeleteAll(dataList); }); + Q_UNUSED(deleter); + + QQuickView view; + view.setInitialProperties({{ "model", QVariant::fromValue(dataList) }}); + view.setSource(testFileUrl("requiredObjectListModel.qml")); + view.show(); + + QVERIFY(QTest::qWaitForWindowExposed(&view)); + + const auto *root = qobject_cast(view.rootObject()); + QVERIFY(root); + + QCOMPARE(root->count(), dataList.count()); + + for (int i = 0, end = dataList.count(); i != end; ++i) { + const auto *rect = qobject_cast(root->itemAtIndex(i)); + QVERIFY(rect); + const auto *data = qobject_cast(dataList.at(i)); + QVERIFY(data); + + QCOMPARE(rect->color(), QColor(data->color())); + QCOMPARE(rect->property("name").toString(), data->name()); + } +} + QTEST_MAIN(tst_QQuickListView) #include "tst_qquicklistview.moc" -- cgit v1.2.3 From 2f3ef4e983362ed8e0c6509ac371bebc58303f0a Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Thu, 23 Jan 2020 15:31:48 +0100 Subject: Add required property documentation Change-Id: I9e2c44ddcbb6c7e3a92b2bd7d2492ece0cd0e62d Reviewed-by: Paul Wicking --- .../qmllanguageref/syntax/objectattributes.qdoc | 52 ++++++++++++-- .../listmodel-listview-required.qml | 81 ++++++++++++++++++++++ .../doc/src/concepts/modelviewsdata/modelview.qdoc | 20 ++++++ 3 files changed, 148 insertions(+), 5 deletions(-) create mode 100644 src/quick/doc/snippets/qml/qml-data-models/listmodel-listview-required.qml diff --git a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc index 401e099ebf..832d9a9e26 100644 --- a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc +++ b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc @@ -112,7 +112,7 @@ Alternatively, a custom property of an object type may be defined in an object declaration in a QML document with the following syntax: \code - [default] property + [default] [required] [readonly] property \endcode In this way an object declaration may \l {Defining Object Types from QML} @@ -121,10 +121,13 @@ state more easily. Property names must begin with a lower case letter and can only contain letters, numbers and underscores. \l {JavaScript Reserved Words} -{JavaScript reserved words} are not valid property names. The \c default -keyword is optional, and modifies the semantics of the property being declared. -See the upcoming section on \l {Default Properties}{default properties} for -more information about the \c default property modifier. +{JavaScript reserved words} are not valid property names. The \c default, +\c required, and \c readonly keywords are optional, and modify the semantics +of the property being declared. +See the upcoming sections on \l {Default Properties}{default properties}, +\l {Required Properties}{required properties} and, +\l {Read-Only Properties}{read-only properties} for more information +about their respective meaning. Declaring a custom property implicitly creates a value-change \l{Signal attributes}{signal} for that property, as well as an associated @@ -647,6 +650,45 @@ the \l{TabWidget Example}, which uses a default property to automatically reassign children of the TabWidget as children of an inner ListView. See also \l {Extending QML}. +\section3 Required Properties + +An object declaration may define a property as required, using the \c required +keyword. The syntax is +\code + required property +\endcode + +As the name suggests, required properties must be set when an instance of the object +is created. Violation of this rule will result in QML applications not starting if it can be +detected statically. In case of dynamically instantiated QML components (for instance via +\l {QtQml::Qt::createComponent()}{Qt.createComponent()}), violating this rule results in a +warning and a null return value. + +It's possible to make an existing property required with +\code + required +\endcode +The following example shows how to create a custom Rectangle component, in which the color +property always needs to be specified. +\qml +// ColorRectangle.qml +Rectangle { + required color +} +\endqml + +\note You can't assign an initial value to a required property from QML, as that would go +directly against the intended usage of required properties. + +Required properties play a special role in model-view-delegate code: +If the delegate of a view has required properties whose names match with +the role names of the view's model, then those properties will be initialized +with the model's corresponding values. +For more information, visit the \l{Models and Views in QtQuick} page. + +\sa {QQmlComponent::createWithInitialProperties}, {QQmlApplicationEngine::setInitialProperties} +and {QQuickView::setInitialProperties} for ways to initialize required properties from C++. + \section3 Read-Only Properties An object declaration may define a read-only property using the \c readonly diff --git a/src/quick/doc/snippets/qml/qml-data-models/listmodel-listview-required.qml b/src/quick/doc/snippets/qml/qml-data-models/listmodel-listview-required.qml new file mode 100644 index 0000000000..e9a668ed8f --- /dev/null +++ b/src/quick/doc/snippets/qml/qml-data-models/listmodel-listview-required.qml @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2020 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$ +** +****************************************************************************/ + +//! [document] +import QtQuick 2.0 + +Item { + width: 200 + height: 250 + + ListModel { + id: myModel + ListElement { type: "Dog"; age: 8; noise: "meow" } + ListElement { type: "Cat"; age: 5; noise: "woof" } + } + + component MyDelegate : Text { + required property string type + required property int age + text: type + ", " + age + // WRONG: Component.onCompleted: () => console.log(noise) + // The above line would cause a ReferenceError + // as there is no required property noise, + // and the presence of the required properties prevents + // noise from being injected into the scope + } + + ListView { + anchors.fill: parent + model: myModel + delegate: MyDelegate {} + } +} +//! [document] diff --git a/src/quick/doc/src/concepts/modelviewsdata/modelview.qdoc b/src/quick/doc/src/concepts/modelviewsdata/modelview.qdoc index 04dbf1cf20..555f730c9e 100644 --- a/src/quick/doc/src/concepts/modelviewsdata/modelview.qdoc +++ b/src/quick/doc/src/concepts/modelviewsdata/modelview.qdoc @@ -164,6 +164,16 @@ To visualize data, bind the view's \c model property to a model and the \snippet qml/qml-data-models/listmodel-listview.qml document + To get finer control over which roles are accessible, and to make delegates + more self-contained and usable outside of views, + \li{Required Properties}{required properties} can be used. If a delegate + contains required properties, the named roles are not provided. Instead, + the QML engine will check if the name of a required property matches that of + a model role. If so, that property will be bound to the corresponding value + from the model. + + \snippet qml/qml-data-models/listmodel-listview-required.qml document + If there is a naming clash between the model's properties and the delegate's properties, the roles can be accessed with the qualified \e model name instead. For example, if a \l Text type had \e type or \e age properties, @@ -186,6 +196,10 @@ To visualize data, bind the view's \c model property to a model and the modelData role is also provided for models that have only one role. In this case the \e modelData role contains the same data as the named role. + \note \e model, \e index, and \e modelData roles are not accessible + if the delegate contains required properties, unless it has also required + properties with matching names. + QML provides several types of data models among the built-in set of QML types. In addition, models can be created with Qt C++ and then made available to \l{QQmlEngine} for use by @@ -417,6 +431,12 @@ ListView { \note The \c edit role is equal to \l Qt::EditRole. See \l{QAbstractItemModel::}{roleNames}() for the built-in role names. However, real life models would usually register custom roles. +\node If a model role is bound to a \li{Required Property}{required property}, assigning to +that property will not modify the model. It will instead break the binding to the model (just +like assigning to any other property breaks existing bindings). If you want to use +required properties and change the model data, make model also a required property and assign to +\e model.propertyName. + For more information, visit the \l{qtquick-modelviewsdata-cppmodels.html#changing-model-data}{Using C++ Models with Qt Quick Views} article. -- cgit v1.2.3 From 5af5015b0c600bd49eecd0782193974ad9405107 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Wed, 5 Feb 2020 18:49:39 +0100 Subject: QQmlTypeLoader: Prevent further trivial cycles We can also detect cycles in the WaitingForDependencies stage, not only in the ResolvingDependencies stage. This is hard to test as the order of state transitions depends on thread scheduling. Also, do output a warning in those cases. Cyclic dependencies are bad style. Fixes: QTBUG-81678 Change-Id: I11f1a993afa29e4f2d6c71bb3379786d666a527a Reviewed-by: Mitch Curtis Reviewed-by: Fabian Kosmale --- src/qml/qml/qqmltypedata.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/qml/qml/qqmltypedata.cpp b/src/qml/qml/qqmltypedata.cpp index f7abe67921..ebe4e32b48 100644 --- a/src/qml/qml/qqmltypedata.cpp +++ b/src/qml/qml/qqmltypedata.cpp @@ -833,8 +833,9 @@ void QQmlTypeData::resolveTypes() if (ref.type.isCompositeSingleton()) { ref.typeData = typeLoader()->getType(ref.type.sourceUrl()); - if (ref.typeData->status() == QQmlDataBlob::ResolvingDependencies || m_waitingOnMe.contains(ref.typeData.data())) { - // TODO: give an error message? If so, we should record and show the path of the cycle. + if (ref.typeData->isWaiting() || m_waitingOnMe.contains(ref.typeData.data())) { + qWarning() << "Cyclic dependency detected between" << ref.typeData->urlString() + << "and" << urlString(); continue; } addDependency(ref.typeData.data()); -- cgit v1.2.3 From 3c2439593460d665dcf64622afae4eb91993eb10 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Thu, 30 Jan 2020 15:54:09 +0100 Subject: Add QML_CORE_PROFILE support to QML tool If QML_CORE_PROFILE is defined we use the CoreProfile surface format. This is required for QtQuick3D. For consistency we also introduce QSG_CORE_PROFILE. Adding QSG_CORE_PROFILE also to qmlscene. Change-Id: I4feee91740162cf36fa2668695b74f5a1279bb89 Reviewed-by: Laszlo Agocs --- tools/qml/main.cpp | 12 ++++++++++++ tools/qmlscene/main.cpp | 3 ++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/tools/qml/main.cpp b/tools/qml/main.cpp index 9f5aacb1dd..dc828b1f75 100644 --- a/tools/qml/main.cpp +++ b/tools/qml/main.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #ifdef QT_WIDGETS_LIB #include #endif // QT_WIDGETS_LIB @@ -563,6 +564,17 @@ int main(int argc, char *argv[]) selector->setExtraSelectors(customSelectors); } +#if defined(QT_GUI_LIB) && QT_CONFIG(opengl) + if (qEnvironmentVariableIsSet("QSG_CORE_PROFILE") || qEnvironmentVariableIsSet("QML_CORE_PROFILE")) { + QSurfaceFormat surfaceFormat; + surfaceFormat.setStencilBufferSize(8); + surfaceFormat.setDepthBufferSize(24); + surfaceFormat.setVersion(4, 1); + surfaceFormat.setProfile(QSurfaceFormat::CoreProfile); + QSurfaceFormat::setDefaultFormat(surfaceFormat); + } +#endif + files << parser.values(qmlFileOption); if (parser.isSet(configOption)) confFile = parser.value(configOption); diff --git a/tools/qmlscene/main.cpp b/tools/qmlscene/main.cpp index 260c5bb7d1..b14166ad8d 100644 --- a/tools/qmlscene/main.cpp +++ b/tools/qmlscene/main.cpp @@ -500,7 +500,8 @@ int main(int argc, char ** argv) } } - if (qEnvironmentVariableIsSet("QMLSCENE_CORE_PROFILE")) + if (qEnvironmentVariableIsSet("QMLSCENE_CORE_PROFILE") + || qEnvironmentVariableIsSet("QSG_CORE_PROFILE")) options.coreProfile = true; // Set default surface format before creating the window -- cgit v1.2.3 From 461ecc535ad203f7c11b1898a16053aebf50cfc1 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Tue, 4 Feb 2020 14:23:16 +0100 Subject: Use inline components for sharing example Change-Id: I9390982bfefa35e6db6c8516c62ba091c231be8a Reviewed-by: Fabian Kosmale --- .../particles/imageparticle/content/sharing.qml | 82 ++++++++++------------ 1 file changed, 38 insertions(+), 44 deletions(-) diff --git a/examples/quick/particles/imageparticle/content/sharing.qml b/examples/quick/particles/imageparticle/content/sharing.qml index 1018a8e8ba..a24d9fd7c7 100644 --- a/examples/quick/particles/imageparticle/content/sharing.qml +++ b/examples/quick/particles/imageparticle/content/sharing.qml @@ -65,53 +65,47 @@ Rectangle { // Define a delegate component. A component will be // instantiated for each visible item in the list. - Component { - id: petDelegate - Item { - id: wrapper - width: 200; height: delegateHeight - z: 10 - Column { - Text {color: "white"; text: name; font.pixelSize: 18 } - Text {color: "white"; text: 'Type: ' + type; font.pixelSize: 14 } - Text {color: "white"; text: 'Age: ' + age; font.pixelSize: 14 } - } - MouseArea { anchors.fill: parent; onClicked: listView.currentIndex = index; } - // indent the item if it is the current item - states: State { - name: "Current" - when: wrapper.ListView.isCurrentItem - PropertyChanges { target: wrapper; x: 20 } - } - transitions: Transition { - NumberAnimation { properties: "x"; duration: 200 } - } + component PetDelegate: Item { + id: wrapper + width: 200; height: delegateHeight + z: 10 + Column { + Text {color: "white"; text: name; font.pixelSize: 18 } + Text {color: "white"; text: 'Type: ' + type; font.pixelSize: 14 } + Text {color: "white"; text: 'Age: ' + age; font.pixelSize: 14 } + } + MouseArea { anchors.fill: parent; onClicked: listView.currentIndex = index; } + // indent the item if it is the current item + states: State { + name: "Current" + when: wrapper.ListView.isCurrentItem + PropertyChanges { target: wrapper; x: 20 } + } + transitions: Transition { + NumberAnimation { properties: "x"; duration: 200 } } } // Define a highlight with customized movement between items. - Component { - id: highlightBar - Rectangle { - z: 0 - width: 200; height: delegateHeight - gradient: Gradient { - GradientStop { position: 0.0; color: "#99FF99" } - GradientStop { position: 1.0; color: "#88FF88" } - } - y: listView.currentItem.y; - Behavior on y { SpringAnimation { spring: 2; damping: 0.2 } } - //! [1] - ImageParticle { - anchors.fill: parent - system: particles - source: "../../images/flower.png" - color: "red" - clip: true - alpha: 1.0 - } - //! [1] + component HighlightBar : Rectangle { + z: 0 + width: 200; height: delegateHeight + gradient: Gradient { + GradientStop { position: 0.0; color: "#99FF99" } + GradientStop { position: 1.0; color: "#88FF88" } + } + y: listView.currentItem.y; + Behavior on y { SpringAnimation { spring: 2; damping: 0.2 } } + //! [1] + ImageParticle { + anchors.fill: parent + system: particles + source: "../../images/flower.png" + color: "red" + clip: true + alpha: 1.0 } + //! [1] } ListView { @@ -119,12 +113,12 @@ Rectangle { width: 200; height: parent.height model: petsModel - delegate: petDelegate + delegate: PetDelegate {} focus: true // Set the highlight delegate. Note we must also set highlightFollowsCurrentItem // to false so the highlight delegate can control how the highlight is moved. - highlight: highlightBar + highlight: HighlightBar {} highlightFollowsCurrentItem: false ParticleSystem { id: particles } -- cgit v1.2.3 From b5a6b4c938660d0cd6eae8a8b36b43b1795d584d Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 18 Nov 2019 15:47:01 +0100 Subject: Avoid access to properties of parent in imagelements example ImageCell's parent is not guaranteed to have these properties. Therefore, rather pass them from the outside. Change-Id: Ib42d1b9087d8757633b14c3a25cb638abb70fb21 Reviewed-by: Fabian Kosmale Reviewed-by: Simon Hausmann --- examples/quick/imageelements/content/ImageCell.qml | 2 -- examples/quick/imageelements/image.qml | 34 ++++++++++++++++++---- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/examples/quick/imageelements/content/ImageCell.qml b/examples/quick/imageelements/content/ImageCell.qml index 4b147633c3..7804346bd4 100644 --- a/examples/quick/imageelements/content/ImageCell.qml +++ b/examples/quick/imageelements/content/ImageCell.qml @@ -53,8 +53,6 @@ Item { property alias mode: image.fillMode property alias caption: captionItem.text - width: parent.cellWidth; height: parent.cellHeight - Image { id: image width: parent.width; height: parent.height - captionItem.height diff --git a/examples/quick/imageelements/image.qml b/examples/quick/imageelements/image.qml index d414f59629..0750ea3b79 100644 --- a/examples/quick/imageelements/image.qml +++ b/examples/quick/imageelements/image.qml @@ -65,12 +65,34 @@ Rectangle { rows: 3 spacing: 30 - ImageCell { mode: Image.Stretch; caption: "Stretch" } - ImageCell { mode: Image.PreserveAspectFit; caption: "PreserveAspectFit" } - ImageCell { mode: Image.PreserveAspectCrop; caption: "PreserveAspectCrop" } + component SizedImageCell: ImageCell { + width: parent.cellWidth + height: parent.cellHeight + } - ImageCell { mode: Image.Tile; caption: "Tile" } - ImageCell { mode: Image.TileHorizontally; caption: "TileHorizontally" } - ImageCell { mode: Image.TileVertically; caption: "TileVertically" } + SizedImageCell { + mode: Image.Stretch + caption: "Stretch" + } + SizedImageCell { + mode: Image.PreserveAspectFit + caption: "PreserveAspectFit" + } + SizedImageCell { + mode: Image.PreserveAspectCrop + caption: "PreserveAspectCrop" + } + SizedImageCell { + mode: Image.Tile + caption: "Tile" + } + SizedImageCell { + mode: Image.TileHorizontally + caption: "TileHorizontally" + } + SizedImageCell { + mode: Image.TileVertically + caption: "TileVertically" + } } } -- cgit v1.2.3 From 60663ad03118503d4c0018c855bbe80381d0ec98 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Thu, 6 Feb 2020 10:40:00 +0100 Subject: rhi: Handle beginFrame() failure correctly in threaded render loop Also add some comments to improve maintainability. Task-number: QTBUG-81740 Change-Id: I4be90768f7a8506b1fb493885062b98be9f4f58a Reviewed-by: Eirik Aavitsland --- src/quick/scenegraph/qsgthreadedrenderloop.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp index 4777f46f0a..9b288029b4 100644 --- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp +++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp @@ -660,6 +660,11 @@ void QSGRenderThread::sync(bool inExpose, bool inGrab) qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- window has bad size, sync aborted"); } + // Two special cases: For grabs we do not care about blocking the gui + // (main) thread. When this is from an expose, we will keep locked until + // the frame is rendered (submitted), so in that case waking happens later + // in syncAndRender(). Otherwise, wake now and let the main thread go on + // while we render. if (!inExpose && !inGrab) { qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- sync complete, waking Gui"); waitCondition.wakeOne(); @@ -756,13 +761,11 @@ void QSGRenderThread::syncAndRender(QImage *grabImage) QCoreApplication::postEvent(window, new QEvent(QEvent::Type(QQuickWindowPrivate::FullUpdateRequest))); // Before returning we need to ensure the same wake up logic that // would have happened if beginFrame() had suceeded. - if (exposeRequested) { + if (syncRequested && !grabRequested) { + // Lock like sync() would do. Note that exposeRequested always includes syncRequested. qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- bailing out due to failed beginFrame, wake Gui"); - waitCondition.wakeOne(); - mutex.unlock(); - } else if (syncRequested && !grabRequested) { - qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- bailing out due to failed beginFrame, wake Gui like sync would do"); mutex.lock(); + // Go ahead with waking because we will return right after this. waitCondition.wakeOne(); mutex.unlock(); } @@ -885,7 +888,8 @@ void QSGRenderThread::syncAndRender(QImage *grabImage) // has started rendering with a bad window, causing makeCurrent to // fail or if the window has a bad size. if (exposeRequested) { - qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- wake Gui after initial expose"); + // With expose sync() did not wake gui, do it now. + qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- wake Gui after expose"); waitCondition.wakeOne(); mutex.unlock(); } -- cgit v1.2.3 From 5b6baf2066114b120b32b4feb39f9549788499a8 Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Tue, 4 Feb 2020 11:42:36 +0100 Subject: Add inline component documentation Change-Id: Ieff73eba115802722afdbb491b74df5eaad9a4f4 Reviewed-by: Paul Wicking Reviewed-by: Pierre-Yves Siret Reviewed-by: Ulf Hermann --- src/qml/doc/snippets/qml/qml-documents/A.qml | 61 ++++++++++++++++ src/qml/doc/snippets/qml/qml-documents/B.qml | 58 +++++++++++++++ src/qml/doc/snippets/qml/qml-documents/Images.qml | 84 ++++++++++++++++++++++ .../snippets/qml/qml-documents/LabeledImageBox.qml | 64 +++++++++++++++++ .../src/qmllanguageref/documents/definetypes.qdoc | 36 ++++++++++ 5 files changed, 303 insertions(+) create mode 100644 src/qml/doc/snippets/qml/qml-documents/A.qml create mode 100644 src/qml/doc/snippets/qml/qml-documents/B.qml create mode 100644 src/qml/doc/snippets/qml/qml-documents/Images.qml create mode 100644 src/qml/doc/snippets/qml/qml-documents/LabeledImageBox.qml diff --git a/src/qml/doc/snippets/qml/qml-documents/A.qml b/src/qml/doc/snippets/qml/qml-documents/A.qml new file mode 100644 index 0000000000..83c59dc5d7 --- /dev/null +++ b/src/qml/doc/snippets/qml/qml-documents/A.qml @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2020 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$ +** +****************************************************************************/ +//! [document] +// A.qml +import QtQuick 2.15 + +Item { + id: root + property string message: "From A" + component MyInlineComponent : Item { + Component.onCompleted: console.log(root.message) + } +} +//! [document] diff --git a/src/qml/doc/snippets/qml/qml-documents/B.qml b/src/qml/doc/snippets/qml/qml-documents/B.qml new file mode 100644 index 0000000000..5e603d50e0 --- /dev/null +++ b/src/qml/doc/snippets/qml/qml-documents/B.qml @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2020 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$ +** +****************************************************************************/ + +//! [document] +// B.qml +import QtQuick 2.15 + +Item { + A.MyInlineComponent {} +} +//! [document] diff --git a/src/qml/doc/snippets/qml/qml-documents/Images.qml b/src/qml/doc/snippets/qml/qml-documents/Images.qml new file mode 100644 index 0000000000..80a4d95fbb --- /dev/null +++ b/src/qml/doc/snippets/qml/qml-documents/Images.qml @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2020 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$ +** +****************************************************************************/ +//! [document] +// Images.qml +import QtQuick 2.15 + +Item { + component LabeledImage: Column { + property alias source: image.source + property alias caption: text.text + + Image { + id: image + width: 50 + height: 50 + } + Text { + id: text + font.bold: true + } + } + + Row { + LabeledImage { + id: before + source: "before.png" + caption: "Before" + } + LabeledImage { + id: after + source: "after.png" + caption: "After" + } + } + property LabeledImage selectedImage: before +} +// Images.qml diff --git a/src/qml/doc/snippets/qml/qml-documents/LabeledImageBox.qml b/src/qml/doc/snippets/qml/qml-documents/LabeledImageBox.qml new file mode 100644 index 0000000000..5a259a0cc6 --- /dev/null +++ b/src/qml/doc/snippets/qml/qml-documents/LabeledImageBox.qml @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2020 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$ +** +****************************************************************************/ + +//! [document] +// LabeledImageBox.qml +import QtQuick 2.15 + +Rectangle { + property alias caption: image.caption + property alias source: image.source + border.width: 2 + border.color: "black" + Images.LabeledImage { + id: image + } +} +//! [document] diff --git a/src/qml/doc/src/qmllanguageref/documents/definetypes.qdoc b/src/qml/doc/src/qmllanguageref/documents/definetypes.qdoc index 2de4eb0c18..0a55f36287 100644 --- a/src/qml/doc/src/qmllanguageref/documents/definetypes.qdoc +++ b/src/qml/doc/src/qmllanguageref/documents/definetypes.qdoc @@ -82,6 +82,42 @@ The \c SquareButton type encapsulates the tree of QML objects declared in \c Squ \note the letter case of the file name is significant on some (notably UNIX) filesystems. It is recommended the file name case matches the case of the desired QML type name exactly - for example, \c Box.qml and not \c BoX.qml - regardless of the platform to which the QML type will be deployed. +\section2 Inline Components + +Sometimes, it can be inconvenient to create a new file for a type, for +instance when reusing a small delegate in multiple views. If you don't actually +need to expose the type, but only need to create an instance, +\l{QtQml::Component}{Component} is an option. +But if you want to declare properties with the component types, or if you +want to use it in multiple files, \c Component is not an option. In that case, +you can use \e {inline components}. Inline components declare a new component +inside of a file. The syntax for that is +\code +component : BaseType { + // declare properties and bindings here +} +\endcode + +Inside the file which declares the inline component, the type can be referenced +simply by its name. + +\snippet src/qml/doc/snippets/qml/qml-documents/Images.qml document + +In other files, it has to be prefixed with the name of its containing component. +\snippet src/qml/doc/snippets/qml/qml-documents/LabeledImageBox.qml document + +\note Inline components don't share their scope with the component they are +declared in. In the following example, when \c A.MyInlineComponent in file +B.qml gets created, a ReferenceError will occur, as \c root does not exist as +an id in B.qml. +It is therefore advisable not to reference objects in an inline component +which are not part of it. + +\snippet src/qml/doc/snippets/qml/qml-documents/A.qml document +\snippet src/qml/doc/snippets/qml/qml-documents/B.qml document + +\note Inline components cannot be nested. + \section2 Importing Types Defined Outside the Current Directory If \c SquareButton.qml was not in the same directory as \c myapplication.qml, -- cgit v1.2.3 From 96d2c71c88cb6353a7d68e6d3cca3f92e2248069 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Wed, 5 Feb 2020 16:10:31 +0100 Subject: Privately export QQuickFlickablePrivate and QQuickTableViewPrivate We need this to implement header views (for TableView) in qtquickcontrols2. Task-number: QTPM-1300 Change-Id: I03068828cdf6dd79ec6a91c75f68eaf7c224d4a2 Reviewed-by: Shawn Rutledge --- src/quick/items/qquickflickable_p_p.h | 2 +- src/quick/items/qquicktableview_p_p.h | 2 +- src/quick/util/qquicktimeline_p_p.h | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/quick/items/qquickflickable_p_p.h b/src/quick/items/qquickflickable_p_p.h index 1ff55dae90..3f5f11effd 100644 --- a/src/quick/items/qquickflickable_p_p.h +++ b/src/quick/items/qquickflickable_p_p.h @@ -73,7 +73,7 @@ class QQuickFlickableVisibleArea; class QQuickTransition; class QQuickFlickableReboundTransition; -class Q_AUTOTEST_EXPORT QQuickFlickablePrivate : public QQuickItemPrivate, public QQuickItemChangeListener +class Q_QUICK_PRIVATE_EXPORT QQuickFlickablePrivate : public QQuickItemPrivate, public QQuickItemChangeListener { Q_DECLARE_PUBLIC(QQuickFlickable) diff --git a/src/quick/items/qquicktableview_p_p.h b/src/quick/items/qquicktableview_p_p.h index bf4bd0b511..7987d8c6d8 100644 --- a/src/quick/items/qquicktableview_p_p.h +++ b/src/quick/items/qquicktableview_p_p.h @@ -90,7 +90,7 @@ private: Q_DECLARE_PRIVATE(QQuickTableSectionSizeProvider) }; -class Q_QML_AUTOTEST_EXPORT QQuickTableViewPrivate : public QQuickFlickablePrivate +class Q_QUICK_PRIVATE_EXPORT QQuickTableViewPrivate : public QQuickFlickablePrivate { Q_DECLARE_PUBLIC(QQuickTableView) diff --git a/src/quick/util/qquicktimeline_p_p.h b/src/quick/util/qquicktimeline_p_p.h index abb5369b7b..fc5bd15ed1 100644 --- a/src/quick/util/qquicktimeline_p_p.h +++ b/src/quick/util/qquicktimeline_p_p.h @@ -52,6 +52,7 @@ // #include +#include #include "private/qabstractanimationjob_p.h" QT_BEGIN_NAMESPACE @@ -61,7 +62,7 @@ class QQuickTimeLineValue; class QQuickTimeLineCallback; struct QQuickTimeLinePrivate; class QQuickTimeLineObject; -class Q_AUTOTEST_EXPORT QQuickTimeLine : public QObject, QAbstractAnimationJob +class Q_QUICK_PRIVATE_EXPORT QQuickTimeLine : public QObject, QAbstractAnimationJob { Q_OBJECT public: -- cgit v1.2.3 From 053547fba7e83e894d8af3a63d022daa6a34ce99 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Wed, 15 Jan 2020 14:31:35 +0100 Subject: statemachine: Use new QQmlListProperty capabilities Change-Id: Ic471ba4f82bdf1ac63953927d0a83f514d0e49d0 Reviewed-by: Simon Hausmann Reviewed-by: Shawn Rutledge --- src/imports/statemachine/childrenprivate.h | 138 +++++++++++++++++++++++------ src/imports/statemachine/finalstate.cpp | 4 +- src/imports/statemachine/finalstate.h | 2 +- src/imports/statemachine/state.cpp | 4 +- src/imports/statemachine/state.h | 2 +- src/imports/statemachine/statemachine.cpp | 4 +- src/imports/statemachine/statemachine.h | 2 +- 7 files changed, 125 insertions(+), 31 deletions(-) diff --git a/src/imports/statemachine/childrenprivate.h b/src/imports/statemachine/childrenprivate.h index 57cda1c796..2dcecd6531 100644 --- a/src/imports/statemachine/childrenprivate.h +++ b/src/imports/statemachine/childrenprivate.h @@ -46,54 +46,142 @@ #include #include -template -class ChildrenPrivate +enum class ChildrenMode { + None = 0x0, + State = 0x1, + Transition = 0x2, + StateOrTransition = State | Transition +}; + +template +static T *parentObject(QQmlListProperty *prop) { return static_cast(prop->object); } + +template +struct ParentHandler { -public: - ChildrenPrivate() - {} + static bool unparentItem(QQmlListProperty *prop, QObject *oldItem); + static bool parentItem(QQmlListProperty *prop, QObject *item); +}; - static void append(QQmlListProperty *prop, QObject *item) +template +struct ParentHandler +{ + static bool unparentItem(QQmlListProperty *, QObject *) { return true; } + static bool parentItem(QQmlListProperty *, QObject *) { return true; } +}; + +template +struct ParentHandler +{ + static bool parentItem(QQmlListProperty *prop, QObject *item) + { + if (QAbstractState *state = qobject_cast(item)) { + state->setParent(parentObject(prop)); + return true; + } + return false; + } + + static bool unparentItem(QQmlListProperty *, QObject *oldItem) + { + if (QAbstractState *state = qobject_cast(oldItem)) { + state->setParent(nullptr); + return true; + } + return false; + } +}; + +template +struct ParentHandler +{ + static bool parentItem(QQmlListProperty *prop, QObject *item) { - QAbstractState *state = qobject_cast(item); - if (state) { - item->setParent(prop->object); - } else { - QAbstractTransition *trans = qobject_cast(item); - if (trans) - static_cast(prop->object)->addTransition(trans); + if (QAbstractTransition *trans = qobject_cast(item)) { + parentObject(prop)->addTransition(trans); + return true; } - static_cast*>(prop->data)->children.append(item); - emit static_cast(prop->object)->childrenChanged(); + return false; } - static void appendNoTransition(QQmlListProperty *prop, QObject *item) + static bool unparentItem(QQmlListProperty *prop, QObject *oldItem) { - QAbstractState *state = qobject_cast(item); - if (state) { - item->setParent(prop->object); + if (QAbstractTransition *trans = qobject_cast(oldItem)) { + parentObject(prop)->removeTransition(trans); + return true; } - static_cast*>(prop->data)->children.append(item); - emit static_cast(prop->object)->childrenChanged(); + return false; + } +}; + +template +struct ParentHandler +{ + static bool parentItem(QQmlListProperty *prop, QObject *oldItem) + { + return ParentHandler::parentItem(prop, oldItem) + || ParentHandler::parentItem(prop, oldItem); + } + + static bool unparentItem(QQmlListProperty *prop, QObject *oldItem) + { + return ParentHandler::unparentItem(prop, oldItem) + || ParentHandler::unparentItem(prop, oldItem); + } +}; + +template +class ChildrenPrivate +{ +public: + static void append(QQmlListProperty *prop, QObject *item) + { + Handler::parentItem(prop, item); + static_cast(prop->data)->children.append(item); + emit parentObject(prop)->childrenChanged(); } static int count(QQmlListProperty *prop) { - return static_cast*>(prop->data)->children.count(); + return static_cast(prop->data)->children.count(); } static QObject *at(QQmlListProperty *prop, int index) { - return static_cast*>(prop->data)->children.at(index); + return static_cast(prop->data)->children.at(index); } static void clear(QQmlListProperty *prop) { - static_cast*>(prop->data)->children.clear(); - emit static_cast(prop->object)->childrenChanged(); + auto &children = static_cast(prop->data)->children; + for (QObject *oldItem : qAsConst(children)) + Handler::unparentItem(prop, oldItem); + + children.clear(); + emit parentObject(prop)->childrenChanged(); + } + + static void replace(QQmlListProperty *prop, int index, QObject *item) + { + auto &children = static_cast(prop->data)->children; + + Handler::unparentItem(prop, children.at(index)); + Handler::parentItem(prop, item); + + children.replace(index, item); + emit parentObject(prop)->childrenChanged(); + } + + static void removeLast(QQmlListProperty *prop) + { + Handler::unparentItem(prop, static_cast(prop->data)->children.takeLast()); + emit parentObject(prop)->childrenChanged(); } private: + using Self = ChildrenPrivate; + using Handler = ParentHandler; + QList children; }; diff --git a/src/imports/statemachine/finalstate.cpp b/src/imports/statemachine/finalstate.cpp index 54dcc82bae..4d4c6b2cc7 100644 --- a/src/imports/statemachine/finalstate.cpp +++ b/src/imports/statemachine/finalstate.cpp @@ -50,7 +50,9 @@ FinalState::FinalState(QState *parent) QQmlListProperty FinalState::children() { - return QQmlListProperty(this, &m_children, m_children.appendNoTransition, m_children.count, m_children.at, m_children.clear); + return QQmlListProperty(this, &m_children, + m_children.append, m_children.count, m_children.at, + m_children.clear, m_children.replace, m_children.removeLast); } /*! diff --git a/src/imports/statemachine/finalstate.h b/src/imports/statemachine/finalstate.h index 9cdbb51584..117a358e53 100644 --- a/src/imports/statemachine/finalstate.h +++ b/src/imports/statemachine/finalstate.h @@ -66,7 +66,7 @@ Q_SIGNALS: void childrenChanged(); private: - ChildrenPrivate m_children; + ChildrenPrivate m_children; }; QT_END_NAMESPACE diff --git a/src/imports/statemachine/state.cpp b/src/imports/statemachine/state.cpp index af76087256..10530c2985 100644 --- a/src/imports/statemachine/state.cpp +++ b/src/imports/statemachine/state.cpp @@ -61,7 +61,9 @@ void State::componentComplete() QQmlListProperty State::children() { - return QQmlListProperty(this, &m_children, m_children.append, m_children.count, m_children.at, m_children.clear); + return QQmlListProperty(this, &m_children, + m_children.append, m_children.count, m_children.at, + m_children.clear, m_children.replace, m_children.removeLast); } /*! diff --git a/src/imports/statemachine/state.h b/src/imports/statemachine/state.h index 4b17ea0e5f..68184775ab 100644 --- a/src/imports/statemachine/state.h +++ b/src/imports/statemachine/state.h @@ -69,7 +69,7 @@ Q_SIGNALS: void childrenChanged(); private: - ChildrenPrivate m_children; + ChildrenPrivate m_children; }; QT_END_NAMESPACE diff --git a/src/imports/statemachine/statemachine.cpp b/src/imports/statemachine/statemachine.cpp index a983644018..bdad2e6bde 100644 --- a/src/imports/statemachine/statemachine.cpp +++ b/src/imports/statemachine/statemachine.cpp @@ -90,7 +90,9 @@ void StateMachine::componentComplete() QQmlListProperty StateMachine::children() { - return QQmlListProperty(this, &m_children, m_children.append, m_children.count, m_children.at, m_children.clear); + return QQmlListProperty(this, &m_children, + m_children.append, m_children.count, m_children.at, + m_children.clear, m_children.replace, m_children.removeLast); } /*! diff --git a/src/imports/statemachine/statemachine.h b/src/imports/statemachine/statemachine.h index 04894477b3..cc0360db54 100644 --- a/src/imports/statemachine/statemachine.h +++ b/src/imports/statemachine/statemachine.h @@ -82,7 +82,7 @@ Q_SIGNALS: void qmlRunningChanged(); private: - ChildrenPrivate m_children; + ChildrenPrivate m_children; bool m_completed; bool m_running; }; -- cgit v1.2.3 From 6d0a453f41d304239285d64b06612c36922be701 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 25 Nov 2019 16:10:04 +0100 Subject: Use the extended QQmlListProperty interface in a few places Task-number: QTBUG-79263 Change-Id: If518f644b5b9eddbacfb1cb16fbb557127ffcfb2 Reviewed-by: Simon Hausmann Reviewed-by: Shawn Rutledge --- .../referenceexamples/attached/birthdayparty.cpp | 2 +- .../referenceexamples/binding/birthdayparty.cpp | 2 +- .../referenceexamples/coercion/birthdayparty.cpp | 2 +- .../referenceexamples/default/birthdayparty.cpp | 2 +- .../referenceexamples/grouped/birthdayparty.cpp | 2 +- .../referenceexamples/methods/birthdayparty.cpp | 2 +- .../referenceexamples/properties/birthdayparty.cpp | 24 ++++++++++++- .../referenceexamples/properties/birthdayparty.h | 4 +++ .../qml/referenceexamples/signal/birthdayparty.cpp | 2 +- .../valuesource/birthdayparty.cpp | 2 +- .../chapter5-listproperties/piechart.cpp | 3 +- .../chapter6-plugins/import/piechart.cpp | 3 +- src/imports/labsmodels/qqmldelegatecomponent.cpp | 24 ++++++++++++- src/imports/labsmodels/qqmldelegatecomponent_p.h | 2 ++ src/imports/labsmodels/qqmltablemodel.cpp | 17 +++++++++- src/imports/labsmodels/qqmltablemodel_p.h | 2 ++ src/particles/qquickimageparticle.cpp | 4 ++- src/particles/qquickparticlegroup.cpp | 13 +++++--- src/qml/qml/qqmlvmemetaobject.cpp | 17 +++++++++- src/qmlmodels/qqmldelegatemodel.cpp | 2 +- src/qmlmodels/qqmlobjectmodel.cpp | 39 +++++++++++++++++----- src/qmlmodels/qquickpackage.cpp | 19 ++++++++--- src/quick/items/qquickspriteengine_p.h | 12 +++++++ src/quick/items/qquickspritesequence.cpp | 4 ++- src/quick/items/qquickwindow.cpp | 25 +++++++++++--- src/quick/items/qquickwindow_p.h | 2 ++ src/quick/util/qquickstate.cpp | 10 ++++-- src/quick/util/qquickstate_p_p.h | 17 ++++++++++ src/quick/util/qquickstategroup.cpp | 36 +++++++++++++++++--- 29 files changed, 250 insertions(+), 45 deletions(-) diff --git a/examples/qml/referenceexamples/attached/birthdayparty.cpp b/examples/qml/referenceexamples/attached/birthdayparty.cpp index da0cb800fc..888aafbc18 100644 --- a/examples/qml/referenceexamples/attached/birthdayparty.cpp +++ b/examples/qml/referenceexamples/attached/birthdayparty.cpp @@ -81,7 +81,7 @@ void BirthdayParty::setHost(Person *c) QQmlListProperty BirthdayParty::guests() { - return {this, m_guests}; + return {this, &m_guests}; } int BirthdayParty::guestCount() const diff --git a/examples/qml/referenceexamples/binding/birthdayparty.cpp b/examples/qml/referenceexamples/binding/birthdayparty.cpp index 866c1f6968..cfedf84be0 100644 --- a/examples/qml/referenceexamples/binding/birthdayparty.cpp +++ b/examples/qml/referenceexamples/binding/birthdayparty.cpp @@ -87,7 +87,7 @@ void BirthdayParty::setHost(Person *c) QQmlListProperty BirthdayParty::guests() { - return QQmlListProperty(this, m_guests); + return QQmlListProperty(this, &m_guests); } int BirthdayParty::guestCount() const diff --git a/examples/qml/referenceexamples/coercion/birthdayparty.cpp b/examples/qml/referenceexamples/coercion/birthdayparty.cpp index 1bae55076c..81db8ab1b8 100644 --- a/examples/qml/referenceexamples/coercion/birthdayparty.cpp +++ b/examples/qml/referenceexamples/coercion/birthdayparty.cpp @@ -66,7 +66,7 @@ void BirthdayParty::setHost(Person *c) QQmlListProperty BirthdayParty::guests() { - return {this, m_guests}; + return {this, &m_guests}; } int BirthdayParty::guestCount() const diff --git a/examples/qml/referenceexamples/default/birthdayparty.cpp b/examples/qml/referenceexamples/default/birthdayparty.cpp index 1bae55076c..81db8ab1b8 100644 --- a/examples/qml/referenceexamples/default/birthdayparty.cpp +++ b/examples/qml/referenceexamples/default/birthdayparty.cpp @@ -66,7 +66,7 @@ void BirthdayParty::setHost(Person *c) QQmlListProperty BirthdayParty::guests() { - return {this, m_guests}; + return {this, &m_guests}; } int BirthdayParty::guestCount() const diff --git a/examples/qml/referenceexamples/grouped/birthdayparty.cpp b/examples/qml/referenceexamples/grouped/birthdayparty.cpp index 1bae55076c..81db8ab1b8 100644 --- a/examples/qml/referenceexamples/grouped/birthdayparty.cpp +++ b/examples/qml/referenceexamples/grouped/birthdayparty.cpp @@ -66,7 +66,7 @@ void BirthdayParty::setHost(Person *c) QQmlListProperty BirthdayParty::guests() { - return {this, m_guests}; + return {this, &m_guests}; } int BirthdayParty::guestCount() const diff --git a/examples/qml/referenceexamples/methods/birthdayparty.cpp b/examples/qml/referenceexamples/methods/birthdayparty.cpp index 7e750e4f4b..4b30d31aeb 100644 --- a/examples/qml/referenceexamples/methods/birthdayparty.cpp +++ b/examples/qml/referenceexamples/methods/birthdayparty.cpp @@ -67,7 +67,7 @@ void BirthdayParty::setHost(Person *c) QQmlListProperty BirthdayParty::guests() { - return {this, m_guests}; + return {this, &m_guests}; } int BirthdayParty::guestCount() const diff --git a/examples/qml/referenceexamples/properties/birthdayparty.cpp b/examples/qml/referenceexamples/properties/birthdayparty.cpp index 9abb08dbd9..fe6abab3f5 100644 --- a/examples/qml/referenceexamples/properties/birthdayparty.cpp +++ b/examples/qml/referenceexamples/properties/birthdayparty.cpp @@ -71,7 +71,9 @@ QQmlListProperty BirthdayParty::guests() &BirthdayParty::appendGuest, &BirthdayParty::guestCount, &BirthdayParty::guest, - &BirthdayParty::clearGuests}; + &BirthdayParty::clearGuests, + &BirthdayParty::replaceGuest, + &BirthdayParty::removeLastGuest}; } void BirthdayParty::appendGuest(Person* p) { @@ -93,6 +95,16 @@ void BirthdayParty::clearGuests() { m_guests.clear(); } +void BirthdayParty::replaceGuest(int index, Person *p) +{ + m_guests[index] = p; +} + +void BirthdayParty::removeLastGuest() +{ + m_guests.removeLast(); +} + // ![0] void BirthdayParty::appendGuest(QQmlListProperty* list, Person* p) { @@ -103,6 +115,16 @@ void BirthdayParty::clearGuests(QQmlListProperty* list) { reinterpret_cast< BirthdayParty* >(list->data)->clearGuests(); } +void BirthdayParty::replaceGuest(QQmlListProperty *list, int i, Person *p) +{ + reinterpret_cast< BirthdayParty* >(list->data)->replaceGuest(i, p); +} + +void BirthdayParty::removeLastGuest(QQmlListProperty *list) +{ + reinterpret_cast< BirthdayParty* >(list->data)->removeLastGuest(); +} + Person* BirthdayParty::guest(QQmlListProperty* list, int i) { return reinterpret_cast< BirthdayParty* >(list->data)->guest(i); } diff --git a/examples/qml/referenceexamples/properties/birthdayparty.h b/examples/qml/referenceexamples/properties/birthdayparty.h index fb8b63a79d..a5704972cc 100644 --- a/examples/qml/referenceexamples/properties/birthdayparty.h +++ b/examples/qml/referenceexamples/properties/birthdayparty.h @@ -79,12 +79,16 @@ public: int guestCount() const; Person *guest(int) const; void clearGuests(); + void replaceGuest(int, Person*); + void removeLastGuest(); private: static void appendGuest(QQmlListProperty*, Person*); static int guestCount(QQmlListProperty*); static Person* guest(QQmlListProperty*, int); static void clearGuests(QQmlListProperty*); + static void replaceGuest(QQmlListProperty*, int, Person*); + static void removeLastGuest(QQmlListProperty*); Person *m_host; QVector m_guests; diff --git a/examples/qml/referenceexamples/signal/birthdayparty.cpp b/examples/qml/referenceexamples/signal/birthdayparty.cpp index 9d34cdf146..405c8af940 100644 --- a/examples/qml/referenceexamples/signal/birthdayparty.cpp +++ b/examples/qml/referenceexamples/signal/birthdayparty.cpp @@ -82,7 +82,7 @@ void BirthdayParty::setHost(Person *c) QQmlListProperty BirthdayParty::guests() { - return {this, m_guests}; + return {this, &m_guests}; } int BirthdayParty::guestCount() const diff --git a/examples/qml/referenceexamples/valuesource/birthdayparty.cpp b/examples/qml/referenceexamples/valuesource/birthdayparty.cpp index 68d5767e8d..6a5e67aa0d 100644 --- a/examples/qml/referenceexamples/valuesource/birthdayparty.cpp +++ b/examples/qml/referenceexamples/valuesource/birthdayparty.cpp @@ -82,7 +82,7 @@ void BirthdayParty::setHost(Person *c) QQmlListProperty BirthdayParty::guests() { - return {this, m_guests}; + return {this, &m_guests}; } int BirthdayParty::guestCount() const diff --git a/examples/qml/tutorials/extending-qml/chapter5-listproperties/piechart.cpp b/examples/qml/tutorials/extending-qml/chapter5-listproperties/piechart.cpp index ac680bb9c9..a8e14db542 100644 --- a/examples/qml/tutorials/extending-qml/chapter5-listproperties/piechart.cpp +++ b/examples/qml/tutorials/extending-qml/chapter5-listproperties/piechart.cpp @@ -68,7 +68,8 @@ void PieChart::setName(const QString &name) //![0] QQmlListProperty PieChart::slices() { - return QQmlListProperty(this, nullptr, &PieChart::append_slice, nullptr, nullptr, nullptr); + return QQmlListProperty(this, nullptr, &PieChart::append_slice, nullptr, + nullptr, nullptr, nullptr, nullptr); } void PieChart::append_slice(QQmlListProperty *list, PieSlice *slice) diff --git a/examples/qml/tutorials/extending-qml/chapter6-plugins/import/piechart.cpp b/examples/qml/tutorials/extending-qml/chapter6-plugins/import/piechart.cpp index 1c712c887a..536c0e16ae 100644 --- a/examples/qml/tutorials/extending-qml/chapter6-plugins/import/piechart.cpp +++ b/examples/qml/tutorials/extending-qml/chapter6-plugins/import/piechart.cpp @@ -67,7 +67,8 @@ void PieChart::setName(const QString &name) QQmlListProperty PieChart::slices() { - return QQmlListProperty(this, nullptr, &PieChart::append_slice, nullptr, nullptr, nullptr); + return QQmlListProperty(this, nullptr, &PieChart::append_slice, nullptr, + nullptr, nullptr, nullptr, nullptr); } void PieChart::append_slice(QQmlListProperty *list, PieSlice *slice) diff --git a/src/imports/labsmodels/qqmldelegatecomponent.cpp b/src/imports/labsmodels/qqmldelegatecomponent.cpp index aaf3fea5da..b8eb8049b3 100644 --- a/src/imports/labsmodels/qqmldelegatecomponent.cpp +++ b/src/imports/labsmodels/qqmldelegatecomponent.cpp @@ -250,7 +250,9 @@ QQmlListProperty QQmlDelegateChooser::choices() QQmlDelegateChooser::choices_append, QQmlDelegateChooser::choices_count, QQmlDelegateChooser::choices_at, - QQmlDelegateChooser::choices_clear); + QQmlDelegateChooser::choices_clear, + QQmlDelegateChooser::choices_replace, + QQmlDelegateChooser::choices_removeLast); } void QQmlDelegateChooser::choices_append(QQmlListProperty *prop, QQmlDelegateChoice *choice) @@ -282,6 +284,26 @@ void QQmlDelegateChooser::choices_clear(QQmlListProperty *pr q->delegateChanged(); } +void QQmlDelegateChooser::choices_replace(QQmlListProperty *prop, int index, + QQmlDelegateChoice *choice) +{ + QQmlDelegateChooser *q = static_cast(prop->object); + disconnect(q->m_choices[index], &QQmlDelegateChoice::changed, + q, &QQmlAbstractDelegateComponent::delegateChanged); + q->m_choices[index] = choice; + connect(choice, &QQmlDelegateChoice::changed, q, + &QQmlAbstractDelegateComponent::delegateChanged); + q->delegateChanged(); +} + +void QQmlDelegateChooser::choices_removeLast(QQmlListProperty *prop) +{ + QQmlDelegateChooser *q = static_cast(prop->object); + disconnect(q->m_choices.takeLast(), &QQmlDelegateChoice::changed, + q, &QQmlAbstractDelegateComponent::delegateChanged); + q->delegateChanged(); +} + QQmlComponent *QQmlDelegateChooser::delegate(QQmlAdaptorModel *adaptorModel, int row, int column) const { QVariant v; diff --git a/src/imports/labsmodels/qqmldelegatecomponent_p.h b/src/imports/labsmodels/qqmldelegatecomponent_p.h index 4c39dc0d0a..8473831b1d 100644 --- a/src/imports/labsmodels/qqmldelegatecomponent_p.h +++ b/src/imports/labsmodels/qqmldelegatecomponent_p.h @@ -116,6 +116,8 @@ public: static int choices_count(QQmlListProperty *); static QQmlDelegateChoice *choices_at(QQmlListProperty *, int); static void choices_clear(QQmlListProperty *); + static void choices_replace(QQmlListProperty *, int, QQmlDelegateChoice *); + static void choices_removeLast(QQmlListProperty *); QQmlComponent *delegate(QQmlAdaptorModel *adaptorModel, int row, int column = -1) const override; diff --git a/src/imports/labsmodels/qqmltablemodel.cpp b/src/imports/labsmodels/qqmltablemodel.cpp index b6468d760f..6ba2cecf19 100644 --- a/src/imports/labsmodels/qqmltablemodel.cpp +++ b/src/imports/labsmodels/qqmltablemodel.cpp @@ -644,7 +644,9 @@ QQmlListProperty QQmlTableModel::columns() &QQmlTableModel::columns_append, &QQmlTableModel::columns_count, &QQmlTableModel::columns_at, - &QQmlTableModel::columns_clear); + &QQmlTableModel::columns_clear, + &QQmlTableModel::columns_replace, + &QQmlTableModel::columns_removeLast); } void QQmlTableModel::columns_append(QQmlListProperty *property, @@ -674,6 +676,19 @@ void QQmlTableModel::columns_clear(QQmlListProperty *prope return model->mColumns.clear(); } +void QQmlTableModel::columns_replace(QQmlListProperty *property, int index, QQmlTableModelColumn *value) +{ + QQmlTableModel *model = static_cast(property->object); + if (QQmlTableModelColumn *column = qobject_cast(value)) + return model->mColumns.replace(index, column); +} + +void QQmlTableModel::columns_removeLast(QQmlListProperty *property) +{ + QQmlTableModel *model = static_cast(property->object); + model->mColumns.removeLast(); +} + /*! \qmlmethod QModelIndex TableModel::index(int row, int column) diff --git a/src/imports/labsmodels/qqmltablemodel_p.h b/src/imports/labsmodels/qqmltablemodel_p.h index d6e982d19a..75e2768849 100644 --- a/src/imports/labsmodels/qqmltablemodel_p.h +++ b/src/imports/labsmodels/qqmltablemodel_p.h @@ -96,6 +96,8 @@ public: static int columns_count(QQmlListProperty *property); static QQmlTableModelColumn *columns_at(QQmlListProperty *property, int index); static void columns_clear(QQmlListProperty *property); + static void columns_replace(QQmlListProperty *property, int index, QQmlTableModelColumn *value); + static void columns_removeLast(QQmlListProperty *property); QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; int rowCount(const QModelIndex &parent = QModelIndex()) const override; diff --git a/src/particles/qquickimageparticle.cpp b/src/particles/qquickimageparticle.cpp index c6fe2f516d..4d67691771 100644 --- a/src/particles/qquickimageparticle.cpp +++ b/src/particles/qquickimageparticle.cpp @@ -1143,7 +1143,9 @@ QQuickImageParticle::~QQuickImageParticle() QQmlListProperty QQuickImageParticle::sprites() { - return QQmlListProperty(this, &m_sprites, spriteAppend, spriteCount, spriteAt, spriteClear); + return QQmlListProperty(this, &m_sprites, + spriteAppend, spriteCount, spriteAt, + spriteClear, spriteReplace, spriteRemoveLast); } void QQuickImageParticle::sceneGraphInvalidated() diff --git a/src/particles/qquickparticlegroup.cpp b/src/particles/qquickparticlegroup.cpp index 052fda6eff..902c23331d 100644 --- a/src/particles/qquickparticlegroup.cpp +++ b/src/particles/qquickparticlegroup.cpp @@ -106,10 +106,15 @@ void delayedRedirect(QQmlListProperty *prop, QObject *value) QQmlListProperty QQuickParticleGroup::particleChildren() { QQuickParticleSystem* system = qobject_cast(parent()); - if (system) - return QQmlListProperty(this, nullptr, &QQuickParticleSystem::statePropertyRedirect, nullptr, nullptr, nullptr); - else - return QQmlListProperty(this, nullptr, &delayedRedirect, nullptr, nullptr, nullptr); + if (system) { + return QQmlListProperty(this, nullptr, + &QQuickParticleSystem::statePropertyRedirect, nullptr, + nullptr, nullptr, nullptr, nullptr); + } else { + return QQmlListProperty(this, nullptr, + &delayedRedirect, nullptr, nullptr, + nullptr, nullptr, nullptr); + } } void QQuickParticleGroup::setSystem(QQuickParticleSystem* arg) diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp index c20bc24a49..de23e929e2 100644 --- a/src/qml/qml/qqmlvmemetaobject.cpp +++ b/src/qml/qml/qqmlvmemetaobject.cpp @@ -136,6 +136,20 @@ static void list_clear(QQmlListProperty *prop) resolved.activateSignal(); } +static void list_replace(QQmlListProperty *prop, int index, QObject *o) +{ + const ResolvedList resolved(prop); + resolved.list()->replace(index, o); + resolved.activateSignal(); +} + +static void list_removeLast(QQmlListProperty *prop) +{ + const ResolvedList resolved(prop); + resolved.list()->removeLast(); + resolved.activateSignal(); +} + QQmlVMEVariantQObjectPtr::QQmlVMEVariantQObjectPtr() : QQmlGuard(nullptr), m_target(nullptr), m_index(-1) { @@ -737,7 +751,8 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void * *static_cast *>(a[0]) = QQmlListProperty( object, reinterpret_cast(quintptr(id)), - list_append, list_count, list_at, list_clear); + list_append, list_count, list_at, + list_clear, list_replace, list_removeLast); } else { *reinterpret_cast(a[0]) = readPropertyAsQObject(id); } diff --git a/src/qmlmodels/qqmldelegatemodel.cpp b/src/qmlmodels/qqmldelegatemodel.cpp index ee407538f1..c32caafaa6 100644 --- a/src/qmlmodels/qqmldelegatemodel.cpp +++ b/src/qmlmodels/qqmldelegatemodel.cpp @@ -731,7 +731,7 @@ QQmlListProperty QQmlDelegateModel::groups() QQmlDelegateModelPrivate::group_append, QQmlDelegateModelPrivate::group_count, QQmlDelegateModelPrivate::group_at, - nullptr); + nullptr, nullptr, nullptr); } /*! diff --git a/src/qmlmodels/qqmlobjectmodel.cpp b/src/qmlmodels/qqmlobjectmodel.cpp index 01e91e98dd..d89ea702fa 100644 --- a/src/qmlmodels/qqmlobjectmodel.cpp +++ b/src/qmlmodels/qqmlobjectmodel.cpp @@ -91,6 +91,15 @@ public: static_cast(prop->data)->clear(); } + static void children_replace(QQmlListProperty *prop, int index, QObject *item) { + static_cast(prop->data)->replace(index, item); + } + + static void children_removeLast(QQmlListProperty *prop) { + auto data = static_cast(prop->data); + data->remove(data->children.count() - 1, 1); + } + void insert(int index, QObject *item) { Q_Q(QQmlObjectModel); children.insert(index, Item(item)); @@ -105,6 +114,19 @@ public: emit q->childrenChanged(); } + void replace(int index, QObject *item) { + Q_Q(QQmlObjectModel); + auto *attached = QQmlObjectModelAttached::properties(children.at(index).item); + emit q->destroyingItem(attached); + attached->setIndex(-1); + children.replace(index, Item(item)); + QQmlObjectModelAttached::properties(children.at(index).item)->setIndex(index); + QQmlChangeSet changeSet; + changeSet.change(index, 1); + emit q->modelUpdated(changeSet, false); + emit q->childrenChanged(); + } + void move(int from, int to, int n) { Q_Q(QQmlObjectModel); if (from > to) { @@ -138,6 +160,7 @@ public: Q_Q(QQmlObjectModel); for (int i = index; i < index + n; ++i) { QQmlObjectModelAttached *attached = QQmlObjectModelAttached::properties(children.at(i).item); + emit q->destroyingItem(attached); attached->setIndex(-1); } children.erase(children.begin() + index, children.begin() + index + n); @@ -153,9 +176,6 @@ public: } void clear() { - Q_Q(QQmlObjectModel); - for (const Item &child : qAsConst(children)) - emit q->destroyingItem(child.item); remove(0, children.count()); } @@ -226,12 +246,13 @@ QQmlObjectModel::QQmlObjectModel(QObject *parent) QQmlListProperty QQmlObjectModel::children() { Q_D(QQmlObjectModel); - return QQmlListProperty(this, - d, - d->children_append, - d->children_count, - d->children_at, - d->children_clear); + return QQmlListProperty(this, d, + QQmlObjectModelPrivate::children_append, + QQmlObjectModelPrivate::children_count, + QQmlObjectModelPrivate::children_at, + QQmlObjectModelPrivate::children_clear, + QQmlObjectModelPrivate::children_replace, + QQmlObjectModelPrivate::children_removeLast); } /*! diff --git a/src/qmlmodels/qquickpackage.cpp b/src/qmlmodels/qquickpackage.cpp index 567381e5ab..42e7d0e09f 100644 --- a/src/qmlmodels/qquickpackage.cpp +++ b/src/qmlmodels/qquickpackage.cpp @@ -115,6 +115,14 @@ public: QList *list = static_cast *>(prop->data); return list->count(); } + static void data_replace(QQmlListProperty *prop, int index, QObject *o) { + QList *list = static_cast *>(prop->data); + list->replace(index, DataGuard(o, list)); + } + static void data_removeLast(QQmlListProperty *prop) { + QList *list = static_cast *>(prop->data); + list->removeLast(); + } }; QHash QQuickPackageAttached::attached; @@ -152,10 +160,13 @@ QQuickPackage::~QQuickPackage() QQmlListProperty QQuickPackage::data() { Q_D(QQuickPackage); - return QQmlListProperty(this, &d->dataList, QQuickPackagePrivate::data_append, - QQuickPackagePrivate::data_count, - QQuickPackagePrivate::data_at, - QQuickPackagePrivate::data_clear); + return QQmlListProperty(this, &d->dataList, + QQuickPackagePrivate::data_append, + QQuickPackagePrivate::data_count, + QQuickPackagePrivate::data_at, + QQuickPackagePrivate::data_clear, + QQuickPackagePrivate::data_replace, + QQuickPackagePrivate::data_removeLast); } bool QQuickPackage::hasPart(const QString &name) diff --git a/src/quick/items/qquickspriteengine_p.h b/src/quick/items/qquickspriteengine_p.h index d76055c831..5ad33389de 100644 --- a/src/quick/items/qquickspriteengine_p.h +++ b/src/quick/items/qquickspriteengine_p.h @@ -330,6 +330,18 @@ inline int spriteCount(QQmlListProperty *p) return reinterpret_cast *>(p->data)->count(); } +inline void spriteReplace(QQmlListProperty *p, int idx, QQuickSprite *s) +{ + reinterpret_cast *>(p->data)->replace(idx, s); + p->object->metaObject()->invokeMethod(p->object, "createEngine"); +} + +inline void spriteRemoveLast(QQmlListProperty *p) +{ + reinterpret_cast *>(p->data)->removeLast(); + p->object->metaObject()->invokeMethod(p->object, "createEngine"); +} + QT_END_NAMESPACE #endif // QQUICKSPRITEENGINE_P_H diff --git a/src/quick/items/qquickspritesequence.cpp b/src/quick/items/qquickspritesequence.cpp index eb4b5335e7..c29938a1bb 100644 --- a/src/quick/items/qquickspritesequence.cpp +++ b/src/quick/items/qquickspritesequence.cpp @@ -162,7 +162,9 @@ void QQuickSpriteSequence::setInterpolate(bool arg) QQmlListProperty QQuickSpriteSequence::sprites() { Q_D(QQuickSpriteSequence); - return QQmlListProperty(this, &d->m_sprites, spriteAppend, spriteCount, spriteAt, spriteClear); + return QQmlListProperty(this, &d->m_sprites, + spriteAppend, spriteCount, spriteAt, + spriteClear, spriteReplace, spriteRemoveLast); } bool QQuickSpriteSequence::running() const diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 9ab3f2d8c2..6c63b83511 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -682,10 +682,13 @@ void QQuickWindow::handleApplicationStateChanged(Qt::ApplicationState state) QQmlListProperty QQuickWindowPrivate::data() { - return QQmlListProperty(q_func(), nullptr, QQuickWindowPrivate::data_append, - QQuickWindowPrivate::data_count, - QQuickWindowPrivate::data_at, - QQuickWindowPrivate::data_clear); + return QQmlListProperty(q_func(), nullptr, + QQuickWindowPrivate::data_append, + QQuickWindowPrivate::data_count, + QQuickWindowPrivate::data_at, + QQuickWindowPrivate::data_clear, + QQuickWindowPrivate::data_replace, + QQuickWindowPrivate::data_removeLast); } static QMouseEvent *touchToMouseEvent(QEvent::Type type, const QTouchEvent::TouchPoint &p, QTouchEvent *event, QQuickItem *item, bool transformNeeded = true) @@ -3257,6 +3260,20 @@ void QQuickWindowPrivate::data_clear(QQmlListProperty *property) itemProperty.clear(&itemProperty); } +void QQuickWindowPrivate::data_replace(QQmlListProperty *property, int i, QObject *o) +{ + QQuickWindow *win = static_cast(property->object); + QQmlListProperty itemProperty = QQuickItemPrivate::get(win->contentItem())->data(); + itemProperty.replace(&itemProperty, i, o); +} + +void QQuickWindowPrivate::data_removeLast(QQmlListProperty *property) +{ + QQuickWindow *win = static_cast(property->object); + QQmlListProperty itemProperty = QQuickItemPrivate::get(win->contentItem())->data(); + itemProperty.removeLast(&itemProperty); +} + bool QQuickWindowPrivate::isRenderable() const { Q_Q(const QQuickWindow); diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h index 6e6dc7a400..86bdaf6396 100644 --- a/src/quick/items/qquickwindow_p.h +++ b/src/quick/items/qquickwindow_p.h @@ -299,6 +299,8 @@ public: static int data_count(QQmlListProperty *); static QObject *data_at(QQmlListProperty *, int); static void data_clear(QQmlListProperty *); + static void data_replace(QQmlListProperty *, int, QObject *); + static void data_removeLast(QQmlListProperty *); static void contextCreationFailureMessage(const QSurfaceFormat &format, QString *translatedMessage, diff --git a/src/quick/util/qquickstate.cpp b/src/quick/util/qquickstate.cpp index c106528f45..71ab1f4d62 100644 --- a/src/quick/util/qquickstate.cpp +++ b/src/quick/util/qquickstate.cpp @@ -267,9 +267,13 @@ void QQuickState::setExtends(const QString &extends) QQmlListProperty QQuickState::changes() { Q_D(QQuickState); - return QQmlListProperty(this, &d->operations, QQuickStatePrivate::operations_append, - QQuickStatePrivate::operations_count, QQuickStatePrivate::operations_at, - QQuickStatePrivate::operations_clear); + return QQmlListProperty(this, &d->operations, + QQuickStatePrivate::operations_append, + QQuickStatePrivate::operations_count, + QQuickStatePrivate::operations_at, + QQuickStatePrivate::operations_clear, + QQuickStatePrivate::operations_replace, + QQuickStatePrivate::operations_removeLast); } int QQuickState::operationCount() const diff --git a/src/quick/util/qquickstate_p_p.h b/src/quick/util/qquickstate_p_p.h index 2fa5321165..ae4ed291b5 100644 --- a/src/quick/util/qquickstate_p_p.h +++ b/src/quick/util/qquickstate_p_p.h @@ -244,6 +244,23 @@ public: QList *list = static_cast *>(prop->data); return list->at(index); } + static void operations_replace(QQmlListProperty *prop, int index, + QQuickStateOperation *op) { + QList *list = static_cast *>(prop->data); + auto &guard = list->at(index); + if (guard.object() == op) { + op->setState(qobject_cast(prop->object)); + } else { + list->at(index)->setState(nullptr); + op->setState(qobject_cast(prop->object)); + list->replace(index, OperationGuard(op, list)); + } + } + static void operations_removeLast(QQmlListProperty *prop) { + QList *list = static_cast *>(prop->data); + list->last()->setState(nullptr); + list->removeLast(); + } QQuickTransitionManager transitionManager; diff --git a/src/quick/util/qquickstategroup.cpp b/src/quick/util/qquickstategroup.cpp index 46e7d62fc1..2109aafc10 100644 --- a/src/quick/util/qquickstategroup.cpp +++ b/src/quick/util/qquickstategroup.cpp @@ -70,6 +70,8 @@ public: static int count_state(QQmlListProperty *list); static QQuickState *at_state(QQmlListProperty *list, int index); static void clear_states(QQmlListProperty *list); + static void replace_states(QQmlListProperty *list, int index, QQuickState *state); + static void removeLast_states(QQmlListProperty *list); static void append_transition(QQmlListProperty *list, QQuickTransition *state); static int count_transitions(QQmlListProperty *list); @@ -163,10 +165,13 @@ QList QQuickStateGroup::states() const QQmlListProperty QQuickStateGroup::statesProperty() { Q_D(QQuickStateGroup); - return QQmlListProperty(this, &d->states, &QQuickStateGroupPrivate::append_state, - &QQuickStateGroupPrivate::count_state, - &QQuickStateGroupPrivate::at_state, - &QQuickStateGroupPrivate::clear_states); + return QQmlListProperty(this, &d->states, + &QQuickStateGroupPrivate::append_state, + &QQuickStateGroupPrivate::count_state, + &QQuickStateGroupPrivate::at_state, + &QQuickStateGroupPrivate::clear_states, + &QQuickStateGroupPrivate::replace_states, + &QQuickStateGroupPrivate::removeLast_states); } void QQuickStateGroupPrivate::append_state(QQmlListProperty *list, QQuickState *state) @@ -201,6 +206,29 @@ void QQuickStateGroupPrivate::clear_states(QQmlListProperty *list) _this->d_func()->states.clear(); } +void QQuickStateGroupPrivate::replace_states(QQmlListProperty *list, int index, QQuickState *state) +{ + auto *self = qobject_cast(list->object); + auto *d = self->d_func(); + auto *oldState = d->states.at(index); + if (oldState != state) { + oldState->setStateGroup(nullptr); + state->setStateGroup(self); + d->states.replace(index, state); + if (d->currentState == oldState->name()) + d->setCurrentStateInternal(state->name(), true); + } +} + +void QQuickStateGroupPrivate::removeLast_states(QQmlListProperty *list) +{ + auto *d = qobject_cast(list->object)->d_func(); + if (d->currentState == d->states.last()->name()) + d->setCurrentStateInternal(d->states.length() > 1 ? d->states.first()->name() : QString(), true); + d->states.last()->setStateGroup(nullptr); + d->states.removeLast(); +} + /*! \qmlproperty list QtQuick::StateGroup::transitions This property holds a list of transitions defined by the state group. -- cgit v1.2.3 From 19cc92d170eaba83812be2abda15348ecfa2f072 Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Fri, 7 Feb 2020 09:57:02 +0100 Subject: QV4Engine: Do not construct invalid QVariant If the provided typeHint is -1, it does not make sense to construct a QVariant of this type and to check whether it is appendable. Fixes: QTBUG-81945 Change-Id: I32cbb9e70e210a7eca8d55801c1783338d1173b7 Reviewed-by: Ulf Hermann --- src/qml/jsruntime/qv4engine.cpp | 40 +++++++++++++++++--------------- tests/auto/qml/qjsvalue/tst_qjsvalue.cpp | 7 +++++- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 81f55673cd..d885c28166 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -1515,27 +1515,29 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int if (succeeded) return retn; #endif - retn = QVariant(typeHint, QMetaType::create(typeHint)); - auto retnAsIterable = retn.value(); - if (retnAsIterable._iteratorCapabilities & QtMetaTypePrivate::ContainerIsAppendable) { - auto const length = a->getLength(); - QV4::ScopedValue arrayValue(scope); - for (qint64 i = 0; i < length; ++i) { - arrayValue = a->get(i); - QVariant asVariant = toVariant(e, arrayValue, retnAsIterable._metaType_id, false, visitedObjects); - auto originalType = asVariant.userType(); - bool couldConvert = asVariant.convert(retnAsIterable._metaType_id); - if (!couldConvert) { - qWarning() << QLatin1String("Could not convert array value at position %1 from %2 to %3") - .arg(QString::number(i), - QMetaType::typeName(originalType), - QMetaType::typeName(retnAsIterable._metaType_id)); - // create default constructed value - asVariant = QVariant(retnAsIterable._metaType_id, nullptr); + if (typeHint != -1) { + retn = QVariant(typeHint, QMetaType::create(typeHint)); + auto retnAsIterable = retn.value(); + if (retnAsIterable._iteratorCapabilities & QtMetaTypePrivate::ContainerIsAppendable) { + auto const length = a->getLength(); + QV4::ScopedValue arrayValue(scope); + for (qint64 i = 0; i < length; ++i) { + arrayValue = a->get(i); + QVariant asVariant = toVariant(e, arrayValue, retnAsIterable._metaType_id, false, visitedObjects); + auto originalType = asVariant.userType(); + bool couldConvert = asVariant.convert(retnAsIterable._metaType_id); + if (!couldConvert) { + qWarning() << QLatin1String("Could not convert array value at position %1 from %2 to %3") + .arg(QString::number(i), + QMetaType::typeName(originalType), + QMetaType::typeName(retnAsIterable._metaType_id)); + // create default constructed value + asVariant = QVariant(retnAsIterable._metaType_id, nullptr); + } + retnAsIterable.append(asVariant.constData()); } - retnAsIterable.append(asVariant.constData()); + return retn; } - return retn; } } diff --git a/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp b/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp index 95f554776f..cab4686c37 100644 --- a/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp +++ b/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp @@ -1128,6 +1128,10 @@ void tst_QJSValue::toVariant() // array { + auto handler = qInstallMessageHandler([](QtMsgType type, const QMessageLogContext &, const QString &) { + if (type == QtMsgType::QtWarningMsg) + QFAIL("Converting QJSValue to QVariant should not cause error messages"); + }); QVariantList listIn; listIn << 123 << "hello"; QJSValue array = eng.toScriptValue(listIn); @@ -1145,8 +1149,9 @@ void tst_QJSValue::toVariant() QCOMPARE(array2.property("length").toInt(), array.property("length").toInt()); for (int i = 0; i < array.property("length").toInt(); ++i) QVERIFY(array2.property(i).strictlyEquals(array.property(i))); - } + qInstallMessageHandler(handler); + } } void tst_QJSValue::toQObject_nonQObject_data() -- cgit v1.2.3 From 4f0c9986069c690e8ed7a7d2b42dfbce5c492368 Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Mon, 10 Feb 2020 09:54:35 +0100 Subject: Fix QML type unregistration When the QQmlEngine gets destroyed, it unregisters all previously registered composite types. So far it only removed them from Qt's metatype system. This is however not enough, as the types also need to be removed from the global qmlLists datastructure. We achieve this by calling QQmlMetaType::unregisterInternalCompositeType. Task-number: QTBUG-81772 Change-Id: Iba124c890bc4613ffbb110003d74fe3a912f8df6 Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlengine.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 07d5429423..f97612ab75 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -683,11 +683,7 @@ QQmlEnginePrivate::~QQmlEnginePrivate() for (auto iter = m_compositeTypes.cbegin(), end = m_compositeTypes.cend(); iter != end; ++iter) { iter.value()->isRegisteredWithEngine = false; - - // since unregisterInternalCompositeType() will not be called in this - // case, we have to clean up the type registration manually - QMetaType::unregisterType(iter.value()->metaTypeId); - QMetaType::unregisterType(iter.value()->listMetaTypeId); + QQmlMetaType::unregisterInternalCompositeType({iter.value()->metaTypeId, iter.value()->listMetaTypeId}); } #if QT_CONFIG(qml_debug) delete profiler; -- cgit v1.2.3 From 01128c02c040373359ad45b64ccde11dc42c59f6 Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Thu, 9 Jan 2020 15:04:24 +0100 Subject: Android: Don't include QtQuickParticles in the dependencies Before qmlimportscanner it was necessary to mark QtQuickParticles as a dependency, but now it is possible to have qmlimportscanner and androiddeployqt handle all of this for us. So we no longer need to make it an explicit dependency. Task-number: QTBUG-38296 Change-Id: I6e0baefdcf002746af26d8c95fa1f318770cc658 Reviewed-by: Assam Boudjelthia Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/quick/quick.pro | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/quick/quick.pro b/src/quick/quick.pro index 700f794af4..cd8ee35135 100644 --- a/src/quick/quick.pro +++ b/src/quick/quick.pro @@ -18,13 +18,10 @@ exists("qqml_enable_gcov") { QMAKE_DOCS = $$PWD/doc/qtquick.qdocconf -ANDROID_LIB_DEPENDENCIES = \ - lib/libQt5QuickParticles.so MODULE_PLUGIN_TYPES += \ scenegraph ANDROID_BUNDLED_FILES += \ - qml \ - lib/libQt5QuickParticles.so + qml include(util/util.pri) include(scenegraph/scenegraph.pri) -- cgit v1.2.3 From c915ac23d9a460070ab4e4f8417df9db461c537c Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Mon, 10 Feb 2020 16:25:47 +0100 Subject: QQmlEngine: Test that types are correctly removed Amends 4f0c9986069c690e8ed7a7d2b42dfbce5c492368 Change-Id: I10a0d7988e1f5a003ccc80faa5b5c9bda62359cd Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlmetatype.cpp | 11 +++++++++++ src/qml/qml/qqmlmetatype_p.h | 2 ++ tests/auto/qml/qqmlenginecleanup/data/MyItem.qml | 2 ++ tests/auto/qml/qqmlenginecleanup/tst_qqmlenginecleanup.cpp | 13 +++++++++++++ 4 files changed, 28 insertions(+) create mode 100644 tests/auto/qml/qqmlenginecleanup/data/MyItem.qml diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index 76816618ac..bff6a8a46f 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -298,6 +298,17 @@ bool QQmlMetaType::qmlRegisterModuleTypes(const QString &uri, int majorVersion) return data->registerModuleTypes(QQmlMetaTypeData::VersionedUri(uri, majorVersion)); } +/*! + \internal + Method is only used to in tst_qqmlenginecleanup.cpp to test whether all + types have been removed from qmlLists after shutdown of QQmlEngine + */ +int QQmlMetaType::qmlRegisteredListTypeCount() +{ + QQmlMetaTypeDataPtr data; + return data->qmlLists.count(); +} + void QQmlMetaType::clearTypeRegistrations() { //Only cleans global static, assumed no running engine diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h index 037cf89beb..0c5bc043c4 100644 --- a/src/qml/qml/qqmlmetatype_p.h +++ b/src/qml/qml/qqmlmetatype_p.h @@ -202,6 +202,8 @@ public: static void qmlRemoveModuleRegistration(const QString &uri, int majorVersion); static bool qmlRegisterModuleTypes(const QString &uri, int majorVersion); + + static int qmlRegisteredListTypeCount(); }; Q_DECLARE_TYPEINFO(QQmlMetaType, Q_MOVABLE_TYPE); diff --git a/tests/auto/qml/qqmlenginecleanup/data/MyItem.qml b/tests/auto/qml/qqmlenginecleanup/data/MyItem.qml new file mode 100644 index 0000000000..4bb8dfb486 --- /dev/null +++ b/tests/auto/qml/qqmlenginecleanup/data/MyItem.qml @@ -0,0 +1,2 @@ +import QtQuick 2.12 +Item {} diff --git a/tests/auto/qml/qqmlenginecleanup/tst_qqmlenginecleanup.cpp b/tests/auto/qml/qqmlenginecleanup/tst_qqmlenginecleanup.cpp index 690db30838..846ac842db 100644 --- a/tests/auto/qml/qqmlenginecleanup/tst_qqmlenginecleanup.cpp +++ b/tests/auto/qml/qqmlenginecleanup/tst_qqmlenginecleanup.cpp @@ -45,6 +45,7 @@ private slots: void test_qmlClearTypeRegistrations(); void test_valueTypeProviderModule(); // QTBUG-43004 void test_customModuleCleanup(); + void test_qmlListCleared(); }; // A wrapper around QQmlComponent to ensure the temporary reference counts @@ -186,6 +187,18 @@ void tst_qqmlenginecleanup::test_customModuleCleanup() } } +void tst_qqmlenginecleanup::test_qmlListCleared() +{ + { + QQmlEngine engine; + auto url = testFileUrl("MyItem.qml"); + QQmlComponent comp(&engine, url); + QScopedPointer item {comp.create()}; + QCOMPARE(QQmlMetaType::qmlRegisteredListTypeCount(), 1); + } + QCOMPARE(QQmlMetaType::qmlRegisteredListTypeCount(), 0); +} + QTEST_MAIN(tst_qqmlenginecleanup) #include "tst_qqmlenginecleanup.moc" -- cgit v1.2.3 From dba4e7dae4c08ff08fbf1858e8bc5cc2b4cbb553 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Mon, 10 Feb 2020 16:32:56 +0100 Subject: Fix QQmlObjectModel::destroyingItem emission The signal is used to tell the view that the item is definitely going away. For the "view" based QQmlObjectModel that is almost never really the case, except - oddly - for clear(). The view is typically a QQuickItemView, which casts the item to a QQuickItem and calls setParentItem(nullptr). That in turn is caught by QQuickContainer, which calls remove() on the QQmlObjectModel. That is why remove() can't emit destroyingItem(). Amends 6d0a453f41d304239285d64b06612c36922be701 Change-Id: I5d82def872550744b947b4b53447647327e03f67 Reviewed-by: Ulf Hermann --- src/qmlmodels/qqmlobjectmodel.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/qmlmodels/qqmlobjectmodel.cpp b/src/qmlmodels/qqmlobjectmodel.cpp index d89ea702fa..90469d06c2 100644 --- a/src/qmlmodels/qqmlobjectmodel.cpp +++ b/src/qmlmodels/qqmlobjectmodel.cpp @@ -117,7 +117,6 @@ public: void replace(int index, QObject *item) { Q_Q(QQmlObjectModel); auto *attached = QQmlObjectModelAttached::properties(children.at(index).item); - emit q->destroyingItem(attached); attached->setIndex(-1); children.replace(index, Item(item)); QQmlObjectModelAttached::properties(children.at(index).item)->setIndex(index); @@ -160,7 +159,6 @@ public: Q_Q(QQmlObjectModel); for (int i = index; i < index + n; ++i) { QQmlObjectModelAttached *attached = QQmlObjectModelAttached::properties(children.at(i).item); - emit q->destroyingItem(attached); attached->setIndex(-1); } children.erase(children.begin() + index, children.begin() + index + n); @@ -176,6 +174,9 @@ public: } void clear() { + Q_Q(QQmlObjectModel); + for (const Item &child : qAsConst(children)) + emit q->destroyingItem(child.item); remove(0, children.count()); } -- cgit v1.2.3 From 897fd7f88b618484ed984b71933b02f40f072a5a Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Tue, 11 Feb 2020 06:29:13 +0100 Subject: Mention styleName in the Font QML type documentation Change-Id: I1f2ec7b4bb96955f57b3afd4a295f04dbb70987f Reviewed-by: Paul Wicking --- src/quick/doc/src/qmltypereference.qdoc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/quick/doc/src/qmltypereference.qdoc b/src/quick/doc/src/qmltypereference.qdoc index 418475f100..528444cad3 100644 --- a/src/quick/doc/src/qmltypereference.qdoc +++ b/src/quick/doc/src/qmltypereference.qdoc @@ -179,6 +179,7 @@ available when you import \c QtQuick. \li \l bool \c font.kerning \li \l bool \c font.preferShaping \li \l enumeration \c font.hintingPreference + \li \l string \c font.styleName \endlist Example: -- cgit v1.2.3 From 2e98ccde7b89bdb45c87c154d27566215533ac76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Klitzing?= Date: Mon, 10 Feb 2020 13:49:43 +0100 Subject: Remove /get from CMAKE_QML_DIR Task-number: QTBUG-80843 Change-Id: I3a871930c9920159f455a1d4e8ef7c20e7966b52 Reviewed-by: Joerg Bornemann Reviewed-by: Alexandru Croitor --- tools/qmlimportscanner/qmlimportscanner.pro | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/qmlimportscanner/qmlimportscanner.pro b/tools/qmlimportscanner/qmlimportscanner.pro index d69f1a3b0b..33089a5c48 100644 --- a/tools/qmlimportscanner/qmlimportscanner.pro +++ b/tools/qmlimportscanner/qmlimportscanner.pro @@ -14,9 +14,9 @@ contains(CMAKE_BIN_DIR, "^\\.\\./.*") { CMAKE_BIN_DIR_IS_ABSOLUTE = True } -CMAKE_QML_DIR = $$cmakeRelativePath($$[QT_INSTALL_QML/get], $$[QT_INSTALL_PREFIX]) +CMAKE_QML_DIR = $$cmakeRelativePath($$[QT_INSTALL_QML], $$[QT_INSTALL_PREFIX]) contains(CMAKE_QML_DIR, "^\\.\\./.*") { - CMAKE_QML_DIR = $$[QT_INSTALL_QML/get]/ + CMAKE_QML_DIR = $$[QT_INSTALL_QML]/ CMAKE_QML_DIR_IS_ABSOLUTE = True } load(qt_build_paths) -- cgit v1.2.3 From 2f4c131805f4009f42abe991e0f92f096bbc55fd Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Tue, 11 Feb 2020 11:21:03 +0100 Subject: Fix QQmlProperty and Connections for properties starting with '_' We do a weird renaming for the change handler of properties starting with '_', now we do it at least in a consistent way. Fixes: QTBUG-82017 Change-Id: I1535a5ee462f3a344c972461f1fb954f039aa854 Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlproperty.cpp | 9 +++++++-- src/qml/types/qqmlconnections.cpp | 3 ++- tests/auto/qml/qqmlconnections/data/underscore.qml | 14 ++++++++++++++ .../auto/qml/qqmlconnections/tst_qqmlconnections.cpp | 15 +++++++++++++++ tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp | 20 ++++++++++++++++++++ 5 files changed, 58 insertions(+), 3 deletions(-) create mode 100644 tests/auto/qml/qqmlconnections/data/underscore.qml diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp index d191d07258..86cb606f83 100644 --- a/src/qml/qml/qqmlproperty.cpp +++ b/src/qml/qml/qqmlproperty.cpp @@ -353,10 +353,15 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name) if (terminal.count() >= 3 && terminal.at(0) == QLatin1Char('o') && terminal.at(1) == QLatin1Char('n') && - terminal.at(2).isUpper()) { + (terminal.at(2).isUpper() || terminal.at(2) == '_')) { QString signalName = terminal.mid(2).toString(); - signalName[0] = signalName.at(0).toLower(); + int firstNon_; + int length = signalName.length(); + for (firstNon_ = 0; firstNon_ < length; ++firstNon_) + if (signalName.at(firstNon_) != '_') + break; + signalName[firstNon_] = signalName.at(firstNon_).toLower(); // XXX - this code treats methods as signals diff --git a/src/qml/types/qqmlconnections.cpp b/src/qml/types/qqmlconnections.cpp index 1e801641e5..4c44bba43e 100644 --- a/src/qml/types/qqmlconnections.cpp +++ b/src/qml/types/qqmlconnections.cpp @@ -238,7 +238,8 @@ void QQmlConnectionsParser::verifyBindings(const QQmlRefPointerstringAt(binding->propertyNameIndex); - if (!propName.startsWith(QLatin1String("on")) || (propName.length() < 3 || !propName.at(2).isUpper())) { + const bool thirdCharacterIsValid = (propName.length() >= 2) && (propName.at(2).isUpper() || propName.at(2) == '_'); + if (!propName.startsWith(QLatin1String("on")) || !thirdCharacterIsValid) { error(props.at(ii), QQmlConnections::tr("Cannot assign to non-existent property \"%1\"").arg(propName)); return; } diff --git a/tests/auto/qml/qqmlconnections/data/underscore.qml b/tests/auto/qml/qqmlconnections/data/underscore.qml new file mode 100644 index 0000000000..0f73dc8f17 --- /dev/null +++ b/tests/auto/qml/qqmlconnections/data/underscore.qml @@ -0,0 +1,14 @@ +import QtQuick 2.12 + +Item { + id: item + property bool success: false + property bool sanityCheck: false + property int __underscore_property: 0 + on__Underscore_propertyChanged: item.sanityCheck = true + + Connections { + target: item + on__Underscore_propertyChanged: item.success = true + } +} diff --git a/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp b/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp index 07af519a3d..f144002875 100644 --- a/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp +++ b/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp @@ -77,6 +77,8 @@ private slots: void noAcceleratedGlobalLookup_data() { prefixes(); } void noAcceleratedGlobalLookup(); + void bindToPropertyWithUnderscoreChangeHandler(); + private: QQmlEngine engine; void prefixes(); @@ -474,6 +476,19 @@ void tst_qqmlconnections::noAcceleratedGlobalLookup() QCOMPARE(val.toInt(), int(Proxy::EnumValue)); } +void tst_qqmlconnections::bindToPropertyWithUnderscoreChangeHandler() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("underscore.qml")); + QScopedPointer root {component.create()}; + QVERIFY(root); + QQmlProperty underscoreProperty(root.get(), "__underscore_property"); + QVERIFY(underscoreProperty.isValid()); + underscoreProperty.write(42); + QVERIFY(root->property("sanityCheck").toBool()); + QVERIFY(root->property("success").toBool()); +} + QTEST_MAIN(tst_qqmlconnections) #include "tst_qqmlconnections.moc" diff --git a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp index a15c00ad62..864a47e998 100644 --- a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp +++ b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp @@ -158,6 +158,8 @@ private slots: void copy(); void nestedQQmlPropertyMap(); + + void underscorePropertyChangeHandler(); private: QQmlEngine engine; }; @@ -2230,6 +2232,24 @@ void tst_qqmlproperty::nestedQQmlPropertyMap() QCOMPARE(success.read().toString(), QLatin1String("success")); } +void tst_qqmlproperty::underscorePropertyChangeHandler() +{ + QQmlEngine engine; + QQmlComponent component(&engine); + component.setData(R"( + import QtQuick 2.12 + + Item { + property int __withUnderScore + } + )", QUrl::fromLocalFile(".")); + QScopedPointer root { component.create() }; + QVERIFY(root); + QQmlProperty changeHandler(root.get(), "on__WithUnderScoreChanged"); + QVERIFY(changeHandler.isValid()); + QVERIFY(changeHandler.isSignalProperty()); +} + QTEST_MAIN(tst_qqmlproperty) #include "tst_qqmlproperty.moc" -- cgit v1.2.3 From a363aa3df44da399d2aeb8785608501eae50e600 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Tue, 11 Feb 2020 14:44:28 +0100 Subject: QQmlCustomParser: Resolve import namespaces Also, don't use plain QObject for testing registrations with extensions and foreign types. This interacts with other tests. Change-Id: I43df8a4e5b22def5a87f508130f1c7b4833ecfb6 Fixes: QTBUG-81970 Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlcustomparser.cpp | 31 +++++++++++++++++++----- tests/auto/qml/qqmllanguage/testtypes.h | 9 +++++-- tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp | 30 +++++++++++++++++++++++ 3 files changed, 62 insertions(+), 8 deletions(-) diff --git a/src/qml/qml/qqmlcustomparser.cpp b/src/qml/qml/qqmlcustomparser.cpp index a5f34dafdf..ecd5020482 100644 --- a/src/qml/qml/qqmlcustomparser.cpp +++ b/src/qml/qml/qqmlcustomparser.cpp @@ -131,8 +131,13 @@ int QQmlCustomParser::evaluateEnum(const QByteArray& script, bool *ok) const // * . // * .. - int dot = script.indexOf('.'); - if (dot == -1 || dot == script.length()-1) + auto nextDot = [&](int dot) { + const int nextDot = script.indexOf('.', dot + 1); + return (nextDot == script.length() - 1) ? -1 : nextDot; + }; + + int dot = nextDot(-1); + if (dot == -1) return -1; QString scope = QString::fromUtf8(script.left(dot)); @@ -143,18 +148,32 @@ int QQmlCustomParser::evaluateEnum(const QByteArray& script, bool *ok) const QQmlType type; if (imports.isT1()) { - imports.asT1()->resolveType(scope, &type, nullptr, nullptr, nullptr); + QQmlImportNamespace *ns = nullptr; + if (!imports.asT1()->resolveType(scope, &type, nullptr, nullptr, &ns)) + return -1; + if (!type.isValid() && ns != nullptr) { + dot = nextDot(dot); + if (dot == -1 || !imports.asT1()->resolveType(QString::fromUtf8(script.left(dot)), + &type, nullptr, nullptr, nullptr)) { + return -1; + } + } } else { QQmlTypeNameCache::Result result = imports.asT2()->query(scope); - if (result.isValid()) + if (result.isValid()) { type = result.type; + } else if (result.importNamespace) { + dot = nextDot(dot); + if (dot != -1) + type = imports.asT2()->query(QString::fromUtf8(script.left(dot))).type; + } } if (!type.isValid()) return -1; - int dot2 = script.indexOf('.', dot+1); - const bool dot2Valid = dot2 != -1 && dot2 != script.length()-1; + const int dot2 = nextDot(dot); + const bool dot2Valid = (dot2 != -1); QByteArray enumValue = script.mid(dot2Valid ? dot2 + 1 : dot + 1); QByteArray scopedEnumName = (dot2Valid ? script.mid(dot + 1, dot2 - dot - 1) : QByteArray()); if (!scopedEnumName.isEmpty()) diff --git a/tests/auto/qml/qqmllanguage/testtypes.h b/tests/auto/qml/qqmllanguage/testtypes.h index 39502372e6..148179cb9c 100644 --- a/tests/auto/qml/qqmllanguage/testtypes.h +++ b/tests/auto/qml/qqmllanguage/testtypes.h @@ -1440,17 +1440,22 @@ public: int base() const { return 43; } }; +class Local : public QObject +{ + Q_OBJECT +}; + class Foreign { Q_GADGET - QML_FOREIGN(QObject) + QML_FOREIGN(Local) QML_NAMED_ELEMENT(Foreign) }; class ForeignExtended { Q_GADGET - QML_FOREIGN(QObject) + QML_FOREIGN(Local) QML_NAMED_ELEMENT(ForeignExtended) QML_EXTENDED(Extension) }; diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index 4f2e203ec2..2112e0cffb 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -325,6 +325,7 @@ private slots: void overrideSingleton(); void arrayToContainer(); + void qualifiedScopeInCustomParser(); private: QQmlEngine engine; @@ -5667,6 +5668,35 @@ void tst_qqmllanguage::arrayToContainer() QCOMPARE(root->m_points.at(0), QPointF (2.0, 3.0) ); } +class EnumTester : public QObject +{ + Q_OBJECT +public: + enum Types + { + FIRST = 0, + SECOND, + THIRD + }; + Q_ENUM(Types) +}; + +void tst_qqmllanguage::qualifiedScopeInCustomParser() +{ + qmlRegisterUncreatableType("scoped.custom.test", 1, 0, "EnumTester", + "Object only creatable in C++"); + QQmlEngine engine; + QQmlComponent component(&engine); + component.setData("import QtQml.Models 2.12\n" + "import scoped.custom.test 1.0 as BACKEND\n" + "ListModel {\n" + " ListElement { text: \"a\"; type: BACKEND.EnumTester.FIRST }\n" + "}\n", QUrl()); + QVERIFY(component.isReady()); + QScopedPointer obj(component.create()); + QVERIFY(!obj.isNull()); +} + QTEST_MAIN(tst_qqmllanguage) #include "tst_qqmllanguage.moc" -- cgit v1.2.3 From e9e4dd50e765153d7f7f0d46fedf14d9aa2b3bec Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Tue, 11 Feb 2020 17:26:09 +0100 Subject: Modernize scarceresources snippets and adapt docs Also, make sure we can actually compile and test-run the snippets. Change-Id: I50d2bd85528ddbd8d6ad3f38e716b600df54a571 Reviewed-by: Paul Wicking --- .../scarceresources/avatarExample.cpp | 144 ++++++++++++--------- .../scarceresources/avatarExample.h | 3 + .../scarceresources/scarceresources.pro | 22 ++++ src/qml/doc/src/javascript/expressions.qdoc | 4 +- 4 files changed, 108 insertions(+), 65 deletions(-) create mode 100644 src/qml/doc/snippets/qml/integrating-javascript/scarceresources/scarceresources.pro diff --git a/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/avatarExample.cpp b/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/avatarExample.cpp index d74cc13d04..b41a9b4dff 100644 --- a/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/avatarExample.cpp +++ b/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/avatarExample.cpp @@ -51,84 +51,102 @@ #include "avatarExample.h" #include #include +#include -void registerTypes() +struct Expectations { -//![0] - qmlRegisterType("Qt.example", 1, 0, "AvatarExample"); -//![0] -} + QQmlEngine engine; -void expectOne() -{ + void expectOne() + { //![1] -QQmlComponent component(&engine, "exampleOne.qml"); -QObject *object = component.create(); -// The scarce resource will have been released automatically -// by this point, after the binding expression was evaluated. -delete object; + QQmlComponent component(&engine, "qrc:/exampleOne.qml"); + QObject *object = component.create(); + // The scarce resource will have been released automatically + // by this point, after the binding expression was evaluated. + bool expectedResult = (object->property("avatarWidth").toInt() == 100); + delete object; //![1] -} + Q_ASSERT(expectedResult); + } -void expectTwo() -{ + void expectTwo() + { //![2] -QQmlComponent component(&engine, "exampleTwo.qml"); -QObject *object = component.create(); -// The scarce resource will not have been released automatically -// after the binding expression was evaluated. -// Since the scarce resource was not released explicitly prior -// to the binding expression being evaluated, we get: -bool expectedResult = (object->property("avatar").isValid() == true); -delete object; + QQmlComponent component(&engine, "qrc:/exampleTwo.qml"); + QObject *object = component.create(); + // The scarce resource will not have been released automatically + // after the binding expression was evaluated. + // Since the scarce resource was not released explicitly prior + // to the binding expression being evaluated, we get: + bool expectedResult = (object->property("avatar").isValid() == true); + delete object; //![2] -} + Q_ASSERT(expectedResult); + } -void expectThree() -{ + void expectThree() + { //![3] -QQmlComponent component(&engine, "exampleThree.qml"); -QObject *object = component.create(); -// The resource was preserved explicitly during evaluation of the -// JavaScript expression. Thus, during property assignment, the -// scarce resource was still valid, and so we get: -bool expectedResult = (object->property("avatar").isValid() == true); -// The scarce resource will not be released until all references to -// the resource are released, and the JavaScript garbage collector runs. -delete object; + QQmlComponent component(&engine, "qrc:/exampleThree.qml"); + QObject *object = component.create(); + // The resource was preserved explicitly during evaluation of the + // JavaScript expression. Thus, during property assignment, the + // scarce resource was still valid, and so we get: + bool expectedResult = (object->property("avatar").isValid() == true); + // The scarce resource will not be released until all references to + // the resource are released, and the JavaScript garbage collector runs. + delete object; //![3] -} + Q_ASSERT(expectedResult); + } -void expectFour() -{ + void expectFour() + { //![4] -QQmlComponent component(&engine, "exampleFour.qml"); -QObject *object = component.create(); -// The scarce resource was explicitly preserved by the client during -// the importAvatar() function, and so the scarce resource -// remains valid until the explicit call to releaseAvatar(). As such, -// we get the expected results: -bool expectedResultOne = (object->property("avatarOne").isValid() == true); -bool expectedResultTwo = (object->property("avatarTwo").isValid() == false); -// Because the scarce resource referenced by avatarTwo was released explicitly, -// it will no longer be consuming any system resources (beyond what a normal -// JS Object would; that small overhead will exist until the JS GC runs, as per -// any other JavaScript object). -delete object; + QQmlComponent component(&engine, "qrc:/exampleFour.qml"); + QObject *object = component.create(); + // The scarce resource was explicitly preserved by the client during + // the importAvatar() function, and so the scarce resource + // remains valid until the explicit call to releaseAvatar(). As such, + // we get the expected results: + bool expectedResultOne = (object->property("avatarOne").isValid() == true); + bool expectedResultTwo = (object->property("avatarTwo").isValid() == false); + // Because the scarce resource referenced by avatarTwo was released explicitly, + // it will no longer be consuming any system resources (beyond what a normal + // JS Object would; that small overhead will exist until the JS GC runs, as per + // any other JavaScript object). + delete object; //![4] -} + Q_ASSERT(expectedResultOne); + Q_ASSERT(expectedResultTwo); + } -void expectFive() -{ + void expectFive() + { //![5] -QQmlComponent component(&engine, "exampleFive.qml"); -QObject *object = component.create(); -// We have the expected results: -bool expectedResultOne = (object->property("avatarOne").isValid() == false); -bool expectedResultTwo = (object->property("avatarTwo").isValid() == false); -// Because although only avatarTwo was explicitly released, -// avatarOne and avatarTwo were referencing the same -// scarce resource. -delete object; + QQmlComponent component(&engine, "qrc:/exampleFive.qml"); + QObject *object = component.create(); + // We have the expected results: + bool expectedResultOne = (object->property("avatarOne").isValid() == false); + bool expectedResultTwo = (object->property("avatarTwo").isValid() == false); + // Because although only avatarTwo was explicitly released, + // avatarOne and avatarTwo were referencing the same + // scarce resource. + delete object; //![5] + Q_ASSERT(expectedResultOne); + Q_ASSERT(expectedResultTwo); + } +}; + +int main(int argc, char *argv[]) +{ + QGuiApplication app(argc, argv); + Expectations expectations; + expectations.expectOne(); + expectations.expectTwo(); + expectations.expectThree(); + expectations.expectFour(); + expectations.expectFive(); } diff --git a/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/avatarExample.h b/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/avatarExample.h index fb9e238512..1acc3a1c2f 100644 --- a/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/avatarExample.h +++ b/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/avatarExample.h @@ -53,6 +53,7 @@ #include #include +#include //![0] // avatarExample.h @@ -60,6 +61,8 @@ class AvatarExample : public QObject { Q_OBJECT Q_PROPERTY(QPixmap avatar READ avatar WRITE setAvatar NOTIFY avatarChanged) + QML_ELEMENT + public: AvatarExample(QObject *parent = 0) : QObject(parent), m_value(100, 100) diff --git a/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/scarceresources.pro b/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/scarceresources.pro new file mode 100644 index 0000000000..d88f8f574c --- /dev/null +++ b/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/scarceresources.pro @@ -0,0 +1,22 @@ +QT += qml gui + +#![0] +CONFIG += qmltypes +QML_IMPORT_NAME = Qt.example +QML_IMPORT_MAJOR_VERSION = 1 +#![0] + +RESOURCES += \ + exampleFive.qml \ + exampleFour.js \ + exampleFour.qml \ + exampleOne.qml \ + exampleThree.js \ + exampleThree.qml \ + exampleTwo.qml + +HEADERS += \ + avatarExample.h + +SOURCES += \ + avatarExample.cpp diff --git a/src/qml/doc/src/javascript/expressions.qdoc b/src/qml/doc/src/javascript/expressions.qdoc index b83127389a..b27bde3cf9 100644 --- a/src/qml/doc/src/javascript/expressions.qdoc +++ b/src/qml/doc/src/javascript/expressions.qdoc @@ -147,7 +147,7 @@ Rectangle { TapHandler { id: inputHandler - onTapped: { + onTapped: { // arbitrary JavaScript expression console.log("Tapped!") } @@ -339,7 +339,7 @@ For the following examples, imagine that we have defined the following class: and that we have registered it with the QML type-system as follows: -\snippet qml/integrating-javascript/scarceresources/avatarExample.cpp 0 +\snippet qml/integrating-javascript/scarceresources/scarceresources.pro 0 The AvatarExample class has a property which is a pixmap. When the property is accessed in JavaScript scope, a copy of the resource will be created and -- cgit v1.2.3 From 38c03709236f6a2114ace7adf1b6bdcdfe8e4e18 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Tue, 11 Feb 2020 16:50:43 +0100 Subject: Doc: Fix "Extending QML" documentation It mentioned qmlRegisterType where that didn't exist anymore. Change-Id: If3e8c8ada746c720bff216df8c5f3fb618e09205 Reviewed-by: Simon Hausmann --- examples/qml/doc/src/qml-extending.qdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/qml/doc/src/qml-extending.qdoc b/examples/qml/doc/src/qml-extending.qdoc index 1ad3ae9a10..723e470d45 100644 --- a/examples/qml/doc/src/qml-extending.qdoc +++ b/examples/qml/doc/src/qml-extending.qdoc @@ -69,7 +69,7 @@ This example builds on: \li \l {Extending QML - Adding Types Example} \endlist -Shows how to use \l {QQmlEngine::}{qmlRegisterExtendedType()} to provide an +Shows how to use \l {QML_EXTENDED} to provide an \l {Registering Extension Objects}{extension object} to a \l QLineEdit without modifying or subclassing it. -- cgit v1.2.3 From 90b4528b846542bfa6f0723487315140b9de17b4 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Tue, 17 Sep 2019 18:10:59 +0200 Subject: Avoid discouraged patterns in examples In particular, use required properties where applicable, explicitly import QtQml where we use it, avoid unqualified access into the root scope of a component, use JavaScript functions with explicit parameters as signal handlers. Change-Id: I3eaaba47cc3c7a2a12d488e36f9eec145cedbb0e Reviewed-by: Fabian Kosmale Reviewed-by: Shawn Rutledge --- examples/qml/referenceexamples/binding/example.qml | 2 +- examples/qml/referenceexamples/signal/example.qml | 2 +- .../qml/referenceexamples/valuesource/example.qml | 2 +- .../quick/animation/basics/property-animation.qml | 1 + examples/quick/animation/behaviors/tvtennis.qml | 9 +- examples/quick/animation/behaviors/wigglytext.qml | 3 +- .../animation/pathanimation/pathanimation.qml | 1 + .../pathinterpolator/pathinterpolator.qml | 1 + examples/quick/animation/states/states.qml | 1 + examples/quick/draganddrop/tiles/DragTile.qml | 10 +- examples/quick/draganddrop/tiles/DropTile.qml | 2 +- .../externaldraganddrop/DragAndDropTextItem.qml | 23 ++- examples/quick/imageelements/animatedsprite.qml | 2 +- .../imageelements/content/BorderImageSelector.qml | 5 +- .../quick/imageelements/content/MyBorderImage.qml | 1 + .../keyinteraction/focus/Core/ContextMenu.qml | 3 +- .../quick/keyinteraction/focus/Core/GridMenu.qml | 21 +-- .../quick/keyinteraction/focus/Core/ListMenu.qml | 20 ++- .../keyinteraction/focus/Core/ListViewDelegate.qml | 6 +- .../quick/keyinteraction/focus/Core/TabMenu.qml | 11 +- examples/quick/keyinteraction/focus/focus.qml | 34 ++++- .../quick/localstorage/localstorage/Header.qml | 11 +- .../quick/localstorage/localstorage/MyDelegate.qml | 19 ++- .../localstorage/localstorage/localstorage.qml | 29 ++-- examples/quick/models/abstractitemmodel/main.cpp | 4 +- examples/quick/models/abstractitemmodel/view.qml | 10 +- examples/quick/models/objectlistmodel/main.cpp | 14 +- examples/quick/models/objectlistmodel/view.qml | 8 +- examples/quick/models/stringlistmodel/main.cpp | 14 +- examples/quick/models/stringlistmodel/view.qml | 8 +- .../quick/mousearea/mousearea-wheel-example.qml | 2 + examples/quick/mousearea/mousearea.qml | 6 +- .../particles/affectors/content/customaffector.qml | 4 +- .../particles/affectors/content/groupgoal.qml | 4 +- .../particles/emitters/content/burstandpulse.qml | 8 +- .../particles/emitters/content/customemitter.qml | 6 +- .../particles/imageparticle/content/sharing.qml | 26 ++-- .../quick/particles/itemparticle/particleview.qml | 13 +- .../quick/positioners/positioners-transitions.qml | 7 +- .../quick/quick-accessibility/content/Slider.qml | 7 +- .../layoutdirection/layoutdirection.qml | 61 ++++---- .../righttoleft/textalignment/textalignment.qml | 85 +++++++---- examples/quick/scenegraph/rendernode/main.qml | 2 +- examples/quick/shared/FlickrRssModel.qml | 2 +- examples/quick/shared/LauncherList.qml | 4 + examples/quick/shared/SimpleLauncherDelegate.qml | 7 +- examples/quick/shared/TabSet.qml | 9 +- examples/quick/tableview/gameoflife/main.qml | 8 +- examples/quick/tableview/pixelator/main.qml | 6 +- examples/quick/text/fonts/availableFonts.qml | 5 +- examples/quick/text/fonts/fonts.qml | 13 +- examples/quick/text/imgtag/TextWithImage.qml | 2 +- examples/quick/text/imgtag/imgtag.qml | 3 +- examples/quick/text/styledtext-layout.qml | 8 +- .../threading/threadedlistmodel/timedisplay.qml | 5 +- examples/quick/threading/workerscript/Spinner.qml | 1 + .../quick/threading/workerscript/workerscript.qml | 2 +- .../touchinteraction/flickable/content/Panel.qml | 168 ++++++++++----------- .../touchinteraction/flickable/corkboards.qml | 4 +- .../content/AugmentedTouchPoint.qml | 2 +- .../quick/views/delegatemodel/dragselection.qml | 5 +- examples/quick/views/delegatemodel/slideshow.qml | 4 +- examples/quick/views/gridview/gridview-example.qml | 10 +- .../views/listview/content/PressAndHoldButton.qml | 4 +- .../quick/views/listview/content/ToggleButton.qml | 2 +- examples/quick/views/listview/displaymargin.qml | 5 +- examples/quick/views/listview/dynamiclist.qml | 37 +++-- .../quick/views/listview/expandingdelegates.qml | 18 ++- examples/quick/views/listview/highlight.qml | 68 ++++----- examples/quick/views/listview/highlightranges.qml | 32 ++-- examples/quick/views/listview/sections.qml | 10 +- examples/quick/views/objectmodel/objectmodel.qml | 10 +- examples/quick/views/package/Delegate.qml | 10 +- examples/quick/views/package/view.qml | 4 +- examples/quick/window/AllScreens.qml | 8 +- examples/quick/window/CurrentScreen.qml | 4 +- examples/quick/window/Splash.qml | 4 +- examples/quick/window/window.qml | 63 ++++---- 78 files changed, 634 insertions(+), 421 deletions(-) diff --git a/examples/qml/referenceexamples/binding/example.qml b/examples/qml/referenceexamples/binding/example.qml index a89b4bc02e..b45ef6881b 100644 --- a/examples/qml/referenceexamples/binding/example.qml +++ b/examples/qml/referenceexamples/binding/example.qml @@ -62,7 +62,7 @@ BirthdayParty { shoe { size: 12; color: "white"; brand: "Nike"; price: 90.0 } } // ![0] - onPartyStarted: console.log("This party started rockin' at " + time); + onPartyStarted: (time) => { console.log("This party started rockin' at " + time); } Boy { diff --git a/examples/qml/referenceexamples/signal/example.qml b/examples/qml/referenceexamples/signal/example.qml index 42d6c44939..5d80d58867 100644 --- a/examples/qml/referenceexamples/signal/example.qml +++ b/examples/qml/referenceexamples/signal/example.qml @@ -53,7 +53,7 @@ import QtQuick 2.0 // For QColor BirthdayParty { // ![0] - onPartyStarted: console.log("This party started rockin' at " + time); + onPartyStarted: (time) => { console.log("This party started rockin' at " + time); } // ![0] host: Boy { diff --git a/examples/qml/referenceexamples/valuesource/example.qml b/examples/qml/referenceexamples/valuesource/example.qml index 0abb76261c..65d511058a 100644 --- a/examples/qml/referenceexamples/valuesource/example.qml +++ b/examples/qml/referenceexamples/valuesource/example.qml @@ -56,7 +56,7 @@ BirthdayParty { HappyBirthdaySong on announcement { name: "Bob Jones" } // ![0] - onPartyStarted: console.log("This party started rockin' at " + time); + onPartyStarted: (time) => { console.log("This party started rockin' at " + time); } host: Boy { diff --git a/examples/quick/animation/basics/property-animation.qml b/examples/quick/animation/basics/property-animation.qml index a764c395ee..8d640c9dda 100644 --- a/examples/quick/animation/basics/property-animation.qml +++ b/examples/quick/animation/basics/property-animation.qml @@ -48,6 +48,7 @@ ** ****************************************************************************/ +import QtQml 2.0 import QtQuick 2.0 Item { diff --git a/examples/quick/animation/behaviors/tvtennis.qml b/examples/quick/animation/behaviors/tvtennis.qml index 89d912777a..261f603de6 100644 --- a/examples/quick/animation/behaviors/tvtennis.qml +++ b/examples/quick/animation/behaviors/tvtennis.qml @@ -116,6 +116,13 @@ Rectangle { Rectangle { color: "#1e1b18"; x: page.width/2+50; y: 10; width: 20; height: 40 } Repeater { model: page.height / 20 - Rectangle { color: "#328930"; x: page.width/2-5; y: index * 20; width: 10; height: 10 } + Rectangle { + required property int index + color: "#328930" + x: page.width / 2 - 5 + y: index * 20 + width: 10 + height: 10 + } } } diff --git a/examples/quick/animation/behaviors/wigglytext.qml b/examples/quick/animation/behaviors/wigglytext.qml index cc2e086b51..81d4a8aef9 100644 --- a/examples/quick/animation/behaviors/wigglytext.qml +++ b/examples/quick/animation/behaviors/wigglytext.qml @@ -48,6 +48,7 @@ ** ****************************************************************************/ +import QtQml 2.0 import QtQuick 2.0 Rectangle { @@ -58,7 +59,7 @@ Rectangle { width: 320; height: 480; color: "#474747"; focus: true - Keys.onPressed: { + Keys.onPressed: (event) => { if (event.key == Qt.Key_Delete || event.key == Qt.Key_Backspace) container.remove() else if (event.text != "") { diff --git a/examples/quick/animation/pathanimation/pathanimation.qml b/examples/quick/animation/pathanimation/pathanimation.qml index b98fbebefc..ae96b32680 100644 --- a/examples/quick/animation/pathanimation/pathanimation.qml +++ b/examples/quick/animation/pathanimation/pathanimation.qml @@ -48,6 +48,7 @@ ** ****************************************************************************/ +import QtQml 2.0 import QtQuick 2.0 Rectangle { diff --git a/examples/quick/animation/pathinterpolator/pathinterpolator.qml b/examples/quick/animation/pathinterpolator/pathinterpolator.qml index 0c0d7bad46..07a82fc916 100644 --- a/examples/quick/animation/pathinterpolator/pathinterpolator.qml +++ b/examples/quick/animation/pathinterpolator/pathinterpolator.qml @@ -48,6 +48,7 @@ ** ****************************************************************************/ +import QtQml 2.0 import QtQuick 2.0 Rectangle { diff --git a/examples/quick/animation/states/states.qml b/examples/quick/animation/states/states.qml index 498fb6867c..5ff8e5318c 100644 --- a/examples/quick/animation/states/states.qml +++ b/examples/quick/animation/states/states.qml @@ -48,6 +48,7 @@ ** ****************************************************************************/ +import QtQml 2.0 import QtQuick 2.0 Rectangle { diff --git a/examples/quick/draganddrop/tiles/DragTile.qml b/examples/quick/draganddrop/tiles/DragTile.qml index 78fe7a483a..47f0ebed5e 100644 --- a/examples/quick/draganddrop/tiles/DragTile.qml +++ b/examples/quick/draganddrop/tiles/DragTile.qml @@ -53,7 +53,9 @@ import QtQuick 2.0 //! [0] Item { id: root - property string colorKey + + required property string colorKey + required property int modelData width: 64; height: 64 @@ -74,9 +76,9 @@ Item { anchors.verticalCenter: parent.verticalCenter anchors.horizontalCenter: parent.horizontalCenter - color: colorKey + color: root.colorKey - Drag.keys: [ colorKey ] + Drag.keys: [ root.colorKey ] Drag.active: mouseArea.drag.active Drag.hotSpot.x: 32 Drag.hotSpot.y: 32 @@ -85,7 +87,7 @@ Item { anchors.fill: parent color: "white" font.pixelSize: 48 - text: modelData + 1 + text: root.modelData + 1 horizontalAlignment:Text.AlignHCenter verticalAlignment: Text.AlignVCenter } diff --git a/examples/quick/draganddrop/tiles/DropTile.qml b/examples/quick/draganddrop/tiles/DropTile.qml index de4c0dee44..bf7101f0f6 100644 --- a/examples/quick/draganddrop/tiles/DropTile.qml +++ b/examples/quick/draganddrop/tiles/DropTile.qml @@ -64,7 +64,7 @@ DropArea { id: dropRectangle anchors.fill: parent - color: colorKey + color: dragTarget.colorKey states: [ State { diff --git a/examples/quick/externaldraganddrop/DragAndDropTextItem.qml b/examples/quick/externaldraganddrop/DragAndDropTextItem.qml index 9858a961c9..605dc07434 100644 --- a/examples/quick/externaldraganddrop/DragAndDropTextItem.qml +++ b/examples/quick/externaldraganddrop/DragAndDropTextItem.qml @@ -71,14 +71,18 @@ Rectangle { id: dropArea anchors.fill: parent keys: ["text/plain"] - onEntered: if (!acceptDropCB.checked) { - drag.accepted = false - rejectAnimation.start() + onEntered: (drag) => { + if (!acceptDropCB.checked) { + drag.accepted = false + rejectAnimation.start() + } } - onDropped: if (drop.hasText && acceptDropCB.checked) { - if (drop.proposedAction == Qt.MoveAction || drop.proposedAction == Qt.CopyAction) { - item.display = drop.text - drop.acceptProposedAction() + onDropped: (drop) => { + if (drop.hasText && acceptDropCB.checked) { + if (drop.proposedAction == Qt.MoveAction || drop.proposedAction == Qt.CopyAction) { + item.display = drop.text + drop.acceptProposedAction() + } } } } @@ -95,7 +99,10 @@ Rectangle { Drag.hotSpot.y: 0 Drag.mimeData: { "text/plain": item.display } Drag.dragType: Drag.Automatic - Drag.onDragFinished: if (dropAction == Qt.MoveAction) item.display = "" + Drag.onDragFinished: (dropAction) => { + if (dropAction == Qt.MoveAction) + item.display = "" + } } Examples.CheckBox { id: acceptDropCB diff --git a/examples/quick/imageelements/animatedsprite.qml b/examples/quick/imageelements/animatedsprite.qml index 0c6bf5e28d..cc5226882a 100644 --- a/examples/quick/imageelements/animatedsprite.qml +++ b/examples/quick/imageelements/animatedsprite.qml @@ -73,7 +73,7 @@ Item { MouseArea { anchors.fill: parent acceptedButtons: Qt.LeftButton | Qt.RightButton - onClicked: { + onClicked: (mouse) => { if (!sprite.running) sprite.start(); if (!sprite.paused) diff --git a/examples/quick/imageelements/content/BorderImageSelector.qml b/examples/quick/imageelements/content/BorderImageSelector.qml index 93ff5136bc..d8c2101be7 100644 --- a/examples/quick/imageelements/content/BorderImageSelector.qml +++ b/examples/quick/imageelements/content/BorderImageSelector.qml @@ -93,7 +93,10 @@ Item { Repeater { model: [ "Scale", "Repeat", "Scale/Repeat", "Round" ] delegate: Text { - text: model.modelData + required property string modelData + required property int index + + text: modelData anchors.verticalCenter: parent.verticalCenter x: (index - selector.curIdx) * 80 + 140 diff --git a/examples/quick/imageelements/content/MyBorderImage.qml b/examples/quick/imageelements/content/MyBorderImage.qml index 01d26a9630..3198de3bf1 100644 --- a/examples/quick/imageelements/content/MyBorderImage.qml +++ b/examples/quick/imageelements/content/MyBorderImage.qml @@ -48,6 +48,7 @@ ** ****************************************************************************/ +import QtQml 2.0 import QtQuick 2.0 Item { diff --git a/examples/quick/keyinteraction/focus/Core/ContextMenu.qml b/examples/quick/keyinteraction/focus/Core/ContextMenu.qml index c5430aa650..31b5e1b83d 100644 --- a/examples/quick/keyinteraction/focus/Core/ContextMenu.qml +++ b/examples/quick/keyinteraction/focus/Core/ContextMenu.qml @@ -52,6 +52,7 @@ import QtQuick 2.1 FocusScope { id: container + required property Item keyRightTarget property bool open: false @@ -62,7 +63,7 @@ FocusScope { anchors.fill: parent color: "#D1DBBD" focus: true - Keys.onRightPressed: mainView.focus = true + Keys.onRightPressed: container.keyRightTarget.focus = true Text { anchors { top: parent.top; horizontalCenter: parent.horizontalCenter; margins: 30 } diff --git a/examples/quick/keyinteraction/focus/Core/GridMenu.qml b/examples/quick/keyinteraction/focus/Core/GridMenu.qml index 3f62adc792..78d6654957 100644 --- a/examples/quick/keyinteraction/focus/Core/GridMenu.qml +++ b/examples/quick/keyinteraction/focus/Core/GridMenu.qml @@ -51,12 +51,11 @@ import QtQuick 2.1 FocusScope { + id: menu property alias interactive: gridView.interactive - - onActiveFocusChanged: { - if (activeFocus) - mainView.state = "showGridViews" - } + required property Item keyUpTarget + required property Item keyDownTarget + required property Item keyLeftTarget Rectangle { anchors.fill: parent @@ -73,13 +72,15 @@ FocusScope { focus: true model: 12 - KeyNavigation.up: tabMenu - KeyNavigation.down: listMenu - KeyNavigation.left: contextMenu + KeyNavigation.up: menu.keyUpTarget + KeyNavigation.down: menu.keyDownTarget + KeyNavigation.left: menu.keyLeftTarget delegate: Item { id: container - width: GridView.view.cellWidth; height: GridView.view.cellHeight + width: GridView.view.cellWidth + height: GridView.view.cellHeight + required property int index Rectangle { id: content @@ -97,7 +98,7 @@ FocusScope { hoverEnabled: true onClicked: { - container.GridView.view.currentIndex = index + container.GridView.view.currentIndex = container.index container.forceActiveFocus() } } diff --git a/examples/quick/keyinteraction/focus/Core/ListMenu.qml b/examples/quick/keyinteraction/focus/Core/ListMenu.qml index d8e9daba78..694ae3cac6 100644 --- a/examples/quick/keyinteraction/focus/Core/ListMenu.qml +++ b/examples/quick/keyinteraction/focus/Core/ListMenu.qml @@ -48,21 +48,22 @@ ** ****************************************************************************/ +import QtQml 2.1 import QtQuick 2.1 FocusScope { + id: menu clip: true - - onActiveFocusChanged: { - if (activeFocus) - mainView.state = "showListViews" - } + required property Item keyUpTarget + required property Item keyLeftTarget ListView { id: list1 y: activeFocus ? 10 : 40; width: parent.width / 3; height: parent.height - 20 focus: true - KeyNavigation.up: gridMenu; KeyNavigation.left: contextMenu; KeyNavigation.right: list2 + KeyNavigation.up: menu.keyUpTarget + KeyNavigation.left: menu.keyLeftTarget + KeyNavigation.right: list2 model: 10; cacheBuffer: 200 delegate: ListViewDelegate {} @@ -74,7 +75,9 @@ FocusScope { ListView { id: list2 y: activeFocus ? 10 : 40; x: parseInt(parent.width / 3); width: parent.width / 3; height: parent.height - 20 - KeyNavigation.up: gridMenu; KeyNavigation.left: list1; KeyNavigation.right: list3 + KeyNavigation.up: menu.keyUpTarget + KeyNavigation.left: list1 + KeyNavigation.right: list3 model: 10; cacheBuffer: 200 delegate: ListViewDelegate {} @@ -86,7 +89,8 @@ FocusScope { ListView { id: list3 y: activeFocus ? 10 : 40; x: parseInt(2 * parent.width / 3); width: parent.width / 3; height: parent.height - 20 - KeyNavigation.up: gridMenu; KeyNavigation.left: list2 + KeyNavigation.up: menu.keyUpTarget + KeyNavigation.left: list2 model: 10; cacheBuffer: 200 delegate: ListViewDelegate {} diff --git a/examples/quick/keyinteraction/focus/Core/ListViewDelegate.qml b/examples/quick/keyinteraction/focus/Core/ListViewDelegate.qml index b1dde9ddc5..5a2957eab0 100644 --- a/examples/quick/keyinteraction/focus/Core/ListViewDelegate.qml +++ b/examples/quick/keyinteraction/focus/Core/ListViewDelegate.qml @@ -52,6 +52,8 @@ import QtQuick 2.1 Item { id: container + required property int index + width: ListView.view.width; height: 60; anchors.leftMargin: 10; anchors.rightMargin: 10 Rectangle { @@ -67,7 +69,7 @@ Item { Text { id: label anchors.centerIn: content - text: "List element " + (index + 1) + text: "List element " + (container.index + 1) color: "#193441" font.pixelSize: 14 } @@ -78,7 +80,7 @@ Item { hoverEnabled: true onClicked: { - container.ListView.view.currentIndex = index + container.ListView.view.currentIndex = container.index container.forceActiveFocus() } } diff --git a/examples/quick/keyinteraction/focus/Core/TabMenu.qml b/examples/quick/keyinteraction/focus/Core/TabMenu.qml index a40e070b2c..11b3d005c3 100644 --- a/examples/quick/keyinteraction/focus/Core/TabMenu.qml +++ b/examples/quick/keyinteraction/focus/Core/TabMenu.qml @@ -51,10 +51,9 @@ import QtQuick 2.1 FocusScope { - onActiveFocusChanged: { - if (activeFocus) - mainView.state = "showTabViews" - } + id: menu + required property Item keyUpTarget + required property Item keyDownTarget Rectangle { anchors.fill: parent @@ -76,8 +75,8 @@ FocusScope { activeFocusOnTab: true focus: true - KeyNavigation.up: listMenu - KeyNavigation.down: gridMenu + KeyNavigation.up: menu.keyUpTarget + KeyNavigation.down: menu.keyDownTarget Rectangle { id: content diff --git a/examples/quick/keyinteraction/focus/focus.qml b/examples/quick/keyinteraction/focus/focus.qml index e07df57697..9db9ab48bc 100644 --- a/examples/quick/keyinteraction/focus/focus.qml +++ b/examples/quick/keyinteraction/focus/focus.qml @@ -48,6 +48,7 @@ ** ****************************************************************************/ +import QtQml 2.1 import QtQuick 2.1 import "Core" @@ -67,20 +68,45 @@ Rectangle { id: tabMenu y: 160; width: parent.width; height: 160 + keyUpTarget: listMenu + keyDownTarget: gridMenu + focus: true activeFocusOnTab: true + + onActiveFocusChanged: { + if (activeFocus) + mainView.state = "showTabViews" + } } GridMenu { id: gridMenu y: 320; width: parent.width; height: 320 activeFocusOnTab: true + + keyUpTarget: tabMenu + keyDownTarget: listMenu + keyLeftTarget: contextMenu + + onActiveFocusChanged: { + if (activeFocus) + mainView.state = "showGridViews" + } } ListMenu { id: listMenu y: 640; width: parent.width; height: 320 activeFocusOnTab: true + + keyUpTarget: gridMenu + keyLeftTarget: contextMenu + + onActiveFocusChanged: { + if (activeFocus) + mainView.state = "showListViews" + } } Rectangle { @@ -129,7 +155,13 @@ Rectangle { } } - ContextMenu { id: contextMenu; x: -265; width: 260; height: parent.height } + ContextMenu { + keyRightTarget: mainView + id: contextMenu + x: -265 + width: 260 + height: parent.height + } states: State { name: "contextMenuOpen" diff --git a/examples/quick/localstorage/localstorage/Header.qml b/examples/quick/localstorage/localstorage/Header.qml index e9446de55e..47879500a7 100644 --- a/examples/quick/localstorage/localstorage/Header.qml +++ b/examples/quick/localstorage/localstorage/Header.qml @@ -59,6 +59,9 @@ Item { width: Screen.width / 2 height: Screen.height / 7 + required property ListView listView + required property Text statusText + function insertrec() { var rowid = parseInt(JS.dbInsert(dateInput.text, descInput.text, distInput.text), 10) if (rowid) { @@ -148,7 +151,7 @@ Item { } onEditingFinished: { if (dateInput.text == "") { - statustext.text = "Please fill in the date" + root.statusText.text = "Please fill in the date" dateInput.forceActiveFocus() } } @@ -161,10 +164,10 @@ Item { activeFocusOnTab: true onEditingFinished: { if (descInput.text.length < 8) { - statustext.text = "Enter a description of minimum 8 characters" + root.statusText.text = "Enter a description of minimum 8 characters" descInput.forceActiveFocus() } else { - statustext.text = "" + root.statusText.text = "" } } } @@ -179,7 +182,7 @@ Item { } onEditingFinished: { if (distInput.text == "") { - statustext.text = "Please fill in the distance" + root.statusText.text = "Please fill in the distance" distInput.forceActiveFocus() } } diff --git a/examples/quick/localstorage/localstorage/MyDelegate.qml b/examples/quick/localstorage/localstorage/MyDelegate.qml index 63a83bfbae..e8575d4f7a 100644 --- a/examples/quick/localstorage/localstorage/MyDelegate.qml +++ b/examples/quick/localstorage/localstorage/MyDelegate.qml @@ -54,18 +54,27 @@ import QtQuick.Layouts 1.1 import "Database.js" as JS Item { + id: delegate + width: parent.width height: rDate.implicitHeight + required property int index + required property int distance + required property string trip_desc + required property string date + + signal clicked() + Rectangle { id: baseRec anchors.fill: parent opacity: 0.8 - color: index % 2 ? "lightgrey" : "grey" + color: delegate.index % 2 ? "lightgrey" : "grey" MouseArea { anchors.fill: parent - onClicked: listView.currentIndex = index + onClicked: delegate.clicked() } GridLayout { anchors.fill:parent @@ -73,21 +82,21 @@ Item { Text { id: rDate - text: date + text: delegate.date font.pixelSize: 22 Layout.preferredWidth: parent.width / 4 color: "black" } Text { id: rDesc - text: trip_desc + text: delegate.trip_desc Layout.fillWidth: true font.pixelSize: 22 color: "black" } Text { id: rDistance - text: distance + text: delegate.distance font.pixelSize: 22 Layout.alignment: Qt.AlignRight color: "black" diff --git a/examples/quick/localstorage/localstorage/localstorage.qml b/examples/quick/localstorage/localstorage/localstorage.qml index 41f5cbd561..418aab838e 100644 --- a/examples/quick/localstorage/localstorage/localstorage.qml +++ b/examples/quick/localstorage/localstorage/localstorage.qml @@ -55,6 +55,7 @@ import QtQuick.LocalStorage 2.0 import "Database.js" as JS Window { + id: window visible: true width: Screen.width / 2 height: Screen.height / 1.8 @@ -72,19 +73,21 @@ Window { Header { id: input Layout.fillWidth: true + listView: listView + statusText: statustext } RowLayout { MyButton { text: "New" onClicked: { input.initrec_new() - creatingNewEntry = true + window.creatingNewEntry = true listView.model.setProperty(listView.currentIndex, "id", 0) } } MyButton { id: saveButton - enabled: (creatingNewEntry || editingEntry) && listView.currentIndex != -1 + enabled: (window.creatingNewEntry || window.editingEntry) && listView.currentIndex != -1 text: "Save" onClicked: { var insertedRow = false; @@ -109,8 +112,8 @@ Window { if (insertedRow) { input.initrec() - creatingNewEntry = false - editingEntry = false + window.creatingNewEntry = false + window.editingEntry = false listView.forceLayout() } } @@ -118,20 +121,20 @@ Window { MyButton { id: editButton text: "Edit" - enabled: !creatingNewEntry && !editingEntry && listView.currentIndex != -1 + enabled: !window.creatingNewEntry && !window.editingEntry && listView.currentIndex != -1 onClicked: { input.editrec(listView.model.get(listView.currentIndex).date, listView.model.get(listView.currentIndex).trip_desc, listView.model.get(listView.currentIndex).distance, listView.model.get(listView.currentIndex).id) - editingEntry = true + window.editingEntry = true } } MyButton { id: deleteButton text: "Delete" - enabled: !creatingNewEntry && listView.currentIndex != -1 + enabled: !window.creatingNewEntry && listView.currentIndex != -1 onClicked: { JS.dbDeleteRow(listView.model.get(listView.currentIndex).id) listView.model.remove(listView.currentIndex, 1) @@ -145,7 +148,7 @@ Window { MyButton { id: cancelButton text: "Cancel" - enabled: (creatingNewEntry || editingEntry) && listView.currentIndex != -1 + enabled: (window.creatingNewEntry || window.editingEntry) && listView.currentIndex != -1 onClicked: { if (listView.model.get(listView.currentIndex).id === 0) { // This entry had an id of 0, which means it was being created and hadn't @@ -153,8 +156,8 @@ Window { listView.model.remove(listView.currentIndex, 1) } listView.forceLayout() - creatingNewEntry = false - editingEntry = false + window.creatingNewEntry = false + window.editingEntry = false input.initrec() } } @@ -176,9 +179,11 @@ Window { Layout.fillWidth: true Layout.fillHeight: true model: MyModel {} - delegate: MyDelegate {} + delegate: MyDelegate { + onClicked: listView.currentIndex = index + } // Don't allow changing the currentIndex while the user is creating/editing values. - enabled: !creatingNewEntry && !editingEntry + enabled: !window.creatingNewEntry && !window.editingEntry highlight: highlightBar highlightFollowsCurrentItem: true diff --git a/examples/quick/models/abstractitemmodel/main.cpp b/examples/quick/models/abstractitemmodel/main.cpp index 515f47ec30..dd5b368c6b 100644 --- a/examples/quick/models/abstractitemmodel/main.cpp +++ b/examples/quick/models/abstractitemmodel/main.cpp @@ -68,10 +68,8 @@ int main(int argc, char ** argv) QQuickView view; view.setResizeMode(QQuickView::SizeRootObjectToView); - QQmlContext *ctxt = view.rootContext(); - ctxt->setContextProperty("myModel", &model); + view.setInitialProperties({{"model", QVariant::fromValue(&model)}}); //![0] - view.setSource(QUrl("qrc:view.qml")); view.show(); diff --git a/examples/quick/models/abstractitemmodel/view.qml b/examples/quick/models/abstractitemmodel/view.qml index f699aa40c8..2b9f87df92 100644 --- a/examples/quick/models/abstractitemmodel/view.qml +++ b/examples/quick/models/abstractitemmodel/view.qml @@ -53,8 +53,14 @@ import QtQuick 2.0 ListView { width: 200; height: 250 - model: myModel - delegate: Text { text: "Animal: " + type + ", " + size } + required model + + delegate: Text { + required property string type + required property string size + + text: "Animal: " + type + ", " + size + } } //![0] diff --git a/examples/quick/models/objectlistmodel/main.cpp b/examples/quick/models/objectlistmodel/main.cpp index 977bbfb93b..8fbe7c183c 100644 --- a/examples/quick/models/objectlistmodel/main.cpp +++ b/examples/quick/models/objectlistmodel/main.cpp @@ -68,16 +68,16 @@ int main(int argc, char ** argv) { QGuiApplication app(argc, argv); - QList dataList; - dataList.append(new DataObject("Item 1", "red")); - dataList.append(new DataObject("Item 2", "green")); - dataList.append(new DataObject("Item 3", "blue")); - dataList.append(new DataObject("Item 4", "yellow")); + QList dataList = { + new DataObject("Item 1", "red"), + new DataObject("Item 2", "green"), + new DataObject("Item 3", "blue"), + new DataObject("Item 4", "yellow") + }; QQuickView view; view.setResizeMode(QQuickView::SizeRootObjectToView); - QQmlContext *ctxt = view.rootContext(); - ctxt->setContextProperty("myModel", QVariant::fromValue(dataList)); + view.setInitialProperties({{ "model", QVariant::fromValue(dataList) }}); //![0] view.setSource(QUrl("qrc:view.qml")); diff --git a/examples/quick/models/objectlistmodel/view.qml b/examples/quick/models/objectlistmodel/view.qml index d9a32aff14..ba0c905e1e 100644 --- a/examples/quick/models/objectlistmodel/view.qml +++ b/examples/quick/models/objectlistmodel/view.qml @@ -53,13 +53,15 @@ import QtQuick 2.0 //![0] ListView { width: 100; height: 100 + required model - model: myModel delegate: Rectangle { + required color + required property string name + height: 25 width: 100 - color: model.modelData.color - Text { text: name } + Text { text: parent.name } } } //![0] diff --git a/examples/quick/models/stringlistmodel/main.cpp b/examples/quick/models/stringlistmodel/main.cpp index 6b4db422a6..d9de69b3aa 100644 --- a/examples/quick/models/stringlistmodel/main.cpp +++ b/examples/quick/models/stringlistmodel/main.cpp @@ -68,15 +68,15 @@ int main(int argc, char ** argv) QGuiApplication app(argc, argv); //![0] - QStringList dataList; - dataList.append("Item 1"); - dataList.append("Item 2"); - dataList.append("Item 3"); - dataList.append("Item 4"); + QStringList dataList = { + "Item 1", + "Item 2", + "Item 3", + "Item 4" + }; QQuickView view; - QQmlContext *ctxt = view.rootContext(); - ctxt->setContextProperty("myModel", QVariant::fromValue(dataList)); + view.setInitialProperties({{ "model", QVariant::fromValue(dataList) }}); //![0] view.setSource(QUrl("qrc:view.qml")); diff --git a/examples/quick/models/stringlistmodel/view.qml b/examples/quick/models/stringlistmodel/view.qml index f74b7db1c1..e392284d0f 100644 --- a/examples/quick/models/stringlistmodel/view.qml +++ b/examples/quick/models/stringlistmodel/view.qml @@ -52,13 +52,15 @@ import QtQuick 2.0 //![0] ListView { - width: 100; height: 100 + width: 100 + height: 100 + required model - model: myModel delegate: Rectangle { + required property string modelData height: 25 width: 100 - Text { text: modelData } + Text { text: parent.modelData } } } //![0] diff --git a/examples/quick/mousearea/mousearea-wheel-example.qml b/examples/quick/mousearea/mousearea-wheel-example.qml index 44b9216285..5e8fba3ac3 100644 --- a/examples/quick/mousearea/mousearea-wheel-example.qml +++ b/examples/quick/mousearea/mousearea-wheel-example.qml @@ -63,6 +63,8 @@ Rectangle { model: ["#9ACD32", "#EEEEEE", "#FFD700", "#87CEEB"] Rectangle { + required property color modelData + property real scaleFactor: 1 height: 40 * scaleFactor diff --git a/examples/quick/mousearea/mousearea.qml b/examples/quick/mousearea/mousearea.qml index 1540d85fdd..cecbc2cfc8 100644 --- a/examples/quick/mousearea/mousearea.qml +++ b/examples/quick/mousearea/mousearea.qml @@ -76,7 +76,7 @@ Rectangle { onEntered: info.text = 'Entered' onExited: info.text = 'Exited (pressed=' + pressed + ')' - onPressed: { + onPressed: (mouse) => { if (mouse.button == Qt.LeftButton) buttonID = 'LeftButton' else if (mouse.button == Qt.RightButton) @@ -139,14 +139,14 @@ Rectangle { + ' (' + posInBox.x + ',' + posInBox.y + ' in window)' } - onReleased: { + onReleased: (mouse) => { btn.text = 'Released (isClick=' + mouse.isClick + ' wasHeld=' + mouse.wasHeld + ')' posInfo.text = '' } //! [clicks] onPressAndHold: btn.text = 'Press and hold' - onClicked: btn.text = 'Clicked (wasHeld=' + mouse.wasHeld + ')' + onClicked: (mouse) => { btn.text = 'Clicked (wasHeld=' + mouse.wasHeld + ')' } onDoubleClicked: btn.text = 'Double clicked' //! [clicks] } diff --git a/examples/quick/particles/affectors/content/customaffector.qml b/examples/quick/particles/affectors/content/customaffector.qml index 71646bcf39..6fabfb3ab2 100644 --- a/examples/quick/particles/affectors/content/customaffector.qml +++ b/examples/quick/particles/affectors/content/customaffector.qml @@ -81,7 +81,7 @@ Item { property real velocity: 1.5 width: parent.width height: parent.height - 100 - onAffectParticles: { + onAffectParticles: (particles, dt) => { /* //Linear movement if (particle.r == 0) { particle.r = Math.random() > 0.5 ? -1 : 1; @@ -117,7 +117,7 @@ Item { width: parent.width + 120 height: 100 anchors.bottom: parent.bottom - onAffectParticles: { + onAffectParticles: (particles, dt) => { for (var i=0; i { for (var i=0; i { + var pos = mouse.x / slider.width * (slider.maximumValue - slider.minimumValue) + + slider.minimumValue slider.value = pos } } diff --git a/examples/quick/righttoleft/layoutdirection/layoutdirection.qml b/examples/quick/righttoleft/layoutdirection/layoutdirection.qml index 4e3e93852c..de111ea025 100644 --- a/examples/quick/righttoleft/layoutdirection/layoutdirection.qml +++ b/examples/quick/righttoleft/layoutdirection/layoutdirection.qml @@ -84,8 +84,8 @@ Rectangle { Repeater { model: 3 Loader { - property int value: index - sourceComponent: positionerDelegate + required property int index + sourceComponent: PositionerDelegate {} } } } @@ -106,8 +106,8 @@ Rectangle { Repeater { model: 8 Loader { - property int value: index - sourceComponent: positionerDelegate + required property int index + sourceComponent: PositionerDelegate {} } } } @@ -128,8 +128,8 @@ Rectangle { Repeater { model: 8 Loader { - property int value: index - sourceComponent: positionerDelegate + required property int index + sourceComponent: PositionerDelegate {} } } } @@ -152,7 +152,7 @@ Rectangle { layoutDirection: root.direction orientation: Qt.Horizontal model: 48 - delegate: viewDelegate + delegate: ViewDelegate {} } Text { @@ -166,7 +166,7 @@ Rectangle { cellWidth: 50; cellHeight: 50 layoutDirection: root.direction model: 48 - delegate: viewDelegate + delegate: ViewDelegate {} } Rectangle { @@ -230,37 +230,36 @@ Rectangle { } } - Component { - id: positionerDelegate + component PositionerDelegate : Rectangle { + width: 40 + height: 40 + property int lightness: parent.index + 1; + color: Qt.rgba(0.8 / lightness, 0.8 / lightness, 0.8 / lightness, 1.0) + Text { + text: parent.lightness + color: "white" + font.pixelSize: 18 + anchors.centerIn: parent + } + } + + component ViewDelegate : Item { + id: delegateItem + required property int index + width: (listView.effectiveLayoutDirection == Qt.LeftToRight ? (index == 48 - 1) : (index == 0)) ? 40 : 50 Rectangle { width: 40; height: 40 - color: Qt.rgba(0.8/(parent.value+1),0.8/(parent.value+1),0.8/(parent.value+1),1.0) + color: Qt.rgba(0.5 + (48 - delegateItem.index) * Math.random() / 48, + 0.3 + delegateItem.index * Math.random() / 48, + 0.3 * Math.random(), + 1.0) Text { - text: parent.parent.value+1 + text: delegateItem.index + 1 color: "white" font.pixelSize: 18 anchors.centerIn: parent } } } - Component { - id: viewDelegate - Item { - width: (listView.effectiveLayoutDirection == Qt.LeftToRight ? (index == 48 - 1) : (index == 0)) ? 40 : 50 - Rectangle { - width: 40; height: 40 - color: Qt.rgba(0.5+(48 - index)*Math.random()/48, - 0.3+index*Math.random()/48, - 0.3*Math.random(), - 1.0) - Text { - text: index+1 - color: "white" - font.pixelSize: 18 - anchors.centerIn: parent - } - } - } - } } diff --git a/examples/quick/righttoleft/textalignment/textalignment.qml b/examples/quick/righttoleft/textalignment/textalignment.qml index c5790027f2..698917a3c0 100644 --- a/examples/quick/righttoleft/textalignment/textalignment.qml +++ b/examples/quick/righttoleft/textalignment/textalignment.qml @@ -93,18 +93,23 @@ Rectangle { width: 320 height: 320 id: editorTypeRow - model: editorType.length + model: root.editorType.length orientation: ListView.Horizontal cacheBuffer: 1000//Load the really expensive ones async if possible delegate: Item { + id: delegate + width: editorColumn.width height: editorColumn.height + + required property int index + Column { id: editorColumn spacing: 5 width: textColumn.width+10 Text { - text: root.editorType[index] + text: root.editorType[delegate.index] font.pixelSize: 16 anchors.horizontalCenter: parent.horizontalCenter } @@ -113,8 +118,8 @@ Rectangle { spacing: 5 anchors.horizontalCenter: parent.horizontalCenter Repeater { - model: textComponents.length - delegate: textComponents[index] + model: root.textComponents.length + delegate: root.textComponents[delegate.index] } } } @@ -203,9 +208,11 @@ Rectangle { Component { id: plainTextComponent Text { + required property int index + width: 180 text: root.text[index] - font.pixelSize: pxSz + font.pixelSize: root.pxSz wrapMode: Text.WordWrap horizontalAlignment: root.horizontalAlignment LayoutMirroring.enabled: root.mirror @@ -216,10 +223,10 @@ Rectangle { anchors.fill: parent } Text { - text: root.description[index] + text: root.description[parent.index] color: Qt.rgba(1,1,1,1.0) anchors.centerIn: parent - font.pixelSize: pxSz - 2 + font.pixelSize: root.pxSz - 2 Rectangle { z: -1 color: Qt.rgba(0.3, 0, 0, 0.3) @@ -228,7 +235,7 @@ Rectangle { } Text { color: "white" - text: shortText(parent.horizontalAlignment) + text: root.shortText(parent.horizontalAlignment) anchors { top: parent.top; right: parent.right; margins: 2 } } } @@ -237,9 +244,11 @@ Rectangle { Component { id: styledTextComponent Text { + required property int index + width: 180 text: root.text[index] - font.pixelSize: pxSz + font.pixelSize: root.pxSz wrapMode: Text.WordWrap horizontalAlignment: root.horizontalAlignment LayoutMirroring.enabled: root.mirror @@ -252,10 +261,10 @@ Rectangle { anchors.fill: parent } Text { - text: root.description[index] + text: root.description[parent.index] color: Qt.rgba(1,1,1,1.0) anchors.centerIn: parent - font.pixelSize: pxSz - 2 + font.pixelSize: root.pxSz - 2 Rectangle { z: -1 color: Qt.rgba(0.3, 0, 0, 0.3) @@ -264,7 +273,7 @@ Rectangle { } Text { color: "white" - text: shortText(parent.horizontalAlignment) + text: root.shortText(parent.horizontalAlignment) anchors { top: parent.top; right: parent.right; margins: 2 } } } @@ -273,9 +282,11 @@ Rectangle { Component { id: richTextComponent Text { + required property int index + width: 180 text: root.text[index] - font.pixelSize: pxSz + font.pixelSize: root.pxSz wrapMode: Text.WordWrap horizontalAlignment: root.horizontalAlignment LayoutMirroring.enabled: root.mirror @@ -286,10 +297,10 @@ Rectangle { anchors.fill: parent } Text { - text: root.description[index] + text: root.description[parent.index] color: Qt.rgba(1,1,1,1.0) anchors.centerIn: parent - font.pixelSize: pxSz - 2 + font.pixelSize: root.pxSz - 2 Rectangle { z: -1 color: Qt.rgba(0.3, 0, 0, 0.3) @@ -298,7 +309,7 @@ Rectangle { } Text { color: "white" - text: shortText(parent.horizontalAlignment) + text: root.shortText(parent.horizontalAlignment) anchors { top: parent.top; right: parent.right; margins: 2 } } } @@ -307,9 +318,11 @@ Rectangle { Component { id: italicRichTextComponent Text { + required property int index + width: 180 text: "" + root.text[index] + "" - font.pixelSize: pxSz + font.pixelSize: root.pxSz wrapMode: Text.WordWrap horizontalAlignment: root.horizontalAlignment LayoutMirroring.enabled: root.mirror @@ -321,10 +334,10 @@ Rectangle { anchors.fill: parent } Text { - text: root.description[index] + text: root.description[parent.index] color: Qt.rgba(1,1,1,1.0) anchors.centerIn: parent - font.pixelSize: pxSz - 2 + font.pixelSize: root.pxSz - 2 Rectangle { z: -1 color: Qt.rgba(0.3, 0, 0, 0.3) @@ -333,7 +346,7 @@ Rectangle { } Text { color: "white" - text: shortText(parent.horizontalAlignment) + text: root.shortText(parent.horizontalAlignment) anchors { top: parent.top; right: parent.right; margins: 2 } } } @@ -342,9 +355,11 @@ Rectangle { Component { id: plainTextEdit TextEdit { + required property int index + width: 180 text: root.text[index] - font.pixelSize: pxSz + font.pixelSize: root.pxSz cursorVisible: true wrapMode: TextEdit.WordWrap horizontalAlignment: root.horizontalAlignment @@ -355,10 +370,10 @@ Rectangle { anchors.fill: parent } Text { - text: root.description[index] + text: root.description[parent.index] color: Qt.rgba(1,1,1,1.0) anchors.centerIn: parent - font.pixelSize: pxSz - 2 + font.pixelSize: root.pxSz - 2 Rectangle { z: -1 color: Qt.rgba(0.3, 0, 0, 0.3) @@ -367,7 +382,7 @@ Rectangle { } Text { color: "white" - text: shortText(parent.horizontalAlignment) + text: root.shortText(parent.horizontalAlignment) anchors { top: parent.top; right: parent.right; margins: 2 } } } @@ -376,9 +391,11 @@ Rectangle { Component { id: italicTextEdit TextEdit { + required property int index + width: 180 text: "" + root.text[index] + "" - font.pixelSize: pxSz + font.pixelSize: root.pxSz cursorVisible: true wrapMode: TextEdit.WordWrap textFormat: TextEdit.RichText @@ -390,10 +407,10 @@ Rectangle { anchors.fill: parent } Text { - text: root.description[index] + text: root.description[parent.index] color: Qt.rgba(1,1,1,1.0) anchors.centerIn: parent - font.pixelSize: pxSz - 2 + font.pixelSize: root.pxSz - 2 Rectangle { z: -1 color: Qt.rgba(0.3, 0, 0, 0.3) @@ -402,7 +419,7 @@ Rectangle { } Text { color: "white" - text: shortText(parent.horizontalAlignment) + text: root.shortText(parent.horizontalAlignment) anchors { top: parent.top; right: parent.right; margins: 2 } } } @@ -411,13 +428,15 @@ Rectangle { Component { id: textInput Item { + id: textDelegate + required property int index width: 180 height: textInput.text.length > 20 ? 3*textInput.height : textInput.height TextInput { id: textInput width: 180 - text: root.text[index] - font.pixelSize: pxSz + text: root.text[textDelegate.index] + font.pixelSize: root.pxSz cursorVisible: true horizontalAlignment: root.horizontalAlignment LayoutMirroring.enabled: root.mirror @@ -427,10 +446,10 @@ Rectangle { anchors.fill: parent } Text { - text: root.description[index] + text: root.description[textDelegate.index] color: Qt.rgba(1,1,1,1.0) anchors.centerIn: parent - font.pixelSize: pxSz - 2 + font.pixelSize: root.pxSz - 2 Rectangle { z: -1 color: Qt.rgba(0.3, 0, 0, 0.3) @@ -439,7 +458,7 @@ Rectangle { } Text { color: "white" - text: shortText(parent.horizontalAlignment) + text: root.shortText(parent.horizontalAlignment) anchors { top: parent.top; right: parent.right; margins: 2 } } } diff --git a/examples/quick/scenegraph/rendernode/main.qml b/examples/quick/scenegraph/rendernode/main.qml index 153a71e097..5631df317c 100644 --- a/examples/quick/scenegraph/rendernode/main.qml +++ b/examples/quick/scenegraph/rendernode/main.qml @@ -66,7 +66,7 @@ Item { MouseArea { anchors.fill: parent acceptedButtons: Qt.LeftButton | Qt.RightButton - onClicked: { + onClicked: (mouse) => { if (mouse.button === Qt.LeftButton) { clipper.clip = !clipper.clip } else if (mouse.button === Qt.RightButton) { diff --git a/examples/quick/shared/FlickrRssModel.qml b/examples/quick/shared/FlickrRssModel.qml index 5f88fabcae..2fb4412ba1 100644 --- a/examples/quick/shared/FlickrRssModel.qml +++ b/examples/quick/shared/FlickrRssModel.qml @@ -72,7 +72,7 @@ ListModel { var jsonText = xhr.responseText; var objArray = JSON.parse(jsonText.replace(/\'/g,"'")) if (objArray.errors !== undefined) - console.log(lCategory, "Error fetching tweets: " + imageItems.errors[0].message) + console.log("Error fetching tweets: " + objArray.errors[0].message) else { for (var key in objArray.items) { var rssItem = objArray.items[key]; diff --git a/examples/quick/shared/LauncherList.qml b/examples/quick/shared/LauncherList.qml index 9859b5b635..cb13ec4372 100644 --- a/examples/quick/shared/LauncherList.qml +++ b/examples/quick/shared/LauncherList.qml @@ -48,6 +48,9 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ + +import QtQml 2.12 +import QtQml.Models 2.12 import QtQuick 2.12 Rectangle { @@ -75,6 +78,7 @@ Rectangle { id: launcherList clip: true delegate: SimpleLauncherDelegate{ + required property url url onClicked: root.showExample(url) } model: ListModel {id:myModel} diff --git a/examples/quick/shared/SimpleLauncherDelegate.qml b/examples/quick/shared/SimpleLauncherDelegate.qml index 7f07dea52a..dd29b8b821 100644 --- a/examples/quick/shared/SimpleLauncherDelegate.qml +++ b/examples/quick/shared/SimpleLauncherDelegate.qml @@ -55,6 +55,9 @@ Rectangle { width: ListView.view.width height: button.implicitHeight + 22 + required property string name + required property string description + signal clicked() gradient: Gradient { @@ -110,7 +113,7 @@ Rectangle { anchors.leftMargin: 10 anchors.right: parent.right anchors.rightMargin: 10 - text: name + text: container.name color: "black" font.pixelSize: 22 wrapMode: Text.WrapAtWordBoundaryOrAnywhere @@ -122,7 +125,7 @@ Rectangle { id: buttonLabel2 anchors.left: parent.left anchors.leftMargin: 10 - text: description + text: container.description wrapMode: Text.WrapAtWordBoundaryOrAnywhere color: "#666" font.pixelSize: 12 diff --git a/examples/quick/shared/TabSet.qml b/examples/quick/shared/TabSet.qml index 9e2759c3ec..ab8476ad44 100644 --- a/examples/quick/shared/TabSet.qml +++ b/examples/quick/shared/TabSet.qml @@ -78,6 +78,7 @@ Item { Repeater { model: stack.children.length delegate: Rectangle { + required property int index width: tabWidget.width / stack.children.length height: Math.max(Screen.pixelDensity * 7, label.implicitHeight * 1.2) @@ -90,18 +91,18 @@ Item { anchors { fill: parent; leftMargin: 2; topMargin: 5; rightMargin: 1 } border { left: 7; right: 7 } source: "images/tab.png" - visible: tabWidget.current == index + visible: tabWidget.current == parent.index } Text { id: label horizontalAlignment: Qt.AlignHCenter; verticalAlignment: Qt.AlignVCenter anchors.fill: parent - text: stack.children[index].title + text: stack.children[parent.index].title elide: Text.ElideRight - font.bold: tabWidget.current == index + font.bold: tabWidget.current == parent.index } TapHandler { - onTapped: tabWidget.current = index + onTapped: tabWidget.current = parent.index } } } diff --git a/examples/quick/tableview/gameoflife/main.qml b/examples/quick/tableview/gameoflife/main.qml index 90be69b9c0..fb3195892f 100644 --- a/examples/quick/tableview/gameoflife/main.qml +++ b/examples/quick/tableview/gameoflife/main.qml @@ -48,6 +48,7 @@ ** ****************************************************************************/ +import QtQml 2.12 import QtQuick 2.12 import QtQuick.Window 2.3 import QtQuick.Controls 2.2 @@ -81,11 +82,14 @@ ApplicationWindow { implicitWidth: 15 implicitHeight: 15 - color: model.value ? "#f3f3f4" : "#b5b7bf" + required property var model + required property bool value + + color: value ? "#f3f3f4" : "#b5b7bf" MouseArea { anchors.fill: parent - onClicked: model.value = !model.value + onClicked: parent.model.value = !parent.value } } //! [tableview] diff --git a/examples/quick/tableview/pixelator/main.qml b/examples/quick/tableview/pixelator/main.qml index 38a25f439f..a5edefae90 100644 --- a/examples/quick/tableview/pixelator/main.qml +++ b/examples/quick/tableview/pixelator/main.qml @@ -65,7 +65,9 @@ Window { id: pixelDelegate Item { - readonly property real gray: model.display / 255.0 + required property real display + + readonly property real gray: display / 255.0 readonly property real size: 16 implicitWidth: size @@ -77,7 +79,7 @@ Window { id: rect anchors.centerIn: parent color: "#09102b" - radius: size - gray * size + radius: parent.size - parent.gray * parent.size implicitWidth: radius implicitHeight: radius //! [rectshape] diff --git a/examples/quick/text/fonts/availableFonts.qml b/examples/quick/text/fonts/availableFonts.qml index ea3bff22b8..41dbae0021 100644 --- a/examples/quick/text/fonts/availableFonts.qml +++ b/examples/quick/text/fonts/availableFonts.qml @@ -61,11 +61,12 @@ Rectangle { delegate: Item { height: 40; width: ListView.view.width + required property string modelData Text { anchors.centerIn: parent - text: modelData + text: parent.modelData //! [delegate] - font.family: modelData + font.family: parent.modelData //! [delegate] font.pixelSize: 20 color: "white" diff --git a/examples/quick/text/fonts/fonts.qml b/examples/quick/text/fonts/fonts.qml index d356e00417..4478db0135 100644 --- a/examples/quick/text/fonts/fonts.qml +++ b/examples/quick/text/fonts/fonts.qml @@ -51,6 +51,7 @@ import QtQuick 2.0 Rectangle { + id: root property string myText: "The quick brown fox jumps over the lazy dog." width: 320; height: 480 @@ -71,7 +72,7 @@ Rectangle { spacing: 15 Text { - text: myText + text: root.myText color: "lightsteelblue" width: parent.width wrapMode: Text.WordWrap @@ -81,7 +82,7 @@ Rectangle { font.pixelSize: 20 } Text { - text: myText + text: root.myText color: "lightsteelblue" width: parent.width wrapMode: Text.WordWrap @@ -89,7 +90,7 @@ Rectangle { font { family: "Times"; pixelSize: 20; capitalization: Font.AllUppercase } } Text { - text: myText + text: root.myText color: "lightsteelblue" width: parent.width horizontalAlignment: Text.AlignRight @@ -97,14 +98,14 @@ Rectangle { font { family: fixedFont.name; pixelSize: 20; weight: Font.Bold; capitalization: Font.AllLowercase } } Text { - text: myText + text: root.myText color: "lightsteelblue" width: parent.width wrapMode: Text.WordWrap font { family: fixedFont.name; pixelSize: 20; italic: true; capitalization: Font.SmallCaps } } Text { - text: myText + text: root.myText color: "lightsteelblue" width: parent.width wrapMode: Text.WordWrap @@ -112,7 +113,7 @@ Rectangle { } Text { text: { - if (webFont.status == FontLoader.Ready) myText + if (webFont.status == FontLoader.Ready) root.myText else if (webFont.status == FontLoader.Loading) "Loading..." else if (webFont.status == FontLoader.Error) "Error loading font" } diff --git a/examples/quick/text/imgtag/TextWithImage.qml b/examples/quick/text/imgtag/TextWithImage.qml index 1cb65e739d..d22e93146d 100644 --- a/examples/quick/text/imgtag/TextWithImage.qml +++ b/examples/quick/text/imgtag/TextWithImage.qml @@ -55,5 +55,5 @@ Text { font.pointSize: 14 wrapMode: Text.WordWrap textFormat: Text.StyledText - horizontalAlignment: main.hAlign + horizontalAlignment: parent.hAlign } diff --git a/examples/quick/text/imgtag/imgtag.qml b/examples/quick/text/imgtag/imgtag.qml index 1790853de2..177008940a 100644 --- a/examples/quick/text/imgtag/imgtag.qml +++ b/examples/quick/text/imgtag/imgtag.qml @@ -56,7 +56,7 @@ Rectangle { focus: true color: "#dedede" - property var hAlign: Text.AlignLeft + property int hAlign: Text.AlignLeft Flickable { anchors.fill: parent @@ -68,6 +68,7 @@ Rectangle { x: 10; y: 10 spacing: 20 width: parent.width - 20 + property int hAlign: main.hAlign TextWithImage { text: "This is a happy face" diff --git a/examples/quick/text/styledtext-layout.qml b/examples/quick/text/styledtext-layout.qml index 631a37b493..b399b638dc 100644 --- a/examples/quick/text/styledtext-layout.qml +++ b/examples/quick/text/styledtext-layout.qml @@ -71,12 +71,12 @@ Rectangle { text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer at ante dui www.digia.com.
Curabitur ante est, pulvinar quis adipiscing a, iaculis id ipsum. Nunc blandit condimentum odio vel egestas.
  • Coffee
    1. Espresso
    2. Cappuccino
    3. Latte
  • Juice
    1. Orange
    2. Apple
    3. Pineapple
    4. Tomato

Proin consectetur sapien in ipsum lacinia sit amet mattis orci interdum. Quisque vitae accumsan lectus. Ut nisi turpis, sollicitudin ut dignissim id, fermentum ac est. Maecenas nec libero leo. Sed ac leo eget ipsum ultricies viverra sit amet eu orci. Praesent et tortor risus, viverra accumsan sapien. Sed faucibus eleifend lectus, sed euismod urna porta eu. Quisque vitae accumsan lectus. Ut nisi turpis, sollicitudin ut dignissim id, fermentum ac est. Maecenas nec libero leo. Sed ac leo eget ipsum ultricies viverra sit amet eu orci." //! [layout] - onLineLaidOut: { - line.width = width / 2 - (margin) + onLineLaidOut: (line) => { + line.width = width / 2 - main.margin if (line.y + line.height >= height) { - line.y -= height - margin - line.x = width / 2 + margin + line.y -= height - main.margin + line.x = width / 2 + main.activeFocusmargin } if (line.isLast) { diff --git a/examples/quick/threading/threadedlistmodel/timedisplay.qml b/examples/quick/threading/threadedlistmodel/timedisplay.qml index 5ad901c676..c4e6e7b249 100644 --- a/examples/quick/threading/threadedlistmodel/timedisplay.qml +++ b/examples/quick/threading/threadedlistmodel/timedisplay.qml @@ -59,7 +59,10 @@ Rectangle { anchors.fill: parent model: listModel delegate: Component { - Text { text: time } + Text { + required property string time + text: time + } } ListModel { id: listModel } diff --git a/examples/quick/threading/workerscript/Spinner.qml b/examples/quick/threading/workerscript/Spinner.qml index 9c70090dba..a2257f8639 100644 --- a/examples/quick/threading/workerscript/Spinner.qml +++ b/examples/quick/threading/workerscript/Spinner.qml @@ -78,6 +78,7 @@ Rectangle { clip: true model: 64 delegate: Text { + required property int index font.pixelSize: 18; color: "white"; text: index; diff --git a/examples/quick/threading/workerscript/workerscript.qml b/examples/quick/threading/workerscript/workerscript.qml index 735cc8d1f1..eb8ad43d01 100644 --- a/examples/quick/threading/workerscript/workerscript.qml +++ b/examples/quick/threading/workerscript/workerscript.qml @@ -58,7 +58,7 @@ Rectangle { id: myWorker source: "workerscript.mjs" - onMessage: { + onMessage: (messageObject) => { if (messageObject.row == rowSpinner.value && messageObject.column == columnSpinner.value){ //Not an old result if (messageObject.result == -1) resultText.text = "Column must be <= Row"; diff --git a/examples/quick/touchinteraction/flickable/content/Panel.qml b/examples/quick/touchinteraction/flickable/content/Panel.qml index 21f8fc8afd..0aae0635b2 100644 --- a/examples/quick/touchinteraction/flickable/content/Panel.qml +++ b/examples/quick/touchinteraction/flickable/content/Panel.qml @@ -50,112 +50,106 @@ import QtQuick 2.0 -Component { - Item { - property variant stickies +Item { + required property string name + required property var notes - id: page - width: ListView.view.width+40; height: ListView.view.height + property real horizontalVelocity: 0 + id: page + width: ListView.view.width+40; height: ListView.view.height - Image { - source: "cork.jpg" - width: page.ListView.view.width - height: page.ListView.view.height - fillMode: Image.PreserveAspectCrop - clip: true - } - - MouseArea { - anchors.fill: parent - onClicked: page.focus = false; - } - Text { - text: name; x: 15; y: 8; height: 40; width: 370 - font.pixelSize: 18; font.bold: true; color: "white" - style: Text.Outline; styleColor: "black" - } + Image { + source: "cork.jpg" + width: page.ListView.view.width + height: page.ListView.view.height + fillMode: Image.PreserveAspectCrop + clip: true + } - Repeater { - model: notes - Item { - id: stickyPage + MouseArea { + anchors.fill: parent + onClicked: page.focus = false; + } - property int randomX: Math.random() * (page.ListView.view.width-0.5*stickyImage.width) +100 - property int randomY: Math.random() * (page.ListView.view.height-0.5*stickyImage.height) +50 + Text { + text: page.name; x: 15; y: 8; height: 40; width: 370 + font.pixelSize: 18; font.bold: true; color: "white" + style: Text.Outline; styleColor: "black" + } - x: randomX; y: randomY + Repeater { + model: page.notes + Item { + id: stickyPage + required property string noteText - rotation: -flickable.horizontalVelocity / 100; - Behavior on rotation { - SpringAnimation { spring: 2.0; damping: 0.15 } - } + property int randomX: Math.random() * (page.ListView.view.width-0.5*stickyImage.width) +100 + property int randomY: Math.random() * (page.ListView.view.height-0.5*stickyImage.height) +50 - Item { - id: sticky - scale: 0.7 - - Image { - id: stickyImage - x: 8 + -width * 0.6 / 2; y: -20 - source: "note-yellow.png" - scale: 0.6; transformOrigin: Item.TopLeft - } + x: randomX; y: randomY - TextEdit { - id: myText - x: -104; y: 36; width: 215; height: 200 - font.pixelSize: 24 - readOnly: false - rotation: -8 - text: noteText - } + rotation: -page.horizontalVelocity / 100 + Behavior on rotation { + SpringAnimation { spring: 2.0; damping: 0.15 } + } - Item { - x: stickyImage.x; y: -20 - width: stickyImage.width * stickyImage.scale - height: stickyImage.height * stickyImage.scale - - MouseArea { - id: mouse - anchors.fill: parent - drag.target: stickyPage - drag.axis: Drag.XAndYAxis - drag.minimumY: 0 - drag.maximumY: page.height - 80 - drag.minimumX: 100 - drag.maximumX: page.width - 140 - onClicked: myText.forceActiveFocus() - } - } - } + Item { + id: sticky + scale: 0.7 Image { - x: -width / 2; y: -height * 0.5 / 2 - source: "tack.png" - scale: 0.7; transformOrigin: Item.TopLeft + id: stickyImage + x: 8 + -width * 0.6 / 2; y: -20 + source: "note-yellow.png" + scale: 0.6; transformOrigin: Item.TopLeft } - states: State { - name: "pressed" - when: mouse.pressed - PropertyChanges { target: sticky; rotation: 8; scale: 1 } - PropertyChanges { target: page; z: 8 } + TextEdit { + id: myText + x: -104; y: 36; width: 215; height: 200 + font.pixelSize: 24 + readOnly: false + rotation: -8 + text: stickyPage.noteText } - transitions: Transition { - NumberAnimation { properties: "rotation,scale"; duration: 200 } + Item { + x: stickyImage.x; y: -20 + width: stickyImage.width * stickyImage.scale + height: stickyImage.height * stickyImage.scale + + MouseArea { + id: mouse + anchors.fill: parent + drag.target: stickyPage + drag.axis: Drag.XAndYAxis + drag.minimumY: 0 + drag.maximumY: page.height - 80 + drag.minimumX: 100 + drag.maximumX: page.width - 140 + onClicked: myText.forceActiveFocus() + } } } - } - } -} - - - - - + Image { + x: -width / 2; y: -height * 0.5 / 2 + source: "tack.png" + scale: 0.7; transformOrigin: Item.TopLeft + } + states: State { + name: "pressed" + when: mouse.pressed + PropertyChanges { target: sticky; rotation: 8; scale: 1 } + PropertyChanges { target: page; z: 8 } + } + transitions: Transition { + NumberAnimation { properties: "rotation,scale"; duration: 200 } + } + } + } +} diff --git a/examples/quick/touchinteraction/flickable/corkboards.qml b/examples/quick/touchinteraction/flickable/corkboards.qml index afb5dd309c..4825053f3f 100644 --- a/examples/quick/touchinteraction/flickable/corkboards.qml +++ b/examples/quick/touchinteraction/flickable/corkboards.qml @@ -92,6 +92,8 @@ Rectangle { orientation: ListView.Horizontal snapMode: ListView.SnapOneItem model: list - delegate: Panel { } + delegate: Panel { + horizontalVelocity: flickable.horizontalVelocity + } } } diff --git a/examples/quick/touchinteraction/multipointtouch/content/AugmentedTouchPoint.qml b/examples/quick/touchinteraction/multipointtouch/content/AugmentedTouchPoint.qml index 5750ffcad1..56f287666f 100644 --- a/examples/quick/touchinteraction/multipointtouch/content/AugmentedTouchPoint.qml +++ b/examples/quick/touchinteraction/multipointtouch/content/AugmentedTouchPoint.qml @@ -66,7 +66,7 @@ TouchPoint { interval: 100 running: false repeat: false - onTriggered: child.enabled = false + onTriggered: container.child.enabled = false } property Item child: SpriteGoal { enabled: false diff --git a/examples/quick/views/delegatemodel/dragselection.qml b/examples/quick/views/delegatemodel/dragselection.qml index 15fd2654c2..f9a0d37311 100644 --- a/examples/quick/views/delegatemodel/dragselection.qml +++ b/examples/quick/views/delegatemodel/dragselection.qml @@ -48,6 +48,7 @@ ** ****************************************************************************/ +import QtQml 2.0 import QtQuick 2.0 import QtQml.Models 2.1 @@ -64,6 +65,8 @@ Item { Package { id: packageRoot + required property var modelData + MouseArea { id: visibleContainer Package.name: "visible" @@ -130,7 +133,7 @@ Item { horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter color: "white" - text: modelData + text: packageRoot.modelData font.pixelSize: 18 } diff --git a/examples/quick/views/delegatemodel/slideshow.qml b/examples/quick/views/delegatemodel/slideshow.qml index b252519bbf..638c8bf10f 100644 --- a/examples/quick/views/delegatemodel/slideshow.qml +++ b/examples/quick/views/delegatemodel/slideshow.qml @@ -74,6 +74,8 @@ Rectangle { width: 76; height: 76 + required property string thumbnail + Rectangle { id: image x: 0; y: 0; width: 76; height: 76 @@ -86,7 +88,7 @@ Rectangle { anchors.leftMargin: 1 anchors.topMargin: 1 - source: thumbnail + source: delegateItem.thumbnail fillMode: Image.PreserveAspectFit } diff --git a/examples/quick/views/gridview/gridview-example.qml b/examples/quick/views/gridview/gridview-example.qml index 76a1d8dd37..4cc30d3736 100644 --- a/examples/quick/views/gridview/gridview-example.qml +++ b/examples/quick/views/gridview/gridview-example.qml @@ -74,20 +74,24 @@ Rectangle { highlight: Rectangle { width: 80; height: 80; color: "lightsteelblue" } delegate: Item { + required property string icon + required property string name + required property int index + width: 100; height: 100 Image { id: myIcon y: 20; anchors.horizontalCenter: parent.horizontalCenter - source: icon + source: parent.icon } Text { anchors { top: myIcon.bottom; horizontalCenter: parent.horizontalCenter } - text: name + text: parent.name } MouseArea { anchors.fill: parent - onClicked: parent.GridView.view.currentIndex = index + onClicked: parent.GridView.view.currentIndex = parent.index } } } diff --git a/examples/quick/views/listview/content/PressAndHoldButton.qml b/examples/quick/views/listview/content/PressAndHoldButton.qml index 527394eb4d..6d633c0264 100644 --- a/examples/quick/views/listview/content/PressAndHoldButton.qml +++ b/examples/quick/views/listview/content/PressAndHoldButton.qml @@ -72,12 +72,12 @@ Image { PropertyAction { target: container; property: "pressed"; value: true } ScriptAction { script: container.clicked() } - PauseAnimation { duration: repeatDelay } + PauseAnimation { duration: container.repeatDelay } SequentialAnimation { loops: Animation.Infinite ScriptAction { script: container.clicked() } - PauseAnimation { duration: repeatDuration } + PauseAnimation { duration: container.repeatDuration } } } diff --git a/examples/quick/views/listview/content/ToggleButton.qml b/examples/quick/views/listview/content/ToggleButton.qml index 0a2747a683..890a94570b 100644 --- a/examples/quick/views/listview/content/ToggleButton.qml +++ b/examples/quick/views/listview/content/ToggleButton.qml @@ -63,6 +63,6 @@ Rectangle { Text { id: text; anchors.centerIn: parent; font.pixelSize: 14 } MouseArea { anchors.fill: parent - onClicked: { active = !active; root.toggled() } + onClicked: { root.active = !root.active; root.toggled() } } } diff --git a/examples/quick/views/listview/displaymargin.qml b/examples/quick/views/listview/displaymargin.qml index e0024e72a9..19261caaa6 100644 --- a/examples/quick/views/listview/displaymargin.qml +++ b/examples/quick/views/listview/displaymargin.qml @@ -68,10 +68,13 @@ Item { width: parent.width height: 25 color: index % 2 ? "steelblue" : "lightsteelblue" + + required property int index + Text { anchors.centerIn: parent color: "white" - text: "Item " + (index + 1) + text: "Item " + (parent.index + 1) } } } diff --git a/examples/quick/views/listview/dynamiclist.qml b/examples/quick/views/listview/dynamiclist.qml index bfc697d094..f37aab98e2 100644 --- a/examples/quick/views/listview/dynamiclist.qml +++ b/examples/quick/views/listview/dynamiclist.qml @@ -101,6 +101,11 @@ Rectangle { width: listView.width; height: 80 clip: true + required property int index + required property string name + required property real cost + required property var attributes + Column { id: arrows anchors { @@ -109,10 +114,16 @@ Rectangle { } Image { source: "content/pics/arrow-up.png" - MouseArea { anchors.fill: parent; onClicked: fruitModel.move(index, index-1, 1) } + MouseArea { + anchors.fill: parent + onClicked: fruitModel.move(delegateItem.index, delegateItem.index - 1, 1) + } } Image { source: "content/pics/arrow-down.png" - MouseArea { anchors.fill: parent; onClicked: fruitModel.move(index, index+1, 1) } + MouseArea { + anchors.fill: parent + onClicked: fruitModel.move(delegateItem.index, delegateItem.index + 1, 1) + } } } @@ -125,7 +136,7 @@ Rectangle { Text { anchors.horizontalCenter: parent.horizontalCenter - text: name + text: delegateItem.name font.pixelSize: 15 color: "white" } @@ -133,8 +144,12 @@ Rectangle { anchors.horizontalCenter: parent.horizontalCenter spacing: 5 Repeater { - model: attributes - Text { text: description; color: "White" } + model: delegateItem.attributes + Text { + required property string description + text: description + color: "White" + } } } } @@ -154,13 +169,13 @@ Rectangle { PressAndHoldButton { anchors.verticalCenter: parent.verticalCenter source: "content/pics/plus-sign.png" - onClicked: fruitModel.setProperty(index, "cost", cost + 0.25) + onClicked: fruitModel.setProperty(delegateItem.index, "cost", delegateItem.cost + 0.25) } Text { id: costText anchors.verticalCenter: parent.verticalCenter - text: '$' + Number(cost).toFixed(2) + text: '$' + Number(delegateItem.cost).toFixed(2) font.pixelSize: 15 color: "white" font.bold: true @@ -169,12 +184,16 @@ Rectangle { PressAndHoldButton { anchors.verticalCenter: parent.verticalCenter source: "content/pics/minus-sign.png" - onClicked: fruitModel.setProperty(index, "cost", Math.max(0,cost-0.25)) + onClicked: fruitModel.setProperty(delegateItem.index, "cost", + Math.max(0, delegateItem.cost - 0.25)) } Image { source: "content/pics/list-delete.png" - MouseArea { anchors.fill:parent; onClicked: fruitModel.remove(index) } + MouseArea { + anchors.fill: parent + onClicked: fruitModel.remove(delegateItem.index) + } } } } diff --git a/examples/quick/views/listview/expandingdelegates.qml b/examples/quick/views/listview/expandingdelegates.qml index 1308e8441d..6ed1d8c341 100644 --- a/examples/quick/views/listview/expandingdelegates.qml +++ b/examples/quick/views/listview/expandingdelegates.qml @@ -67,6 +67,11 @@ Rectangle { Item { id: recipe + required property string title + required property string picture + required property string ingredients + required property string method + // Create a property to contain the visibility of the details. // We can bind multiple element's opacity to this one property, // rather than having a "PropertyChanges" line for each element we @@ -106,7 +111,7 @@ Rectangle { Image { id: recipeImage width: 50; height: 50 - source: picture + source: recipe.picture } //! [1] Column { @@ -114,7 +119,7 @@ Rectangle { spacing: 5 Text { - text: title + text: recipe.title font.bold: true; font.pointSize: 16 } @@ -125,7 +130,7 @@ Rectangle { } SmallText { - text: ingredients + text: recipe.ingredients wrapMode: Text.WordWrap width: parent.width opacity: recipe.detailsOpacity @@ -155,7 +160,12 @@ Rectangle { contentHeight: methodText.height clip: true - Text { id: methodText; text: method; wrapMode: Text.WordWrap; width: details.width } + Text { + id: methodText + text: recipe.method + wrapMode: Text.WordWrap + width: details.width + } } Image { diff --git a/examples/quick/views/listview/highlight.qml b/examples/quick/views/listview/highlight.qml index 5b03d30f25..092b4d59bd 100644 --- a/examples/quick/views/listview/highlight.qml +++ b/examples/quick/views/listview/highlight.qml @@ -58,44 +58,44 @@ import "content" Rectangle { width: 200; height: 300 - // Define a delegate component. A component will be + // Define a delegate component. The component will be // instantiated for each visible item in the list. - Component { - id: petDelegate - Item { - id: wrapper - width: 200; height: 55 - Column { - SmallText { text: 'Name: ' + name } - SmallText { text: 'Type: ' + type } - SmallText { text: 'Age: ' + age } - } - // indent the item if it is the current item - states: State { - name: "Current" - when: wrapper.ListView.isCurrentItem - PropertyChanges { target: wrapper; x: 20 } - } - transitions: Transition { - NumberAnimation { properties: "x"; duration: 200 } - } - MouseArea { - anchors.fill: parent - onClicked: wrapper.ListView.view.currentIndex = index - } + component PetDelegate: Item { + id: pet + width: 200; height: 55 + + required property int index + required property string name + required property string type + required property int age + + Column { + SmallText { text: 'Name: ' + pet.name } + SmallText { text: 'Type: ' + pet.type } + SmallText { text: 'Age: ' + pet.age } + } + // indent the item if it is the current item + states: State { + name: "Current" + when: pet.ListView.isCurrentItem + PropertyChanges { target: pet; x: 20 } + } + transitions: Transition { + NumberAnimation { properties: "x"; duration: 200 } + } + MouseArea { + anchors.fill: parent + onClicked: pet.ListView.view.currentIndex = pet.index } } //! [0] // Define a highlight with customized movement between items. - Component { - id: highlightBar - Rectangle { - width: 200; height: 50 - color: "#FFFF88" - y: listView.currentItem.y; - Behavior on y { SpringAnimation { spring: 2; damping: 0.1 } } - } + component HighlightBar : Rectangle { + width: 200; height: 50 + color: "#FFFF88" + y: listView.currentItem.y + Behavior on y { SpringAnimation { spring: 2; damping: 0.1 } } } ListView { @@ -104,12 +104,12 @@ Rectangle { x: 30 model: PetsModel {} - delegate: petDelegate + delegate: PetDelegate {} focus: true // Set the highlight delegate. Note we must also set highlightFollowsCurrentItem // to false so the highlight delegate can control how the highlight is moved. - highlight: highlightBar + highlight: HighlightBar {} highlightFollowsCurrentItem: false } //! [0] diff --git a/examples/quick/views/listview/highlightranges.qml b/examples/quick/views/listview/highlightranges.qml index 7bc9ab7fe1..dafd064332 100644 --- a/examples/quick/views/listview/highlightranges.qml +++ b/examples/quick/views/listview/highlightranges.qml @@ -62,17 +62,17 @@ Rectangle { loops: -1 running: true ScriptAction { - script: if (increasing) { - current++; - if (current >= aModel.count -1) { - current = aModel.count - 1; - increasing = !increasing; + script: if (root.increasing) { + root.current++; + if (root.current >= aModel.count -1) { + root.current = aModel.count - 1; + root.increasing = !root.increasing; } } else { - current--; - if (current <= 0) { - current = 0; - increasing = !increasing; + root.current--; + if (root.current <= 0) { + root.current = 0; + root.increasing = !root.increasing; } } } @@ -161,16 +161,22 @@ Rectangle { Item { width: 160 height: column.height + + required property int index + required property string name + required property string type + required property int age + Column { id: column - Text { text: 'Name: ' + name } - Text { text: 'Type: ' + type } - Text { text: 'Age: ' + age } + Text { text: 'Name: ' + parent.name } + Text { text: 'Type: ' + parent.type } + Text { text: 'Age: ' + parent.age } } MouseArea { anchors.fill: parent - onClicked: root.current = index + onClicked: root.current = parent.index } } } diff --git a/examples/quick/views/listview/sections.qml b/examples/quick/views/listview/sections.qml index 75b0f5c6d9..d51ed89789 100644 --- a/examples/quick/views/listview/sections.qml +++ b/examples/quick/views/listview/sections.qml @@ -87,8 +87,10 @@ Rectangle { height: childrenRect.height color: "lightsteelblue" + required property string section + Text { - text: section + text: parent.section font.bold: true font.pixelSize: 20 } @@ -101,7 +103,11 @@ Rectangle { anchors.bottom: buttonBar.top width: parent.width model: animalsModel - delegate: Text { text: name; font.pixelSize: 18 } + delegate: Text { + required property string name + text: name + font.pixelSize: 18 + } section.property: "size" section.criteria: ViewSection.FullString diff --git a/examples/quick/views/objectmodel/objectmodel.qml b/examples/quick/views/objectmodel/objectmodel.qml index 8fc2f7c386..c9e4b8a5cd 100644 --- a/examples/quick/views/objectmodel/objectmodel.qml +++ b/examples/quick/views/objectmodel/objectmodel.qml @@ -70,21 +70,21 @@ Rectangle { color: "#FFFEF0" Text { text: "Page 1"; font.bold: true; anchors.centerIn: parent } - Component.onDestruction: if (printDestruction) print("destroyed 1") + Component.onDestruction: if (root.printDestruction) print("destroyed 1") } Rectangle { width: view.width; height: view.height color: "#F0FFF7" Text { text: "Page 2"; font.bold: true; anchors.centerIn: parent } - Component.onDestruction: if (printDestruction) print("destroyed 2") + Component.onDestruction: if (root.printDestruction) print("destroyed 2") } Rectangle { width: view.width; height: view.height color: "#F4F0FF" Text { text: "Page 3"; font.bold: true; anchors.centerIn: parent } - Component.onDestruction: if (printDestruction) print("destroyed 3") + Component.onDestruction: if (root.activeFocusprintDestruction) print("destroyed 3") } } @@ -112,6 +112,8 @@ Rectangle { model: itemModel.count Rectangle { + required property int index + width: 5; height: 5 radius: 3 color: view.currentIndex == index ? "blue" : "white" @@ -119,7 +121,7 @@ Rectangle { MouseArea { width: 20; height: 20 anchors.centerIn: parent - onClicked: view.currentIndex = index + onClicked: view.currentIndex = parent.index } } } diff --git a/examples/quick/views/package/Delegate.qml b/examples/quick/views/package/Delegate.qml index 7c73f35c3d..9f4f1946d8 100644 --- a/examples/quick/views/package/Delegate.qml +++ b/examples/quick/views/package/Delegate.qml @@ -52,6 +52,12 @@ import QtQuick 2.0 //! [0] Package { + id: delegate + + required property int upTo + required property int index + required property string display + Text { id: listDelegate; width: parent.width; height: 25; text: 'Empty'; Package.name: 'list' } Text { id: gridDelegate; width: parent.width / 2; height: 50; text: 'Empty'; Package.name: 'grid' } @@ -60,8 +66,8 @@ Package { width: parent.width; height: 25 color: 'lightsteelblue' - Text { text: display; anchors.centerIn: parent } - state: root.upTo > index ? 'inGrid' : 'inList' + Text { text: delegate.display; anchors.centerIn: parent } + state: delegate.upTo > delegate.index ? 'inGrid' : 'inList' states: [ State { name: 'inList' diff --git a/examples/quick/views/package/view.qml b/examples/quick/views/package/view.qml index 311cc3be8e..632d27c724 100644 --- a/examples/quick/views/package/view.qml +++ b/examples/quick/views/package/view.qml @@ -77,7 +77,9 @@ Rectangle { //![0] DelegateModel { id: visualModel - delegate: Delegate {} + delegate: Delegate { + upTo: root.upTo + } model: myModel } diff --git a/examples/quick/window/AllScreens.qml b/examples/quick/window/AllScreens.qml index a5da380025..ac0e1cb821 100644 --- a/examples/quick/window/AllScreens.qml +++ b/examples/quick/window/AllScreens.qml @@ -69,8 +69,14 @@ Column { id: screenInfo model: Qt.application.screens Shared.Label { + required property string name + required property int virtualX + required property int virtualY + required property int width + required property int height + lineHeight: 1.5 - text: name + "\n" + virtualX + ", " + virtualY + " " + modelData.width + "x" + modelData.height + text: name + "\n" + virtualX + ", " + virtualY + " " + width + "x" + height } } } diff --git a/examples/quick/window/CurrentScreen.qml b/examples/quick/window/CurrentScreen.qml index 2703582399..563cca32a5 100644 --- a/examples/quick/window/CurrentScreen.qml +++ b/examples/quick/window/CurrentScreen.qml @@ -115,10 +115,10 @@ Item { Shared.Label { text: Screen.virtualX + ", " + Screen.virtualY } Shared.Label { text: "orientation" } - Shared.Label { text: orientationToString(Screen.orientation) + " (" + Screen.orientation + ")" } + Shared.Label { text: root.orientationToString(Screen.orientation) + " (" + Screen.orientation + ")" } Shared.Label { text: "primary orientation" } - Shared.Label { text: orientationToString(Screen.primaryOrientation) + " (" + Screen.primaryOrientation + ")" } + Shared.Label { text: root.orientationToString(Screen.primaryOrientation) + " (" + Screen.primaryOrientation + ")" } //! [screen] Shared.Label { text: "10mm rectangle" } diff --git a/examples/quick/window/Splash.qml b/examples/quick/window/Splash.qml index c3e36d9b3b..b33ad6c168 100644 --- a/examples/quick/window/Splash.qml +++ b/examples/quick/window/Splash.qml @@ -78,9 +78,9 @@ Window { } //! [timer] Timer { - interval: timeoutInterval; running: true; repeat: false + interval: splash.timeoutInterval; running: true; repeat: false onTriggered: { - visible = false + splash.visible = false splash.timeout() } } diff --git a/examples/quick/window/window.qml b/examples/quick/window/window.qml index 2ee7fb6e09..4280b6a4c0 100644 --- a/examples/quick/window/window.qml +++ b/examples/quick/window/window.qml @@ -53,65 +53,66 @@ import QtQuick.Window 2.3 import "../shared" as Shared QtObject { + id: root property real defaultSpacing: 10 property SystemPalette palette: SystemPalette { } property var controlWindow: Window { - width: col.implicitWidth + defaultSpacing * 2 - height: col.implicitHeight + defaultSpacing * 2 - color: palette.window + width: col.implicitWidth + root.defaultSpacing * 2 + height: col.implicitHeight + root.defaultSpacing * 2 + color: root.palette.window title: "Control Window" Column { id: col anchors.fill: parent - anchors.margins: defaultSpacing - spacing: defaultSpacing + anchors.margins: root.defaultSpacing + spacing: root.defaultSpacing property real cellWidth: col.width / 3 - spacing Shared.Label { text: "Control the second window:" } Grid { id: grid columns: 3 - spacing: defaultSpacing + spacing: root.defaultSpacing width: parent.width Shared.Button { id: showButton width: col.cellWidth - text: testWindow.visible ? "Hide" : "Show" - onClicked: testWindow.visible = !testWindow.visible + text: root.testWindow.visible ? "Hide" : "Show" + onClicked: root.testWindow.visible = !root.testWindow.visible } //! [windowedCheckbox] Shared.CheckBox { text: "Windowed" height: showButton.height width: col.cellWidth - Binding on checked { value: testWindow.visibility === Window.Windowed } - onClicked: testWindow.visibility = Window.Windowed + Binding on checked { value: root.testWindow.visibility === Window.Windowed } + onClicked: root.testWindow.visibility = Window.Windowed } //! [windowedCheckbox] Shared.CheckBox { height: showButton.height width: col.cellWidth text: "Full Screen" - Binding on checked { value: testWindow.visibility === Window.FullScreen } - onClicked: testWindow.visibility = Window.FullScreen + Binding on checked { value: root.testWindow.visibility === Window.FullScreen } + onClicked: root.testWindow.visibility = Window.FullScreen } Shared.Button { id: autoButton width: col.cellWidth text: "Automatic" - onClicked: testWindow.visibility = Window.AutomaticVisibility + onClicked: root.testWindow.visibility = Window.AutomaticVisibility } Shared.CheckBox { height: autoButton.height text: "Minimized" - Binding on checked { value: testWindow.visibility === Window.Minimized } - onClicked: testWindow.visibility = Window.Minimized + Binding on checked { value: root.testWindow.visibility === Window.Minimized } + onClicked: root.testWindow.visibility = Window.Minimized } Shared.CheckBox { height: autoButton.height text: "Maximized" - Binding on checked { value: testWindow.visibility === Window.Maximized } - onClicked: testWindow.visibility = Window.Maximized + Binding on checked { value: root.testWindow.visibility === Window.Maximized } + onClicked: root.testWindow.visibility = Window.Maximized } } function visibilityToString(v) { @@ -133,17 +134,17 @@ QtObject { } Shared.Label { id: visibilityLabel - text: "second window is " + (testWindow.visible ? "visible" : "invisible") + - " and has visibility " + parent.visibilityToString(testWindow.visibility) + text: "second window is " + (root.testWindow.visible ? "visible" : "invisible") + + " and has visibility " + parent.visibilityToString(root.testWindow.visibility) } Rectangle { - color: palette.text + color: root.palette.text width: parent.width height: 1 } CurrentScreen { } Rectangle { - color: palette.text + color: root.palette.text width: parent.width height: 1 } @@ -159,40 +160,40 @@ QtObject { flags: Qt.Window | Qt.WindowFullscreenButtonHint Rectangle { anchors.fill: parent - anchors.margins: defaultSpacing + anchors.margins: root.defaultSpacing Shared.Label { anchors.centerIn: parent text: "Second Window" } MouseArea { anchors.fill: parent - onClicked: testWindow.color = "#e0c31e" + onClicked: root.testWindow.color = "#e0c31e" } Shared.Button { anchors.right: parent.right anchors.top: parent.top - anchors.margins: defaultSpacing - text: testWindow.visibility === Window.FullScreen ? "exit fullscreen" : "go fullscreen" + anchors.margins: root.defaultSpacing + text: root.testWindow.visibility === Window.FullScreen ? "exit fullscreen" : "go fullscreen" width: 150 onClicked: { - if (testWindow.visibility === Window.FullScreen) - testWindow.visibility = Window.AutomaticVisibility + if (root.testWindow.visibility === Window.FullScreen) + root.testWindow.visibility = Window.AutomaticVisibility else - testWindow.visibility = Window.FullScreen + root.testWindow.visibility = Window.FullScreen } } Shared.Button { anchors.left: parent.left anchors.top: parent.top - anchors.margins: defaultSpacing + anchors.margins: root.defaultSpacing text: "X" width: 30 - onClicked: testWindow.close() + onClicked: root.testWindow.close() } } } property var splashWindow: Splash { - onTimeout: controlWindow.visible = true + onTimeout: root.controlWindow.visible = true } } -- cgit v1.2.3 From c398e6701d15d13efe242085f51c59722e32d037 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Tue, 11 Feb 2020 16:00:11 +0100 Subject: Modernize type registration in new examples Change-Id: I26671d47d663c126e2bff41e8db7b0945db78643 Reviewed-by: Simon Hausmann --- examples/quick/scenegraph/metaltextureimport/main.cpp | 4 ---- examples/quick/scenegraph/metaltextureimport/metaltextureimport.h | 1 + examples/quick/scenegraph/metaltextureimport/metaltextureimport.pro | 3 +++ examples/quick/scenegraph/vulkantextureimport/main.cpp | 3 --- examples/quick/scenegraph/vulkantextureimport/vulkantextureimport.h | 1 + .../quick/scenegraph/vulkantextureimport/vulkantextureimport.pro | 5 +++-- examples/quick/scenegraph/vulkanunderqml/main.cpp | 3 --- examples/quick/scenegraph/vulkanunderqml/vulkansquircle.h | 1 + examples/quick/scenegraph/vulkanunderqml/vulkanunderqml.pro | 3 +++ 9 files changed, 12 insertions(+), 12 deletions(-) diff --git a/examples/quick/scenegraph/metaltextureimport/main.cpp b/examples/quick/scenegraph/metaltextureimport/main.cpp index c969817e8f..4fc010e710 100644 --- a/examples/quick/scenegraph/metaltextureimport/main.cpp +++ b/examples/quick/scenegraph/metaltextureimport/main.cpp @@ -50,14 +50,10 @@ #include #include -#include "metaltextureimport.h" int main(int argc, char **argv) { QGuiApplication app(argc, argv); - - qmlRegisterType("MetalTextureImport", 1, 0, "CustomTextureItem"); - QQuickWindow::setSceneGraphBackend(QSGRendererInterface::MetalRhi); QQuickView view; diff --git a/examples/quick/scenegraph/metaltextureimport/metaltextureimport.h b/examples/quick/scenegraph/metaltextureimport/metaltextureimport.h index afc5aced97..49a29565a7 100644 --- a/examples/quick/scenegraph/metaltextureimport/metaltextureimport.h +++ b/examples/quick/scenegraph/metaltextureimport/metaltextureimport.h @@ -60,6 +60,7 @@ class CustomTextureItem : public QQuickItem { Q_OBJECT Q_PROPERTY(qreal t READ t WRITE setT NOTIFY tChanged) + QML_ELEMENT public: CustomTextureItem(); diff --git a/examples/quick/scenegraph/metaltextureimport/metaltextureimport.pro b/examples/quick/scenegraph/metaltextureimport/metaltextureimport.pro index bbdfd358d3..9e88c50dc6 100644 --- a/examples/quick/scenegraph/metaltextureimport/metaltextureimport.pro +++ b/examples/quick/scenegraph/metaltextureimport/metaltextureimport.pro @@ -1,6 +1,9 @@ !macos:!ios: error("This example requires macOS or iOS") QT += qml quick +CONFIG += qmltypes +QML_IMPORT_NAME = MetalTextureImport +QML_IMPORT_MAJOR_VERSION = 1 HEADERS += metaltextureimport.h SOURCES += metaltextureimport.mm main.cpp diff --git a/examples/quick/scenegraph/vulkantextureimport/main.cpp b/examples/quick/scenegraph/vulkantextureimport/main.cpp index 1c42e87043..5dc28eb8a3 100644 --- a/examples/quick/scenegraph/vulkantextureimport/main.cpp +++ b/examples/quick/scenegraph/vulkantextureimport/main.cpp @@ -50,14 +50,11 @@ #include #include -#include "vulkantextureimport.h" int main(int argc, char **argv) { QGuiApplication app(argc, argv); - qmlRegisterType("VulkanTextureImport", 1, 0, "CustomTextureItem"); - QQuickWindow::setSceneGraphBackend(QSGRendererInterface::VulkanRhi); QQuickView view; diff --git a/examples/quick/scenegraph/vulkantextureimport/vulkantextureimport.h b/examples/quick/scenegraph/vulkantextureimport/vulkantextureimport.h index f604faf66f..b8c13b44f6 100644 --- a/examples/quick/scenegraph/vulkantextureimport/vulkantextureimport.h +++ b/examples/quick/scenegraph/vulkantextureimport/vulkantextureimport.h @@ -60,6 +60,7 @@ class CustomTextureItem : public QQuickItem { Q_OBJECT Q_PROPERTY(qreal t READ t WRITE setT NOTIFY tChanged) + QML_ELEMENT public: CustomTextureItem(); diff --git a/examples/quick/scenegraph/vulkantextureimport/vulkantextureimport.pro b/examples/quick/scenegraph/vulkantextureimport/vulkantextureimport.pro index f2f78a6ed3..11e422ecad 100644 --- a/examples/quick/scenegraph/vulkantextureimport/vulkantextureimport.pro +++ b/examples/quick/scenegraph/vulkantextureimport/vulkantextureimport.pro @@ -1,12 +1,13 @@ !qtConfig(vulkan): error("This example requires Qt built with Vulkan support") QT += qml quick +CONFIG += qmltypes +QML_IMPORT_NAME = VulkanTextureImport +QML_IMPORT_MAJOR_VERSION = 1 HEADERS += vulkantextureimport.h SOURCES += vulkantextureimport.cpp main.cpp RESOURCES += vulkantextureimport.qrc - - target.path = $$[QT_INSTALL_EXAMPLES]/quick/scenegraph/vulkantextureimport INSTALLS += target diff --git a/examples/quick/scenegraph/vulkanunderqml/main.cpp b/examples/quick/scenegraph/vulkanunderqml/main.cpp index a04497b1d6..6ed0efacdd 100644 --- a/examples/quick/scenegraph/vulkanunderqml/main.cpp +++ b/examples/quick/scenegraph/vulkanunderqml/main.cpp @@ -50,14 +50,11 @@ #include #include -#include "vulkansquircle.h" int main(int argc, char **argv) { QGuiApplication app(argc, argv); - qmlRegisterType("VulkanUnderQML", 1, 0, "VulkanSquircle"); - // This example needs Vulkan. It will not run otherwise. QQuickWindow::setSceneGraphBackend(QSGRendererInterface::VulkanRhi); diff --git a/examples/quick/scenegraph/vulkanunderqml/vulkansquircle.h b/examples/quick/scenegraph/vulkanunderqml/vulkansquircle.h index 7e65d01a15..16feeacb5b 100644 --- a/examples/quick/scenegraph/vulkanunderqml/vulkansquircle.h +++ b/examples/quick/scenegraph/vulkanunderqml/vulkansquircle.h @@ -59,6 +59,7 @@ class VulkanSquircle : public QQuickItem { Q_OBJECT Q_PROPERTY(qreal t READ t WRITE setT NOTIFY tChanged) + QML_ELEMENT public: VulkanSquircle(); diff --git a/examples/quick/scenegraph/vulkanunderqml/vulkanunderqml.pro b/examples/quick/scenegraph/vulkanunderqml/vulkanunderqml.pro index 9ea57b91c3..8f7ea5861d 100644 --- a/examples/quick/scenegraph/vulkanunderqml/vulkanunderqml.pro +++ b/examples/quick/scenegraph/vulkanunderqml/vulkanunderqml.pro @@ -1,6 +1,9 @@ !qtConfig(vulkan): error("This example requires Qt built with Vulkan support") QT += qml quick +CONFIG += qmltypes +QML_IMPORT_NAME = VulkanUnderQML +QML_IMPORT_MAJOR_VERSION = 1 HEADERS += vulkansquircle.h SOURCES += vulkansquircle.cpp main.cpp -- cgit v1.2.3 From c48b0902b56a62808e78b10d89435e85b840c8dc Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Tue, 11 Feb 2020 16:53:00 +0100 Subject: tst_qquickwindow: construct pointer events with proper devices In the QQuickPointerMouseEvent constructor, the device pointer became mandatory mainly because it's mandatory in QQuickSinglePointEvent, because we want to ensure that we distinguish mouse from tablet events. Change-Id: I3d314c6877493b8b5b6407f5eb5631f7083900a5 Reviewed-by: Shawn Rutledge --- tests/auto/quick/qquickwindow/tst_qquickwindow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp index bf58ce961c..0bf83c267a 100644 --- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp +++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp @@ -2860,7 +2860,7 @@ void tst_qquickwindow::pointerEventTypeAndPointCount() QList() << QTouchEvent::TouchPoint(1)); - QQuickPointerMouseEvent pme; + QQuickPointerMouseEvent pme(nullptr, QQuickPointerDevice::genericMouseDevice()); pme.reset(&me); QCOMPARE(pme.asMouseEvent(localPosition), &me); QVERIFY(pme.asPointerMouseEvent()); @@ -2872,7 +2872,7 @@ void tst_qquickwindow::pointerEventTypeAndPointCount() QCOMPARE(pme.asMouseEvent(localPosition)->localPos(), localPosition); QCOMPARE(pme.asMouseEvent(localPosition)->screenPos(), screenPosition); - QQuickPointerTouchEvent pte; + QQuickPointerTouchEvent pte(nullptr, QQuickPointerDevice::touchDevice(touchDevice)); pte.reset(&te); QCOMPARE(pte.asTouchEvent(), &te); QVERIFY(!pte.asPointerMouseEvent()); -- cgit v1.2.3 From 8e822e981d91e688799c8670f11dfdf6aaf9e0d1 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Sat, 14 Dec 2019 16:02:21 +0100 Subject: Deliver QTabletEvents to pointer handlers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At this time, there are not yet any specialized handlers to do anything specifically with tablet events; but we demonstrate how to use HoverHandler to detect the type of stylus in use, and how to use PointHandler to draw on a Canvas. Unfortunately, events of types TabletEnterProximity and TabletLeaveProximity are not delivered to the window, only to QGuiApplication. So HoverHandler can detect when the stylus is moved out of its parent Item (as long as it's still hovering over the tablet surface), but cannot detect when the stylus leaves the tablet completely. In Qt 5 that would require a custom application subclass (see qtbase/examples/widgets/widgets/tablet/tabletapplication.cpp). Fixes: QTBUG-79660 Change-Id: I81fdb99082dc41c0455085e6b6d3952402bf8742 Reviewed-by: Qt CI Bot Reviewed-by: Jan Arve Sæther --- src/quick/handlers/qquickhandlerpoint.cpp | 5 +- src/quick/handlers/qquickhoverhandler.cpp | 19 +- src/quick/handlers/qquickhoverhandler_p.h | 1 + src/quick/items/qquickevents.cpp | 162 +++++++++++++- src/quick/items/qquickevents_p_p.h | 71 +++++- src/quick/items/qquickwindow.cpp | 33 ++- src/quick/items/qquickwindow.h | 3 + .../qquickpointhandler/tst_qquickpointhandler.cpp | 60 +++++ tests/manual/pointer/main.qml | 3 +- tests/manual/pointer/qml.qrc | 5 + tests/manual/pointer/resources/cursor-airbrush.png | Bin 0 -> 823 bytes tests/manual/pointer/resources/cursor-eraser.png | Bin 0 -> 1454 bytes .../pointer/resources/cursor-felt-marker.png | Bin 0 -> 513 bytes tests/manual/pointer/resources/cursor-pencil.png | Bin 0 -> 1307 bytes tests/manual/pointer/tabletCanvasDrawing.qml | 242 +++++++++++++++++++++ 15 files changed, 583 insertions(+), 21 deletions(-) create mode 100644 tests/manual/pointer/resources/cursor-airbrush.png create mode 100644 tests/manual/pointer/resources/cursor-eraser.png create mode 100644 tests/manual/pointer/resources/cursor-felt-marker.png create mode 100644 tests/manual/pointer/resources/cursor-pencil.png create mode 100644 tests/manual/pointer/tabletCanvasDrawing.qml diff --git a/src/quick/handlers/qquickhandlerpoint.cpp b/src/quick/handlers/qquickhandlerpoint.cpp index f3d92cf200..e6148ca072 100644 --- a/src/quick/handlers/qquickhandlerpoint.cpp +++ b/src/quick/handlers/qquickhandlerpoint.cpp @@ -120,7 +120,10 @@ void QQuickHandlerPoint::reset(const QQuickEventPoint *point) m_pressure = tp->pressure(); m_ellipseDiameters = tp->ellipseDiameters(); } else if (event->asPointerTabletEvent()) { - // TODO + m_uniqueId = event->device()->uniqueId(); + m_rotation = static_cast(point)->rotation(); + m_pressure = static_cast(point)->pressure(); + m_ellipseDiameters = QSizeF(); } else { m_uniqueId = event->device()->uniqueId(); m_rotation = 0; diff --git a/src/quick/handlers/qquickhoverhandler.cpp b/src/quick/handlers/qquickhoverhandler.cpp index 1216eda477..b12d85784a 100644 --- a/src/quick/handlers/qquickhoverhandler.cpp +++ b/src/quick/handlers/qquickhoverhandler.cpp @@ -93,11 +93,22 @@ bool QQuickHoverHandler::wantsPointerEvent(QQuickPointerEvent *event) { QQuickEventPoint *point = event->point(0); if (QQuickPointerDeviceHandler::wantsPointerEvent(event) && wantsEventPoint(point) && parentContains(point)) { - // assume this is a mouse event, so there's only one point + // assume this is a mouse or tablet event, so there's only one point setPointId(point->pointId()); return true; } - setHovered(false); + + // Some hover events come from QQuickWindow::tabletEvent(). In between, + // some hover events come from QQWindowPrivate::flushFrameSynchronousEvents(), + // but those look like mouse events. If a particular HoverHandler instance + // is filtering for tablet events only (e.g. by setting + // acceptedDevices:PointerDevice.Stylus), those events should not cause + // the hovered property to transition to false prematurely. + // If a QQuickPointerTabletEvent caused the hovered property to become true, + // then only another QQuickPointerTabletEvent can make it become false. + if (!(m_hoveredTablet && event->asPointerMouseEvent())) + setHovered(false); + return false; } @@ -107,6 +118,8 @@ void QQuickHoverHandler::handleEventPoint(QQuickEventPoint *point) if (point->state() == QQuickEventPoint::Released && point->pointerEvent()->device()->pointerType() == QQuickPointerDevice::Finger) hovered = false; + else if (point->pointerEvent()->asPointerTabletEvent()) + m_hoveredTablet = true; setHovered(hovered); setPassiveGrab(point); } @@ -124,6 +137,8 @@ void QQuickHoverHandler::setHovered(bool hovered) if (m_hovered != hovered) { qCDebug(lcHoverHandler) << objectName() << "hovered" << m_hovered << "->" << hovered; m_hovered = hovered; + if (!hovered) + m_hoveredTablet = false; emit hoveredChanged(); } } diff --git a/src/quick/handlers/qquickhoverhandler_p.h b/src/quick/handlers/qquickhoverhandler_p.h index e4786bfa53..313b87217c 100644 --- a/src/quick/handlers/qquickhoverhandler_p.h +++ b/src/quick/handlers/qquickhoverhandler_p.h @@ -84,6 +84,7 @@ private: private: bool m_hovered = false; + bool m_hoveredTablet = false; }; QT_END_NAMESPACE diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp index 0a6faf04af..0a9abb3322 100644 --- a/src/quick/items/qquickevents.cpp +++ b/src/quick/items/qquickevents.cpp @@ -658,14 +658,73 @@ QQuickPointerDevice *QQuickPointerDevice::genericMouseDevice() return g_genericMouseDevice; } -QQuickPointerDevice *QQuickPointerDevice::tabletDevice(qint64 id) -{ - auto it = g_tabletDevices->find(id); +QQuickPointerDevice *QQuickPointerDevice::tabletDevice(const QTabletEvent *event) +{ + // QTabletEvent::uniqueId() is the same for the pointy end and the eraser end of the stylus. + // We need to make those unique. QTabletEvent::PointerType only needs 2 bits' worth of storage. + // The key into g_tabletDevices just needs to be unique; we don't need to extract uniqueId + // back out of it, because QQuickPointerDevice stores that separately anyway. + // So the shift-and-add can be thought of as a sort of hash function, even though + // most of the time the result will be recognizable because the uniqueId MSBs are often 0. + qint64 key = event->uniqueId() + (qint64(event->pointerType()) << 60); + auto it = g_tabletDevices->find(key); if (it != g_tabletDevices->end()) return it.value(); - // ### Figure out how to populate the tablet devices - return nullptr; + DeviceType type = UnknownDevice; + int buttonCount = 0; + Capabilities caps = Position | Pressure | Hover; + // TODO Qt 6: we can't know for sure about XTilt or YTilt until we have a + // QTabletDevice populated with capabilities provided by QPA plugins + + switch (event->device()) { + case QTabletEvent::Stylus: + type = QQuickPointerDevice::Stylus; + buttonCount = 3; + break; + case QTabletEvent::RotationStylus: + type = QQuickPointerDevice::Stylus; + caps |= QQuickPointerDevice::Rotation; + buttonCount = 1; + break; + case QTabletEvent::Airbrush: + type = QQuickPointerDevice::Airbrush; + buttonCount = 2; + break; + case QTabletEvent::Puck: + type = QQuickPointerDevice::Puck; + buttonCount = 3; + break; + case QTabletEvent::FourDMouse: + type = QQuickPointerDevice::Mouse; + caps |= QQuickPointerDevice::Rotation; + buttonCount = 3; + break; + default: + type = QQuickPointerDevice::UnknownDevice; + break; + } + + PointerType ptype = GenericPointer; + switch (event->pointerType()) { + case QTabletEvent::Pen: + ptype = Pen; + break; + case QTabletEvent::Eraser: + ptype = Eraser; + break; + case QTabletEvent::Cursor: + ptype = Cursor; + break; + case QTabletEvent::UnknownPointer: + break; + } + + QQuickPointerDevice *device = new QQuickPointerDevice(type, ptype, caps, 1, buttonCount, + QLatin1String("tablet tool ") + QString::number(event->uniqueId()), event->uniqueId()); + + g_tabletDevices->insert(key, device); + return device; } /*! @@ -1284,6 +1343,12 @@ QVector2D QQuickEventPoint::estimatedVelocity() const QQuickPointerEvent::~QQuickPointerEvent() {} +QQuickPointerMouseEvent::QQuickPointerMouseEvent(QObject *parent, QQuickPointerDevice *device) + : QQuickSinglePointEvent(parent, device) +{ + m_point = new QQuickEventPoint(this); +} + QQuickPointerEvent *QQuickPointerMouseEvent::reset(QEvent *event) { auto ev = static_cast(event); @@ -1398,6 +1463,12 @@ void QQuickPointerTouchEvent::localize(QQuickItem *target) } #if QT_CONFIG(gestures) +QQuickPointerNativeGestureEvent::QQuickPointerNativeGestureEvent(QObject *parent, QQuickPointerDevice *device) + : QQuickSinglePointEvent(parent, device) +{ + m_point = new QQuickEventPoint(this); +} + QQuickPointerEvent *QQuickPointerNativeGestureEvent::reset(QEvent *event) { auto ev = static_cast(event); @@ -1560,6 +1631,12 @@ QQuickEventPoint *QQuickSinglePointEvent::point(int i) const \note Many platforms provide no such information. On such platforms, \c inverted always returns false. */ +QQuickPointerScrollEvent::QQuickPointerScrollEvent(QObject *parent, QQuickPointerDevice *device) + : QQuickSinglePointEvent(parent, device) +{ + m_point = new QQuickEventPoint(this); +} + QQuickPointerEvent *QQuickPointerScrollEvent::reset(QEvent *event) { m_event = static_cast(event); @@ -1832,6 +1909,81 @@ QMouseEvent *QQuickPointerTouchEvent::syntheticMouseEvent(int pointID, QQuickIte return &m_synthMouseEvent; } +#if QT_CONFIG(tabletevent) +QQuickPointerTabletEvent::QQuickPointerTabletEvent(QObject *parent, QQuickPointerDevice *device) + : QQuickSinglePointEvent(parent, device) +{ + m_point = new QQuickEventTabletPoint(this); +} + +QQuickPointerEvent *QQuickPointerTabletEvent::reset(QEvent *event) +{ + auto ev = static_cast(event); + m_event = ev; + if (!event) + return this; + + Q_ASSERT(m_device == QQuickPointerDevice::tabletDevice(ev)); + m_device->eventDeliveryTargets().clear(); + m_button = ev->button(); + m_pressedButtons = ev->buttons(); + static_cast(m_point)->reset(ev); + return this; +} + +QQuickEventTabletPoint::QQuickEventTabletPoint(QQuickPointerTabletEvent *parent) + : QQuickEventPoint(parent) +{ +} + +void QQuickEventTabletPoint::reset(const QTabletEvent *ev) +{ + Qt::TouchPointState state = Qt::TouchPointStationary; + switch (ev->type()) { + case QEvent::TabletPress: + state = Qt::TouchPointPressed; + clearPassiveGrabbers(); + break; + case QEvent::TabletRelease: + state = Qt::TouchPointReleased; + break; + case QEvent::TabletMove: + state = Qt::TouchPointMoved; + break; + default: + break; + } + QQuickEventPoint::reset(state, ev->posF(), 1, ev->timestamp()); + m_rotation = ev->rotation(); + m_pressure = ev->pressure(); + m_tangentialPressure = ev->tangentialPressure(); + m_tilt = QVector2D(ev->xTilt(), ev->yTilt()); +} + +bool QQuickPointerTabletEvent::isPressEvent() const +{ + auto me = static_cast(m_event); + return me->type() == QEvent::TabletPress; +} + +bool QQuickPointerTabletEvent::isUpdateEvent() const +{ + auto me = static_cast(m_event); + return me->type() == QEvent::TabletMove; +} + +bool QQuickPointerTabletEvent::isReleaseEvent() const +{ + auto me = static_cast(m_event); + return me->type() == QEvent::TabletRelease; +} + +QTabletEvent *QQuickPointerTabletEvent::asTabletEvent() const +{ + return static_cast(m_event); +} +#endif // QT_CONFIG(tabletevent) + #if QT_CONFIG(gestures) bool QQuickPointerNativeGestureEvent::isPressEvent() const { diff --git a/src/quick/items/qquickevents_p_p.h b/src/quick/items/qquickevents_p_p.h index 4615ce43d2..3a8028678e 100644 --- a/src/quick/items/qquickevents_p_p.h +++ b/src/quick/items/qquickevents_p_p.h @@ -476,8 +476,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickSinglePointEvent : public QQuickPointerEvent { Q_OBJECT public: - QQuickSinglePointEvent(QObject *parent = nullptr, QQuickPointerDevice *device = nullptr) - : QQuickPointerEvent(parent, device), m_point(new QQuickEventPoint(this)) { } + QQuickSinglePointEvent(QObject *parent, QQuickPointerDevice *device) + : QQuickPointerEvent(parent, device) { } void localize(QQuickItem *target) override; int pointCount() const override { return 1; } @@ -491,7 +491,7 @@ public: bool hasExclusiveGrabber(const QQuickPointerHandler *handler) const override; protected: - QQuickEventPoint *m_point; + QQuickEventPoint *m_point = nullptr; Q_DISABLE_COPY(QQuickSinglePointEvent) }; @@ -505,8 +505,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPointerMouseEvent : public QQuickSinglePointE QML_ADDED_IN_MINOR_VERSION(12) public: - QQuickPointerMouseEvent(QObject *parent = nullptr, QQuickPointerDevice *device = nullptr) - : QQuickSinglePointEvent(parent, device) { } + QQuickPointerMouseEvent(QObject *parent, QQuickPointerDevice *device); QQuickPointerEvent *reset(QEvent *) override; bool isPressEvent() const override; @@ -568,6 +567,60 @@ private: Q_DISABLE_COPY(QQuickPointerTouchEvent) }; +#if QT_CONFIG(tabletevent) +class Q_QUICK_PRIVATE_EXPORT QQuickEventTabletPoint : public QQuickEventPoint +{ + Q_OBJECT + Q_PROPERTY(qreal rotation READ rotation) + Q_PROPERTY(qreal pressure READ pressure) + Q_PROPERTY(qreal tangentialPressure READ tangentialPressure) + Q_PROPERTY(QVector2D tilt READ tilt) + + QML_NAMED_ELEMENT(EventTabletPoint) + QML_UNCREATABLE("EventTouchPoint is only available as a member of PointerEvent.") + QML_ADDED_IN_MINOR_VERSION(15) + +public: + QQuickEventTabletPoint(QQuickPointerTabletEvent *parent); + + void reset(const QTabletEvent *e); + + qreal rotation() const { return m_rotation; } + qreal pressure() const { return m_pressure; } + qreal tangentialPressure() const { return m_tangentialPressure; } + QVector2D tilt() const { return m_tilt; } + +private: + qreal m_rotation; + qreal m_pressure; + qreal m_tangentialPressure; + QVector2D m_tilt; + + friend class QQuickPointerTouchEvent; + + Q_DISABLE_COPY(QQuickEventTabletPoint) +}; + +class Q_QUICK_PRIVATE_EXPORT QQuickPointerTabletEvent : public QQuickSinglePointEvent +{ + Q_OBJECT +public: + QQuickPointerTabletEvent(QObject *parent, QQuickPointerDevice *device); + + QQuickPointerEvent *reset(QEvent *) override; + bool isPressEvent() const override; + bool isUpdateEvent() const override; + bool isReleaseEvent() const override; + QQuickPointerTabletEvent *asPointerTabletEvent() override { return this; } + const QQuickPointerTabletEvent *asPointerTabletEvent() const override { return this; } + const QQuickEventTabletPoint *tabletPoint() const { return static_cast(m_point); } + + QTabletEvent *asTabletEvent() const; + + Q_DISABLE_COPY(QQuickPointerTabletEvent) +}; +#endif // QT_CONFIG(tabletevent) + #if QT_CONFIG(gestures) class Q_QUICK_PRIVATE_EXPORT QQuickPointerNativeGestureEvent : public QQuickSinglePointEvent { @@ -576,8 +629,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPointerNativeGestureEvent : public QQuickSing Q_PROPERTY(qreal value READ value CONSTANT) public: - QQuickPointerNativeGestureEvent(QObject *parent = nullptr, QQuickPointerDevice *device = nullptr) - : QQuickSinglePointEvent(parent, device) { } + QQuickPointerNativeGestureEvent(QObject *parent, QQuickPointerDevice *device); QQuickPointerEvent *reset(QEvent *) override; bool isPressEvent() const override; @@ -606,8 +658,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPointerScrollEvent : public QQuickSinglePoint QML_ADDED_IN_MINOR_VERSION(14) public: - QQuickPointerScrollEvent(QObject *parent = nullptr, QQuickPointerDevice *device = nullptr) - : QQuickSinglePointEvent(parent, device) { } + QQuickPointerScrollEvent(QObject *parent, QQuickPointerDevice *device); QQuickPointerEvent *reset(QEvent *) override; void localize(QQuickItem *target) override; @@ -712,7 +763,7 @@ public: static QQuickPointerDevice *touchDevice(const QTouchDevice *d); static QList touchDevices(); static QQuickPointerDevice *genericMouseDevice(); - static QQuickPointerDevice *tabletDevice(qint64); + static QQuickPointerDevice *tabletDevice(const QTabletEvent *event); QVector &eventDeliveryTargets() { return m_eventDeliveryTargets; } diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 6c63b83511..dda0cfef3e 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -93,6 +93,7 @@ Q_LOGGING_CATEGORY(DBG_TOUCH, "qt.quick.touch") Q_LOGGING_CATEGORY(DBG_TOUCH_TARGET, "qt.quick.touch.target") Q_LOGGING_CATEGORY(DBG_MOUSE, "qt.quick.mouse") Q_LOGGING_CATEGORY(DBG_MOUSE_TARGET, "qt.quick.mouse.target") +Q_LOGGING_CATEGORY(lcTablet, "qt.quick.tablet") Q_LOGGING_CATEGORY(lcWheelTarget, "qt.quick.wheel.target") Q_LOGGING_CATEGORY(lcGestureTarget, "qt.quick.gesture.target") Q_LOGGING_CATEGORY(DBG_HOVER_TRACE, "qt.quick.hover.trace") @@ -2122,6 +2123,17 @@ void QQuickWindow::wheelEvent(QWheelEvent *event) } #endif // wheelevent +#if QT_CONFIG(tabletevent) +/*! \reimp */ +void QQuickWindow::tabletEvent(QTabletEvent *event) +{ + Q_D(QQuickWindow); + qCDebug(lcTablet) << event; + // TODO Qt 6: make sure TabletEnterProximity and TabletLeaveProximity are delivered here + d->deliverPointerEvent(d->pointerEventInstance(event)); +} +#endif // tabletevent + bool QQuickWindowPrivate::deliverTouchCancelEvent(QTouchEvent *event) { qCDebug(DBG_TOUCH) << event; @@ -2400,8 +2412,12 @@ QQuickPointerEvent *QQuickWindowPrivate::pointerEventInstance(QQuickPointerDevic #endif ev = new QQuickPointerTouchEvent(q, device); break; + case QQuickPointerDevice::Stylus: + case QQuickPointerDevice::Airbrush: + case QQuickPointerDevice::Puck: + ev = new QQuickPointerTabletEvent(q, device); + break; default: - // TODO tablet event types break; } pointerEventInstances << ev; @@ -2432,7 +2448,15 @@ QQuickPointerEvent *QQuickWindowPrivate::pointerEventInstance(QEvent *event) con case QEvent::TouchCancel: dev = QQuickPointerDevice::touchDevice(static_cast(event)->device()); break; - // TODO tablet event types +#if QT_CONFIG(tabletevent) + case QEvent::TabletPress: + case QEvent::TabletMove: + case QEvent::TabletRelease: + case QEvent::TabletEnterProximity: + case QEvent::TabletLeaveProximity: + dev = QQuickPointerDevice::tabletDevice(static_cast(event)); + break; +#endif #if QT_CONFIG(gestures) case QEvent::NativeGesture: dev = QQuickPointerDevice::touchDevice(static_cast(event)->device()); @@ -2467,6 +2491,11 @@ void QQuickWindowPrivate::deliverPointerEvent(QQuickPointerEvent *event) deliverTouchEvent(event->asPointerTouchEvent()); } else { deliverSinglePointEventUntilAccepted(event); + // If any handler got interested in the tablet event, we don't want to receive a synth-mouse event from QtGui + // TODO Qt 6: QTabletEvent will be accepted by default, like other events + if (event->asPointerTabletEvent() && + (!event->point(0)->passiveGrabbers().isEmpty() || event->point(0)->exclusiveGrabber())) + event->setAccepted(true); } event->reset(nullptr); diff --git a/src/quick/items/qquickwindow.h b/src/quick/items/qquickwindow.h index d22bba4512..097627374c 100644 --- a/src/quick/items/qquickwindow.h +++ b/src/quick/items/qquickwindow.h @@ -252,6 +252,9 @@ protected: #if QT_CONFIG(wheelevent) void wheelEvent(QWheelEvent *) override; #endif +#if QT_CONFIG(tabletevent) + void tabletEvent(QTabletEvent *) override; +#endif private Q_SLOTS: void maybeUpdate(); diff --git a/tests/auto/quick/pointerhandlers/qquickpointhandler/tst_qquickpointhandler.cpp b/tests/auto/quick/pointerhandlers/qquickpointhandler/tst_qquickpointhandler.cpp index d0b3bc3d36..ca6463f365 100644 --- a/tests/auto/quick/pointerhandlers/qquickpointhandler/tst_qquickpointhandler.cpp +++ b/tests/auto/quick/pointerhandlers/qquickpointhandler/tst_qquickpointhandler.cpp @@ -55,6 +55,7 @@ private slots: void initTestCase(); void singleTouch(); + void tabletStylus(); void simultaneousMultiTouch(); void pressedMultipleButtons_data(); void pressedMultipleButtons(); @@ -136,6 +137,65 @@ void tst_PointHandler::singleTouch() QCOMPARE(translationSpy.count(), 3); } +void tst_PointHandler::tabletStylus() +{ + qApp->setAttribute(Qt::AA_SynthesizeMouseForUnhandledTabletEvents, false); + QScopedPointer windowPtr; + createView(windowPtr, "pointTracker.qml"); + QQuickView * window = windowPtr.data(); + QQuickPointHandler *handler = window->rootObject()->findChild("pointHandler"); + QVERIFY(handler); + handler->setAcceptedDevices(QQuickPointerDevice::Stylus); + + QSignalSpy activeSpy(handler, SIGNAL(activeChanged())); + QSignalSpy pointSpy(handler, SIGNAL(pointChanged())); + QSignalSpy translationSpy(handler, SIGNAL(translationChanged())); + + QPoint point(100,100); + const qint64 stylusId = 1234567890; + + QWindowSystemInterface::handleTabletEvent(window, point, window->mapToGlobal(point), + QTabletEvent::Stylus, QTabletEvent::Pen, Qt::LeftButton, 0.5, 25, 35, 0.6, 12.3, 3, stylusId, Qt::NoModifier); + QTRY_COMPARE(handler->active(), true); + QCOMPARE(activeSpy.count(), 1); + QCOMPARE(pointSpy.count(), 1); + QCOMPARE(handler->point().position().toPoint(), point); + QCOMPARE(handler->point().scenePosition().toPoint(), point); + QCOMPARE(handler->point().pressedButtons(), Qt::LeftButton); + QCOMPARE(handler->point().pressure(), 0.5); + QCOMPARE(handler->point().rotation(), 12.3); + QCOMPARE(handler->point().uniqueId().numericId(), stylusId); + QCOMPARE(handler->translation(), QVector2D()); + QCOMPARE(translationSpy.count(), 1); + + point += QPoint(10, 10); + QWindowSystemInterface::handleTabletEvent(window, point, window->mapToGlobal(point), + QTabletEvent::Stylus, QTabletEvent::Pen, Qt::LeftButton, 0.45, 23, 33, 0.57, 15.6, 3.4, stylusId, Qt::NoModifier); + QTRY_COMPARE(pointSpy.count(), 2); + QCOMPARE(handler->active(), true); + QCOMPARE(activeSpy.count(), 1); + QCOMPARE(handler->point().position().toPoint(), point); + QCOMPARE(handler->point().scenePosition().toPoint(), point); + QCOMPARE(handler->point().pressPosition().toPoint(), QPoint(100, 100)); + QCOMPARE(handler->point().scenePressPosition().toPoint(), QPoint(100, 100)); + QCOMPARE(handler->point().pressedButtons(), Qt::LeftButton); + QCOMPARE(handler->point().pressure(), 0.45); + QCOMPARE(handler->point().rotation(), 15.6); + QCOMPARE(handler->point().uniqueId().numericId(), stylusId); + QVERIFY(handler->point().velocity().x() > 0); + QVERIFY(handler->point().velocity().y() > 0); + QCOMPARE(handler->translation(), QVector2D(10, 10)); + QCOMPARE(translationSpy.count(), 2); + + QWindowSystemInterface::handleTabletEvent(window, point, window->mapToGlobal(point), + QTabletEvent::Stylus, QTabletEvent::Pen, Qt::NoButton, 0, 0, 0, 0, 0, 0, stylusId, Qt::NoModifier); + QTRY_COMPARE(handler->active(), false); + QCOMPARE(activeSpy.count(), 2); + QCOMPARE(pointSpy.count(), 3); + QCOMPARE(handler->translation(), QVector2D()); + QCOMPARE(translationSpy.count(), 3); +} + void tst_PointHandler::simultaneousMultiTouch() { QScopedPointer windowPtr; diff --git a/tests/manual/pointer/main.qml b/tests/manual/pointer/main.qml index d382d8b23d..83e1d3b2ba 100644 --- a/tests/manual/pointer/main.qml +++ b/tests/manual/pointer/main.qml @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the manual tests of the Qt Toolkit. @@ -57,6 +57,7 @@ Window { addExample("multibuttons", "TapHandler: gesturePolicy (99 red balloons)", Qt.resolvedUrl("multibuttons.qml")) addExample("flickable with Handlers", "Flickable with buttons, sliders etc. implemented in various ways", Qt.resolvedUrl("flickableWithHandlers.qml")) addExample("tap and drag", "Flickable with all possible combinations of TapHandler and DragHandler children", Qt.resolvedUrl("pointerDrag.qml")) + addExample("tablet canvas", "PointHandler and HoverHandler with a tablet: detect the stylus, and draw", Qt.resolvedUrl("tabletCanvasDrawing.qml")) } } Item { diff --git a/tests/manual/pointer/qml.qrc b/tests/manual/pointer/qml.qrc index 95bece180a..20956fcbac 100644 --- a/tests/manual/pointer/qml.qrc +++ b/tests/manual/pointer/qml.qrc @@ -13,6 +13,7 @@ pointerDrag.qml singlePointHandlerProperties.qml sidebar.qml + tabletCanvasDrawing.qml tapHandler.qml content/CheckBox.qml content/FakeFlickable.qml @@ -30,6 +31,10 @@ content/TouchpointFeedbackSprite.qml resources/arrowhead.png resources/balloon.png + resources/cursor-airbrush.png + resources/cursor-eraser.png + resources/cursor-felt-marker.png + resources/cursor-pencil.png resources/fighter.png resources/fingersprite.png resources/grabbing-location.svg diff --git a/tests/manual/pointer/resources/cursor-airbrush.png b/tests/manual/pointer/resources/cursor-airbrush.png new file mode 100644 index 0000000000..bea756ed6f Binary files /dev/null and b/tests/manual/pointer/resources/cursor-airbrush.png differ diff --git a/tests/manual/pointer/resources/cursor-eraser.png b/tests/manual/pointer/resources/cursor-eraser.png new file mode 100644 index 0000000000..e5488a89f2 Binary files /dev/null and b/tests/manual/pointer/resources/cursor-eraser.png differ diff --git a/tests/manual/pointer/resources/cursor-felt-marker.png b/tests/manual/pointer/resources/cursor-felt-marker.png new file mode 100644 index 0000000000..132f09aa39 Binary files /dev/null and b/tests/manual/pointer/resources/cursor-felt-marker.png differ diff --git a/tests/manual/pointer/resources/cursor-pencil.png b/tests/manual/pointer/resources/cursor-pencil.png new file mode 100644 index 0000000000..cc2f447d02 Binary files /dev/null and b/tests/manual/pointer/resources/cursor-pencil.png differ diff --git a/tests/manual/pointer/tabletCanvasDrawing.qml b/tests/manual/pointer/tabletCanvasDrawing.qml new file mode 100644 index 0000000000..c340dee5f4 --- /dev/null +++ b/tests/manual/pointer/tabletCanvasDrawing.qml @@ -0,0 +1,242 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the manual tests 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$ +** +****************************************************************************/ + +import QtQuick 2.15 +import QtQuick.Layouts 1.15 +import "content" + +Rectangle { + width: 1024 + height: 1024 + color: "#444" + + ColumnLayout { + x: -15; width: 80 + height: parent.height + Slider { + id: hueSlider + width: 80; height: 200 + Layout.fillHeight: true + label: "hue" + Rectangle { + color: "beige" + width: 30 + height: 25 + anchors.bottom: parent.bottom + anchors.bottomMargin: 2 + anchors.horizontalCenter: parent.horizontalCenter + Rectangle { + border.color: "white" + color: canvas.drawingColor + anchors.fill: parent + } + } + } + Slider { + id: saturationSlider + width: 80; height: 200 + Layout.fillHeight: true + label: "sat" + } + Slider { + id: lightnessSlider + width: 80; height: 200 + Layout.fillHeight: true + label: "light" + } + } + + ColumnLayout { + x: parent.width - 65; width: 80 + height: parent.height + Slider { + id: widthSlider + width: 80; height: 200 + Layout.fillHeight: true + label: "width" + } + Slider { + id: alphaSlider + width: 80; height: 200 + Layout.fillHeight: true + label: "alpha" + } + } + + Rectangle { + id: rect + width: 640 + height: 480 + color: "beige" + anchors { + fill: parent + margins: 10 + leftMargin: 50 + rightMargin: 50 + } + + Canvas { + id: canvas + anchors.fill: parent + antialiasing: true + renderTarget: Canvas.FramebufferObject + property color drawingColor: Qt.hsla(hueSlider.value / 100.0, + saturationSlider.value / 100.0, + lightnessSlider.value / 100.0, + alphaSlider.value / 100.0) + property var points: [] + property var pressures: [] + property var pointerType: PointerDevice.Pen + onPaint: { + if (points.length < 2) + return + var ctx = canvas.getContext('2d'); + ctx.save() + ctx.strokeStyle = pointerType === PointerDevice.Pen ? drawingColor : "beige" + ctx.lineCap = "round" + if (pressures.length === points.length) { + for (var i = 1; i < points.length; i++) { + ctx.lineWidth = pressures[i] * widthSlider.value + ctx.beginPath() + ctx.moveTo(points[i - 1].x, points[i - 1].y) + ctx.lineTo(points[i].x, points[i].y) + ctx.stroke() + } + points = points.slice(points.length - 2, 1) + pressures = pressures.slice(pressures.length - 2, 1) + } else { + ctx.beginPath() + ctx.moveTo(points[0].x, points[0].y) + for (var i = 1; i < points.length; i++) + ctx.lineTo(points[i].x, points[i].y) + ctx.lineWidth = widthSlider + ctx.stroke() + points = points.slice(points.length - 2, 1) + pressures = [] + } + ctx.restore() + } + } + + PointHandler { + acceptedPointerTypes: PointerDevice.Pen + onActiveChanged: + if (active) { + canvas.pointerType = PointerDevice.Pen + } else { + canvas.points = [] + canvas.pressures = [] + } + onPointChanged: + if (active) { + canvas.points.push(point.position) + canvas.pressures.push(point.pressure) + canvas.requestPaint() + } + } + + PointHandler { + acceptedPointerTypes: PointerDevice.Eraser + onActiveChanged: + if (active) { + canvas.pointerType = PointerDevice.Eraser + } else { + canvas.points = [] + canvas.pressures = [] + } + onPointChanged: + if (active) { + canvas.points.push(point.position) + canvas.pressures.push(point.pressure) + canvas.requestPaint() + } + } + + HoverHandler { + id: stylusHandler + acceptedDevices: PointerDevice.Stylus + acceptedPointerTypes: PointerDevice.Pen + target: Image { + parent: rect + source: stylusHandler.point.rotation === 0 ? + "resources/cursor-pencil.png" : "resources/cursor-felt-marker.png" + visible: stylusHandler.hovered + rotation: stylusHandler.point.rotation + x: stylusHandler.point.position.x + y: stylusHandler.point.position.y + } + } + + HoverHandler { + id: airbrushHandler + acceptedDevices: PointerDevice.Airbrush + acceptedPointerTypes: PointerDevice.Pen + target: Image { + parent: rect + source: "resources/cursor-airbrush.png" + visible: airbrushHandler.hovered + x: airbrushHandler.point.position.x + y: airbrushHandler.point.position.y + } + } + + HoverHandler { + id: eraserHandler + acceptedPointerTypes: PointerDevice.Eraser + target: Image { + parent: rect + source: "resources/cursor-eraser.png" + visible: eraserHandler.hovered + x: eraserHandler.point.position.x + y: eraserHandler.point.position.y - 32 + } + } + } +} -- cgit v1.2.3 From 87f5cc385b670a63c2f2ba0ef90cba95ab215200 Mon Sep 17 00:00:00 2001 From: Fawzi Mohamed Date: Thu, 6 Feb 2020 14:15:09 +0100 Subject: Add annotations to AST Annotations are added to UiObjectMember. This makes it easy to find the annotations of any UiObjectMember through the annotations attribute. The clean AST approach would add an UiAnnotatedObjectMember that contains both the annotation list and an UiObjectMember, but that makes finding the annotation more difficult. The annotations are not visited by default, if one wants to dump them before the current object the simplest way is to use the preVisit and use .uiObjectMemberCast(). Depending on how we use annotation we could change the current approach. Task-number: QTBUG-81714 Change-Id: I543a2cfe5157bcc86de6de9faebde9aea22974eb Reviewed-by: Ulf Hermann --- src/qml/parser/qqmljs.g | 17 +++++++++++--- src/qml/parser/qqmljsast.cpp | 9 ++++++++ src/qml/parser/qqmljsast_p.h | 44 +++++++++++++++++++++++++++++++++++-- src/qml/parser/qqmljsastfwd_p.h | 1 + src/qml/parser/qqmljsastvisitor_p.h | 2 ++ 5 files changed, 68 insertions(+), 5 deletions(-) diff --git a/src/qml/parser/qqmljs.g b/src/qml/parser/qqmljs.g index 879de92e5f..a5062aafc7 100644 --- a/src/qml/parser/qqmljs.g +++ b/src/qml/parser/qqmljs.g @@ -326,6 +326,7 @@ public: AST::UiQualifiedId *UiQualifiedId; AST::UiEnumMemberList *UiEnumMemberList; AST::UiVersionSpecifier *UiVersionSpecifier; + AST::UiAnnotationList *UiAnnotationList; }; public: @@ -958,18 +959,24 @@ UiAnnotationObjectDefinition: UiSimpleQualifiedId UiObjectInitializer; ./ UiAnnotation: T_AT UiAnnotationObjectDefinition; +/. +case $rule_number: { + sym(1).Node = sym(2).Node; +} break; +./ + UiAnnotationList: UiAnnotation; /. case $rule_number: { - sym(1).Node = new (pool) AST::UiArrayMemberList(sym(1).UiObjectMember); + sym(1).Node = new (pool) AST::UiAnnotationList(sym(1).UiObjectDefinition); } break; ./ UiAnnotationList: UiAnnotationList UiAnnotation; /. case $rule_number: { - AST::UiArrayMemberList *node = new (pool) AST::UiArrayMemberList(sym(1).UiArrayMemberList, sym(3).UiObjectMember); + AST::UiAnnotationList *node = new (pool) AST::UiAnnotationList(sym(1).UiAnnotationList, sym(2).UiObjectDefinition); sym(1).Node = node; } break; ./ @@ -977,7 +984,9 @@ UiAnnotationList: UiAnnotationList UiAnnotation; UiAnnotatedObject: UiAnnotationList UiObjectDefinition; /. case $rule_number: { - sym(1).Node = sym(2).Node; + AST::UiObjectMember *node = sym(2).UiObjectMember; + node->annotations = sym(1).UiAnnotationList->finish(); + sym(1).Node = node; } break; ./ @@ -1045,6 +1054,8 @@ UiObjectDefinition: UiQualifiedId UiObjectInitializer; UiAnnotatedObjectMember: UiAnnotationList UiObjectMember; /. case $rule_number: { + AST::UiObjectMember *node = sym(2).UiObjectMember; + node->annotations = sym(1).UiAnnotationList->finish(); sym(1).Node = sym(2).Node; } break; ./ diff --git a/src/qml/parser/qqmljsast.cpp b/src/qml/parser/qqmljsast.cpp index 416916c547..19b03d3cd1 100644 --- a/src/qml/parser/qqmljsast.cpp +++ b/src/qml/parser/qqmljsast.cpp @@ -1562,6 +1562,15 @@ void UiRequired::accept0(Visitor *visitor) visitor->endVisit(this); } +void UiAnnotationList::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(annotation, visitor); + } + + visitor->endVisit(this); +} + } } // namespace QQmlJS::AST QT_END_NAMESPACE diff --git a/src/qml/parser/qqmljsast_p.h b/src/qml/parser/qqmljsast_p.h index f3369676e9..a5ef3ca67b 100644 --- a/src/qml/parser/qqmljsast_p.h +++ b/src/qml/parser/qqmljsast_p.h @@ -259,7 +259,8 @@ public: Kind_UiEnumDeclaration, Kind_UiEnumMemberList, Kind_UiVersionSpecifier, - Kind_UiRequired + Kind_UiRequired, + Kind_UiAnnotationList }; inline Node() {} @@ -3042,6 +3043,9 @@ public: SourceLocation lastSourceLocation() const override = 0; UiObjectMember *uiObjectMemberCast() override; + +// attributes + UiAnnotationList *annotations = nullptr; }; class QML_PARSER_EXPORT UiObjectMemberList: public Node @@ -3624,8 +3628,44 @@ public: UiEnumMemberList *members; }; -} } // namespace AST +class QML_PARSER_EXPORT UiAnnotationList: public Node +{ +public: + QQMLJS_DECLARE_AST_NODE(UiAnnotationList) + + UiAnnotationList(UiObjectDefinition *annotation) + : next(this), annotation(annotation) + { kind = K; } + + UiAnnotationList(UiAnnotationList *previous, UiObjectDefinition *annotation) + : annotation(annotation) + { + kind = K; + next = previous->next; + previous->next = this; + } + + void accept0(Visitor *visitor) override; + + SourceLocation firstSourceLocation() const override + { return annotation->firstSourceLocation(); } + + SourceLocation lastSourceLocation() const override + { return lastListElement(this)->annotation->lastSourceLocation(); } + + UiAnnotationList *finish() + { + UiAnnotationList *head = next; + next = nullptr; + return head; + } +// attributes + UiAnnotationList *next; + UiObjectDefinition *annotation; +}; + +} } // namespace AST QT_END_NAMESPACE diff --git a/src/qml/parser/qqmljsastfwd_p.h b/src/qml/parser/qqmljsastfwd_p.h index fe260e2bb5..595319e3c2 100644 --- a/src/qml/parser/qqmljsastfwd_p.h +++ b/src/qml/parser/qqmljsastfwd_p.h @@ -184,6 +184,7 @@ class UiEnumDeclaration; class UiEnumMemberList; class UiVersionSpecifier; class UiRequired; +class UiAnnotationList; } // namespace AST } // namespace QQmlJS diff --git a/src/qml/parser/qqmljsastvisitor_p.h b/src/qml/parser/qqmljsastvisitor_p.h index fcc48da1d3..566c6336b0 100644 --- a/src/qml/parser/qqmljsastvisitor_p.h +++ b/src/qml/parser/qqmljsastvisitor_p.h @@ -113,6 +113,7 @@ public: virtual bool visit(UiEnumMemberList *) { return true; } virtual bool visit(UiVersionSpecifier *) { return true; } virtual bool visit(UiInlineComponent *) { return true; } + virtual bool visit(UiAnnotationList *) { return true; } virtual void endVisit(UiProgram *) {} virtual void endVisit(UiImport *) {} @@ -133,6 +134,7 @@ public: virtual void endVisit(UiEnumMemberList *) { } virtual void endVisit(UiVersionSpecifier *) {} virtual void endVisit(UiInlineComponent *) {} + virtual void endVisit(UiAnnotationList *) {} // QQmlJS virtual bool visit(ThisExpression *) { return true; } -- cgit v1.2.3 From 9b1dc349a58f82d130feb73dcd30f3766c924d20 Mon Sep 17 00:00:00 2001 From: Fawzi Mohamed Date: Thu, 6 Feb 2020 14:20:16 +0100 Subject: Mark non visited AST parts Add a commented out accept call for the non visited fields in accept0 Change-Id: Icb1ab0c77440f4c3eae5404bff2cf71086f96a2f Reviewed-by: Ulf Hermann --- src/qml/parser/qqmljsast.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/qml/parser/qqmljsast.cpp b/src/qml/parser/qqmljsast.cpp index 19b03d3cd1..7cf263e2ba 100644 --- a/src/qml/parser/qqmljsast.cpp +++ b/src/qml/parser/qqmljsast.cpp @@ -1186,8 +1186,11 @@ void UiProgram::accept0(Visitor *visitor) void UiPublicMember::accept0(Visitor *visitor) { if (visitor->visit(this)) { + // accept(annotations, visitor); // accept manually in visit if interested + // accept(memberType, visitor); // accept manually in visit if interested accept(statement, visitor); accept(binding, visitor); + // accept(parameters, visitor); // accept manually in visit if interested } visitor->endVisit(this); @@ -1196,6 +1199,7 @@ void UiPublicMember::accept0(Visitor *visitor) void UiObjectDefinition::accept0(Visitor *visitor) { if (visitor->visit(this)) { + // accept(annotations, visitor); // accept manually in visit if interested accept(qualifiedTypeNameId, visitor); accept(initializer, visitor); } @@ -1215,6 +1219,7 @@ void UiObjectInitializer::accept0(Visitor *visitor) void UiParameterList::accept0(Visitor *visitor) { if (visitor->visit(this)) { + // accept(type, visitor); // accept manually in visit if interested } visitor->endVisit(this); } @@ -1222,6 +1227,7 @@ void UiParameterList::accept0(Visitor *visitor) void UiObjectBinding::accept0(Visitor *visitor) { if (visitor->visit(this)) { + // accept(annotations, visitor); // accept manually in visit if interested accept(qualifiedId, visitor); accept(qualifiedTypeNameId, visitor); accept(initializer, visitor); @@ -1233,6 +1239,7 @@ void UiObjectBinding::accept0(Visitor *visitor) void UiScriptBinding::accept0(Visitor *visitor) { if (visitor->visit(this)) { + // accept(annotations, visitor); // accept manually in visit if interested accept(qualifiedId, visitor); accept(statement, visitor); } @@ -1243,6 +1250,7 @@ void UiScriptBinding::accept0(Visitor *visitor) void UiArrayBinding::accept0(Visitor *visitor) { if (visitor->visit(this)) { + // accept(annotations, visitor); // accept manually in visit if interested accept(qualifiedId, visitor); accept(members, visitor); } @@ -1273,6 +1281,7 @@ void UiArrayMemberList::accept0(Visitor *visitor) void UiQualifiedId::accept0(Visitor *visitor) { if (visitor->visit(this)) { + // accept(next, visitor) // accept manually in visit if interested } visitor->endVisit(this); @@ -1311,6 +1320,7 @@ void UiImport::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(importUri, visitor); + // accept(version, visitor); // accept manually in visit if interested } visitor->endVisit(this); @@ -1340,6 +1350,7 @@ void UiHeaderItemList::accept0(Visitor *visitor) void UiSourceElement::accept0(Visitor *visitor) { if (visitor->visit(this)) { + // accept(annotations, visitor); // accept manually in visit if interested accept(sourceElement, visitor); } @@ -1349,6 +1360,7 @@ void UiSourceElement::accept0(Visitor *visitor) void UiEnumDeclaration::accept0(Visitor *visitor) { if (visitor->visit(this)) { + // accept(annotations, visitor); // accept manually in visit if interested accept(members, visitor); } @@ -1548,6 +1560,7 @@ void Type::toString(QString *out) const void UiInlineComponent::accept0(Visitor *visitor) { if (visitor->visit(this)) { + // accept(annotations, visitor); // accept manually in visit if interested accept(component, visitor); } -- cgit v1.2.3 From 1249761a341ea2cd959a311d9a6523a3e9936887 Mon Sep 17 00:00:00 2001 From: Fawzi Mohamed Date: Thu, 6 Feb 2020 14:23:00 +0100 Subject: Make UiObjectDefinition uniform attributes are always at the end of AST objects, move them there also for UiObjectDefinition. Change-Id: I7630b1c40627913c3e7e46e752acf1d80203ce63 Reviewed-by: Fabian Kosmale --- src/qml/parser/qqmljsast_p.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/qml/parser/qqmljsast_p.h b/src/qml/parser/qqmljsast_p.h index a5ef3ca67b..a8b15e6874 100644 --- a/src/qml/parser/qqmljsast_p.h +++ b/src/qml/parser/qqmljsast_p.h @@ -3414,10 +3414,6 @@ public: : name(inlineComponentName), component(inlineComponent) { kind = K; } - QStringRef name; - UiObjectDefinition* component; - SourceLocation componentToken; - SourceLocation lastSourceLocation() const override {return component->lastSourceLocation();} @@ -3425,6 +3421,11 @@ public: {return componentToken;} void accept0(Visitor *visitor) override; + + // attributes + QStringRef name; + UiObjectDefinition* component; + SourceLocation componentToken; }; class QML_PARSER_EXPORT UiSourceElement: public UiObjectMember -- cgit v1.2.3 From 2b31d84cc06cc70e753f91a9a4fef3b22c6de62b Mon Sep 17 00:00:00 2001 From: Fawzi Mohamed Date: Thu, 6 Feb 2020 14:25:34 +0100 Subject: Remove unused AST::ModuleItem ModuleItem is unused we should either remove it or make it a used abstract superclass like UiObjectMember. Here we remove it. Change-Id: Icfcebd450e09ebe324a99728613eea0348b980ac Reviewed-by: Fabian Kosmale --- src/qml/parser/qqmljsastfwd_p.h | 1 - src/qml/parser/qqmljsastvisitor_p.h | 3 --- 2 files changed, 4 deletions(-) diff --git a/src/qml/parser/qqmljsastfwd_p.h b/src/qml/parser/qqmljsastfwd_p.h index 595319e3c2..b7148158d5 100644 --- a/src/qml/parser/qqmljsastfwd_p.h +++ b/src/qml/parser/qqmljsastfwd_p.h @@ -151,7 +151,6 @@ class NamedImport; class ImportClause; class FromClause; class ImportDeclaration; -class ModuleItem; class ESModule; class DebuggerStatement; class NestedExpression; diff --git a/src/qml/parser/qqmljsastvisitor_p.h b/src/qml/parser/qqmljsastvisitor_p.h index 566c6336b0..8339d2113d 100644 --- a/src/qml/parser/qqmljsastvisitor_p.h +++ b/src/qml/parser/qqmljsastvisitor_p.h @@ -398,9 +398,6 @@ public: virtual bool visit(ExportDeclaration *) { return true; } virtual void endVisit(ExportDeclaration *) {} - virtual bool visit(ModuleItem *) { return true; } - virtual void endVisit(ModuleItem *) {} - virtual bool visit(ESModule *) { return true; } virtual void endVisit(ESModule *) {} -- cgit v1.2.3 From cc918272bb5d329d42905713925a59a1513120f2 Mon Sep 17 00:00:00 2001 From: Fawzi Mohamed Date: Mon, 10 Feb 2020 17:55:13 +0100 Subject: Avoid cast from ASCII in qv4engine warning message Change-Id: Idb48122c4e7e294de820cd40036d7a6537ea2cac Reviewed-by: Ulf Hermann Reviewed-by: Fabian Kosmale --- src/qml/jsruntime/qv4engine.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 04650ab979..0b2d657141 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -1532,8 +1532,8 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int if (!couldConvert) { qWarning() << QLatin1String("Could not convert array value at position %1 from %2 to %3") .arg(QString::number(i), - QMetaType::typeName(originalType), - QMetaType::typeName(retnAsIterable._metaType_id)); + QString::fromUtf8(QMetaType::typeName(originalType)), + QString::fromUtf8(QMetaType::typeName(retnAsIterable._metaType_id))); // create default constructed value asVariant = QVariant(retnAsIterable._metaType_id, nullptr); } -- cgit v1.2.3 From 731c85c2a42d7398a0319df5b8d0b465d118ba0d Mon Sep 17 00:00:00 2001 From: Fawzi Mohamed Date: Mon, 10 Feb 2020 18:03:04 +0100 Subject: Put Ui visitors together UiRequired is not with all Ui Vistors and introduced with a // Ui comment. Move it there for consistency. Change-Id: I51315ad380fd50998e7efe095c873d14a5ae7a97 Reviewed-by: Ulf Hermann Reviewed-by: Fabian Kosmale --- src/qml/parser/qqmljsastvisitor_p.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/qml/parser/qqmljsastvisitor_p.h b/src/qml/parser/qqmljsastvisitor_p.h index 8339d2113d..2671587b62 100644 --- a/src/qml/parser/qqmljsastvisitor_p.h +++ b/src/qml/parser/qqmljsastvisitor_p.h @@ -114,6 +114,7 @@ public: virtual bool visit(UiVersionSpecifier *) { return true; } virtual bool visit(UiInlineComponent *) { return true; } virtual bool visit(UiAnnotationList *) { return true; } + virtual bool visit(UiRequired *) { return true; } virtual void endVisit(UiProgram *) {} virtual void endVisit(UiImport *) {} @@ -135,6 +136,7 @@ public: virtual void endVisit(UiVersionSpecifier *) {} virtual void endVisit(UiInlineComponent *) {} virtual void endVisit(UiAnnotationList *) {} + virtual void endVisit(UiRequired *) {} // QQmlJS virtual bool visit(ThisExpression *) { return true; } @@ -413,9 +415,6 @@ public: virtual bool visit(TypeAnnotation *) { return true; } virtual void endVisit(TypeAnnotation *) {} - virtual bool visit(UiRequired *) { return true; } - virtual void endVisit(UiRequired *) {} - virtual void throwRecursionDepthError() = 0; quint16 recursionDepth() const { return m_recursionDepth; } -- cgit v1.2.3 From 70120c931faa0c6139354c75fcf8d39b77ec3b4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Arve=20S=C3=A6ther?= Date: Fri, 22 Nov 2019 17:03:43 +0100 Subject: Fix a bug where a layout could crash or become non-responsive This happened because of that QQuickText is ill-behaving: When the width on a QQuickText with word wrap enabled is changed to something less than its implicitWidth, its implicitHeight is changed to reflect the height it needs in order to fit all lines. This will cause the layout to be invalidated, and rearranged again. However, at the same time it will also change its implicitWidth actually become wider than its initial implicitWidth (this seems to be a bug). So the next time it is rearranged it will actually be wide enough so that it doesn't need to wrap. This again will cause its implicitWidth and implicitHeight to change to reflect that only one line is needed, which again will cause it to rearrange, but since the item has a too small width for that it will again change the implicitHeight to reflect that it needs more lines..... This went on forever until there was a stack overflow. In addition it also caused an endless (that is, if it didn't stack overflow) updatePolish()/polish() loop (basically polish() was called from within updatePolish() continuously). To make the layout more robust for such "ill-behaving" items we have to add one recursion guard, and one polish-loop guard. Change-Id: I9f752ed320a100c8d0f0fd340347a556e63318e5 Task-number: QTBUG-73683 Reviewed-by: Richard Moe Gustavsen --- src/imports/layouts/qquicklayout.cpp | 21 ++++++++++++--- src/imports/layouts/qquicklayout_p.h | 4 ++- src/imports/layouts/qquicklinearlayout.cpp | 10 +++++++ src/imports/layouts/qquicklinearlayout_p.h | 4 ++- .../quick/qquicklayouts/data/tst_rowlayout.qml | 31 ++++++++++++++++++++++ 5 files changed, 65 insertions(+), 5 deletions(-) diff --git a/src/imports/layouts/qquicklayout.cpp b/src/imports/layouts/qquicklayout.cpp index 450cf26cea..17d37b5c4e 100644 --- a/src/imports/layouts/qquicklayout.cpp +++ b/src/imports/layouts/qquicklayout.cpp @@ -701,8 +701,10 @@ QQuickItem *QQuickLayoutAttached::item() const QQuickLayout::QQuickLayout(QQuickLayoutPrivate &dd, QQuickItem *parent) - : QQuickItem(dd, parent), - m_dirty(false) + : QQuickItem(dd, parent) + , m_dirty(false) + , m_inUpdatePolish(false) + , m_polishInsideUpdatePolish(0) { } @@ -729,7 +731,9 @@ QQuickLayoutAttached *QQuickLayout::qmlAttachedProperties(QObject *object) void QQuickLayout::updatePolish() { + m_inUpdatePolish = true; rearrange(QSizeF(width(), height())); + m_inUpdatePolish = false; } void QQuickLayout::componentComplete() @@ -750,7 +754,18 @@ void QQuickLayout::invalidate(QQuickItem * /*childItem*/) if (!qobject_cast(parentItem())) { quickLayoutDebug() << "QQuickLayout::invalidate(), polish()"; - polish(); + + if (m_inUpdatePolish) + ++m_polishInsideUpdatePolish; + else + m_polishInsideUpdatePolish = 0; + + if (m_polishInsideUpdatePolish <= 2) + // allow at most two consecutive loops in order to respond to height-for-width + // (e.g QQuickText changes implicitHeight when its width gets changed) + polish(); + else + qWarning() << "Qt Quick Layouts: Polish loop detected. Aborting after two iterations."; } } diff --git a/src/imports/layouts/qquicklayout_p.h b/src/imports/layouts/qquicklayout_p.h index 3f076c7304..d2421667be 100644 --- a/src/imports/layouts/qquicklayout_p.h +++ b/src/imports/layouts/qquicklayout_p.h @@ -119,7 +119,9 @@ protected slots: void invalidateSenderItem(); private: - bool m_dirty; + unsigned m_dirty : 1; + unsigned m_inUpdatePolish : 1; + unsigned m_polishInsideUpdatePolish : 2; Q_DECLARE_PRIVATE(QQuickLayout) diff --git a/src/imports/layouts/qquicklinearlayout.cpp b/src/imports/layouts/qquicklinearlayout.cpp index c8d2ac5eb2..911793d748 100644 --- a/src/imports/layouts/qquicklinearlayout.cpp +++ b/src/imports/layouts/qquicklinearlayout.cpp @@ -469,6 +469,16 @@ void QQuickGridLayoutBase::rearrange(const QSizeF &size) if (!isReady()) return; + const auto refCounter = qScopeGuard([&d] { + --(d->m_recurRearrangeCounter); + }); + if (d->m_recurRearrangeCounter++ == 2) { + // allow a recursive depth of two in order to respond to height-for-width + // (e.g QQuickText changes implicitHeight when its width gets changed) + qWarning() << "Qt Quick Layouts: Detected recursive rearrange. Aborting after two iterations."; + return; + } + d->m_rearranging = true; quickLayoutDebug() << objectName() << "QQuickGridLayoutBase::rearrange()" << size; Qt::LayoutDirection visualDir = effectiveLayoutDirection(); diff --git a/src/imports/layouts/qquicklinearlayout_p.h b/src/imports/layouts/qquicklinearlayout_p.h index 6706ebf9fa..866d0884a2 100644 --- a/src/imports/layouts/qquicklinearlayout_p.h +++ b/src/imports/layouts/qquicklinearlayout_p.h @@ -104,7 +104,8 @@ class QQuickGridLayoutBasePrivate : public QQuickLayoutPrivate Q_DECLARE_PUBLIC(QQuickGridLayoutBase) public: - QQuickGridLayoutBasePrivate() : m_rearranging(false) + QQuickGridLayoutBasePrivate() : m_recurRearrangeCounter(0) + , m_rearranging(false) , m_updateAfterRearrange(false) , m_layoutDirection(Qt::LeftToRight) {} @@ -117,6 +118,7 @@ public: QQuickGridLayoutEngine engine; Qt::Orientation orientation; + unsigned m_recurRearrangeCounter : 2; unsigned m_rearranging : 1; unsigned m_updateAfterRearrange : 1; QVector m_invalidateAfterRearrange; diff --git a/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml b/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml index 07af6a77ac..0732884c97 100644 --- a/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml +++ b/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml @@ -1100,5 +1100,36 @@ Item { waitForRendering(rootRect.layout) compare(rootRect.item1.width, 100) } + +//--------------------------- + Component { + id: rowlayoutWithTextItems_Component + RowLayout { + Text { + Layout.fillWidth: true + text: "OneWord" + wrapMode: Text.WrapAtWordBoundaryOrAnywhere + } + Text { + Layout.fillWidth: true + text: "OneWord" + wrapMode: Text.WrapAtWordBoundaryOrAnywhere + } + } + } + + // QTBUG-73683 + function test_rowlayoutWithTextItems() { + var layout = createTemporaryObject(rowlayoutWithTextItems_Component, container) + waitForRendering(layout) + for (var i = 0; i < 3; i++) { + ignoreWarning(/Qt Quick Layouts: Detected recursive rearrange. Aborting after two iterations./) + } + ignoreWarning(/Qt Quick Layouts: Polish loop detected. Aborting after two iterations./) + layout.width = layout.width - 2 // set the size to be smaller than its "minimum size" + waitForRendering(layout) // do not exit before all warnings have been received + + // DO NOT CRASH due to stack overflow (or loop endlessly due to updatePolish()/polish() loop) + } } } -- cgit v1.2.3 From 20e8a55838f0dadb218d7b0dd85bf16b6caddc65 Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Thu, 6 Feb 2020 11:21:40 +0100 Subject: Documentation: reflow to limit line length Change-Id: I5f2f8383e4e8f6e650dcad1ae7c07e0bacd36136 Reviewed-by: Paul Wicking --- .../src/qmllanguageref/documents/definetypes.qdoc | 77 ++++++++++++++++++---- 1 file changed, 63 insertions(+), 14 deletions(-) diff --git a/src/qml/doc/src/qmllanguageref/documents/definetypes.qdoc b/src/qml/doc/src/qmllanguageref/documents/definetypes.qdoc index 0a55f36287..2eaedf8f9b 100644 --- a/src/qml/doc/src/qmllanguageref/documents/definetypes.qdoc +++ b/src/qml/doc/src/qmllanguageref/documents/definetypes.qdoc @@ -29,25 +29,37 @@ \title Defining Object Types through QML Documents \brief Description of how a QML document is a reusable type definition -One of the core features of QML is that it enables QML object types to be easily defined in a lightweight manner through QML documents to suit the needs of individual QML applications. The standard \l {Qt Quick} module provides various types like \l Rectangle, \l Text and \l Image for building a QML application; beyond these, you can easily define your own QML types to be reused within your application. This ability to create your own types forms the building blocks of any QML application. +One of the core features of QML is that it enables QML object types to be +easily defined in a lightweight manner through QML documents to suit the needs +of individual QML applications. The standard \l {Qt Quick} module provides +various types like \l Rectangle, \l Text and \l Image for building a QML +application; beyond these, you can easily define your own QML types to be +reused within your application. This ability to create your own types forms the +building blocks of any QML application. \section1 Defining an Object Type with a QML File \section2 Naming Custom QML Object Types -To create an object type, a QML document should be placed into a text file named as \e .qml where \e is the desired name of the type. The type name has the following requirements: +To create an object type, a QML document should be placed into a text file +named as \e .qml where \e is the desired name of the type. +The type name has the following requirements: \list \li It must be comprised of alphanumeric characters or underscores. \li It must begin with an uppercase letter. \endlist -This document is then automatically recognized by the engine as a definition of a QML type. Additionally, a type defined in this manner is automatically made available to other QML files within the same directory as the engine searches within the immediate directory when resolving QML type names. +This document is then automatically recognized by the engine as a definition of +a QML type. Additionally, a type defined in this manner is automatically made +available to other QML files within the same directory as the engine searches +within the immediate directory when resolving QML type names. \section2 Custom QML Type Definition -For example, below is a document that declares a \l Rectangle with a child \l MouseArea. The document has been saved to file named \c SquareButton.qml: +For example, below is a document that declares a \l Rectangle with a child \l +MouseArea. The document has been saved to file named \c SquareButton.qml: \qml // SquareButton.qml @@ -65,7 +77,10 @@ Rectangle { } \endqml -Since the file is named \c SquareButton.qml, \b {this can now be used as a type named \c SquareButton by any other QML file within the same directory}. For example, if there was a \c myapplication.qml file in the same directory, it could refer to the \c SquareButton type: +Since the file is named \c SquareButton.qml, \b {this can now be used as a type +named \c SquareButton by any other QML file within the same directory}. For +example, if there was a \c myapplication.qml file in the same directory, it +could refer to the \c SquareButton type: \qml // myapplication.qml @@ -76,11 +91,20 @@ SquareButton {} \image documents-definetypes-simple.png -This creates a 100 x 100 red \l Rectangle with an inner \l MouseArea, as defined in \c SquareButton.qml. When this \c myapplication.qml document is loaded by the engine, it loads the SquareButton.qml document as a component and instantiates it to create a \c SquareButton object. +This creates a 100 x 100 red \l Rectangle with an inner \l MouseArea, as +defined in \c SquareButton.qml. When this \c myapplication.qml document is +loaded by the engine, it loads the SquareButton.qml document as a component and +instantiates it to create a \c SquareButton object. -The \c SquareButton type encapsulates the tree of QML objects declared in \c SquareButton.qml. When the QML engine instantiates a \c SquareButton object from this type, it is instantiating an object from the \l Rectangle tree declared in \c SquareButton.qml. +The \c SquareButton type encapsulates the tree of QML objects declared in \c +SquareButton.qml. When the QML engine instantiates a \c SquareButton object +from this type, it is instantiating an object from the \l Rectangle tree +declared in \c SquareButton.qml. -\note the letter case of the file name is significant on some (notably UNIX) filesystems. It is recommended the file name case matches the case of the desired QML type name exactly - for example, \c Box.qml and not \c BoX.qml - regardless of the platform to which the QML type will be deployed. +\note the letter case of the file name is significant on some (notably UNIX) +filesystems. It is recommended the file name case matches the case of the +desired QML type name exactly - for example, \c Box.qml and not \c BoX.qml - +regardless of the platform to which the QML type will be deployed. \section2 Inline Components @@ -121,14 +145,25 @@ which are not part of it. \section2 Importing Types Defined Outside the Current Directory If \c SquareButton.qml was not in the same directory as \c myapplication.qml, -the \c SquareButton type would need to be specifically made available through an \e import statement in \c myapplication.qml. It could be imported from a relative path on the file system, or as an installed module; see \l {QML Modules}{module} for more details. +the \c SquareButton type would need to be specifically made available through +an \e import statement in \c myapplication.qml. It could be imported from a +relative path on the file system, or as an installed module; see \l {QML +Modules}{module} for more details. \section1 Accessible Attributes of Custom Types -The \b {root object} definition in a .qml file \b {defines the attributes that are available for a QML type}. All properties, signals and methods that belong to this root object - whether they are custom declared, or come from the QML type of the root object - are externally accessible and can be read and modified for objects of this type. +The \b {root object} definition in a .qml file \b {defines the attributes that +are available for a QML type}. All properties, signals and methods that belong +to this root object - whether they are custom declared, or come from the QML +type of the root object - are externally accessible and can be read and +modified for objects of this type. -For example, the root object type in the \c SquareButton.qml file above is \l Rectangle. This means any properties defined by the \l Rectangle type can be modified for a \c SquareButton object. The code below defines three \c SquareButton objects with customized values for some of the properties of the root \l Rectangle object of the \c SquareButton type: +For example, the root object type in the \c SquareButton.qml file above is \l +Rectangle. This means any properties defined by the \l Rectangle type can be +modified for a \c SquareButton object. The code below defines three \c +SquareButton objects with customized values for some of the properties of the +root \l Rectangle object of the \c SquareButton type: \qml // application.qml @@ -143,7 +178,12 @@ Column { \image documents-definetypes-attributes.png -The attributes that are accessible to objects of the custom QML type include any \l{Defining Property Attributes}{custom properties}, \l{Defining Method Attributes}{methods} and \l{Defining Signal Attributes}{signals} that have additionally been defined for an object. For example, suppose the \l Rectangle in \c SquareButton.qml had been defined as follows, with additional properties, methods and signals: +The attributes that are accessible to objects of the custom QML type include +any \l{Defining Property Attributes}{custom properties}, \l{Defining Method +Attributes}{methods} and \l{Defining Signal Attributes}{signals} that have +additionally been defined for an object. For example, suppose the \l Rectangle +in \c SquareButton.qml had been defined as follows, with additional properties, +methods and signals: \qml // SquareButton.qml @@ -172,7 +212,9 @@ Rectangle { } \endqml -Any \c SquareButton object could make use of the \c pressed property, \c buttonClicked signal and \c randomizeColor() method that have been added to the root \l Rectangle: +Any \c SquareButton object could make use of the \c pressed property, \c +buttonClicked signal and \c randomizeColor() method that have been added to the +root \l Rectangle: \qml // application.qml @@ -190,7 +232,14 @@ SquareButton { } \endqml -Note that any of the \c id values defined in \c SquareButton.qml are not accessible to \c SquareButton objects, as id values are only accessible from within the component scope in which a component is declared. The \c SquareButton object definition above cannot refer to \c mouseArea in order to refer to the \l MouseArea child, and if it had an \c id of \c root rather than \c squareButton, this would not conflict with the \c id of the same value for the root object defined in \c SquareButton.qml as the two would be declared within separate scopes. +Note that any of the \c id values defined in \c SquareButton.qml are not +accessible to \c SquareButton objects, as id values are only accessible from +within the component scope in which a component is declared. The \c +SquareButton object definition above cannot refer to \c mouseArea in order to +refer to the \l MouseArea child, and if it had an \c id of \c root rather than +\c squareButton, this would not conflict with the \c id of the same value for +the root object defined in \c SquareButton.qml as the two would be declared +within separate scopes. */ -- cgit v1.2.3 From 1a7ca47a7a92945e16006ddd00adea186535cdd5 Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Wed, 12 Feb 2020 13:29:08 +0100 Subject: QQuickLoader: store status This allows us to emit the change signal only when the status has actually changed. Due to alignment restrictions, this does not even change the size of the class. Fixes: QTBUG-82002 Change-Id: I2192bf80e72b92108046780811c3acdab39af518 Reviewed-by: Ulf Hermann --- src/quick/items/qquickloader.cpp | 93 +++++++++++++--------- src/quick/items/qquickloader_p_p.h | 7 ++ .../auto/quick/qquickloader/data/statusChanged.qml | 16 ++++ tests/auto/quick/qquickloader/tst_qquickloader.cpp | 14 ++++ 4 files changed, 91 insertions(+), 39 deletions(-) create mode 100644 tests/auto/quick/qquickloader/data/statusChanged.qml diff --git a/src/quick/items/qquickloader.cpp b/src/quick/items/qquickloader.cpp index b389e7a11b..8c15b60712 100644 --- a/src/quick/items/qquickloader.cpp +++ b/src/quick/items/qquickloader.cpp @@ -55,7 +55,7 @@ static const QQuickItemPrivate::ChangeTypes watchedChanges QQuickLoaderPrivate::QQuickLoaderPrivate() : item(nullptr), object(nullptr), itemContext(nullptr), incubator(nullptr), updatingSize(false), - active(true), loadingFromSource(false), asynchronous(false) + active(true), loadingFromSource(false), asynchronous(false), status(computeStatus()) { } @@ -378,7 +378,7 @@ void QQuickLoader::setActive(bool newVal) d->object = nullptr; emit itemChanged(); } - emit statusChanged(); + d->updateStatus(); } emit activeChanged(); } @@ -431,7 +431,7 @@ void QQuickLoader::loadFromSource() Q_D(QQuickLoader); if (d->source.isEmpty()) { emit sourceChanged(); - emit statusChanged(); + d->updateStatus(); emit progressChanged(); emit itemChanged(); return; @@ -502,7 +502,7 @@ void QQuickLoader::loadFromSourceComponent() Q_D(QQuickLoader); if (!d->component) { emit sourceComponentChanged(); - emit statusChanged(); + d->updateStatus(); emit progressChanged(); emit itemChanged(); return; @@ -618,7 +618,7 @@ void QQuickLoaderPrivate::load() q, SLOT(_q_sourceLoaded())); QObject::connect(component, SIGNAL(progressChanged(qreal)), q, SIGNAL(progressChanged())); - emit q->statusChanged(); + updateStatus(); emit q->progressChanged(); if (loadingFromSource) emit q->sourceChanged(); @@ -705,7 +705,7 @@ void QQuickLoaderPrivate::incubatorStateChanged(QQmlIncubator::Status status) emit q->sourceChanged(); else emit q->sourceComponentChanged(); - emit q->statusChanged(); + updateStatus(); emit q->progressChanged(); if (status == QQmlIncubator::Ready) emit q->loaded(); @@ -722,7 +722,7 @@ void QQuickLoaderPrivate::_q_sourceLoaded() emit q->sourceChanged(); else emit q->sourceComponentChanged(); - emit q->statusChanged(); + updateStatus(); emit q->progressChanged(); emit q->itemChanged(); //Like clearing source, emit itemChanged even if previous item was also null disposeInitialPropertyValues(); // cleanup @@ -740,7 +740,7 @@ void QQuickLoaderPrivate::_q_sourceLoaded() component->create(*incubator, itemContext); if (incubator && incubator->status() == QQmlIncubator::Loading) - emit q->statusChanged(); + updateStatus(); } /*! @@ -787,37 +787,7 @@ QQuickLoader::Status QQuickLoader::status() const { Q_D(const QQuickLoader); - if (!d->active) - return Null; - - if (d->component) { - switch (d->component->status()) { - case QQmlComponent::Loading: - return Loading; - case QQmlComponent::Error: - return Error; - case QQmlComponent::Null: - return Null; - default: - break; - } - } - - if (d->incubator) { - switch (d->incubator->status()) { - case QQmlIncubator::Loading: - return Loading; - case QQmlIncubator::Error: - return Error; - default: - break; - } - } - - if (d->object) - return Ready; - - return d->source.isEmpty() ? Null : Error; + return static_cast(d->status); } void QQuickLoader::componentComplete() @@ -1018,6 +988,51 @@ QV4::ReturnedValue QQuickLoaderPrivate::extractInitialPropertyValues(QQmlV4Funct return valuemap->asReturnedValue(); } +QQuickLoader::Status QQuickLoaderPrivate::computeStatus() const +{ + if (!active) + return QQuickLoader::Status::Null; + + if (component) { + switch (component->status()) { + case QQmlComponent::Loading: + return QQuickLoader::Status::Loading; + case QQmlComponent::Error: + return QQuickLoader::Status::Error; + case QQmlComponent::Null: + return QQuickLoader::Status::Null; + default: + break; + } + } + + if (incubator) { + switch (incubator->status()) { + case QQmlIncubator::Loading: + return QQuickLoader::Status::Loading; + case QQmlIncubator::Error: + return QQuickLoader::Status::Error; + default: + break; + } + } + + if (object) + return QQuickLoader::Status::Ready; + + return source.isEmpty() ? QQuickLoader::Status::Null : QQuickLoader::Status::Error; +} + +void QQuickLoaderPrivate::updateStatus() +{ + Q_Q(QQuickLoader); + auto newStatus = computeStatus(); + if (status != newStatus) { + status = newStatus; + emit q->statusChanged(); + } +} + #include QT_END_NAMESPACE diff --git a/src/quick/items/qquickloader_p_p.h b/src/quick/items/qquickloader_p_p.h index 349b5c6c06..39d50280c5 100644 --- a/src/quick/items/qquickloader_p_p.h +++ b/src/quick/items/qquickloader_p_p.h @@ -96,6 +96,8 @@ public: void disposeInitialPropertyValues(); static QUrl resolveSourceUrl(QQmlV4Function *args); QV4::ReturnedValue extractInitialPropertyValues(QQmlV4Function *args, QObject *loader, bool *error); + QQuickLoader::Status computeStatus() const; + void updateStatus(); qreal getImplicitWidth() const override; qreal getImplicitHeight() const override; @@ -112,6 +114,11 @@ public: bool active : 1; bool loadingFromSource : 1; bool asynchronous : 1; + // We need to use char instead of QQuickLoader::Status + // as otherwise the size of the class would increase + // on 32-bit systems, as sizeof(Status) == sizeof(int) + // and sizeof(int) > remaining padding on 32 bit + char status; void _q_sourceLoaded(); void _q_updateSize(bool loaderGeometryChanged = true); diff --git a/tests/auto/quick/qquickloader/data/statusChanged.qml b/tests/auto/quick/qquickloader/data/statusChanged.qml new file mode 100644 index 0000000000..fe46bc7b24 --- /dev/null +++ b/tests/auto/quick/qquickloader/data/statusChanged.qml @@ -0,0 +1,16 @@ +import QtQuick 2.12 +import QtQuick.Window 2.12 + +Window { + id: root + property int statusChangedCounter: 0 + property alias status: loader.status + visible: true; width: 640; height: 480 + Loader { + id: loader + anchors.fill: parent + asynchronous: true + source: "./RedRect.qml" + onStatusChanged: root.statusChangedCounter++ + } +} diff --git a/tests/auto/quick/qquickloader/tst_qquickloader.cpp b/tests/auto/quick/qquickloader/tst_qquickloader.cpp index d0a1a8a45b..7bd6f9466a 100644 --- a/tests/auto/quick/qquickloader/tst_qquickloader.cpp +++ b/tests/auto/quick/qquickloader/tst_qquickloader.cpp @@ -39,6 +39,7 @@ #include "testhttpserver.h" #include "../../shared/util.h" #include "../shared/geometrytestutil.h" +#include Q_LOGGING_CATEGORY(lcTests, "qt.quick.tests") @@ -128,6 +129,7 @@ private slots: void rootContext(); void sourceURLKeepComponent(); + void statusChangeOnlyEmittedOnce(); }; Q_DECLARE_METATYPE(QList) @@ -1446,6 +1448,18 @@ void tst_QQuickLoader::sourceURLKeepComponent() } +// QTBUG-82002 +void tst_QQuickLoader::statusChangeOnlyEmittedOnce() +{ + QQmlApplicationEngine engine; + auto url = testFileUrl("statusChanged.qml"); + engine.load(url); + auto root = engine.rootObjects().at(0); + QVERIFY(root); + QTRY_COMPARE(QQuickLoader::Status(root->property("status").toInt()), QQuickLoader::Ready); + QCOMPARE(root->property("statusChangedCounter").toInt(), 2); // 1xLoading + 1xReady*/ +} + QTEST_MAIN(tst_QQuickLoader) #include "tst_qquickloader.moc" -- cgit v1.2.3 From bc3700d7468d90210b9080732914343674b97fd7 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Wed, 12 Feb 2020 13:01:28 +0100 Subject: Add uri and version parameters to qmlRegisterExtendedType() We want to know which module a registration belongs to, even if the type is uncreatable. Change-Id: I8c417eeca2c0bfa186df43edc0c2f455ed0880e6 Reviewed-by: Fabian Kosmale Reviewed-by: Maximilian Goldstein --- src/qml/qml/qqml.h | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h index ae3893dd73..8407a0269b 100644 --- a/src/qml/qml/qqml.h +++ b/src/qml/qml/qqml.h @@ -415,9 +415,8 @@ int qmlRegisterRevision(const char *uri, int versionMajor, int versionMinor) return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type); } - template -int qmlRegisterExtendedType() +int qmlRegisterExtendedType(const char *uri, int versionMajor) { QML_GETTYPENAMES @@ -430,7 +429,7 @@ int qmlRegisterExtendedType() nullptr, QString(), - nullptr, 0, 0, nullptr, &T::staticMetaObject, + uri, versionMajor, 0, nullptr, &T::staticMetaObject, QQmlPrivate::attachedPropertiesFunc(), QQmlPrivate::attachedPropertiesMetaObject(), @@ -448,6 +447,15 @@ int qmlRegisterExtendedType() return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type); } +#if QT_DEPRECATED_SINCE(5, 15) +template +QT_DEPRECATED_VERSION_X_5_15("Use qmlRegisterExtendedType(uri, versionMajor) instead") +int qmlRegisterExtendedType() +{ + return qmlRegisterExtendedType("", 0); +} +#endif + template int qmlRegisterExtendedType(const char *uri, int versionMajor, int versionMinor, const char *qmlName) -- cgit v1.2.3 From 2fae1d7e8f0bd6619c560fed65ce8507664dacb9 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Wed, 12 Feb 2020 10:42:24 +0100 Subject: Allow dynamic and static registration of same URI in any order Previously, a static registration would not go through if a dynamic registration was carried out before the first type of the statically registered module was referenced. Change-Id: Icf6a2b78dff7d0e5b29138501e04723510d6a668 Reviewed-by: Fabian Kosmale --- src/qml/qml/qqmltypeloader.cpp | 80 ++++++----- .../qml/qqmlproperty/data/interfaceBinding2.qml | 27 ++++ tests/auto/qml/qqmlproperty/interfaces.h | 160 +++++++++++++++++++++ tests/auto/qml/qqmlproperty/qqmlproperty.pro | 8 +- tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp | 79 ++-------- 5 files changed, 253 insertions(+), 101 deletions(-) create mode 100644 tests/auto/qml/qqmlproperty/data/interfaceBinding2.qml create mode 100644 tests/auto/qml/qqmlproperty/interfaces.h diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index e9a38945fa..983592fccf 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -602,49 +602,57 @@ bool QQmlTypeLoader::Blob::addImport(QQmlTypeLoader::Blob::PendingImportPtr impo scriptImported(blob, import->location, script.nameSpace, import->qualifier); } } + } else if ( + // Major version of module already registered: + // We believe that the registration is complete. + QQmlMetaType::typeModule(import->uri, import->majorVersion) + + // Otherwise, try to register further module types. + || (qmldirResult != QQmlImports::QmldirInterceptedToRemote + && QQmlMetaType::qmlRegisterModuleTypes(import->uri, import->majorVersion)) + + // Otherwise, there is no way to register any further types. + // Try with any module of that name. + || QQmlMetaType::isAnyModule(import->uri)) { + + if (!m_importCache.addLibraryImport( + importDatabase, import->uri, import->qualifier, import->majorVersion, + import->minorVersion, QString(), QString(), false, errors)) { + return false; + } } else { - // Is this a module? - if (QQmlMetaType::isAnyModule(import->uri) - || (qmldirResult != QQmlImports::QmldirInterceptedToRemote - && QQmlMetaType::qmlRegisterModuleTypes(import->uri, - import->majorVersion))) { + // We haven't yet resolved this import + m_unresolvedImports << import; + + QQmlAbstractUrlInterceptor *interceptor = typeLoader()->engine()->urlInterceptor(); + + // Query any network import paths for this library. + // Interceptor might redirect local paths. + QStringList remotePathList = importDatabase->importPathList( + interceptor ? QQmlImportDatabase::LocalOrRemote + : QQmlImportDatabase::Remote); + if (!remotePathList.isEmpty()) { + // Add this library and request the possible locations for it if (!m_importCache.addLibraryImport(importDatabase, import->uri, import->qualifier, import->majorVersion, - import->minorVersion, QString(), QString(), false, errors)) + import->minorVersion, QString(), QString(), true, errors)) return false; - } else { - // We haven't yet resolved this import - m_unresolvedImports << import; - - QQmlAbstractUrlInterceptor *interceptor = typeLoader()->engine()->urlInterceptor(); - - // Query any network import paths for this library. - // Interceptor might redirect local paths. - QStringList remotePathList = importDatabase->importPathList( - interceptor ? QQmlImportDatabase::LocalOrRemote - : QQmlImportDatabase::Remote); - if (!remotePathList.isEmpty()) { - // Add this library and request the possible locations for it - if (!m_importCache.addLibraryImport(importDatabase, import->uri, import->qualifier, import->majorVersion, - import->minorVersion, QString(), QString(), true, errors)) - return false; - // Probe for all possible locations - int priority = 0; - const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(import->uri, remotePathList, import->majorVersion, import->minorVersion); - for (const QString &qmldirPath : qmlDirPaths) { - if (interceptor) { - QUrl url = interceptor->intercept( - QQmlImports::urlFromLocalFileOrQrcOrUrl(qmldirPath), - QQmlAbstractUrlInterceptor::QmldirFile); - if (!QQmlFile::isLocalFile(url) - && !fetchQmldir(url, import, ++priority, errors)) { - return false; - } - } else if (!fetchQmldir(QUrl(qmldirPath), import, ++priority, errors)) { + // Probe for all possible locations + int priority = 0; + const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(import->uri, remotePathList, import->majorVersion, import->minorVersion); + for (const QString &qmldirPath : qmlDirPaths) { + if (interceptor) { + QUrl url = interceptor->intercept( + QQmlImports::urlFromLocalFileOrQrcOrUrl(qmldirPath), + QQmlAbstractUrlInterceptor::QmldirFile); + if (!QQmlFile::isLocalFile(url) + && !fetchQmldir(url, import, ++priority, errors)) { return false; } - + } else if (!fetchQmldir(QUrl(qmldirPath), import, ++priority, errors)) { + return false; } + } } } diff --git a/tests/auto/qml/qqmlproperty/data/interfaceBinding2.qml b/tests/auto/qml/qqmlproperty/data/interfaceBinding2.qml new file mode 100644 index 0000000000..e7c5dc7344 --- /dev/null +++ b/tests/auto/qml/qqmlproperty/data/interfaceBinding2.qml @@ -0,0 +1,27 @@ +import QtQuick 2.12 +import io.qt.bugreports 2.0 +Item { + InterfaceConsumer2 { + objectName: "a1" + i: A2 { + property int i: 42 + } + } + + InterfaceConsumer2 { + objectName: "a2" + property A2 a: A2 { + property int i: 43 + } + i: a + } + + InterfaceConsumer2 { + objectName: "a3" + property A2 a: A2 { + id : aa + property int i: 44 + } + i: aa + } +} diff --git a/tests/auto/qml/qqmlproperty/interfaces.h b/tests/auto/qml/qqmlproperty/interfaces.h new file mode 100644 index 0000000000..191c3e84e8 --- /dev/null +++ b/tests/auto/qml/qqmlproperty/interfaces.h @@ -0,0 +1,160 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef INTERFACES_H +#define INTERFACES_H + +#include + +struct Interface { +}; + +QT_BEGIN_NAMESPACE +#define MyInterface_iid "io.qt.bugreports.Interface" +Q_DECLARE_INTERFACE(Interface, MyInterface_iid); +QT_END_NAMESPACE + +class A : public QObject, Interface { + Q_OBJECT + Q_INTERFACES(Interface) +}; + +class B : public QObject, Interface { + Q_OBJECT + Q_INTERFACES(Interface) +}; + +class C : public QObject { + Q_OBJECT +}; + +struct Interface2 +{ + Q_GADGET +}; + +QT_BEGIN_NAMESPACE +#define MyInterface2_iid "io.qt.bugreports.Interface2" +Q_DECLARE_INTERFACE(Interface2, MyInterface2_iid); +QT_END_NAMESPACE + +class A2 : public QObject, Interface2 { + Q_OBJECT + QML_ELEMENT + Q_INTERFACES(Interface2) +}; + +class B2 : public QObject, Interface2 { + Q_OBJECT + QML_ELEMENT + Q_INTERFACES(Interface2) +}; + +class C2 : public QObject { + Q_OBJECT + QML_ELEMENT +}; + +class InterfaceConsumer : public QObject { + Q_OBJECT + Q_PROPERTY(Interface *i READ interface WRITE setInterface NOTIFY interfaceChanged) + Q_PROPERTY(int testValue READ testValue NOTIFY testValueChanged) + +public: + + Interface* interface() const + { + return m_interface; + } + void setInterface(Interface* interface) + { + QObject* object = reinterpret_cast(interface); + m_testValue = object->property("i").toInt(); + emit testValueChanged(); + if (m_interface == interface) + return; + + m_interface = interface; + emit interfaceChanged(); + } + + int testValue() { + return m_testValue; + } + +signals: + void interfaceChanged(); + void testValueChanged(); + +private: + Interface* m_interface = nullptr; + int m_testValue = 0; +}; + + +class InterfaceConsumer2 : public QObject +{ + Q_OBJECT + + Q_PROPERTY(Interface2 *i READ interface WRITE setInterface NOTIFY interfaceChanged) + Q_PROPERTY(int testValue READ testValue NOTIFY testValueChanged) + + QML_ELEMENT + +public: + + Interface2* interface() const + { + return m_interface; + } + void setInterface(Interface2* interface2) + { + QObject* object = reinterpret_cast(interface2); + m_testValue = object->property("i").toInt(); + emit testValueChanged(); + if (m_interface == interface2) + return; + + m_interface = interface2; + emit interfaceChanged(); + } + + int testValue() { + return m_testValue; + } + +signals: + void interfaceChanged(); + void testValueChanged(); + +private: + Interface2 *m_interface = nullptr; + int m_testValue = 0; +}; + +#endif // INTERFACES_H diff --git a/tests/auto/qml/qqmlproperty/qqmlproperty.pro b/tests/auto/qml/qqmlproperty/qqmlproperty.pro index b1bcf1f17d..4d42975369 100644 --- a/tests/auto/qml/qqmlproperty/qqmlproperty.pro +++ b/tests/auto/qml/qqmlproperty/qqmlproperty.pro @@ -1,7 +1,10 @@ -CONFIG += testcase +CONFIG += testcase qmltypes TARGET = tst_qqmlproperty macx:CONFIG -= app_bundle +QML_IMPORT_NAME = io.qt.bugreports +QML_IMPORT_VERSION = 2.0 + SOURCES += tst_qqmlproperty.cpp include (../../shared/util.pri) @@ -9,3 +12,6 @@ include (../../shared/util.pri) TESTDATA = data/* QT += core-private gui-private qml-private testlib + +HEADERS += \ + interfaces.h diff --git a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp index 83e173f379..1223c7cc07 100644 --- a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp +++ b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp @@ -25,6 +25,8 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ + +#include "interfaces.h" #include #include #include @@ -2090,74 +2092,22 @@ void tst_qqmlproperty::nullPropertyBinding() QMetaObject::invokeMethod(root.get(), "tog"); } -struct Interface { -}; - -QT_BEGIN_NAMESPACE -#define MyInterface_iid "io.qt.bugreports.Interface" -Q_DECLARE_INTERFACE(Interface, MyInterface_iid); -QT_END_NAMESPACE - -class A : public QObject, Interface { - Q_OBJECT - Q_INTERFACES(Interface) -}; - -class B : public QObject, Interface { - Q_OBJECT - Q_INTERFACES(Interface) -}; - -class C : public QObject { - Q_OBJECT -}; - -class InterfaceConsumer : public QObject { - Q_OBJECT - Q_PROPERTY(Interface* i READ interface WRITE setInterface NOTIFY interfaceChanged) - Q_PROPERTY(int testValue READ testValue NOTIFY testValueChanged) - - -public: - - Interface* interface() const - { - return m_interface; - } - void setInterface(Interface* interface) - { - QObject* object = reinterpret_cast(interface); - m_testValue = object->property("i").toInt(); - emit testValueChanged(); - if (m_interface == interface) - return; - - m_interface = interface; - emit interfaceChanged(); - } - - int testValue() { - return m_testValue; - } - -signals: - void interfaceChanged(); - void testValueChanged(); - -private: - Interface* m_interface = nullptr; - int m_testValue = 0; -}; void tst_qqmlproperty::interfaceBinding() { + qmlRegisterInterface("Interface"); + qmlRegisterType("io.qt.bugreports", 1, 0, "A"); + qmlRegisterType("io.qt.bugreports", 1, 0, "B"); + qmlRegisterType("io.qt.bugreports", 1, 0, "C"); + qmlRegisterType("io.qt.bugreports", 1, 0, "InterfaceConsumer"); - qmlRegisterInterface("Interface"); - qmlRegisterType("io.qt.bugreports", 1, 0, "A"); - qmlRegisterType("io.qt.bugreports", 1, 0, "B"); - qmlRegisterType("io.qt.bugreports", 1, 0, "C"); - qmlRegisterType("io.qt.bugreports", 1, 0, "InterfaceConsumer"); + qmlRegisterInterface("Interface2"); - const QUrl url = testFileUrl("interfaceBinding.qml"); + const QVector urls = { + testFileUrl("interfaceBinding.qml"), + testFileUrl("interfaceBinding2.qml") + }; + + for (const QUrl &url : urls) { QQmlEngine engine; QQmlComponent component(&engine, url); QScopedPointer root(component.create()); @@ -2165,6 +2115,7 @@ void tst_qqmlproperty::interfaceBinding() QCOMPARE(root->findChild("a1")->property("testValue").toInt(), 42); QCOMPARE(root->findChild("a2")->property("testValue").toInt(), 43); QCOMPARE(root->findChild("a3")->property("testValue").toInt(), 44); + } } void tst_qqmlproperty::floatToStringPrecision_data() -- cgit v1.2.3 From b9fcb1d4543fe19962b4cf8dcdb45c6c497e39d8 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Tue, 11 Feb 2020 18:45:40 +0100 Subject: Doc: Modernize the type definition docs Mention the QML_* macros instead of the qmlRegister* functions and adapt the code examples to use them. Task-number: QTBUG-81615 Change-Id: I9e4cf5b3700b7e727b0f2a93035559b75b733adb Reviewed-by: Paul Wicking Reviewed-by: Fabian Kosmale --- src/qml/doc/src/cppintegration/definetypes.qdoc | 136 ++++++++++-------------- 1 file changed, 57 insertions(+), 79 deletions(-) diff --git a/src/qml/doc/src/cppintegration/definetypes.qdoc b/src/qml/doc/src/cppintegration/definetypes.qdoc index 2e8102bd65..f66dc44383 100644 --- a/src/qml/doc/src/cppintegration/definetypes.qdoc +++ b/src/qml/doc/src/cppintegration/definetypes.qdoc @@ -80,9 +80,17 @@ class instance can be manipulated from QML; as Types to QML} explains, the properties, methods and signals of any QObject-derived class are accessible from QML code. -To register a QObject-derived class as an instantiable QML object type, call -qmlRegisterType() to register the class as QML type into a particular type -namespace. Clients can then import that namespace in order to use the type. +To register a QObject-derived class as an instantiable QML object type, add +\c QML_ELEMENT or \c QML_NAMED_ELEMENT() to the class declaration and +\c {CONFIG += qmltypes}, a \c {QML_IMPORT_NAME}, and a +\c QML_IMPORT_MAJOR_VERSION to your project file. This will register the class +into the type namespace under the given major version, using either the class +name or an explicitly given name as QML type name. The minor version(s) will +be derived from any revisions attached to properties, methods, or signals. The +default minor version is \c 0. You can explicitly restrict the type to be +available only from specific minor versions by adding the +\c QML_ADDED_IN_MINOR_VERSION() macro to the class declaration. Clients can +import suitable versions of the namespace in order to use the type. For example, suppose there is a \c Message class with \c author and \c creationDate properties: @@ -93,17 +101,20 @@ class Message : public QObject Q_OBJECT Q_PROPERTY(QString author READ author WRITE setAuthor NOTIFY authorChanged) Q_PROPERTY(QDateTime creationDate READ creationDate WRITE setCreationDate NOTIFY creationDateChanged) + QML_ELEMENT public: // ... }; \endcode -This type can be registered by calling qmlRegisterType() with an appropriate -type namespace and version number. For example, to make the type available in -the \c com.mycompany.messaging namespace with version 1.0: +This type can be registered by adding an appropriate type namespace and version +number to the project file. For example, to make the type available in the +\c com.mycompany.messaging namespace with version 1.0: \code -qmlRegisterType("com.mycompany.messaging", 1, 0, "Message"); +CONFIG += qmltypes +QML_IMPORT_NAME = com.mycompany.messaging +QML_IMPORT_MAJOR_VERSION = 1 \endcode The type can be used in an \l{qtqml-syntax-basics.html#object-declarations} @@ -135,23 +146,25 @@ not be instantiable should not be instantiable from QML \endlist -The \l {Qt QML} module provides several methods for registering non-instantiable +The \l {Qt QML} module provides several macros for registering non-instantiable types: \list -\li qmlRegisterType() (with no parameters) registers a C++ type that is not -instantiable and cannot be referred to from QML. This enables the engine to -coerce any inherited types that are instantiable from QML. -\li qmlRegisterInterface() registers an existing Qt interface type. The type is +\li QML_ANONYMOUS registers a C++ type that is not instantiable and cannot be +referred to from QML. This enables the engine to coerce any inherited types that +are instantiable from QML. +\li QML_INTERFACE registers an existing Qt interface type. The type is not instantiable from QML, and you cannot declare QML properties with it. Using C++ properties of this type from QML will do the expected interface casts, though. -\li qmlRegisterUncreatableType() registers a named C++ type that is not -instantiable but should be identifiable as a type to the QML type system. This -is useful if a type's enums or attached properties should be accessible from QML -but the type itself should not be instantiable. -\li qmlRegisterSingletonType() registers a singleton type that can be imported -from QML, as discussed below. +\li QML_UNCREATABLE(reason) combined with with QML_ELEMENT or QML_NAMED_ELEMENT +registers a named C++ type that is not instantiable but should be identifiable +as a type to the QML type system. This is useful if a type's enums or attached +properties should be accessible from QML but the type itself should not be +instantiable. The parameter should be an error message to be emitted if an +attempt at creating an instance of the type is detected. +\li QML_SINGLETON combined with QML_ELEMENT or QML_NAMED_ELEMENT registers a +singleton type that can be imported from QML, as discussed below. \endlist Note that all C++ types registered with the QML type system must be @@ -195,7 +208,7 @@ Rectangle { A QJSValue may also be exposed as a singleton type, however clients should be aware that properties of such a singleton type cannot be bound to. -See \l{qmlRegisterSingletonType()} for more information on how implement and +See \l{QML_SINGLETON} for more information on how implement and register a new singleton type, and how to use an existing singleton type. \note Enum values for registered types in QML should start with a capital. @@ -245,30 +258,20 @@ class CppType : public BaseType { Q_OBJECT Q_PROPERTY(int root READ root WRITE setRoot NOTIFY rootChanged REVISION 1) + QML_ELEMENT signals: Q_REVISION(1) void rootChanged(); }; \endcode -To register the new class revision to a particular version the following -function is used: +The revisions given this way are automatically interpreted as minor versions to +the major version given in the project file. In this case, \c root is only +available when \c MyTypes version 1.1 or higher is imported. Imports of +\c MyTypes version 1.0 remain unaffected. -\code -template -int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName) -\endcode - -To register \c CppType version 1 for \c {MyTypes 1.1}: - -\code -qmlRegisterType("MyTypes", 1, 1, "CppType") -\endcode - -\c root is only available when \c MyTypes version 1.1 is imported. - -For the same reason, new types introduced in later versions should use -the minor version argument of qmlRegisterType. +For the same reason, new types introduced in later versions should be tagged +with the QML_ADDED_IN_MINOR_VERSION macro. This feature of the language allows for behavioural changes to be made without breaking existing applications. Consequently QML module authors @@ -276,29 +279,10 @@ should always remember to document what changed between minor versions, and QML module users should check that their application still runs correctly before deploying an updated import statement. -You may also register the revision of a base class that your type depends -upon using the qmlRegisterRevision() function: - -\code -template -int qmlRegisterRevision(const char *uri, int versionMajor, int versionMinor) - -template -int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& reason) - -template -int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& reason) -\endcode - -For example, if \c BaseType is changed and now has a revision 1, you can -specify that your type uses the new revision: - -\code -qmlRegisterRevision("MyTypes", 1, 1); -\endcode - -This is useful when deriving from base classes provided by other authors, -e.g. when extending classes from the Qt Quick module. +Revisions of a base class that your type depends upon are automatically +registered when registering the type itself. This is useful when deriving +from base classes provided by other authors, e.g. when extending classes from +the Qt Quick module. \note The QML engine does not support revisions for properties or signals of grouped and attached property objects. @@ -323,21 +307,8 @@ merged with the original target class when used from within QML. For example: The \c leftMargin property is a new property added to an existing C++ type, \l QLineEdit, without modifying its source code. -The \l {QQmlEngine::}{qmlRegisterExtendedType()} function is for registering extended types. -Note that it has two forms. - -\code -template -int qmlRegisterExtendedType(const char *uri, int versionMajor, int versionMinor, const char *qmlName) - -template -int qmlRegisterExtendedType() -\endcode - -This functions should be used instead of the regular \c qmlRegisterType() -variations. The arguments are identical to the corresponding non-extension -registration functions, except for the ExtendedT parameter which is the type of -the extension object. +The \l {QML_EXTENDED(extended)} macro is for registering extended types. The +argument is the name of another class to be used as extension. An extension class is a regular QObject, with a constructor that takes a QObject pointer. However, the extension class creation is delayed until the first @@ -425,8 +396,9 @@ the attributes to be made accessible to \e attachee objects. For the attached property accesses. Consequently the attachment object may not be deleted until the attachee \c object is destroyed. -\li is declared as an attaching type, by calling the QML_DECLARE_TYPEINFO() - macro with the QML_HAS_ATTACHED_PROPERTIES flag +\li is declared as an attaching type, by adding the QML_ATTACHED(attached) macro + to the class declaration. The argument is the name of the + \e{attached object type} \endlist @@ -441,6 +413,7 @@ class Message : public QObject Q_OBJECT Q_PROPERTY(QString author READ author WRITE setAuthor NOTIFY authorChanged) Q_PROPERTY(QDateTime creationDate READ creationDate WRITE setCreationDate NOTIFY creationDateChanged) + QML_ELEMENT public: // ... }; @@ -472,6 +445,7 @@ class MessageBoardAttachedType : public QObject { Q_OBJECT Q_PROPERTY(bool expired READ expired WRITE setExpired NOTIFY expiredChanged) + QML_ANONYMOUS public: MessageBoardAttachedType(QObject *parent); bool expired() const; @@ -485,20 +459,21 @@ signals: Then the \e {attaching type}, \c MessageBoard, must declare a \c qmlAttachedProperties() method that returns an instance of the \e {attached object type} as implemented by MessageBoardAttachedType. -Additionally, \c Message board must be declared as an attached type -through the QML_DECLARE_TYPEINFO() macro: +Additionally, \c MessageBoard must be declared as an attaching type +via the QML_ATTACHED() macro: \code class MessageBoard : public QObject { Q_OBJECT + QML_ATTACHED(MessageBoardAttachedType) + QML_ELEMENT public: static MessageBoardAttachedType *qmlAttachedProperties(QObject *object) { return new MessageBoardAttachedType(object); } }; -QML_DECLARE_TYPEINFO(MessageBoard, QML_HAS_ATTACHED_PROPERTIES) \endcode Now, a \c Message type can access the properties and signals of the attached @@ -607,6 +582,7 @@ class RandomNumberGenerator : public QObject, public QQmlPropertyValueSource Q_OBJECT Q_INTERFACES(QQmlPropertyValueSource) Q_PROPERTY(int maxValue READ maxValue WRITE setMaxValue NOTIFY maxValueChanged); + QML_ELEMENT public: RandomNumberGenerator(QObject *parent) : QObject(parent), m_maxValue(100) @@ -690,6 +666,7 @@ class MessageBoard : public QObject Q_OBJECT Q_PROPERTY(QQmlListProperty messages READ messages) Q_CLASSINFO("DefaultProperty", "messages") + QML_ELEMENT public: QQmlListProperty messages(); @@ -766,6 +743,7 @@ class MyQmlType : public QObject, public QQmlParserStatus { Q_OBJECT Q_INTERFACES(QQmlParserStatus) + QML_ELEMENT public: virtual void componentComplete() { -- cgit v1.2.3 From c70452a65af222343451f19ec62744314444c181 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Tue, 11 Feb 2020 16:49:55 +0100 Subject: Doc: Modernize backend example and adapt C++ integration docs We want people to use the static type registration. Change-Id: I98e51af9df1a2f73df10f82458a7b7f5c5e5aad1 Reviewed-by: Fabian Kosmale Reviewed-by: Paul Wicking --- src/qml/doc/snippets/code/backend/backend.h | 2 ++ src/qml/doc/snippets/code/backend/backend.pro | 17 +++++++++++++++++ src/qml/doc/snippets/code/backend/main.cpp | 4 ---- src/qml/doc/src/cppintegration/topic.qdoc | 18 +++++++++--------- 4 files changed, 28 insertions(+), 13 deletions(-) create mode 100644 src/qml/doc/snippets/code/backend/backend.pro diff --git a/src/qml/doc/snippets/code/backend/backend.h b/src/qml/doc/snippets/code/backend/backend.h index fa7ce9eb86..6c64236bc7 100644 --- a/src/qml/doc/snippets/code/backend/backend.h +++ b/src/qml/doc/snippets/code/backend/backend.h @@ -53,11 +53,13 @@ #include #include +#include class BackEnd : public QObject { Q_OBJECT Q_PROPERTY(QString userName READ userName WRITE setUserName NOTIFY userNameChanged) + QML_ELEMENT public: explicit BackEnd(QObject *parent = nullptr); diff --git a/src/qml/doc/snippets/code/backend/backend.pro b/src/qml/doc/snippets/code/backend/backend.pro new file mode 100644 index 0000000000..8bd2422718 --- /dev/null +++ b/src/qml/doc/snippets/code/backend/backend.pro @@ -0,0 +1,17 @@ +QT += qml + +#![registration] +CONFIG += qmltypes +QML_IMPORT_NAME = io.qt.examples.backend +QML_IMPORT_MAJOR_VERSION = 1 +#![registration] + +HEADERS += \ + backend.h + +SOURCES += \ + backend.cpp \ + main.cpp + +RESOURCES += \ + main.qml diff --git a/src/qml/doc/snippets/code/backend/main.cpp b/src/qml/doc/snippets/code/backend/main.cpp index 91a012dfda..52fcb38621 100644 --- a/src/qml/doc/snippets/code/backend/main.cpp +++ b/src/qml/doc/snippets/code/backend/main.cpp @@ -51,14 +51,10 @@ #include #include -#include "backend.h" - int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); - qmlRegisterType("io.qt.examples.backend", 1, 0, "BackEnd"); - QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); diff --git a/src/qml/doc/src/cppintegration/topic.qdoc b/src/qml/doc/src/cppintegration/topic.qdoc index fbb654378d..bf4565a996 100644 --- a/src/qml/doc/src/cppintegration/topic.qdoc +++ b/src/qml/doc/src/cppintegration/topic.qdoc @@ -49,8 +49,16 @@ file contents with: \snippet code/backend/backend.h backend_header The \c Q_PROPERTY macro declares a property that could be accessed from QML. +The \c QML_ELEMENT macro makes the BackEnd class available in QML. -\li Replace its C++ file contents with: +\li Add the following lines to your project file: + +\snippet code/backend/backend.pro registration + +The BackEnd class is automatically registered as a type, which is accessible +from QML by importing the URL, "\c{io.qt.examples.backend 1.0}". + +\li Replace the contents of \c{backend.cpp} with: \snippet code/backend/backend.cpp backend_cpp @@ -58,14 +66,6 @@ The \c setUserName function emits the \c userNameChanged signal every time \c m_userName value changes. The signal can be handled from QML using the \c onUserNameChanged handler. -\li Include \c "backend.h" in \c main.cpp and register the class as a QML type -under a import URL as shown below: - -\snippet code/backend/main.cpp main_cpp - -The BackEnd class is registered as a type, which is accessible from QML by -importing the URL, "\c{io.qt.examples.backend 1.0}". - \li Replace the contents of \c main.qml with the following code: \snippet code/backend/main.qml main_qml -- cgit v1.2.3 From ac0ce38dcfeeded87db0c1dd5d348f5ed6fc1af3 Mon Sep 17 00:00:00 2001 From: Anton Kreuzkamp Date: Wed, 12 Feb 2020 12:48:47 +0100 Subject: Add a null check to QQuickWindowPrivate::renderer Afaik there currently is no case in a regular execution where the renderer would actually be null, but for the sake of correctness add a null check as this seems to be the only code location that actually assumes the renderer to be non-null. Additionally, in order to en-/disable custom render modes at runtime, GammaRay actually needs to recreate the renderer and therefore resets the renderer to null in order for QQuickWindowPrivate::syncSceneGraph to recreate it. Thus we need a null check to make sure we don't crash in the short time frame where the renderer is null. Change-Id: Ief5c405f3bc8725d55e22cd33f2164830764e33d Reviewed-by: Laszlo Agocs --- src/quick/items/qquickwindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index faa22ec83f..f07136fcd3 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -548,7 +548,7 @@ void QQuickWindowPrivate::renderSceneGraph(const QSize &size, const QSize &surfa else context->endNextFrame(renderer); - if (renderer->hasCustomRenderModeWithContinuousUpdate()) { + if (renderer && renderer->hasCustomRenderModeWithContinuousUpdate()) { // For the overdraw visualizer. This update is not urgent so avoid a // direct update() call, this is only here to keep the overdraw // visualization box rotating even when the scene is static. -- cgit v1.2.3 From a2b31f073530f61203fe0e9799ad158c4fe6b9f9 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Tue, 11 Feb 2020 19:15:59 +0100 Subject: Add a static variant of qmlRegisterInterface() qmlRegisterInterface() should not be called procedurally, for the same reason that qmlRegisterType() should not be called procedurally. Also, add URI and major version parameters to qmlRegisterInterface(), and deprecate the typeName parameter. We want to identify which import an interface belongs to. Task-number: QTBUG-68796 Change-Id: Iba3d66e5ce6219b30aadba34396f12fca92f35a7 Reviewed-by: Fabian Kosmale --- src/qml/qml/qqml.h | 51 +++++++++++++++++++++--- src/qml/qml/qqmlmetatype.cpp | 11 +++-- src/qml/qml/qqmlprivate.h | 15 +++++++ tests/auto/qml/qqmlproperty/interfaces.h | 1 + tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp | 2 - 5 files changed, 68 insertions(+), 12 deletions(-) diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h index 8407a0269b..153cb0c071 100644 --- a/src/qml/qml/qqml.h +++ b/src/qml/qml/qqml.h @@ -113,6 +113,13 @@ template \ friend void QML_REGISTER_TYPES_AND_REVISIONS(const char *uri, int versionMajor); +#define QML_INTERFACE \ + Q_CLASSINFO("QML.Element", "anonymous") \ + enum class QmlIsInterface {yes = true}; \ + template friend struct QML_PRIVATE_NAMESPACE::QmlInterface; \ + template \ + friend void QML_REGISTER_TYPES_AND_REVISIONS(const char *uri, int versionMajor); + enum { /* TYPEINFO flags */ QML_HAS_ATTACHED_PROPERTIES = 0x01 }; @@ -495,7 +502,9 @@ int qmlRegisterExtendedType(const char *uri, int versionMajor, int versionMinor, return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type); } +#if QT_DEPRECATED_SINCE(5, 15) template +QT_DEPRECATED_VERSION_X_5_15("Use qmlRegisterInterface(uri, versionMajor) instead") int qmlRegisterInterface(const char *typeName) { QByteArray name(typeName); @@ -504,12 +513,33 @@ int qmlRegisterInterface(const char *typeName) QByteArray listName("QQmlListProperty<" + name + '>'); QQmlPrivate::RegisterInterface qmlInterface = { - 0, + 1, qRegisterNormalizedMetaType(pointerName.constData()), qRegisterNormalizedMetaType >(listName.constData()), - qobject_interface_iid() + qobject_interface_iid(), + "", + 0 + }; + + return QQmlPrivate::qmlregister(QQmlPrivate::InterfaceRegistration, &qmlInterface); +} +#endif + +template +int qmlRegisterInterface(const char *uri, int versionMajor) +{ + QML_GETTYPENAMES + + QQmlPrivate::RegisterInterface qmlInterface = { + 1, + qRegisterNormalizedMetaType(pointerName.constData()), + qRegisterNormalizedMetaType>(listName.constData()), + qobject_interface_iid(), + + uri, + versionMajor }; return QQmlPrivate::qmlregister(QQmlPrivate::InterfaceRegistration, &qmlInterface); @@ -767,11 +797,11 @@ inline int qmlRegisterType(const QUrl &url, const char *uri, int versionMajor, i return QQmlPrivate::qmlregister(QQmlPrivate::CompositeRegistration, &type); } -template +template struct QmlTypeAndRevisionsRegistration; template -struct QmlTypeAndRevisionsRegistration { +struct QmlTypeAndRevisionsRegistration { static void registerTypeAndRevisions(const char *uri, int versionMajor) { QQmlPrivate::qmlRegisterTypeAndRevisions( @@ -780,7 +810,7 @@ struct QmlTypeAndRevisionsRegistration { }; template -struct QmlTypeAndRevisionsRegistration { +struct QmlTypeAndRevisionsRegistration { static void registerTypeAndRevisions(const char *uri, int versionMajor) { QQmlPrivate::qmlRegisterSingletonAndRevisions( @@ -788,6 +818,14 @@ struct QmlTypeAndRevisionsRegistration { } }; +template +struct QmlTypeAndRevisionsRegistration { + static void registerTypeAndRevisions(const char *uri, int versionMajor) + { + qmlRegisterInterface(uri, versionMajor); + } +}; + template void qmlRegisterTypesAndRevisions(const char *uri, int versionMajor); @@ -797,7 +835,8 @@ void qmlRegisterTypesAndRevisions(const char *uri, int versionMajor) QmlTypeAndRevisionsRegistration< T, typename QQmlPrivate::QmlResolved::Type, typename QQmlPrivate::QmlExtended::Type, - QQmlPrivate::QmlSingleton::Value> + QQmlPrivate::QmlSingleton::Value, + QQmlPrivate::QmlInterface::Value> ::registerTypeAndRevisions(uri, versionMajor); qmlRegisterTypesAndRevisions(uri, versionMajor); } diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index bff6a8a46f..b2a769cab4 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -92,8 +92,13 @@ static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, d->typeId = type.typeId; d->listId = type.listId; d->isSetup = true; - d->version_maj = 0; d->version_min = 0; + if (type.version > 0) { + d->module = QString::fromUtf8(type.uri); + d->version_maj = type.versionMajor; + } else { + d->version_maj = 0; + } data->registerType(d); return d; } @@ -345,7 +350,7 @@ void QQmlMetaType::unregisterAutoParentFunction(const QQmlPrivate::AutoParentFun QQmlType QQmlMetaType::registerInterface(const QQmlPrivate::RegisterInterface &type) { - if (type.version > 0) + if (type.version > 1) qFatal("qmlRegisterType(): Cannot mix incompatible QML versions."); QQmlMetaTypeDataPtr data; @@ -354,8 +359,6 @@ QQmlType QQmlMetaType::registerInterface(const QQmlPrivate::RegisterInterface &t data->idToType.insert(priv->typeId, priv); data->idToType.insert(priv->listId, priv); - if (!priv->elementName.isEmpty()) - data->nameToType.insert(priv->elementName, priv); if (data->interfaces.size() <= type.typeId) data->interfaces.resize(type.typeId + 16); diff --git a/src/qml/qml/qqmlprivate.h b/src/qml/qml/qqmlprivate.h index 9504fc37dc..9d260f5e94 100644 --- a/src/qml/qml/qqmlprivate.h +++ b/src/qml/qml/qqmlprivate.h @@ -406,6 +406,9 @@ namespace QQmlPrivate int listId; const char *iid; + + const char *uri; + int versionMajor; }; struct RegisterAutoParent { @@ -579,6 +582,18 @@ namespace QQmlPrivate static constexpr bool Value = bool(T::QmlIsSingleton::yes); }; + template> + struct QmlInterface + { + static constexpr bool Value = false; + }; + + template + struct QmlInterface> + { + static constexpr bool Value = bool(T::QmlIsInterface::yes); + }; + template void qmlRegisterSingletonAndRevisions(const char *uri, int versionMajor, const QMetaObject *classInfoMetaObject) diff --git a/tests/auto/qml/qqmlproperty/interfaces.h b/tests/auto/qml/qqmlproperty/interfaces.h index 191c3e84e8..2c06c5f594 100644 --- a/tests/auto/qml/qqmlproperty/interfaces.h +++ b/tests/auto/qml/qqmlproperty/interfaces.h @@ -56,6 +56,7 @@ class C : public QObject { struct Interface2 { Q_GADGET + QML_INTERFACE }; QT_BEGIN_NAMESPACE diff --git a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp index 1223c7cc07..166437c8de 100644 --- a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp +++ b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp @@ -2100,8 +2100,6 @@ void tst_qqmlproperty::interfaceBinding() qmlRegisterType("io.qt.bugreports", 1, 0, "C"); qmlRegisterType("io.qt.bugreports", 1, 0, "InterfaceConsumer"); - qmlRegisterInterface("Interface2"); - const QVector urls = { testFileUrl("interfaceBinding.qml"), testFileUrl("interfaceBinding2.qml") -- cgit v1.2.3 From 8791fc19f04d51d1efc077205e39a11047e732b5 Mon Sep 17 00:00:00 2001 From: Fawzi Mohamed Date: Mon, 10 Feb 2020 13:15:37 +0100 Subject: Added AstDumper: better describe and compare AST trees This is just added to the test sources (via tests/auto/shared/astdump.pri) Fixes: QTBUG-81819 Change-Id: Icc70e6f7a6ded9e9957c6d4151f696be34c942e6 Reviewed-by: Fabian Kosmale Reviewed-by: Ulf Hermann --- tests/auto/qml/qqmlparser/qqmlparser.pro | 1 + tests/auto/qml/qqmlparser/tst_qqmlparser.cpp | 3 +- tests/auto/shared/astdump.pri | 7 + tests/auto/shared/qqmljsastdumper.cpp | 1065 ++++++++++++++++++++++++++ tests/auto/shared/qqmljsastdumper.h | 442 +++++++++++ 5 files changed, 1517 insertions(+), 1 deletion(-) create mode 100644 tests/auto/shared/astdump.pri create mode 100644 tests/auto/shared/qqmljsastdumper.cpp create mode 100644 tests/auto/shared/qqmljsastdumper.h diff --git a/tests/auto/qml/qqmlparser/qqmlparser.pro b/tests/auto/qml/qqmlparser/qqmlparser.pro index d8e4b0dd06..7f117b3157 100644 --- a/tests/auto/qml/qqmlparser/qqmlparser.pro +++ b/tests/auto/qml/qqmlparser/qqmlparser.pro @@ -11,3 +11,4 @@ cross_compile: DEFINES += QTEST_CROSS_COMPILED TESTDATA = data/* include (../../shared/util.pri) +include (../../shared/astdump.pri) diff --git a/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp b/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp index 0b88358d4a..c7d09f9d6e 100644 --- a/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp +++ b/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp @@ -33,6 +33,7 @@ #include #include "../../shared/util.h" +#include "../../shared/qqmljsastdumper.h" #include #include @@ -580,7 +581,7 @@ void tst_qqmlparser::annotations() Parser parser2(&engine2); QVERIFY(parser2.parse()); - // to do: compare for equality skipping annotations + QCOMPARE(AstDumper::diff(parser.ast(), parser2.rootNode(), 3, DumperOptions::NoAnnotations | DumperOptions::NoLocations), QString()); } } diff --git a/tests/auto/shared/astdump.pri b/tests/auto/shared/astdump.pri new file mode 100644 index 0000000000..365b12fc51 --- /dev/null +++ b/tests/auto/shared/astdump.pri @@ -0,0 +1,7 @@ + +INCLUDEPATH += $$PWD +HEADERS += \ + $$PWD/qqmljsastdumper.h + +SOURCES += \ + $$PWD/qqmljsastdumper.cpp diff --git a/tests/auto/shared/qqmljsastdumper.cpp b/tests/auto/shared/qqmljsastdumper.cpp new file mode 100644 index 0000000000..7c7485fd1f --- /dev/null +++ b/tests/auto/shared/qqmljsastdumper.cpp @@ -0,0 +1,1065 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +**/ +#include "qqmljsastdumper.h" +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace QQmlJS { +using namespace AST; +/*! +\internal +\enum QQmlJS::DumperOptions + +This enum type specifies the options for the AstDumper. +The values can be combined with the '|' operator, and checked using the '&' operator. + +\value None + Default dumping options +\value NoLocations + Does not dump SourceLocations, allowing one to compare equivalent AST + generated by code formatted differently +\value NoAnnotations + Does not dump annotations +\value DumpNode + Does dump a in preVisit/postVisit +*/ + +/*! +\internal +\class QQmlJS::AstDumper +\brief Dumps or compares AST in an xml like format, mostly for testing/debugging + +Initialize it with a lambda that dumps a string, and configure it with .setX methods. +If \l{indent} is set to a non zero value the xml is indented by that amount, and +\l{baseIndent} is the initial indent. +If \l{emitNode} is true the node tag is emitted in the preVisit/postVisit. +If \l{emitLocation} is true the SourceLocations are emitted. +If \l{emitAnnotations} is true annotations are emitted + +The implementation has unnecessary roundtrips to QString, but it is supposed to be used +for debugging purposes... + +Probably you will not use the visitor at all but rather the static method diff or +the qDebug() and ostream operator << that use the visitor... + +\fn AstDumper::diff(AST::Node *n1, AST::Node *n2, int nContext, DumperOptions opt, int indent) + +\brief compares the two AST::Node n1 and n2 and returns a string describing their first difference + +If there are no differences the empty string is returned, so .isEmpty() can be use to check +for no differences. +\l{nContext} decides how much context is printed out. + +*/ + + +QDebug operator<<(QDebug d, AST::Node *n) { + QDebug noQuote = d.noquote().nospace(); + AstDumper visitor([&noQuote](const QString &s){ noQuote << s; }); + Node::accept(n, &visitor); + return d; +} + + +std::ostream &operator<<(std::ostream &stream, AST::Node *n) { + AstDumper visitor([&stream](const QString &s){ stream << s.toStdString(); }); + Node::accept(n, &visitor); + return stream; +} + +bool operator & (DumperOptions lhs, DumperOptions rhs) { + return bool(static_cast(lhs) & static_cast(rhs)); +} + +DumperOptions operator | (DumperOptions lhs, DumperOptions rhs) { + return DumperOptions(static_cast(lhs) | static_cast(rhs)); +} + +QString AstDumper::diff(AST::Node *n1, AST::Node *n2, int nContext, DumperOptions opt, int indent) { + QString s1, s2; + QTextStream d1(&s1), d2(&s2); + AstDumper visitor1=AstDumper([&d1](const QString &s){ d1 << s; }, opt, indent); + AstDumper visitor2=AstDumper([&d2](const QString &s){ d2 << s; }, opt, indent); + Node::accept(n1, &visitor1); + Node::accept(n2, &visitor2); + d1.seek(0); + d2.seek(0); + std::vector preLines(nContext); + int nLine = 0; + bool same = true; + QString l1, l2; + while (same && !d1.atEnd() && !d2.atEnd()) { + l1=d1.readLine(); + l2=d2.readLine(); + if (l1 == l2) + preLines[nLine++ % nContext] = l1; + else + same = false; + } + QString res; + QTextStream ss(&res); + if (!same || !d1.atEnd() || !d2.atEnd()) { + for (int iline = qMin(nLine, nContext); iline > 0; --iline) { + ss << QLatin1String(" ") << preLines[(nLine - iline) % nContext] << QLatin1String("\n"); + } + int iline = 0; + if (!same) { + ss << QLatin1String("-") << l1 << QLatin1String("\n"); + ++iline; + } + if (same && nContext == 0) + nContext = 1; + for (;iline < nContext && !d1.atEnd(); iline ++) { + l1 = d1.readLine(); + ss << QLatin1String("-") << l1 << QLatin1String("\n"); + } + iline = 0; + if (!same) { + ss << QLatin1String("+") << l2 << QLatin1String("\n"); + ++iline; + } + for (;iline < nContext && !d2.atEnd(); iline ++) { + l2 = d2.readLine(); + ss << QLatin1String("+") << l2 << QLatin1String("\n"); + } + } + return res; +} + +QString AstDumper::printNode(Node *n, DumperOptions opt, int indent, int baseIndent) +{ + QString res; + QTextStream d(&res); + AstDumper visitor=AstDumper([&d](const QString &s){ d << s; }, opt, indent, baseIndent); + Node::accept(n, &visitor); + return res; +} + +AstDumper::AstDumper(const std::function &dumper, DumperOptions options, int indent, int baseIndent): + dumper(dumper), options(options), indent(indent), baseIndent(baseIndent) {} + +void AstDumper::start(const QString &str) { + dumper(QString::fromLatin1(" ").repeated(baseIndent)); + dumper(QLatin1String("<")); + dumper(str); + dumper(QLatin1String(">\n")); + baseIndent += indent; +} + +void AstDumper::start(const char *str) { + start(QLatin1String(str)); +} + +void AstDumper::stop(const QString &str) { + baseIndent -= indent; + dumper(QString::fromLatin1(" ").repeated(baseIndent)); + dumper(QLatin1String("\n")); +} + +void AstDumper::stop(const char *str) { + stop(QLatin1String(str)); +} + +QString AstDumper::qs(const QString &s) { + QString res(s); + return QLatin1String("\"") + res + .replace(QLatin1String("\\"), QLatin1String("\\\\")) + .replace(QLatin1String("\""), QLatin1String("\\\"")) + QLatin1String("\""); +} + +QString AstDumper::qs(const char *s) { + return qs(QLatin1String(s)); +} + +QString AstDumper::qs(const QStringRef &s) { + return qs(s.toString()); +} + +QString AstDumper::loc(const AST::SourceLocation &s) { + if (noLocations() || !s.isValid()) + return QLatin1String("\"\""); + else { + return QLatin1String("\"off:%1 len:%2 l:%3 c:%4\"").arg(QString::number(s.offset), QString::number(s.length), QString::number(s.startLine), QString::number(s.startColumn)); + } +} + +QString AstDumper::boolStr(bool v) { return (v ? qs("true"): qs("false")); } + +bool AstDumper::preVisit(Node *) { if (dumpNode()) start("Node"); return true; } + +void AstDumper::postVisit(Node *) { if (dumpNode()) stop("Node"); } + +bool AstDumper::visit(UiProgram *) { start("UiProgram"); return true; } + +bool AstDumper::visit(UiHeaderItemList *) { start("UiHeaderItemList"); return true; } + +bool AstDumper::visit(UiPragma *el) { + start(QLatin1String("UiPragma name=%1 pragmaToken=%2 semicolonToken=%3") + .arg(qs(el->name), loc(el->pragmaToken), loc(el->semicolonToken))); + return true; +} + +bool AstDumper::visit(UiImport *el) +{ + start(QLatin1String("UiImport fileName=%1 importId=%2 importToken=%3 fileNameToken=%4 asToken=%5 importIdToken=%6 semicolonToken=%7") + .arg(qs(el->fileName), qs(el->importId), loc(el->importToken), loc(el->fileNameToken), loc(el->asToken), loc(el->importIdToken), loc(el->semicolonToken))); + return true; +} + +bool AstDumper::visit(UiPublicMember *el) { + QString typeStr = ((el->type == UiPublicMember::Signal) ? QLatin1String("Signal") : + (el->type == UiPublicMember::Property) ? QLatin1String("Property") : QLatin1String("Unexpected(%1)").arg(el->type)); + start(QLatin1String("UiPublicMember type=%1 typeModifier=%2 name=%3 isDefaultMember=%4 isReadonlyMember=%5 isRequired=%6 " + "defaultToken=%7 readonlyToken=%8 propertyToken=%9 requiredToken=%10 typeModifierToken=%11 typeToken=%12 " + "identifierToken=%13 colonToken=%14 semicolonToken=%15") + .arg(qs(typeStr), qs(el->typeModifier), qs(el->name), + el->isDefaultMember, el->isReadonlyMember, el->isRequired, + loc(el->defaultToken), loc(el->readonlyToken), loc(el->propertyToken), + loc(el->requiredToken), loc(el->typeModifierToken), loc(el->typeToken), + loc(el->identifierToken), loc(el->colonToken), loc(el->semicolonToken) + )); + if (!noAnnotations()) // put annotations inside the node they refer to + Node::accept(el->annotations, this); + Node::accept(el->memberType, this); + return true; +} + +bool AstDumper::visit(AST::UiSourceElement *el) { + start(QLatin1String("UiSourceElement")); + if (!noAnnotations()) // put annotations inside the node they refer to + Node::accept(el->annotations, this); + return true; +} + +bool AstDumper::visit(AST::UiObjectDefinition *el) { + start("UiObjectDefinition"); + if (!noAnnotations()) // put annotations inside the node they refer to + Node::accept(el->annotations, this); + return true; +} + +bool AstDumper::visit(AST::UiObjectInitializer *el) { + start(QLatin1String("UiObjectInitializer lbraceToken=%1 rbraceToken=%2") + .arg(loc(el->lbraceToken), loc(el->rbraceToken))); + return true; +} + +bool AstDumper::visit(AST::UiObjectBinding *el) { + start(QLatin1String("UiObjectBinding colonToken=%1 hasOnToken=%2") + .arg(loc(el->colonToken), boolStr(el->hasOnToken))); + if (!noAnnotations()) // put annotations inside the node they refer to + Node::accept(el->annotations, this); + return true; +} + +bool AstDumper::visit(AST::UiScriptBinding *el) { + start(QLatin1String("UiScriptBinding colonToken=%1") + .arg(loc(el->colonToken))); + if (!noAnnotations()) // put annotations inside the node they refer to + Node::accept(el->annotations, this); + return true; +} + +bool AstDumper::visit(AST::UiArrayBinding *el) { + start(QLatin1String("UiArrayBinding colonToken=%1 lbracketToken=%2 rbracketToken=%3") + .arg(loc(el->colonToken), loc(el->lbracketToken), loc(el->rbracketToken))); + if (!noAnnotations()) // put annotations inside the node they refer to + Node::accept(el->annotations, this); + return true; +} + +bool AstDumper::visit(AST::UiParameterList *el) { + start(QLatin1String("UiArrayBinding name=%1 commaToken=%2 propertyTypeToken=%3 identifierToken=%4 colonToken=%5") + .arg(qs(el->name), loc(el->commaToken), loc(el->propertyTypeToken), loc(el->identifierToken), loc(el->colonToken))); + Node::accept(el->type, this); + return true; +} + +bool AstDumper::visit(AST::UiObjectMemberList *) { start("UiObjectMemberList"); return true; } + +bool AstDumper::visit(AST::UiArrayMemberList *el) { + start(QLatin1String("UiArrayMemberList commaToken=%1") + .arg(loc(el->commaToken))); + return true; +} + +bool AstDumper::visit(AST::UiQualifiedId *el) { + start(QLatin1String("UiQualifiedId name=%1 identifierToken=%2") + .arg(qs(el->name), loc(el->identifierToken))); + Node::accept(el->next, this); + return true; +} + +bool AstDumper::visit(AST::UiEnumDeclaration *el) { + start(QLatin1String("UiEnumDeclaration enumToken=%1 rbraceToken=%2 name=%3") + .arg(loc(el->enumToken), loc(el->rbraceToken), qs(el->name))); + if (!noAnnotations()) // put annotations inside the node they refer to + Node::accept(el->annotations, this); + return true; +} + +bool AstDumper::visit(AST::UiEnumMemberList *el) { + start(QLatin1String("UiEnumMemberList member=%1 value=%2 memberToken=%3 valueToken=%4") + .arg(qs(el->member), qs(QString::number(el->value)), loc(el->memberToken), loc(el->valueToken))); + return true; +} + +bool AstDumper::visit(AST::UiVersionSpecifier *el) { + start(QLatin1String("UiVersionSpecifier majorVersion=%1 minorVersion=%2 majorToken=%3 minorToken=%4") + .arg(qs(QString::number(el->majorVersion)), qs(QString::number(el->minorVersion)), loc(el->majorToken), loc(el->minorToken))); + return true; +} + +bool AstDumper::visit(AST::UiInlineComponent *el) { + start(QLatin1String("UiInlineComponent name=%1 componentToken=%2") + .arg(qs(el->name), loc(el->componentToken))); + if (!noAnnotations()) // put annotations inside the node they refer to + Node::accept(el->annotations, this); + return true; +} + +bool AstDumper::visit(UiRequired *el) +{ + start(QLatin1String("UiRequired name=%1 requiredToken=%2 semicolonToken=%3") + .arg(qs(el->name), loc(el->requiredToken), loc(el->semicolonToken))); + return true; +} + +void AstDumper::endVisit(AST::UiProgram *) { stop("UiProgram"); } + +void AstDumper::endVisit(AST::UiImport *el) { + Node::accept(el->version, this); + stop("UiImport"); +} + +void AstDumper::endVisit(AST::UiHeaderItemList *) { stop("UiHeaderItemList"); } + +void AstDumper::endVisit(AST::UiPragma *) { stop("UiPragma"); } + +void AstDumper::endVisit(AST::UiPublicMember *el) { + Node::accept(el->parameters, this); + stop("UiPublicMember"); +} + +void AstDumper::endVisit(AST::UiSourceElement *) { stop("UiSourceElement"); } +void AstDumper::endVisit(AST::UiObjectDefinition *) { stop("UiObjectDefinition"); } +void AstDumper::endVisit(AST::UiObjectInitializer *) { stop("UiObjectInitializer"); } +void AstDumper::endVisit(AST::UiObjectBinding *) { stop("UiObjectBinding"); } +void AstDumper::endVisit(AST::UiScriptBinding *) { stop("UiScriptBinding"); } +void AstDumper::endVisit(AST::UiArrayBinding *) { stop("UiArrayBinding"); } +void AstDumper::endVisit(AST::UiParameterList *el) { + stop("UiParameterList"); + Node::accept(el->next, this); // put other args at the same level as this one... +} +void AstDumper::endVisit(AST::UiObjectMemberList *) { stop("UiObjectMemberList"); } +void AstDumper::endVisit(AST::UiArrayMemberList *) { stop("UiArrayMemberList"); } +void AstDumper::endVisit(AST::UiQualifiedId *) { stop("UiQualifiedId"); } +void AstDumper::endVisit(AST::UiEnumDeclaration *) { stop("UiEnumDeclaration"); } +void AstDumper::endVisit(AST::UiEnumMemberList *el) { + stop("UiEnumMemberList"); + Node::accept(el->next, this); // put other enum members at the same level as this one... +} +void AstDumper::endVisit(AST::UiVersionSpecifier *) { stop("UiVersionSpecifier"); } +void AstDumper::endVisit(AST::UiInlineComponent *) { stop("UiInlineComponent"); } +void AstDumper::endVisit(UiRequired *) { stop("UiRequired"); } + +// QQmlJS +bool AstDumper::visit(AST::ThisExpression *el) { + start(QLatin1String("ThisExpression thisToken=%1") + .arg(loc(el->thisToken))); + return true; +} +void AstDumper::endVisit(AST::ThisExpression *) { stop("ThisExpression"); } + +bool AstDumper::visit(AST::IdentifierExpression *el) { + start(QLatin1String("IdentifierExpression name=%1 identiferToken=%2") + .arg(qs(el->name), loc(el->identifierToken))); + return true; +} +void AstDumper::endVisit(AST::IdentifierExpression *) { stop("IdentifierExpression"); } + +bool AstDumper::visit(AST::NullExpression *el) { + start(QLatin1String("NullExpression nullToken=%1") + .arg(loc(el->nullToken))); + return true; +} +void AstDumper::endVisit(AST::NullExpression *) { stop("NullExpression"); } + +bool AstDumper::visit(AST::TrueLiteral *el) { + start(QLatin1String("TrueLiteral trueToken=%1") + .arg(loc(el->trueToken))); + return true; +} +void AstDumper::endVisit(AST::TrueLiteral *) { stop("TrueLiteral"); } + +bool AstDumper::visit(AST::FalseLiteral *el) { + start(QLatin1String("FalseLiteral falseToken=%1") + .arg(loc(el->falseToken))); + return true; +} +void AstDumper::endVisit(AST::FalseLiteral *) { stop("FalseLiteral"); } + +bool AstDumper::visit(AST::SuperLiteral *el) { + start(QLatin1String("SuperLiteral superToken=%1") + .arg(loc(el->superToken))); + return true; +} +void AstDumper::endVisit(AST::SuperLiteral *) { stop("SuperLiteral"); } + +bool AstDumper::visit(AST::StringLiteral *el) { + start(QLatin1String("StringLiteral value=%1 literalToken=%2") + .arg(qs(el->value), loc(el->literalToken))); + return true; +} +void AstDumper::endVisit(AST::StringLiteral *) { stop("StringLiteral"); } + +bool AstDumper::visit(AST::TemplateLiteral *el) { + start(QLatin1String("TemplateLiteral value=%1 rawValue=%2 literalToken=%3") + .arg(qs(el->value), qs(el->rawValue), loc(el->literalToken))); + Node::accept(el->expression, this); + return true; +} +void AstDumper::endVisit(AST::TemplateLiteral *) { stop("TemplateLiteral"); } + +bool AstDumper::visit(AST::NumericLiteral *el) { + start(QLatin1String("NumericLiteral value=%1 literalToken=%2") + .arg(qs(QString::number(el->value)), loc(el->literalToken))); + return true; +} +void AstDumper::endVisit(AST::NumericLiteral *) { stop("NumericLiteral"); } + +bool AstDumper::visit(AST::RegExpLiteral *el) { + start(QLatin1String("RegExpLiteral pattern=%1 flags=%2 literalToken=%3") + .arg(qs(el->pattern), qs(QString::number(el->flags, 16)), loc(el->literalToken))); + return true; +} +void AstDumper::endVisit(AST::RegExpLiteral *) { stop("RegExpLiteral"); } + +bool AstDumper::visit(AST::ArrayPattern *el) { + start(QLatin1String("ArrayPattern lbracketToken=%1, commaToken=%2, rbracketToken=%3 parseMode=%4") + .arg(loc(el->lbracketToken),loc(el->commaToken),loc(el->rbracketToken), qs(QString::number(el->parseMode, 16)))); + return true; +} +void AstDumper::endVisit(AST::ArrayPattern *) { stop("ArrayPattern"); } + +bool AstDumper::visit(AST::ObjectPattern *el) { + start(QLatin1String("ObjectPattern lbraceToken=%1 rbraceToken=%2 parseMode=%3") + .arg(loc(el->lbraceToken), loc(el->rbraceToken), qs(QString::number(el->parseMode, 16)))); + return true; +} +void AstDumper::endVisit(AST::ObjectPattern *) { stop("ObjectPattern"); } + +bool AstDumper::visit(AST::PatternElementList *) { start("PatternElementList"); return true; } +void AstDumper::endVisit(AST::PatternElementList *) { stop("PatternElementList"); } + +bool AstDumper::visit(AST::PatternPropertyList *) { start("PatternPropertyList"); return true; } +void AstDumper::endVisit(AST::PatternPropertyList *) { stop("PatternPropertyList"); } + +bool AstDumper::visit(AST::PatternElement *el) { + start(QLatin1String("PatternElement identifierToken=%1 bindingIdentifier=%2 type=%3 scope=%4 isForDeclaration=%5") + .arg(loc(el->identifierToken), qs(el->bindingIdentifier), qs(QString::number(el->type, 16)), + qs(QString::number(static_cast(el->scope), 16)), boolStr(el->isForDeclaration))); + return true; +} +void AstDumper::endVisit(AST::PatternElement *) { stop("PatternElement"); } + +bool AstDumper::visit(AST::PatternProperty *el) { + start(QLatin1String("PatternProperty identifierToken=%1 bindingIdentifier=%2 type=%3 scope=%4 isForDeclaration=%5 colonToken=%6") + .arg(loc(el->identifierToken), qs(el->bindingIdentifier), qs(QString::number(el->type, 16)), + qs(QString::number(static_cast(el->scope), 16)), boolStr(el->isForDeclaration), loc(el->colonToken))); + return true; +} +void AstDumper::endVisit(AST::PatternProperty *) { stop("PatternProperty"); } + +bool AstDumper::visit(AST::Elision *el) { + start(QLatin1String("Elision commaToken=%1") + .arg(loc(el->commaToken))); + return true; +} +void AstDumper::endVisit(AST::Elision *el) { + stop("Elision"); + Node::accept(el->next, this); // emit other elisions at the same level +} + +bool AstDumper::visit(AST::NestedExpression *el) { + start(QLatin1String("NestedExpression lparenToken=%1 rparenToken=%2") + .arg(loc(el->lparenToken), loc(el->rparenToken))); + return true; +} +void AstDumper::endVisit(AST::NestedExpression *) { stop("NestedExpression"); } + +bool AstDumper::visit(AST::IdentifierPropertyName *el) { + start(QLatin1String("IdentifierPropertyName id=%1 propertyNameToken=%2") + .arg(qs(el->id), loc(el->propertyNameToken))); + return true; +} +void AstDumper::endVisit(AST::IdentifierPropertyName *) { stop("IdentifierPropertyName"); } + +bool AstDumper::visit(AST::StringLiteralPropertyName *el) { + start(QLatin1String("StringLiteralPropertyName id=%1 propertyNameToken=%2") + .arg(qs(el->id), loc(el->propertyNameToken))); + return true; +} +void AstDumper::endVisit(AST::StringLiteralPropertyName *) { stop("StringLiteralPropertyName"); } + +bool AstDumper::visit(AST::NumericLiteralPropertyName *el) { + start(QLatin1String("NumericLiteralPropertyName id=%1 propertyNameToken=%2") + .arg(qs(QString::number(el->id)),loc(el->propertyNameToken))); + return true; +} +void AstDumper::endVisit(AST::NumericLiteralPropertyName *) { stop("NumericLiteralPropertyName"); } + +bool AstDumper::visit(AST::ComputedPropertyName *) { + start(QLatin1String("ComputedPropertyName")); + return true; +} +void AstDumper::endVisit(AST::ComputedPropertyName *) { stop("ComputedPropertyName"); } + +bool AstDumper::visit(AST::ArrayMemberExpression *el) { + start(QLatin1String("ArrayMemberExpression lbraketToken=%1 rbraketToken=%2") + .arg(loc(el->lbracketToken), loc(el->rbracketToken))); + return true; +} +void AstDumper::endVisit(AST::ArrayMemberExpression *) { stop("ArrayMemberExpression"); } + +bool AstDumper::visit(AST::FieldMemberExpression *el) { + start(QLatin1String("FieldMemberExpression name=%1 dotToken=%2 identifierToken=%3") + .arg(qs(el->name), loc(el->dotToken), loc(el->identifierToken))); + return true; +} +void AstDumper::endVisit(AST::FieldMemberExpression *) { stop("FieldMemberExpression"); } + +bool AstDumper::visit(AST::TaggedTemplate *) { + start(QLatin1String("TaggedTemplate")); + return true; +} +void AstDumper::endVisit(AST::TaggedTemplate *) { stop("TaggedTemplate"); } + +bool AstDumper::visit(AST::NewMemberExpression *el) { + start(QLatin1String("NewMemberExpression newToken=%1 lparenToken=%2 rparenToken=%3") + .arg(loc(el->newToken), loc(el->lparenToken), loc(el->rparenToken))); + return true; +} +void AstDumper::endVisit(AST::NewMemberExpression *) { stop("NewMemberExpression"); } + +bool AstDumper::visit(AST::NewExpression *el) { + start(QLatin1String("NewExpression newToken=%1") + .arg(loc(el->newToken))); + return true; +} +void AstDumper::endVisit(AST::NewExpression *) { stop("NewExpression"); } + +bool AstDumper::visit(AST::CallExpression *el) { + start(QLatin1String("CallExpression lparenToken=%1 rparenToken=%2") + .arg(loc(el->lparenToken), loc(el->rparenToken))); + return true; +} +void AstDumper::endVisit(AST::CallExpression *) { stop("CallExpression"); } + +bool AstDumper::visit(AST::ArgumentList *el) { + start(QLatin1String("ArgumentList commaToken=%1 isSpreadElement=%2") + .arg(loc(el->commaToken), boolStr(el->isSpreadElement))); + return true; +} +void AstDumper::endVisit(AST::ArgumentList *) { stop("ArgumentList"); } + +bool AstDumper::visit(AST::PostIncrementExpression *el) { + start(QLatin1String("PostIncrementExpression incrementToken=%1") + .arg(loc(el->incrementToken))); + return true; +} +void AstDumper::endVisit(AST::PostIncrementExpression *) { stop("PostIncrementExpression"); } + +bool AstDumper::visit(AST::PostDecrementExpression *el) { + start(QLatin1String("PostDecrementExpression decrementToken=%1") + .arg(loc(el->decrementToken))); + return true; +} +void AstDumper::endVisit(AST::PostDecrementExpression *) { stop("PostDecrementExpression"); } + +bool AstDumper::visit(AST::DeleteExpression *el) { + start(QLatin1String("DeleteExpression deleteToken=%1") + .arg(loc(el->deleteToken))); + return true; +} +void AstDumper::endVisit(AST::DeleteExpression *) { stop("DeleteExpression"); } + +bool AstDumper::visit(AST::VoidExpression *el) { + start(QLatin1String("VoidExpression voidToken=%1") + .arg(loc(el->voidToken))); + return true; +} +void AstDumper::endVisit(AST::VoidExpression *) { stop("VoidExpression"); } + +bool AstDumper::visit(AST::TypeOfExpression *el) { + start(QLatin1String("TypeOfExpression typeofToken=%1") + .arg(loc(el->typeofToken))); + return true; +} +void AstDumper::endVisit(AST::TypeOfExpression *) { stop("TypeOfExpression"); } + +bool AstDumper::visit(AST::PreIncrementExpression *el) { + start(QLatin1String("PreIncrementExpression incrementToken=%1") + .arg(loc(el->incrementToken))); + return true; +} +void AstDumper::endVisit(AST::PreIncrementExpression *) { stop("PreIncrementExpression"); } + +bool AstDumper::visit(AST::PreDecrementExpression *el) { + start(QLatin1String("PreDecrementExpression decrementToken=%1") + .arg(loc(el->decrementToken))); + return true; +} +void AstDumper::endVisit(AST::PreDecrementExpression *) { stop("PreDecrementExpression"); } + +bool AstDumper::visit(AST::UnaryPlusExpression *el) { + start(QLatin1String("UnaryPlusExpression plusToken=%1") + .arg(loc(el->plusToken))); + return true; +} +void AstDumper::endVisit(AST::UnaryPlusExpression *) { stop("UnaryPlusExpression"); } + +bool AstDumper::visit(AST::UnaryMinusExpression *el) { + start(QLatin1String("UnaryMinusExpression minusToken=%1") + .arg(loc(el->minusToken))); + return true; +} +void AstDumper::endVisit(AST::UnaryMinusExpression *) { stop("UnaryMinusExpression"); } + +bool AstDumper::visit(AST::TildeExpression *el) { + start(QLatin1String("TildeExpression tildeToken=%1") + .arg(loc(el->tildeToken))); + return true; +} +void AstDumper::endVisit(AST::TildeExpression *) { stop("TildeExpression"); } + +bool AstDumper::visit(AST::NotExpression *el) { + start(QLatin1String("NotExpression notToken=%1") + .arg(loc(el->notToken))); + return true; +} +void AstDumper::endVisit(AST::NotExpression *) { stop("NotExpression"); } + +bool AstDumper::visit(AST::BinaryExpression *el) { + start(QLatin1String("BinaryExpression op=%1 operatorToken=%2") + .arg(qs(QString::number(el->op,16)), loc(el->operatorToken))); + return true; +} +void AstDumper::endVisit(AST::BinaryExpression *) { stop("BinaryExpression"); } + +bool AstDumper::visit(AST::ConditionalExpression *el) { + start(QLatin1String("ConditionalExpression questionToken=%1 colonToken=%2") + .arg(loc(el->questionToken), loc(el->colonToken))); + return true; +} +void AstDumper::endVisit(AST::ConditionalExpression *) { stop("ConditionalExpression"); } + +bool AstDumper::visit(AST::Expression *el) { + start(QLatin1String("Expression commaToken=%1") + .arg(loc(el->commaToken))); + return true; +} +void AstDumper::endVisit(AST::Expression *) { stop("Expression"); } + +bool AstDumper::visit(AST::Block *el) { + start(QLatin1String("Block lbraceToken=%1 rbraceToken=%2") + .arg(loc(el->lbraceToken), loc(el->rbraceToken))); + return true; +} +void AstDumper::endVisit(AST::Block *) { stop("Block"); } + +bool AstDumper::visit(AST::StatementList *) { + start(QLatin1String("StatementList")); + return true; +} +void AstDumper::endVisit(AST::StatementList *) { stop("StatementList"); } + +bool AstDumper::visit(AST::VariableStatement *el) { + start(QLatin1String("VariableStatement declarationKindToken=%1") + .arg(loc(el->declarationKindToken))); + return true; +} +void AstDumper::endVisit(AST::VariableStatement *) { stop("VariableStatement"); } + +bool AstDumper::visit(AST::VariableDeclarationList *el) { + start(QLatin1String("VariableDeclarationList commaToken=%1") + .arg(loc(el->commaToken))); + return true; +} +void AstDumper::endVisit(AST::VariableDeclarationList *) { stop("VariableDeclarationList"); } + +bool AstDumper::visit(AST::EmptyStatement *el) { + start(QLatin1String("EmptyStatement semicolonToken=%1") + .arg(loc(el->semicolonToken))); + return true; +} +void AstDumper::endVisit(AST::EmptyStatement *) { stop("EmptyStatement"); } + +bool AstDumper::visit(AST::ExpressionStatement *el) { + start(QLatin1String("ExpressionStatement semicolonToken=%1") + .arg(loc(el->semicolonToken))); + return true; +} +void AstDumper::endVisit(AST::ExpressionStatement *) { stop("ExpressionStatement"); } + +bool AstDumper::visit(AST::IfStatement *el) { + start(QLatin1String("IfStatement ifToken=%1 lparenToken=%2 rparenToken=%3 elseToken=%4") + .arg(loc(el->ifToken), loc(el->lparenToken), loc(el->rparenToken), loc(el->elseToken))); + return true; +} +void AstDumper::endVisit(AST::IfStatement *) { stop("IfStatement"); } + +bool AstDumper::visit(AST::DoWhileStatement *el) { + start(QLatin1String("DoWhileStatement doToken=%1 whileToken=%2 lparenToken=%3 rparenToken=%4 semicolonToken=%5") + .arg(loc(el->doToken), loc(el->whileToken), loc(el->lparenToken), loc(el->rparenToken), loc(el->semicolonToken))); + return true; +} +void AstDumper::endVisit(AST::DoWhileStatement *) { stop("DoWhileStatement"); } + +bool AstDumper::visit(AST::WhileStatement *el) { + start(QLatin1String("WhileStatement whileToken=%1 lparenToken=%2 rparenToken=%3") + .arg(loc(el->whileToken), loc(el->lparenToken), loc(el->rparenToken))); + return true; +} +void AstDumper::endVisit(AST::WhileStatement *) { stop("WhileStatement"); } + +bool AstDumper::visit(AST::ForStatement *el) { + start(QLatin1String("ForStatement forToken=%1 lparenToken=%2 firstSemicolonToken=%3 secondSemicolonToken=%4 rparenToken=%5") + .arg(loc(el->forToken), loc(el->lparenToken), loc(el->firstSemicolonToken), loc(el->secondSemicolonToken), loc(el->rparenToken))); + return true; +} +void AstDumper::endVisit(AST::ForStatement *) { stop("ForStatement"); } + +bool AstDumper::visit(AST::ForEachStatement *el) { + start(QLatin1String("ForEachStatement forToken=%1 lparenToken=%2 inOfToken=%3 rparenToken=%4 type=%5") + .arg(loc(el->forToken), loc(el->lparenToken), loc(el->inOfToken), loc(el->rparenToken), qs(QString::number(static_cast(el->type), 16)))); + return true; +} +void AstDumper::endVisit(AST::ForEachStatement *) { stop("ForEachStatement"); } + +bool AstDumper::visit(AST::ContinueStatement *el) { + start(QLatin1String("ContinueStatement label=%1 continueToken=%2 identifierToken=%3 semicolonToken=%4") + .arg(qs(el->label), loc(el->continueToken), loc(el->identifierToken), loc(el->semicolonToken))); + return true; +} +void AstDumper::endVisit(AST::ContinueStatement *) { stop("ContinueStatement"); } + +bool AstDumper::visit(AST::BreakStatement *el) { + start(QLatin1String("BreakStatement label=%1 breakToken=%2 identifierToken=%3 semicolonToken=%4") + .arg(qs(el->label), loc(el->breakToken), loc(el->identifierToken), loc(el->semicolonToken))); + return true; +} +void AstDumper::endVisit(AST::BreakStatement *) { stop("BreakStatement"); } + +bool AstDumper::visit(AST::ReturnStatement *el) { + start(QLatin1String("ReturnStatement returnToken=%1 semicolonToken=%2") + .arg(loc(el->returnToken), loc(el->semicolonToken))); + return true; +} +void AstDumper::endVisit(AST::ReturnStatement *) { stop("ReturnStatement"); } + +bool AstDumper::visit(AST::YieldExpression *el) { + start(QLatin1String("YieldExpression isYieldStar=%1 yieldToken=%2") + .arg(boolStr(el->isYieldStar), loc(el->yieldToken))); + return true; +} +void AstDumper::endVisit(AST::YieldExpression *) { stop("YieldExpression"); } + +bool AstDumper::visit(AST::WithStatement *el) { + start(QLatin1String("WithStatement withToken=%1 lparenToken=%2 rparenToken=%3") + .arg(loc(el->withToken), loc(el->lparenToken), loc(el->rparenToken))); + return true; +} +void AstDumper::endVisit(AST::WithStatement *) { stop("WithStatement"); } + +bool AstDumper::visit(AST::SwitchStatement *el) { + start(QLatin1String("SwitchStatement switchToken=%1 lparenToken=%2 rparenToken=%3") + .arg(loc(el->switchToken), loc(el->lparenToken), loc(el->rparenToken))); + return true; +} +void AstDumper::endVisit(AST::SwitchStatement *) { stop("SwitchStatement"); } + +bool AstDumper::visit(AST::CaseBlock *el) { + start(QLatin1String("CaseBlock lbraceToken=%1 rbraceToken=%2") + .arg(loc(el->lbraceToken), loc(el->rbraceToken))); + return true; +} +void AstDumper::endVisit(AST::CaseBlock *) { stop("CaseBlock"); } + +bool AstDumper::visit(AST::CaseClauses *) { + start(QLatin1String("CaseClauses")); + return true; +} +void AstDumper::endVisit(AST::CaseClauses *) { stop("CaseClauses"); } + +bool AstDumper::visit(AST::CaseClause *el) { + start(QLatin1String("CaseClause caseToken=%1 colonToken=%2") + .arg(loc(el->caseToken), loc(el->colonToken))); + return true; +} +void AstDumper::endVisit(AST::CaseClause *) { stop("CaseClause"); } + +bool AstDumper::visit(AST::DefaultClause *el) { + start(QLatin1String("DefaultClause defaultToken=%1 colonToken=%2") + .arg(loc(el->defaultToken), loc(el->colonToken))); + return true; +} +void AstDumper::endVisit(AST::DefaultClause *) { stop("DefaultClause"); } + +bool AstDumper::visit(AST::LabelledStatement *el) { + start(QLatin1String("LabelledStatement label=%1 identifierToken=%2 colonToken=%3") + .arg(qs(el->label), loc(el->identifierToken), loc(el->colonToken))); + return true; +} +void AstDumper::endVisit(AST::LabelledStatement *) { stop("LabelledStatement"); } + +bool AstDumper::visit(AST::ThrowStatement *el) { + start(QLatin1String("ThrowStatement throwToken=%1 semicolonToken=%2") + .arg(loc(el->throwToken), loc(el->semicolonToken))); + return true; +} +void AstDumper::endVisit(AST::ThrowStatement *) { stop("ThrowStatement"); } + +bool AstDumper::visit(AST::TryStatement *el) { + start(QLatin1String("TryStatement tryToken=%1") + .arg(loc(el->tryToken))); + return true; +} +void AstDumper::endVisit(AST::TryStatement *) { stop("TryStatement"); } + +bool AstDumper::visit(AST::Catch *el) { + start(QLatin1String("Catch catchToken=%1 lparenToken=%2 identifierToken=%3 rparenToken=%4") + .arg(loc(el->catchToken), loc(el->lparenToken), loc(el->identifierToken), loc(el->rparenToken))); + return true; +} +void AstDumper::endVisit(AST::Catch *) { stop("Catch"); } + +bool AstDumper::visit(AST::Finally *el) { + start(QLatin1String("Finally finallyToken=%1") + .arg(loc(el->finallyToken))); + return true; +} +void AstDumper::endVisit(AST::Finally *) { stop("Finally"); } + +bool AstDumper::visit(AST::FunctionDeclaration *el) { + start(QLatin1String("FunctionDeclaration name=%1 isArrowFunction=%2 isGenerator=%3 functionToken=%4 " + "identifierToken=%5 lparenToken=%6 rparenToken=%7 lbraceToken=%8 rbraceToken=%9") + .arg(qs(el->name), boolStr(el->isArrowFunction), boolStr(el->isGenerator), loc(el->functionToken), + loc(el->identifierToken), loc(el->lparenToken), loc(el->rparenToken), loc(el->lbraceToken), + loc(el->rbraceToken))); + return true; +} +void AstDumper::endVisit(AST::FunctionDeclaration *) { stop("FunctionDeclaration"); } + +bool AstDumper::visit(AST::FunctionExpression *el) { + start(QLatin1String("FunctionExpression name=%1 isArrowFunction=%2 isGenerator=%3 functionToken=%4 " + "identifierToken=%5 lparenToken=%6 rparenToken=%7 lbraceToken=%8 rbraceToken=%9") + .arg(qs(el->name), boolStr(el->isArrowFunction), boolStr(el->isGenerator), loc(el->functionToken), + loc(el->identifierToken), loc(el->lparenToken), loc(el->rparenToken), loc(el->lbraceToken), + loc(el->rbraceToken))); + return true; +} +void AstDumper::endVisit(AST::FunctionExpression *) { stop("FunctionExpression"); } + +bool AstDumper::visit(AST::FormalParameterList *) { + start(QLatin1String("FormalParameterList")); + return true; +} +void AstDumper::endVisit(AST::FormalParameterList *) { stop("FormalParameterList"); } + +bool AstDumper::visit(AST::ClassExpression *el) { + start(QLatin1String("ClassExpression name=%1 classToken=%2 identifierToken=%3 lbraceToken=%4 rbraceToken=%5") + .arg(qs(el->name), loc(el->classToken), loc(el->identifierToken), loc(el->lbraceToken), loc(el->rbraceToken))); + return true; +} +void AstDumper::endVisit(AST::ClassExpression *) { stop("ClassExpression"); } + +bool AstDumper::visit(AST::ClassDeclaration *el) { + start(QLatin1String("ClassDeclaration name=%1 classToken=%2 identifierToken=%3 lbraceToken=%4 rbraceToken=%5") + .arg(qs(el->name), loc(el->classToken), loc(el->identifierToken), loc(el->lbraceToken), loc(el->rbraceToken))); + return true; +} +void AstDumper::endVisit(AST::ClassDeclaration *) { stop("ClassDeclaration"); } + +bool AstDumper::visit(AST::ClassElementList *el) { + start(QLatin1String("ClassElementList isStatic=%1") + .arg(boolStr(el->isStatic))); + return true; +} +void AstDumper::endVisit(AST::ClassElementList *) { stop("ClassElementList"); } + +bool AstDumper::visit(AST::Program *) { + start(QLatin1String("Program")); + return true; +} +void AstDumper::endVisit(AST::Program *) { stop("Program"); } + +bool AstDumper::visit(AST::NameSpaceImport *el) { + start(QLatin1String("NameSpaceImport starToken=%1 importedBindingToken=%2 importedBinding=%3") + .arg(loc(el->starToken), loc(el->importedBindingToken), qs(el->importedBinding))); + return true; +} +void AstDumper::endVisit(AST::NameSpaceImport *) { stop("NameSpaceImport"); } + +bool AstDumper::visit(AST::ImportSpecifier *el) { + start(QLatin1String("ImportSpecifier identifierToken=%1 importedBindingToken=%2 identifier=%3 importedBinding=%4") + .arg(loc(el->identifierToken), loc(el->importedBindingToken), qs(el->identifier), qs(el->importedBinding))); + return true; +} +void AstDumper::endVisit(AST::ImportSpecifier *) { stop("ImportSpecifier"); } + +bool AstDumper::visit(AST::ImportsList *el) { + start(QLatin1String("ImportsList importSpecifierToken=%1") + .arg(loc(el->importSpecifierToken))); + return true; +} +void AstDumper::endVisit(AST::ImportsList *) { stop("ImportsList"); } + +bool AstDumper::visit(AST::NamedImports *el) { + start(QLatin1String("NamedImports leftBraceToken=%1 rightBraceToken=%2") + .arg(loc(el->leftBraceToken), loc(el->rightBraceToken))); + return true; +} +void AstDumper::endVisit(AST::NamedImports *) { stop("NamedImports"); } + +bool AstDumper::visit(AST::FromClause *el) { + start(QLatin1String("FromClause fromToken=%1 moduleSpecifierToken=%2 moduleSpecifier=%3") + .arg(loc(el->fromToken), loc(el->moduleSpecifierToken), qs(el->moduleSpecifier))); + return true; +} +void AstDumper::endVisit(AST::FromClause *) { stop("FromClause"); } + +bool AstDumper::visit(AST::ImportClause *el) { + start(QLatin1String("ImportClause importedDefaultBindingToken=%1 importedDefaultBinding=%2") + .arg(loc(el->importedDefaultBindingToken), qs(el->importedDefaultBinding))); + return true; +} +void AstDumper::endVisit(AST::ImportClause *) { stop("ImportClause"); } + +bool AstDumper::visit(AST::ImportDeclaration *el) { + start(QLatin1String("ImportDeclaration importToken=%1 moduleSpecifierToken=%2 moduleSpecifier=%3") + .arg(loc(el->importToken), loc(el->moduleSpecifierToken), qs(el->moduleSpecifier))); + return true; +} +void AstDumper::endVisit(AST::ImportDeclaration *) { stop("ImportDeclaration"); } + +bool AstDumper::visit(AST::ExportSpecifier *el) { + start(QLatin1String("ExportSpecifier identifierToken=%1 exportedIdentifierToken=%2 identifier=%3 exportedIdentifier=%4") + .arg(loc(el->identifierToken), loc(el->exportedIdentifierToken), qs(el->identifier), qs(el->exportedIdentifier))); + return true; +} +void AstDumper::endVisit(AST::ExportSpecifier *) { stop("ExportSpecifier"); } + +bool AstDumper::visit(AST::ExportsList *) { + start(QLatin1String("ExportsList")); + return true; +} +void AstDumper::endVisit(AST::ExportsList *) { stop("ExportsList"); } + +bool AstDumper::visit(AST::ExportClause *el) { + start(QLatin1String("ExportClause leftBraceToken=%1 rightBraceToken=%2") + .arg(loc(el->leftBraceToken), loc(el->rightBraceToken))); + return true; +} +void AstDumper::endVisit(AST::ExportClause *) { stop("ExportClause"); } + +bool AstDumper::visit(AST::ExportDeclaration *el) { + start(QLatin1String("ExportDeclaration exportToken=%1 exportAll=%2 exportDefault=%3") + .arg(loc(el->exportToken), boolStr(el->exportAll), boolStr(el->exportDefault))); + return true; +} +void AstDumper::endVisit(AST::ExportDeclaration *) { stop("ExportDeclaration"); } + +bool AstDumper::visit(AST::ESModule *) { + start(QLatin1String("ESModule")); + return true; +} +void AstDumper::endVisit(AST::ESModule *) { stop("ESModule"); } + +bool AstDumper::visit(AST::DebuggerStatement *el) { + start(QLatin1String("DebuggerStatement debuggerToken=%1 semicolonToken=%2") + .arg(loc(el->debuggerToken), loc(el->semicolonToken))); + return true; +} +void AstDumper::endVisit(AST::DebuggerStatement *) { stop("DebuggerStatement"); } + +bool AstDumper::visit(AST::Type *) { + start(QLatin1String("Type")); + return true; +} +void AstDumper::endVisit(AST::Type *) { stop("Type"); } + +bool AstDumper::visit(AST::TypeArgumentList *) { + start(QLatin1String("TypeArgumentList")); + return true; +} +void AstDumper::endVisit(AST::TypeArgumentList *) { stop("TypeArgumentList"); } + +bool AstDumper::visit(AST::TypeAnnotation *el) { + start(QLatin1String("TypeAnnotation colonToken=%1") + .arg(loc(el->colonToken))); + return true; +} +void AstDumper::endVisit(AST::TypeAnnotation *) { stop("TypeAnnotation"); } + +void AstDumper::throwRecursionDepthError() +{ + qDebug() << "Maximum statement or expression depth exceeded in AstDumper"; +} + +bool AstDumper::dumpNode() { + return options & DumperOptions::DumpNode; +} + +bool AstDumper::noLocations() { + return options & DumperOptions::NoLocations; +} + +bool AstDumper::noAnnotations() { + return options & DumperOptions::NoAnnotations; +} + +} // end namespace QQmlJS + +QT_END_NAMESPACE diff --git a/tests/auto/shared/qqmljsastdumper.h b/tests/auto/shared/qqmljsastdumper.h new file mode 100644 index 0000000000..919b80f38c --- /dev/null +++ b/tests/auto/shared/qqmljsastdumper.h @@ -0,0 +1,442 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +**/ +#ifndef ASTDUMPER_H +#define ASTDUMPER_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 +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE +class QDebug; + +namespace QQmlJS { + +enum class DumperOptions { + None=0, + NoLocations=0x1, + NoAnnotations=0x2, + DumpNode=0x4 +}; +bool operator & (DumperOptions lhs, DumperOptions rhs); +DumperOptions operator | (DumperOptions lhs, DumperOptions rhs); + +// no export, currently just a supporting file... +class AstDumper: public AST::Visitor +{ +public: + static QString printNode2(AST::Node *); + + static QString diff(AST::Node *n1, AST::Node *n2, int nContext=3, DumperOptions opt=DumperOptions::None, int indent=0); + static QString printNode(AST::Node *n, DumperOptions opt=DumperOptions::None, int indent=1, int baseIndent=0); + + AstDumper(const std::function &dumper, DumperOptions options=DumperOptions::None, + int indent=1, int baseIndent=0); + + void start(const QString &str); + void start(const char *str); + void stop(const QString &str); + void stop(const char *str); + + QString qs(const QString &s); + QString qs(const char *s); + QString qs(const QStringRef &s); + + QString loc(const AST::SourceLocation &s); + + QString boolStr(bool v); + + bool preVisit(AST::Node *el) override; + void postVisit(AST::Node *el) override; + + // Ui + bool visit(AST::UiProgram *el) override; + bool visit(AST::UiHeaderItemList *) override; + bool visit(AST::UiPragma *el) override; + bool visit(AST::UiImport *el) override; + bool visit(AST::UiPublicMember *el) override; + bool visit(AST::UiSourceElement *) override; + bool visit(AST::UiObjectDefinition *) override; + bool visit(AST::UiObjectInitializer *) override; + bool visit(AST::UiObjectBinding *) override; + bool visit(AST::UiScriptBinding *) override; + bool visit(AST::UiArrayBinding *) override; + bool visit(AST::UiParameterList *) override; + bool visit(AST::UiObjectMemberList *) override; + bool visit(AST::UiArrayMemberList *) override; + bool visit(AST::UiQualifiedId *) override; + bool visit(AST::UiEnumDeclaration *) override; + bool visit(AST::UiEnumMemberList *) override; + bool visit(AST::UiVersionSpecifier *) override; + bool visit(AST::UiInlineComponent *) override; + bool visit(AST::UiRequired *) override; + + void endVisit(AST::UiProgram *) override; + void endVisit(AST::UiImport *) override; + void endVisit(AST::UiHeaderItemList *) override; + void endVisit(AST::UiPragma *) override; + void endVisit(AST::UiPublicMember *) override; + void endVisit(AST::UiSourceElement *) override; + void endVisit(AST::UiObjectDefinition *) override; + void endVisit(AST::UiObjectInitializer *) override; + void endVisit(AST::UiObjectBinding *) override; + void endVisit(AST::UiScriptBinding *) override; + void endVisit(AST::UiArrayBinding *) override; + void endVisit(AST::UiParameterList *) override; + void endVisit(AST::UiObjectMemberList *) override; + void endVisit(AST::UiArrayMemberList *) override; + void endVisit(AST::UiQualifiedId *) override; + void endVisit(AST::UiEnumDeclaration *) override; + void endVisit(AST::UiEnumMemberList *) override; + void endVisit(AST::UiVersionSpecifier *) override; + void endVisit(AST::UiInlineComponent *) override; + void endVisit(AST::UiRequired *) override; + + // QQmlJS + bool visit(AST::ThisExpression *) override; + void endVisit(AST::ThisExpression *) override; + + bool visit(AST::IdentifierExpression *) override; + void endVisit(AST::IdentifierExpression *) override; + + bool visit(AST::NullExpression *) override; + void endVisit(AST::NullExpression *) override; + + bool visit(AST::TrueLiteral *) override; + void endVisit(AST::TrueLiteral *) override; + + bool visit(AST::FalseLiteral *) override; + void endVisit(AST::FalseLiteral *) override; + + bool visit(AST::SuperLiteral *) override; + void endVisit(AST::SuperLiteral *) override; + + bool visit(AST::StringLiteral *) override; + void endVisit(AST::StringLiteral *) override; + + bool visit(AST::TemplateLiteral *) override; + void endVisit(AST::TemplateLiteral *) override; + + bool visit(AST::NumericLiteral *) override; + void endVisit(AST::NumericLiteral *) override; + + bool visit(AST::RegExpLiteral *) override; + void endVisit(AST::RegExpLiteral *) override; + + bool visit(AST::ArrayPattern *) override; + void endVisit(AST::ArrayPattern *) override; + + bool visit(AST::ObjectPattern *) override; + void endVisit(AST::ObjectPattern *) override; + + bool visit(AST::PatternElementList *) override; + void endVisit(AST::PatternElementList *) override; + + bool visit(AST::PatternPropertyList *) override; + void endVisit(AST::PatternPropertyList *) override; + + bool visit(AST::PatternElement *) override; + void endVisit(AST::PatternElement *) override; + + bool visit(AST::PatternProperty *) override; + void endVisit(AST::PatternProperty *) override; + + bool visit(AST::Elision *) override; + void endVisit(AST::Elision *) override; + + bool visit(AST::NestedExpression *) override; + void endVisit(AST::NestedExpression *) override; + + bool visit(AST::IdentifierPropertyName *) override; + void endVisit(AST::IdentifierPropertyName *) override; + + bool visit(AST::StringLiteralPropertyName *) override; + void endVisit(AST::StringLiteralPropertyName *) override; + + bool visit(AST::NumericLiteralPropertyName *) override; + void endVisit(AST::NumericLiteralPropertyName *) override; + + bool visit(AST::ComputedPropertyName *) override; + void endVisit(AST::ComputedPropertyName *) override; + + bool visit(AST::ArrayMemberExpression *) override; + void endVisit(AST::ArrayMemberExpression *) override; + + bool visit(AST::FieldMemberExpression *) override; + void endVisit(AST::FieldMemberExpression *) override; + + bool visit(AST::TaggedTemplate *) override; + void endVisit(AST::TaggedTemplate *) override; + + bool visit(AST::NewMemberExpression *) override; + void endVisit(AST::NewMemberExpression *) override; + + bool visit(AST::NewExpression *) override; + void endVisit(AST::NewExpression *) override; + + bool visit(AST::CallExpression *) override; + void endVisit(AST::CallExpression *) override; + + bool visit(AST::ArgumentList *) override; + void endVisit(AST::ArgumentList *) override; + + bool visit(AST::PostIncrementExpression *) override; + void endVisit(AST::PostIncrementExpression *) override; + + bool visit(AST::PostDecrementExpression *) override; + void endVisit(AST::PostDecrementExpression *) override; + + bool visit(AST::DeleteExpression *) override; + void endVisit(AST::DeleteExpression *) override; + + bool visit(AST::VoidExpression *) override; + void endVisit(AST::VoidExpression *) override; + + bool visit(AST::TypeOfExpression *) override; + void endVisit(AST::TypeOfExpression *) override; + + bool visit(AST::PreIncrementExpression *) override; + void endVisit(AST::PreIncrementExpression *) override; + + bool visit(AST::PreDecrementExpression *) override; + void endVisit(AST::PreDecrementExpression *) override; + + bool visit(AST::UnaryPlusExpression *) override; + void endVisit(AST::UnaryPlusExpression *) override; + + bool visit(AST::UnaryMinusExpression *) override; + void endVisit(AST::UnaryMinusExpression *) override; + + bool visit(AST::TildeExpression *) override; + void endVisit(AST::TildeExpression *) override; + + bool visit(AST::NotExpression *) override; + void endVisit(AST::NotExpression *) override; + + bool visit(AST::BinaryExpression *) override; + void endVisit(AST::BinaryExpression *) override; + + bool visit(AST::ConditionalExpression *) override; + void endVisit(AST::ConditionalExpression *) override; + + bool visit(AST::Expression *) override; + void endVisit(AST::Expression *) override; + + bool visit(AST::Block *) override; + void endVisit(AST::Block *) override; + + bool visit(AST::StatementList *) override; + void endVisit(AST::StatementList *) override; + + bool visit(AST::VariableStatement *) override; + void endVisit(AST::VariableStatement *) override; + + bool visit(AST::VariableDeclarationList *) override; + void endVisit(AST::VariableDeclarationList *) override; + + bool visit(AST::EmptyStatement *) override; + void endVisit(AST::EmptyStatement *) override; + + bool visit(AST::ExpressionStatement *) override; + void endVisit(AST::ExpressionStatement *) override; + + bool visit(AST::IfStatement *) override; + void endVisit(AST::IfStatement *) override; + + bool visit(AST::DoWhileStatement *) override; + void endVisit(AST::DoWhileStatement *) override; + + bool visit(AST::WhileStatement *) override; + void endVisit(AST::WhileStatement *) override; + + bool visit(AST::ForStatement *) override; + void endVisit(AST::ForStatement *) override; + + bool visit(AST::ForEachStatement *) override; + void endVisit(AST::ForEachStatement *) override; + + bool visit(AST::ContinueStatement *) override; + void endVisit(AST::ContinueStatement *) override; + + bool visit(AST::BreakStatement *) override; + void endVisit(AST::BreakStatement *) override; + + bool visit(AST::ReturnStatement *) override; + void endVisit(AST::ReturnStatement *) override; + + bool visit(AST::YieldExpression *) override; + void endVisit(AST::YieldExpression *) override; + + bool visit(AST::WithStatement *) override; + void endVisit(AST::WithStatement *) override; + + bool visit(AST::SwitchStatement *) override; + void endVisit(AST::SwitchStatement *) override; + + bool visit(AST::CaseBlock *) override; + void endVisit(AST::CaseBlock *) override; + + bool visit(AST::CaseClauses *) override; + void endVisit(AST::CaseClauses *) override; + + bool visit(AST::CaseClause *) override; + void endVisit(AST::CaseClause *) override; + + bool visit(AST::DefaultClause *) override; + void endVisit(AST::DefaultClause *) override; + + bool visit(AST::LabelledStatement *) override; + void endVisit(AST::LabelledStatement *) override; + + bool visit(AST::ThrowStatement *) override; + void endVisit(AST::ThrowStatement *) override; + + bool visit(AST::TryStatement *) override; + void endVisit(AST::TryStatement *) override; + + bool visit(AST::Catch *) override; + void endVisit(AST::Catch *) override; + + bool visit(AST::Finally *) override; + void endVisit(AST::Finally *) override; + + bool visit(AST::FunctionDeclaration *) override; + void endVisit(AST::FunctionDeclaration *) override; + + bool visit(AST::FunctionExpression *) override; + void endVisit(AST::FunctionExpression *) override; + + bool visit(AST::FormalParameterList *) override; + void endVisit(AST::FormalParameterList *) override; + + bool visit(AST::ClassExpression *) override; + void endVisit(AST::ClassExpression *) override; + + bool visit(AST::ClassDeclaration *) override; + void endVisit(AST::ClassDeclaration *) override; + + bool visit(AST::ClassElementList *) override; + void endVisit(AST::ClassElementList *) override; + + bool visit(AST::Program *) override; + void endVisit(AST::Program *) override; + + bool visit(AST::NameSpaceImport *) override; + void endVisit(AST::NameSpaceImport *) override; + + bool visit(AST::ImportSpecifier *) override; + void endVisit(AST::ImportSpecifier *) override; + + bool visit(AST::ImportsList *) override; + void endVisit(AST::ImportsList *) override; + + bool visit(AST::NamedImports *) override; + void endVisit(AST::NamedImports *) override; + + bool visit(AST::FromClause *) override; + void endVisit(AST::FromClause *) override; + + bool visit(AST::ImportClause *) override; + void endVisit(AST::ImportClause *) override; + + bool visit(AST::ImportDeclaration *) override; + void endVisit(AST::ImportDeclaration *) override; + + bool visit(AST::ExportSpecifier *) override; + void endVisit(AST::ExportSpecifier *) override; + + bool visit(AST::ExportsList *) override; + void endVisit(AST::ExportsList *) override; + + bool visit(AST::ExportClause *) override; + void endVisit(AST::ExportClause *) override; + + bool visit(AST::ExportDeclaration *) override; + void endVisit(AST::ExportDeclaration *) override; + + bool visit(AST::ESModule *) override; + void endVisit(AST::ESModule *) override; + + bool visit(AST::DebuggerStatement *) override; + void endVisit(AST::DebuggerStatement *) override; + + bool visit(AST::Type *) override; + void endVisit(AST::Type *) override; + + bool visit(AST::TypeArgumentList *) override; + void endVisit(AST::TypeArgumentList *) override; + + bool visit(AST::TypeAnnotation *) override; + void endVisit(AST::TypeAnnotation *) override; + + void throwRecursionDepthError() override; + +private: + // attributes + std::function dumper; + DumperOptions options = DumperOptions::None; + int indent = 0; + int baseIndent = 0; + bool dumpNode(); + bool noLocations(); + bool noAnnotations(); +}; + +QDebug operator<<(QDebug d, AST::Node *n); + +std::ostream &operator<<(std::ostream &stream, AST::Node *n); + +} // namespace AST + +QT_END_NAMESPACE + +#endif // ASTDUMPER_H -- cgit v1.2.3 From 7f7bf177f41d7824aecee9f046a8a63ef4d82521 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Fri, 7 Feb 2020 13:45:07 +0100 Subject: Provide a macro for qmlRegisterTypeNotAvailable That is, register QQmlTypeNotAvailable as foreign type under the name given as parameter. Also, statically register QQuickAnimatedImage as unavailable in case of !quick_animatedimage and register it for the right version. Task-number: QTBUG-68796 Change-Id: I2ea292d2aeda66d8ce43b3bccbd3d21663330bd6 Reviewed-by: Simon Hausmann --- src/qml/qml/qqml.cpp | 37 +++++++++++++++++++++++++++++++++++ src/qml/qml/qqml.h | 6 +++++- src/qml/qml/qqmlprivate.h | 6 ++++++ src/qml/qml/qqmltypenotavailable.cpp | 2 -- src/qml/qml/qqmltypenotavailable_p.h | 4 ---- src/quick/items/qquickitemsmodule.cpp | 7 ------- src/quick/items/qquickitemsmodule_p.h | 12 ++++++++++++ 7 files changed, 60 insertions(+), 14 deletions(-) diff --git a/src/qml/qml/qqml.cpp b/src/qml/qml/qqml.cpp index a33936647f..fe4e2f4e55 100644 --- a/src/qml/qml/qqml.cpp +++ b/src/qml/qml/qqml.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include @@ -321,4 +322,40 @@ void QQmlPrivate::qmlunregister(RegistrationType type, quintptr data) } } +namespace QQmlPrivate { + template<> + void qmlRegisterTypeAndRevisions( + const char *uri, int versionMajor, const QMetaObject *classInfoMetaObject) + { + using T = QQmlTypeNotAvailable; + + QML_GETTYPENAMES + + RegisterTypeAndRevisions type = { + 0, + qRegisterNormalizedMetaType(pointerName.constData()), + qRegisterNormalizedMetaType >(listName.constData()), + 0, + nullptr, + + uri, + versionMajor, + + &QQmlTypeNotAvailable::staticMetaObject, + classInfoMetaObject, + + attachedPropertiesFunc(), + attachedPropertiesMetaObject(), + + StaticCastSelector::cast(), + StaticCastSelector::cast(), + StaticCastSelector::cast(), + + nullptr, nullptr, qmlCreateCustomParser + }; + + qmlregister(TypeAndRevisionsRegistration, &type); + } +} + QT_END_NAMESPACE diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h index 153cb0c071..ef7fdd1945 100644 --- a/src/qml/qml/qqml.h +++ b/src/qml/qml/qqml.h @@ -120,6 +120,9 @@ template \ friend void QML_REGISTER_TYPES_AND_REVISIONS(const char *uri, int versionMajor); +#define QML_UNAVAILABLE \ + QML_FOREIGN(QQmlTypeNotAvailable) + enum { /* TYPEINFO flags */ QML_HAS_ATTACHED_PROPERTIES = 0x01 }; @@ -183,7 +186,8 @@ QT_DEPRECATED_VERSION_X_5_14("Use qmlRegisterAnonymousType instead") int qmlRegi } #endif -int Q_QML_EXPORT qmlRegisterTypeNotAvailable(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& message); +int Q_QML_EXPORT qmlRegisterTypeNotAvailable(const char *uri, int versionMajor, int versionMinor, + const char *qmlName, const QString& message); template int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& reason) diff --git a/src/qml/qml/qqmlprivate.h b/src/qml/qml/qqmlprivate.h index 9d260f5e94..d6a9e73763 100644 --- a/src/qml/qml/qqmlprivate.h +++ b/src/qml/qml/qqmlprivate.h @@ -124,6 +124,7 @@ class QJSValue; class QJSEngine; class QQmlEngine; class QQmlCustomParser; +class QQmlTypeNotAvailable; template QQmlCustomParser *qmlCreateCustomParser() @@ -652,6 +653,11 @@ namespace QQmlPrivate qmlregister(TypeAndRevisionsRegistration, &type); } + + template<> + void Q_QML_EXPORT qmlRegisterTypeAndRevisions( + const char *uri, int versionMajor, const QMetaObject *classInfoMetaObject); + } // namespace QQmlPrivate QT_END_NAMESPACE diff --git a/src/qml/qml/qqmltypenotavailable.cpp b/src/qml/qml/qqmltypenotavailable.cpp index ffa4472e4b..0e95d6062c 100644 --- a/src/qml/qml/qqmltypenotavailable.cpp +++ b/src/qml/qml/qqmltypenotavailable.cpp @@ -46,8 +46,6 @@ int qmlRegisterTypeNotAvailable(const char *uri, int versionMajor, int versionMi return qmlRegisterUncreatableType(uri,versionMajor,versionMinor,qmlName,message); } -QQmlTypeNotAvailable::QQmlTypeNotAvailable() { } - QT_END_NAMESPACE #include "moc_qqmltypenotavailable_p.cpp" diff --git a/src/qml/qml/qqmltypenotavailable_p.h b/src/qml/qml/qqmltypenotavailable_p.h index 8db5876b10..9bb19ed86c 100644 --- a/src/qml/qml/qqmltypenotavailable_p.h +++ b/src/qml/qml/qqmltypenotavailable_p.h @@ -55,14 +55,10 @@ QT_BEGIN_NAMESPACE - class QQmlTypeNotAvailable : public QObject { Q_OBJECT QML_NAMED_ELEMENT(TypeNotAvailable) QML_UNCREATABLE("Type not available.") - -public: - QQmlTypeNotAvailable(); }; QT_END_NAMESPACE diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp index 2bd3d2a9cb..125518e51b 100644 --- a/src/quick/items/qquickitemsmodule.cpp +++ b/src/quick/items/qquickitemsmodule.cpp @@ -183,13 +183,6 @@ static void qt_quickitems_defineModule() qRegisterMetaType("QQuickAnchorLine"); qRegisterMetaType("QPointingDeviceUniqueId"); qRegisterMetaType(); - -#if !QT_CONFIG(quick_animatedimage) - qmlRegisterTypeNotAvailable( - uri, major, 15, "AnimatedImage", - QCoreApplication::translate("QQuickAnimatedImage", - "Qt was built without support for QMovie")); -#endif } static void initResources() diff --git a/src/quick/items/qquickitemsmodule_p.h b/src/quick/items/qquickitemsmodule_p.h index 6ceb0d56e6..28dff65dff 100644 --- a/src/quick/items/qquickitemsmodule_p.h +++ b/src/quick/items/qquickitemsmodule_p.h @@ -51,6 +51,7 @@ // We mean it. // +#include #include #include @@ -71,6 +72,17 @@ struct QPointingDeviceUniqueIdForeign QML_UNCREATABLE("PointingDeviceUniqueId is only available via read-only properties.") }; +#if !QT_CONFIG(quick_animatedimage) +struct QQuickAnimatedImageNotAvailable +{ + Q_GADGET + QML_UNAVAILABLE + QML_NAMED_ELEMENT(AnimatedImage) + QML_ADDED_IN_VERSION(2, 0) + QML_UNCREATABLE("Qt was built without support for QMovie.") +}; +#endif + QT_END_NAMESPACE #endif // QQUICKITEMSMODULE_P_H -- cgit v1.2.3 From c2e756dc1962eeb3575f618b38272359d4fccc89 Mon Sep 17 00:00:00 2001 From: Fawzi Mohamed Date: Tue, 11 Feb 2020 16:22:12 +0100 Subject: Introduce BaseVisitor Base Visitor is an abstract visitor that has all visit methods abstract, subclassing this one gets an error if some visit method is not implemented (dumper and reformatter for example will gain from this. Change-Id: I3f8cfeb6fc0ef917acf725bbe1c293d761304287 Reviewed-by: Ulf Hermann --- src/qml/parser/qqmljsast.cpp | 226 +++++----- src/qml/parser/qqmljsast_p.h | 236 +++++----- src/qml/parser/qqmljsastfwd_p.h | 1 + src/qml/parser/qqmljsastvisitor.cpp | 6 +- src/qml/parser/qqmljsastvisitor_p.h | 799 ++++++++++++++++++++++++---------- tests/auto/shared/qqmljsastdumper.cpp | 7 + tests/auto/shared/qqmljsastdumper.h | 2 +- 7 files changed, 809 insertions(+), 468 deletions(-) diff --git a/src/qml/parser/qqmljsast.cpp b/src/qml/parser/qqmljsast.cpp index 7cf263e2ba..ef25427076 100644 --- a/src/qml/parser/qqmljsast.cpp +++ b/src/qml/parser/qqmljsast.cpp @@ -167,7 +167,7 @@ UiObjectMember *UiObjectMember::uiObjectMemberCast() return this; } -void NestedExpression::accept0(Visitor *visitor) +void NestedExpression::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(expression, visitor); @@ -185,7 +185,7 @@ ClassExpression *NestedExpression::asClassDefinition() return expression->asClassDefinition(); } -void ThisExpression::accept0(Visitor *visitor) +void ThisExpression::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { } @@ -193,7 +193,7 @@ void ThisExpression::accept0(Visitor *visitor) visitor->endVisit(this); } -void IdentifierExpression::accept0(Visitor *visitor) +void IdentifierExpression::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { } @@ -201,7 +201,7 @@ void IdentifierExpression::accept0(Visitor *visitor) visitor->endVisit(this); } -void NullExpression::accept0(Visitor *visitor) +void NullExpression::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { } @@ -209,7 +209,7 @@ void NullExpression::accept0(Visitor *visitor) visitor->endVisit(this); } -void TrueLiteral::accept0(Visitor *visitor) +void TrueLiteral::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { } @@ -217,7 +217,7 @@ void TrueLiteral::accept0(Visitor *visitor) visitor->endVisit(this); } -void FalseLiteral::accept0(Visitor *visitor) +void FalseLiteral::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { } @@ -225,7 +225,7 @@ void FalseLiteral::accept0(Visitor *visitor) visitor->endVisit(this); } -void SuperLiteral::accept0(Visitor *visitor) +void SuperLiteral::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { } @@ -234,7 +234,7 @@ void SuperLiteral::accept0(Visitor *visitor) } -void StringLiteral::accept0(Visitor *visitor) +void StringLiteral::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { } @@ -242,7 +242,7 @@ void StringLiteral::accept0(Visitor *visitor) visitor->endVisit(this); } -void TemplateLiteral::accept0(Visitor *visitor) +void TemplateLiteral::accept0(BaseVisitor *visitor) { bool accepted = true; for (TemplateLiteral *it = this; it && accepted; it = it->next) { @@ -251,7 +251,7 @@ void TemplateLiteral::accept0(Visitor *visitor) } } -void NumericLiteral::accept0(Visitor *visitor) +void NumericLiteral::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { } @@ -259,7 +259,7 @@ void NumericLiteral::accept0(Visitor *visitor) visitor->endVisit(this); } -void RegExpLiteral::accept0(Visitor *visitor) +void RegExpLiteral::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { } @@ -267,7 +267,7 @@ void RegExpLiteral::accept0(Visitor *visitor) visitor->endVisit(this); } -void ArrayPattern::accept0(Visitor *visitor) +void ArrayPattern::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) accept(elements, visitor); @@ -287,7 +287,7 @@ bool ArrayPattern::isValidArrayLiteral(SourceLocation *errorLocation) const { return true; } -void ObjectPattern::accept0(Visitor *visitor) +void ObjectPattern::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(properties, visitor); @@ -462,7 +462,7 @@ bool PatternProperty::convertLiteralToAssignmentPattern(MemoryPool *pool, Source } -void Elision::accept0(Visitor *visitor) +void Elision::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { // ### @@ -471,7 +471,7 @@ void Elision::accept0(Visitor *visitor) visitor->endVisit(this); } -void IdentifierPropertyName::accept0(Visitor *visitor) +void IdentifierPropertyName::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { } @@ -479,7 +479,7 @@ void IdentifierPropertyName::accept0(Visitor *visitor) visitor->endVisit(this); } -void StringLiteralPropertyName::accept0(Visitor *visitor) +void StringLiteralPropertyName::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { } @@ -487,7 +487,7 @@ void StringLiteralPropertyName::accept0(Visitor *visitor) visitor->endVisit(this); } -void NumericLiteralPropertyName::accept0(Visitor *visitor) +void NumericLiteralPropertyName::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { } @@ -517,7 +517,7 @@ QString NumericLiteralPropertyName::asString()const return locale.toString(id, 'g', 16); } -void ArrayMemberExpression::accept0(Visitor *visitor) +void ArrayMemberExpression::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(base, visitor); @@ -527,7 +527,7 @@ void ArrayMemberExpression::accept0(Visitor *visitor) visitor->endVisit(this); } -void FieldMemberExpression::accept0(Visitor *visitor) +void FieldMemberExpression::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(base, visitor); @@ -536,7 +536,7 @@ void FieldMemberExpression::accept0(Visitor *visitor) visitor->endVisit(this); } -void NewMemberExpression::accept0(Visitor *visitor) +void NewMemberExpression::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(base, visitor); @@ -546,7 +546,7 @@ void NewMemberExpression::accept0(Visitor *visitor) visitor->endVisit(this); } -void NewExpression::accept0(Visitor *visitor) +void NewExpression::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(expression, visitor); @@ -555,7 +555,7 @@ void NewExpression::accept0(Visitor *visitor) visitor->endVisit(this); } -void CallExpression::accept0(Visitor *visitor) +void CallExpression::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(base, visitor); @@ -565,7 +565,7 @@ void CallExpression::accept0(Visitor *visitor) visitor->endVisit(this); } -void ArgumentList::accept0(Visitor *visitor) +void ArgumentList::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { for (ArgumentList *it = this; it; it = it->next) { @@ -576,7 +576,7 @@ void ArgumentList::accept0(Visitor *visitor) visitor->endVisit(this); } -void PostIncrementExpression::accept0(Visitor *visitor) +void PostIncrementExpression::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(base, visitor); @@ -585,7 +585,7 @@ void PostIncrementExpression::accept0(Visitor *visitor) visitor->endVisit(this); } -void PostDecrementExpression::accept0(Visitor *visitor) +void PostDecrementExpression::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(base, visitor); @@ -594,7 +594,7 @@ void PostDecrementExpression::accept0(Visitor *visitor) visitor->endVisit(this); } -void DeleteExpression::accept0(Visitor *visitor) +void DeleteExpression::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(expression, visitor); @@ -603,7 +603,7 @@ void DeleteExpression::accept0(Visitor *visitor) visitor->endVisit(this); } -void VoidExpression::accept0(Visitor *visitor) +void VoidExpression::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(expression, visitor); @@ -612,7 +612,7 @@ void VoidExpression::accept0(Visitor *visitor) visitor->endVisit(this); } -void TypeOfExpression::accept0(Visitor *visitor) +void TypeOfExpression::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(expression, visitor); @@ -621,7 +621,7 @@ void TypeOfExpression::accept0(Visitor *visitor) visitor->endVisit(this); } -void PreIncrementExpression::accept0(Visitor *visitor) +void PreIncrementExpression::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(expression, visitor); @@ -630,7 +630,7 @@ void PreIncrementExpression::accept0(Visitor *visitor) visitor->endVisit(this); } -void PreDecrementExpression::accept0(Visitor *visitor) +void PreDecrementExpression::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(expression, visitor); @@ -639,7 +639,7 @@ void PreDecrementExpression::accept0(Visitor *visitor) visitor->endVisit(this); } -void UnaryPlusExpression::accept0(Visitor *visitor) +void UnaryPlusExpression::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(expression, visitor); @@ -648,7 +648,7 @@ void UnaryPlusExpression::accept0(Visitor *visitor) visitor->endVisit(this); } -void UnaryMinusExpression::accept0(Visitor *visitor) +void UnaryMinusExpression::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(expression, visitor); @@ -657,7 +657,7 @@ void UnaryMinusExpression::accept0(Visitor *visitor) visitor->endVisit(this); } -void TildeExpression::accept0(Visitor *visitor) +void TildeExpression::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(expression, visitor); @@ -666,7 +666,7 @@ void TildeExpression::accept0(Visitor *visitor) visitor->endVisit(this); } -void NotExpression::accept0(Visitor *visitor) +void NotExpression::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(expression, visitor); @@ -675,7 +675,7 @@ void NotExpression::accept0(Visitor *visitor) visitor->endVisit(this); } -void BinaryExpression::accept0(Visitor *visitor) +void BinaryExpression::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(left, visitor); @@ -685,7 +685,7 @@ void BinaryExpression::accept0(Visitor *visitor) visitor->endVisit(this); } -void ConditionalExpression::accept0(Visitor *visitor) +void ConditionalExpression::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(expression, visitor); @@ -696,7 +696,7 @@ void ConditionalExpression::accept0(Visitor *visitor) visitor->endVisit(this); } -void Expression::accept0(Visitor *visitor) +void Expression::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(left, visitor); @@ -706,7 +706,7 @@ void Expression::accept0(Visitor *visitor) visitor->endVisit(this); } -void Block::accept0(Visitor *visitor) +void Block::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(statements, visitor); @@ -715,7 +715,7 @@ void Block::accept0(Visitor *visitor) visitor->endVisit(this); } -void StatementList::accept0(Visitor *visitor) +void StatementList::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { for (StatementList *it = this; it; it = it->next) { @@ -726,7 +726,7 @@ void StatementList::accept0(Visitor *visitor) visitor->endVisit(this); } -void VariableStatement::accept0(Visitor *visitor) +void VariableStatement::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(declarations, visitor); @@ -735,7 +735,7 @@ void VariableStatement::accept0(Visitor *visitor) visitor->endVisit(this); } -void VariableDeclarationList::accept0(Visitor *visitor) +void VariableDeclarationList::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { for (VariableDeclarationList *it = this; it; it = it->next) { @@ -746,7 +746,7 @@ void VariableDeclarationList::accept0(Visitor *visitor) visitor->endVisit(this); } -void EmptyStatement::accept0(Visitor *visitor) +void EmptyStatement::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { } @@ -754,7 +754,7 @@ void EmptyStatement::accept0(Visitor *visitor) visitor->endVisit(this); } -void ExpressionStatement::accept0(Visitor *visitor) +void ExpressionStatement::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(expression, visitor); @@ -763,7 +763,7 @@ void ExpressionStatement::accept0(Visitor *visitor) visitor->endVisit(this); } -void IfStatement::accept0(Visitor *visitor) +void IfStatement::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(expression, visitor); @@ -774,7 +774,7 @@ void IfStatement::accept0(Visitor *visitor) visitor->endVisit(this); } -void DoWhileStatement::accept0(Visitor *visitor) +void DoWhileStatement::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(statement, visitor); @@ -784,7 +784,7 @@ void DoWhileStatement::accept0(Visitor *visitor) visitor->endVisit(this); } -void WhileStatement::accept0(Visitor *visitor) +void WhileStatement::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(expression, visitor); @@ -794,7 +794,7 @@ void WhileStatement::accept0(Visitor *visitor) visitor->endVisit(this); } -void ForStatement::accept0(Visitor *visitor) +void ForStatement::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(initialiser, visitor); @@ -807,7 +807,7 @@ void ForStatement::accept0(Visitor *visitor) visitor->endVisit(this); } -void ForEachStatement::accept0(Visitor *visitor) +void ForEachStatement::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(lhs, visitor); @@ -818,7 +818,7 @@ void ForEachStatement::accept0(Visitor *visitor) visitor->endVisit(this); } -void ContinueStatement::accept0(Visitor *visitor) +void ContinueStatement::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { } @@ -826,7 +826,7 @@ void ContinueStatement::accept0(Visitor *visitor) visitor->endVisit(this); } -void BreakStatement::accept0(Visitor *visitor) +void BreakStatement::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { } @@ -834,7 +834,7 @@ void BreakStatement::accept0(Visitor *visitor) visitor->endVisit(this); } -void ReturnStatement::accept0(Visitor *visitor) +void ReturnStatement::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(expression, visitor); @@ -843,7 +843,7 @@ void ReturnStatement::accept0(Visitor *visitor) visitor->endVisit(this); } -void YieldExpression::accept0(Visitor *visitor) +void YieldExpression::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(expression, visitor); @@ -853,7 +853,7 @@ void YieldExpression::accept0(Visitor *visitor) } -void WithStatement::accept0(Visitor *visitor) +void WithStatement::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(expression, visitor); @@ -863,7 +863,7 @@ void WithStatement::accept0(Visitor *visitor) visitor->endVisit(this); } -void SwitchStatement::accept0(Visitor *visitor) +void SwitchStatement::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(expression, visitor); @@ -873,7 +873,7 @@ void SwitchStatement::accept0(Visitor *visitor) visitor->endVisit(this); } -void CaseBlock::accept0(Visitor *visitor) +void CaseBlock::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(clauses, visitor); @@ -884,7 +884,7 @@ void CaseBlock::accept0(Visitor *visitor) visitor->endVisit(this); } -void CaseClauses::accept0(Visitor *visitor) +void CaseClauses::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { for (CaseClauses *it = this; it; it = it->next) { @@ -895,7 +895,7 @@ void CaseClauses::accept0(Visitor *visitor) visitor->endVisit(this); } -void CaseClause::accept0(Visitor *visitor) +void CaseClause::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(expression, visitor); @@ -905,7 +905,7 @@ void CaseClause::accept0(Visitor *visitor) visitor->endVisit(this); } -void DefaultClause::accept0(Visitor *visitor) +void DefaultClause::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(statements, visitor); @@ -914,7 +914,7 @@ void DefaultClause::accept0(Visitor *visitor) visitor->endVisit(this); } -void LabelledStatement::accept0(Visitor *visitor) +void LabelledStatement::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(statement, visitor); @@ -923,7 +923,7 @@ void LabelledStatement::accept0(Visitor *visitor) visitor->endVisit(this); } -void ThrowStatement::accept0(Visitor *visitor) +void ThrowStatement::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(expression, visitor); @@ -932,7 +932,7 @@ void ThrowStatement::accept0(Visitor *visitor) visitor->endVisit(this); } -void TryStatement::accept0(Visitor *visitor) +void TryStatement::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(statement, visitor); @@ -943,7 +943,7 @@ void TryStatement::accept0(Visitor *visitor) visitor->endVisit(this); } -void Catch::accept0(Visitor *visitor) +void Catch::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(patternElement, visitor); @@ -953,7 +953,7 @@ void Catch::accept0(Visitor *visitor) visitor->endVisit(this); } -void Finally::accept0(Visitor *visitor) +void Finally::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(statement, visitor); @@ -962,7 +962,7 @@ void Finally::accept0(Visitor *visitor) visitor->endVisit(this); } -void FunctionDeclaration::accept0(Visitor *visitor) +void FunctionDeclaration::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(formals, visitor); @@ -973,7 +973,7 @@ void FunctionDeclaration::accept0(Visitor *visitor) visitor->endVisit(this); } -void FunctionExpression::accept0(Visitor *visitor) +void FunctionExpression::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(formals, visitor); @@ -1018,7 +1018,7 @@ BoundNames FormalParameterList::boundNames() const return names; } -void FormalParameterList::accept0(Visitor *visitor) +void FormalParameterList::accept0(BaseVisitor *visitor) { bool accepted = true; for (FormalParameterList *it = this; it && accepted; it = it->next) { @@ -1043,7 +1043,7 @@ FormalParameterList *FormalParameterList::finish(QQmlJS::MemoryPool *pool) return front; } -void Program::accept0(Visitor *visitor) +void Program::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(statements, visitor); @@ -1052,7 +1052,7 @@ void Program::accept0(Visitor *visitor) visitor->endVisit(this); } -void ImportSpecifier::accept0(Visitor *visitor) +void ImportSpecifier::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { @@ -1060,7 +1060,7 @@ void ImportSpecifier::accept0(Visitor *visitor) visitor->endVisit(this); } -void ImportsList::accept0(Visitor *visitor) +void ImportsList::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { for (ImportsList *it = this; it; it = it->next) { @@ -1071,7 +1071,7 @@ void ImportsList::accept0(Visitor *visitor) visitor->endVisit(this); } -void NamedImports::accept0(Visitor *visitor) +void NamedImports::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(importsList, visitor); @@ -1080,7 +1080,7 @@ void NamedImports::accept0(Visitor *visitor) visitor->endVisit(this); } -void FromClause::accept0(Visitor *visitor) +void FromClause::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { } @@ -1088,7 +1088,7 @@ void FromClause::accept0(Visitor *visitor) visitor->endVisit(this); } -void NameSpaceImport::accept0(Visitor *visitor) +void NameSpaceImport::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { } @@ -1096,7 +1096,7 @@ void NameSpaceImport::accept0(Visitor *visitor) visitor->endVisit(this); } -void ImportClause::accept0(Visitor *visitor) +void ImportClause::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(nameSpaceImport, visitor); @@ -1106,7 +1106,7 @@ void ImportClause::accept0(Visitor *visitor) visitor->endVisit(this); } -void ImportDeclaration::accept0(Visitor *visitor) +void ImportDeclaration::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(importClause, visitor); @@ -1116,7 +1116,7 @@ void ImportDeclaration::accept0(Visitor *visitor) visitor->endVisit(this); } -void ExportSpecifier::accept0(Visitor *visitor) +void ExportSpecifier::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { @@ -1125,7 +1125,7 @@ void ExportSpecifier::accept0(Visitor *visitor) visitor->endVisit(this); } -void ExportsList::accept0(Visitor *visitor) +void ExportsList::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { for (ExportsList *it = this; it; it = it->next) { @@ -1136,7 +1136,7 @@ void ExportsList::accept0(Visitor *visitor) visitor->endVisit(this); } -void ExportClause::accept0(Visitor *visitor) +void ExportClause::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(exportsList, visitor); @@ -1145,7 +1145,7 @@ void ExportClause::accept0(Visitor *visitor) visitor->endVisit(this); } -void ExportDeclaration::accept0(Visitor *visitor) +void ExportDeclaration::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(fromClause, visitor); @@ -1156,7 +1156,7 @@ void ExportDeclaration::accept0(Visitor *visitor) visitor->endVisit(this); } -void ESModule::accept0(Visitor *visitor) +void ESModule::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(body, visitor); @@ -1165,7 +1165,7 @@ void ESModule::accept0(Visitor *visitor) visitor->endVisit(this); } -void DebuggerStatement::accept0(Visitor *visitor) +void DebuggerStatement::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { } @@ -1173,7 +1173,7 @@ void DebuggerStatement::accept0(Visitor *visitor) visitor->endVisit(this); } -void UiProgram::accept0(Visitor *visitor) +void UiProgram::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(headers, visitor); @@ -1183,7 +1183,7 @@ void UiProgram::accept0(Visitor *visitor) visitor->endVisit(this); } -void UiPublicMember::accept0(Visitor *visitor) +void UiPublicMember::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { // accept(annotations, visitor); // accept manually in visit if interested @@ -1196,7 +1196,7 @@ void UiPublicMember::accept0(Visitor *visitor) visitor->endVisit(this); } -void UiObjectDefinition::accept0(Visitor *visitor) +void UiObjectDefinition::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { // accept(annotations, visitor); // accept manually in visit if interested @@ -1207,7 +1207,7 @@ void UiObjectDefinition::accept0(Visitor *visitor) visitor->endVisit(this); } -void UiObjectInitializer::accept0(Visitor *visitor) +void UiObjectInitializer::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(members, visitor); @@ -1216,7 +1216,7 @@ void UiObjectInitializer::accept0(Visitor *visitor) visitor->endVisit(this); } -void UiParameterList::accept0(Visitor *visitor) +void UiParameterList::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { // accept(type, visitor); // accept manually in visit if interested @@ -1224,7 +1224,7 @@ void UiParameterList::accept0(Visitor *visitor) visitor->endVisit(this); } -void UiObjectBinding::accept0(Visitor *visitor) +void UiObjectBinding::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { // accept(annotations, visitor); // accept manually in visit if interested @@ -1236,7 +1236,7 @@ void UiObjectBinding::accept0(Visitor *visitor) visitor->endVisit(this); } -void UiScriptBinding::accept0(Visitor *visitor) +void UiScriptBinding::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { // accept(annotations, visitor); // accept manually in visit if interested @@ -1247,7 +1247,7 @@ void UiScriptBinding::accept0(Visitor *visitor) visitor->endVisit(this); } -void UiArrayBinding::accept0(Visitor *visitor) +void UiArrayBinding::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { // accept(annotations, visitor); // accept manually in visit if interested @@ -1258,7 +1258,7 @@ void UiArrayBinding::accept0(Visitor *visitor) visitor->endVisit(this); } -void UiObjectMemberList::accept0(Visitor *visitor) +void UiObjectMemberList::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { for (UiObjectMemberList *it = this; it; it = it->next) @@ -1268,7 +1268,7 @@ void UiObjectMemberList::accept0(Visitor *visitor) visitor->endVisit(this); } -void UiArrayMemberList::accept0(Visitor *visitor) +void UiArrayMemberList::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { for (UiArrayMemberList *it = this; it; it = it->next) @@ -1278,7 +1278,7 @@ void UiArrayMemberList::accept0(Visitor *visitor) visitor->endVisit(this); } -void UiQualifiedId::accept0(Visitor *visitor) +void UiQualifiedId::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { // accept(next, visitor) // accept manually in visit if interested @@ -1287,7 +1287,7 @@ void UiQualifiedId::accept0(Visitor *visitor) visitor->endVisit(this); } -void Type::accept0(Visitor *visitor) +void Type::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(typeId, visitor); @@ -1297,7 +1297,7 @@ void Type::accept0(Visitor *visitor) visitor->endVisit(this); } -void TypeArgumentList::accept0(Visitor *visitor) +void TypeArgumentList::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { for (TypeArgumentList *it = this; it; it = it->next) @@ -1307,7 +1307,7 @@ void TypeArgumentList::accept0(Visitor *visitor) visitor->endVisit(this); } -void TypeAnnotation::accept0(Visitor *visitor) +void TypeAnnotation::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(type, visitor); @@ -1316,7 +1316,7 @@ void TypeAnnotation::accept0(Visitor *visitor) visitor->endVisit(this); } -void UiImport::accept0(Visitor *visitor) +void UiImport::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(importUri, visitor); @@ -1326,7 +1326,7 @@ void UiImport::accept0(Visitor *visitor) visitor->endVisit(this); } -void UiPragma::accept0(Visitor *visitor) +void UiPragma::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { } @@ -1334,7 +1334,7 @@ void UiPragma::accept0(Visitor *visitor) visitor->endVisit(this); } -void UiHeaderItemList::accept0(Visitor *visitor) +void UiHeaderItemList::accept0(BaseVisitor *visitor) { bool accepted = true; for (UiHeaderItemList *it = this; it && accepted; it = it->next) { @@ -1347,7 +1347,7 @@ void UiHeaderItemList::accept0(Visitor *visitor) } -void UiSourceElement::accept0(Visitor *visitor) +void UiSourceElement::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { // accept(annotations, visitor); // accept manually in visit if interested @@ -1357,7 +1357,7 @@ void UiSourceElement::accept0(Visitor *visitor) visitor->endVisit(this); } -void UiEnumDeclaration::accept0(Visitor *visitor) +void UiEnumDeclaration::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { // accept(annotations, visitor); // accept manually in visit if interested @@ -1367,7 +1367,7 @@ void UiEnumDeclaration::accept0(Visitor *visitor) visitor->endVisit(this); } -void UiEnumMemberList::accept0(Visitor *visitor) +void UiEnumMemberList::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { } @@ -1375,7 +1375,7 @@ void UiEnumMemberList::accept0(Visitor *visitor) visitor->endVisit(this); } -void TaggedTemplate::accept0(Visitor *visitor) +void TaggedTemplate::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(base, visitor); @@ -1385,7 +1385,7 @@ void TaggedTemplate::accept0(Visitor *visitor) visitor->endVisit(this); } -void PatternElement::accept0(Visitor *visitor) +void PatternElement::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(bindingTarget, visitor); @@ -1408,7 +1408,7 @@ void PatternElement::boundNames(BoundNames *names) } } -void PatternElementList::accept0(Visitor *visitor) +void PatternElementList::accept0(BaseVisitor *visitor) { bool accepted = true; for (PatternElementList *it = this; it && accepted; it = it->next) { @@ -1429,7 +1429,7 @@ void PatternElementList::boundNames(BoundNames *names) } } -void PatternProperty::accept0(Visitor *visitor) +void PatternProperty::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(name, visitor); @@ -1446,7 +1446,7 @@ void PatternProperty::boundNames(BoundNames *names) PatternElement::boundNames(names); } -void PatternPropertyList::accept0(Visitor *visitor) +void PatternPropertyList::accept0(BaseVisitor *visitor) { bool accepted = true; for (PatternPropertyList *it = this; it && accepted; it = it->next) { @@ -1463,7 +1463,7 @@ void PatternPropertyList::boundNames(BoundNames *names) it->property->boundNames(names); } -void ComputedPropertyName::accept0(Visitor *visitor) +void ComputedPropertyName::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(expression, visitor); @@ -1472,7 +1472,7 @@ void ComputedPropertyName::accept0(Visitor *visitor) visitor->endVisit(this); } -void ClassExpression::accept0(Visitor *visitor) +void ClassExpression::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(heritage, visitor); @@ -1487,7 +1487,7 @@ ClassExpression *ClassExpression::asClassDefinition() return this; } -void ClassDeclaration::accept0(Visitor *visitor) +void ClassDeclaration::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(heritage, visitor); @@ -1497,7 +1497,7 @@ void ClassDeclaration::accept0(Visitor *visitor) visitor->endVisit(this); } -void ClassElementList::accept0(Visitor *visitor) +void ClassElementList::accept0(BaseVisitor *visitor) { bool accepted = true; for (ClassElementList *it = this; it && accepted; it = it->next) { @@ -1526,7 +1526,7 @@ LeftHandSideExpression *LeftHandSideExpression::leftHandSideExpressionCast() return this; } -void UiVersionSpecifier::accept0(Visitor *visitor) +void UiVersionSpecifier::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { } @@ -1557,7 +1557,7 @@ void Type::toString(QString *out) const }; } -void UiInlineComponent::accept0(Visitor *visitor) +void UiInlineComponent::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { // accept(annotations, visitor); // accept manually in visit if interested @@ -1567,7 +1567,7 @@ void UiInlineComponent::accept0(Visitor *visitor) visitor->endVisit(this); } -void UiRequired::accept0(Visitor *visitor) +void UiRequired::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { } @@ -1575,7 +1575,7 @@ void UiRequired::accept0(Visitor *visitor) visitor->endVisit(this); } -void UiAnnotationList::accept0(Visitor *visitor) +void UiAnnotationList::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { accept(annotation, visitor); diff --git a/src/qml/parser/qqmljsast_p.h b/src/qml/parser/qqmljsast_p.h index a8b15e6874..feabb5b22d 100644 --- a/src/qml/parser/qqmljsast_p.h +++ b/src/qml/parser/qqmljsast_p.h @@ -282,9 +282,9 @@ public: bool ignoreRecursionDepth() const; - inline void accept(Visitor *visitor) + inline void accept(BaseVisitor *visitor) { - Visitor::RecursionDepthCheck recursionCheck(visitor); + BaseVisitor::RecursionDepthCheck recursionCheck(visitor); // Stack overflow is uncommon, ignoreRecursionDepth() only returns true if // QV4_CRASH_ON_STACKOVERFLOW is set, and ignoreRecursionDepth() needs to be out of line. @@ -298,19 +298,19 @@ public: } } - inline static void accept(Node *node, Visitor *visitor) + inline static void accept(Node *node, BaseVisitor *visitor) { if (node) node->accept(visitor); } // ### Remove when we can. This is part of the qmldevtools library, though. - inline static void acceptChild(Node *node, Visitor *visitor) + inline static void acceptChild(Node *node, BaseVisitor *visitor) { return accept(node, visitor); } - virtual void accept0(Visitor *visitor) = 0; + virtual void accept0(BaseVisitor *visitor) = 0; virtual SourceLocation firstSourceLocation() const = 0; virtual SourceLocation lastSourceLocation() const = 0; @@ -351,7 +351,7 @@ public: return head; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return identifierToken; } @@ -375,7 +375,7 @@ public: , typeArguments(typeArguments) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return typeId->firstSourceLocation(); } @@ -410,7 +410,7 @@ public: previous->next = this; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return typeId->firstSourceLocation(); } @@ -439,7 +439,7 @@ public: : type(type) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return colonToken; } @@ -484,7 +484,7 @@ public: : expression(expression) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return lparenToken; } @@ -509,7 +509,7 @@ public: ThisExpression() { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return thisToken; } @@ -529,7 +529,7 @@ public: IdentifierExpression(const QStringRef &n): name (n) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return identifierToken; } @@ -549,7 +549,7 @@ public: NullExpression() { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return nullToken; } @@ -568,7 +568,7 @@ public: TrueLiteral() { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return trueToken; } @@ -587,7 +587,7 @@ public: FalseLiteral() { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return falseToken; } @@ -606,7 +606,7 @@ public: SuperLiteral() { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return superToken; } @@ -627,7 +627,7 @@ public: NumericLiteral(double v): value(v) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return literalToken; } @@ -647,7 +647,7 @@ public: UiVersionSpecifier(int majorum, int minorum) : majorVersion(majorum), minorVersion(minorum) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return majorToken; } @@ -671,7 +671,7 @@ public: StringLiteral(const QStringRef &v): value (v) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return literalToken; } @@ -702,7 +702,7 @@ public: return (last->expression ? last->expression->lastSourceLocation() : last->literalToken); } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; QStringRef value; QStringRef rawValue; @@ -719,7 +719,7 @@ public: RegExpLiteral(const QStringRef &p, int f): pattern (p), flags (f) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return literalToken; } @@ -754,7 +754,7 @@ public: : elements(elts) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return lbracketToken; } @@ -785,7 +785,7 @@ public: : properties(plist) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return lbraceToken; } @@ -816,7 +816,7 @@ public: previous->next = this; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return commaToken; } @@ -922,7 +922,7 @@ public: kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; virtual bool convertLiteralToAssignmentPattern(MemoryPool *pool, SourceLocation *errorLocation, QString *errorMessage); SourceLocation firstSourceLocation() const override @@ -975,7 +975,7 @@ public: return front; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; void boundNames(BoundNames *names); @@ -1010,7 +1010,7 @@ public: : PatternElement(pattern, i), name(name) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return name->firstSourceLocation(); } @@ -1046,7 +1046,7 @@ public: previous->next = this; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; void boundNames(BoundNames *names); @@ -1075,7 +1075,7 @@ public: IdentifierPropertyName(const QStringRef &n): id (n) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; QString asString() const override { return id.toString(); } @@ -1091,7 +1091,7 @@ public: StringLiteralPropertyName(const QStringRef &n): id (n) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; QString asString() const override { return id.toString(); } @@ -1107,7 +1107,7 @@ public: NumericLiteralPropertyName(double n): id (n) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; QString asString() const override; @@ -1124,7 +1124,7 @@ public: : expression(expression) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; QString asString() const override { return QString(); } @@ -1148,7 +1148,7 @@ public: base (b), expression (e) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return base->firstSourceLocation(); } @@ -1172,7 +1172,7 @@ public: base (b), name (n) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return base->firstSourceLocation(); } @@ -1196,7 +1196,7 @@ public: : base (b), templateLiteral(t) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return base->firstSourceLocation(); } @@ -1218,7 +1218,7 @@ public: base (b), arguments (a) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return newToken; } @@ -1242,7 +1242,7 @@ public: NewExpression(ExpressionNode *e): expression (e) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return newToken; } @@ -1264,7 +1264,7 @@ public: base (b), arguments (a) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return base->firstSourceLocation(); } @@ -1296,7 +1296,7 @@ public: previous->next = this; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return expression->firstSourceLocation(); } @@ -1330,7 +1330,7 @@ public: PostIncrementExpression(ExpressionNode *b): base (b) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return base->firstSourceLocation(); } @@ -1351,7 +1351,7 @@ public: PostDecrementExpression(ExpressionNode *b): base (b) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return base->firstSourceLocation(); } @@ -1372,7 +1372,7 @@ public: DeleteExpression(ExpressionNode *e): expression (e) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return deleteToken; } @@ -1393,7 +1393,7 @@ public: VoidExpression(ExpressionNode *e): expression (e) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return voidToken; } @@ -1414,7 +1414,7 @@ public: TypeOfExpression(ExpressionNode *e): expression (e) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return typeofToken; } @@ -1435,7 +1435,7 @@ public: PreIncrementExpression(ExpressionNode *e): expression (e) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return incrementToken; } @@ -1456,7 +1456,7 @@ public: PreDecrementExpression(ExpressionNode *e): expression (e) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return decrementToken; } @@ -1477,7 +1477,7 @@ public: UnaryPlusExpression(ExpressionNode *e): expression (e) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return plusToken; } @@ -1498,7 +1498,7 @@ public: UnaryMinusExpression(ExpressionNode *e): expression (e) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return minusToken; } @@ -1519,7 +1519,7 @@ public: TildeExpression(ExpressionNode *e): expression (e) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return tildeToken; } @@ -1540,7 +1540,7 @@ public: NotExpression(ExpressionNode *e): expression (e) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return notToken; } @@ -1564,7 +1564,7 @@ public: BinaryExpression *binaryExpressionCast() override; - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return left->firstSourceLocation(); } @@ -1588,7 +1588,7 @@ public: expression (e), ok (t), ko (f) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return expression->firstSourceLocation(); } @@ -1612,7 +1612,7 @@ public: Expression(ExpressionNode *l, ExpressionNode *r): left (l), right (r) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return left->firstSourceLocation(); } @@ -1634,7 +1634,7 @@ public: Block(StatementList *slist): statements (slist) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return lbraceToken; } @@ -1664,7 +1664,7 @@ public: return n; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return statement->firstSourceLocation(); } @@ -1703,7 +1703,7 @@ public: previous->next = this; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return declaration->firstSourceLocation(); } @@ -1741,7 +1741,7 @@ public: declarations (vlist) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return declarationKindToken; } @@ -1761,7 +1761,7 @@ public: EmptyStatement() { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return semicolonToken; } @@ -1781,7 +1781,7 @@ public: ExpressionStatement(ExpressionNode *e): expression (e) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return expression->firstSourceLocation(); } @@ -1803,7 +1803,7 @@ public: expression (e), ok (t), ko (f) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return ifToken; } @@ -1835,7 +1835,7 @@ public: statement (stmt), expression (e) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return doToken; } @@ -1862,7 +1862,7 @@ public: expression (e), statement (stmt) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return whileToken; } @@ -1892,7 +1892,7 @@ public: { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return forToken; } @@ -1930,7 +1930,7 @@ public: : lhs(v), expression(e), statement(stmt) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return forToken; } @@ -1961,7 +1961,7 @@ public: ContinueStatement(const QStringRef &l = QStringRef()): label (l) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return continueToken; } @@ -1984,7 +1984,7 @@ public: BreakStatement(const QStringRef &l): label (l) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return breakToken; } @@ -2007,7 +2007,7 @@ public: ReturnStatement(ExpressionNode *e): expression (e) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return returnToken; } @@ -2029,7 +2029,7 @@ public: YieldExpression(ExpressionNode *e = nullptr): expression (e) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return yieldToken; } @@ -2052,7 +2052,7 @@ public: expression (e), statement (stmt) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return withToken; } @@ -2077,7 +2077,7 @@ public: clauses (c), defaultClause (d), moreClauses (r) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return lbraceToken; } @@ -2102,7 +2102,7 @@ public: expression (e), block (b) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return switchToken; } @@ -2127,7 +2127,7 @@ public: expression (e), statements (slist) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return caseToken; } @@ -2159,7 +2159,7 @@ public: previous->next = this; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return clause->firstSourceLocation(); } @@ -2190,7 +2190,7 @@ public: statements (slist) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return defaultToken; } @@ -2213,7 +2213,7 @@ public: label (l), statement (stmt) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return identifierToken; } @@ -2236,7 +2236,7 @@ public: ThrowStatement(ExpressionNode *e): expression (e) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return throwToken; } @@ -2259,7 +2259,7 @@ public: : patternElement(p), statement(stmt) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return catchToken; } @@ -2285,7 +2285,7 @@ public: statement (stmt) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return finallyToken; } @@ -2315,7 +2315,7 @@ public: statement (stmt), catchExpression (c), finallyExpression (nullptr) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return tryToken; } @@ -2347,7 +2347,7 @@ public: typeAnnotation(typeAnnotation) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return functionToken; } @@ -2381,7 +2381,7 @@ public: FunctionExpression(n, f, b, typeAnnotation) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; }; class QML_PARSER_EXPORT FormalParameterList: public Node @@ -2452,7 +2452,7 @@ public: BoundNames boundNames() const; - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return element->firstSourceLocation(); } @@ -2478,7 +2478,7 @@ public: : name(n), heritage(heritage), elements(elements) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return classToken; } @@ -2507,7 +2507,7 @@ public: : ClassExpression(n, heritage, elements) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; }; @@ -2529,7 +2529,7 @@ public: return n; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return property->firstSourceLocation(); } @@ -2557,7 +2557,7 @@ public: : statements(statements) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return statements ? statements->firstSourceLocation() : SourceLocation(); } @@ -2586,7 +2586,7 @@ public: kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return identifier.isNull() ? importedBindingToken : identifierToken; } @@ -2631,7 +2631,7 @@ public: return head; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return importSpecifierToken; } @@ -2663,7 +2663,7 @@ public: kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return leftBraceToken; } @@ -2687,7 +2687,7 @@ public: kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; virtual SourceLocation firstSourceLocation() const override { return starToken; } @@ -2737,7 +2737,7 @@ public: kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; virtual SourceLocation firstSourceLocation() const override { return importedDefaultBinding.isNull() ? (nameSpaceImport ? nameSpaceImport->firstSourceLocation() : namedImports->firstSourceLocation()) : importedDefaultBindingToken; } @@ -2762,7 +2762,7 @@ public: kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return fromToken; } @@ -2793,7 +2793,7 @@ public: kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return importToken; } @@ -2826,7 +2826,7 @@ public: kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return identifierToken; } @@ -2871,7 +2871,7 @@ public: return head; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return exportSpecifier->firstSourceLocation(); } @@ -2899,7 +2899,7 @@ public: kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return leftBraceToken; } @@ -2943,7 +2943,7 @@ public: kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return exportToken; } @@ -2970,7 +2970,7 @@ public: kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return body ? body->firstSourceLocation() : SourceLocation(); } @@ -2990,7 +2990,7 @@ public: DebuggerStatement() { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return debuggerToken; } @@ -3016,7 +3016,7 @@ public: : importUri(uri) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return importToken; } @@ -3065,7 +3065,7 @@ public: previous->next = this; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return member->firstSourceLocation(); } @@ -3094,7 +3094,7 @@ public: : name(name) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return pragmaToken; } @@ -3117,7 +3117,7 @@ public: :name(name) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return requiredToken; } @@ -3166,7 +3166,7 @@ public: return head; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return headerItem->firstSourceLocation(); } @@ -3188,7 +3188,7 @@ public: : headers(headers), members(members) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { @@ -3230,7 +3230,7 @@ public: previous->next = this; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return member->firstSourceLocation(); } @@ -3260,7 +3260,7 @@ public: : members(members) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return lbraceToken; } @@ -3291,7 +3291,7 @@ public: previous->next = this; } - void accept0(Visitor *) override; + void accept0(BaseVisitor *) override; SourceLocation firstSourceLocation() const override { return colonToken.isValid() ? identifierToken : propertyTypeToken; } @@ -3335,7 +3335,7 @@ public: : type(Property), memberType(memberType), name(name), statement(statement), binding(nullptr), isDefaultMember(false), isReadonlyMember(false), parameters(nullptr) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { @@ -3392,7 +3392,7 @@ public: : qualifiedTypeNameId(qualifiedTypeNameId), initializer(initializer) { kind = K; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return qualifiedTypeNameId->identifierToken; } @@ -3420,7 +3420,7 @@ public: SourceLocation firstSourceLocation() const override {return componentToken;} - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; // attributes QStringRef name; @@ -3457,7 +3457,7 @@ public: return SourceLocation(); } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; // attributes @@ -3489,7 +3489,7 @@ public: SourceLocation lastSourceLocation() const override { return initializer->rbraceToken; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; // attributes @@ -3517,7 +3517,7 @@ public: SourceLocation lastSourceLocation() const override { return statement->lastSourceLocation(); } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; // attributes UiQualifiedId *qualifiedId; @@ -3542,7 +3542,7 @@ public: SourceLocation lastSourceLocation() const override { return rbracketToken; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; // attributes UiQualifiedId *qualifiedId; @@ -3586,7 +3586,7 @@ public: return last->valueToken.isValid() ? last->valueToken : last->memberToken; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; UiEnumMemberList *finish() { @@ -3620,7 +3620,7 @@ public: SourceLocation lastSourceLocation() const override { return rbraceToken; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; // attributes SourceLocation enumToken; @@ -3646,7 +3646,7 @@ public: previous->next = this; } - void accept0(Visitor *visitor) override; + void accept0(BaseVisitor *visitor) override; SourceLocation firstSourceLocation() const override { return annotation->firstSourceLocation(); } diff --git a/src/qml/parser/qqmljsastfwd_p.h b/src/qml/parser/qqmljsastfwd_p.h index b7148158d5..49949cce61 100644 --- a/src/qml/parser/qqmljsastfwd_p.h +++ b/src/qml/parser/qqmljsastfwd_p.h @@ -60,6 +60,7 @@ QT_BEGIN_NAMESPACE namespace QQmlJS { namespace AST { +class BaseVisitor; class Visitor; class Node; class ExpressionNode; diff --git a/src/qml/parser/qqmljsastvisitor.cpp b/src/qml/parser/qqmljsastvisitor.cpp index 5ecac36423..7388eccebb 100644 --- a/src/qml/parser/qqmljsastvisitor.cpp +++ b/src/qml/parser/qqmljsastvisitor.cpp @@ -43,11 +43,13 @@ QT_BEGIN_NAMESPACE namespace QQmlJS { namespace AST { -Visitor::Visitor(quint16 parentRecursionDepth) : m_recursionDepth(parentRecursionDepth) +Visitor::Visitor(quint16 parentRecursionDepth) : BaseVisitor(parentRecursionDepth) { } -Visitor::~Visitor() +BaseVisitor::BaseVisitor(quint16 parentRecursionDepth) : m_recursionDepth(parentRecursionDepth) {} + +BaseVisitor::~BaseVisitor() { } diff --git a/src/qml/parser/qqmljsastvisitor_p.h b/src/qml/parser/qqmljsastvisitor_p.h index 2671587b62..2c17e9ba36 100644 --- a/src/qml/parser/qqmljsastvisitor_p.h +++ b/src/qml/parser/qqmljsastvisitor_p.h @@ -58,7 +58,7 @@ QT_BEGIN_NAMESPACE namespace QQmlJS { namespace AST { -class QML_PARSER_EXPORT Visitor +class QML_PARSER_EXPORT BaseVisitor { public: class RecursionDepthCheck @@ -68,7 +68,7 @@ public: RecursionDepthCheck(RecursionDepthCheck &&) = delete; RecursionDepthCheck &operator=(RecursionDepthCheck &&) = delete; - RecursionDepthCheck(Visitor *visitor) : m_visitor(visitor) + RecursionDepthCheck(BaseVisitor *visitor) : m_visitor(visitor) { ++(m_visitor->m_recursionDepth); } @@ -84,336 +84,336 @@ public: private: static const quint16 s_recursionLimit = 4096; - Visitor *m_visitor; + BaseVisitor *m_visitor; }; - Visitor(quint16 parentRecursionDepth = 0); - virtual ~Visitor(); + BaseVisitor(quint16 parentRecursionDepth = 0); + virtual ~BaseVisitor(); - virtual bool preVisit(Node *) { return true; } - virtual void postVisit(Node *) {} + virtual bool preVisit(Node *) = 0; + virtual void postVisit(Node *) = 0; // Ui - virtual bool visit(UiProgram *) { return true; } - virtual bool visit(UiHeaderItemList *) { return true; } - virtual bool visit(UiPragma *) { return true; } - virtual bool visit(UiImport *) { return true; } - virtual bool visit(UiPublicMember *) { return true; } - virtual bool visit(UiSourceElement *) { return true; } - virtual bool visit(UiObjectDefinition *) { return true; } - virtual bool visit(UiObjectInitializer *) { return true; } - virtual bool visit(UiObjectBinding *) { return true; } - virtual bool visit(UiScriptBinding *) { return true; } - virtual bool visit(UiArrayBinding *) { return true; } - virtual bool visit(UiParameterList *) { return true; } - virtual bool visit(UiObjectMemberList *) { return true; } - virtual bool visit(UiArrayMemberList *) { return true; } - virtual bool visit(UiQualifiedId *) { return true; } - virtual bool visit(UiEnumDeclaration *) { return true; } - virtual bool visit(UiEnumMemberList *) { return true; } - virtual bool visit(UiVersionSpecifier *) { return true; } - virtual bool visit(UiInlineComponent *) { return true; } - virtual bool visit(UiAnnotationList *) { return true; } - virtual bool visit(UiRequired *) { return true; } - - virtual void endVisit(UiProgram *) {} - virtual void endVisit(UiImport *) {} - virtual void endVisit(UiHeaderItemList *) {} - virtual void endVisit(UiPragma *) {} - virtual void endVisit(UiPublicMember *) {} - virtual void endVisit(UiSourceElement *) {} - virtual void endVisit(UiObjectDefinition *) {} - virtual void endVisit(UiObjectInitializer *) {} - virtual void endVisit(UiObjectBinding *) {} - virtual void endVisit(UiScriptBinding *) {} - virtual void endVisit(UiArrayBinding *) {} - virtual void endVisit(UiParameterList *) {} - virtual void endVisit(UiObjectMemberList *) {} - virtual void endVisit(UiArrayMemberList *) {} - virtual void endVisit(UiQualifiedId *) {} - virtual void endVisit(UiEnumDeclaration *) {} - virtual void endVisit(UiEnumMemberList *) { } - virtual void endVisit(UiVersionSpecifier *) {} - virtual void endVisit(UiInlineComponent *) {} - virtual void endVisit(UiAnnotationList *) {} - virtual void endVisit(UiRequired *) {} + virtual bool visit(UiProgram *) = 0; + virtual bool visit(UiHeaderItemList *) = 0; + virtual bool visit(UiPragma *) = 0; + virtual bool visit(UiImport *) = 0; + virtual bool visit(UiPublicMember *) = 0; + virtual bool visit(UiSourceElement *) = 0; + virtual bool visit(UiObjectDefinition *) = 0; + virtual bool visit(UiObjectInitializer *) = 0; + virtual bool visit(UiObjectBinding *) = 0; + virtual bool visit(UiScriptBinding *) = 0; + virtual bool visit(UiArrayBinding *) = 0; + virtual bool visit(UiParameterList *) = 0; + virtual bool visit(UiObjectMemberList *) = 0; + virtual bool visit(UiArrayMemberList *) = 0; + virtual bool visit(UiQualifiedId *) = 0; + virtual bool visit(UiEnumDeclaration *) = 0; + virtual bool visit(UiEnumMemberList *) = 0; + virtual bool visit(UiVersionSpecifier *) = 0; + virtual bool visit(UiInlineComponent *) = 0; + virtual bool visit(UiAnnotationList *) = 0; + virtual bool visit(UiRequired *) = 0; + + virtual void endVisit(UiProgram *) = 0; + virtual void endVisit(UiImport *) = 0; + virtual void endVisit(UiHeaderItemList *) = 0; + virtual void endVisit(UiPragma *) = 0; + virtual void endVisit(UiPublicMember *) = 0; + virtual void endVisit(UiSourceElement *) = 0; + virtual void endVisit(UiObjectDefinition *) = 0; + virtual void endVisit(UiObjectInitializer *) = 0; + virtual void endVisit(UiObjectBinding *) = 0; + virtual void endVisit(UiScriptBinding *) = 0; + virtual void endVisit(UiArrayBinding *) = 0; + virtual void endVisit(UiParameterList *) = 0; + virtual void endVisit(UiObjectMemberList *) = 0; + virtual void endVisit(UiArrayMemberList *) = 0; + virtual void endVisit(UiQualifiedId *) = 0; + virtual void endVisit(UiEnumDeclaration *) = 0; + virtual void endVisit(UiEnumMemberList *) = 0; + virtual void endVisit(UiVersionSpecifier *) = 0; + virtual void endVisit(UiInlineComponent *) = 0; + virtual void endVisit(UiAnnotationList *) = 0; + virtual void endVisit(UiRequired *) = 0; // QQmlJS - virtual bool visit(ThisExpression *) { return true; } - virtual void endVisit(ThisExpression *) {} + virtual bool visit(ThisExpression *) = 0; + virtual void endVisit(ThisExpression *) = 0; - virtual bool visit(IdentifierExpression *) { return true; } - virtual void endVisit(IdentifierExpression *) {} + virtual bool visit(IdentifierExpression *) = 0; + virtual void endVisit(IdentifierExpression *) = 0; - virtual bool visit(NullExpression *) { return true; } - virtual void endVisit(NullExpression *) {} + virtual bool visit(NullExpression *) = 0; + virtual void endVisit(NullExpression *) = 0; - virtual bool visit(TrueLiteral *) { return true; } - virtual void endVisit(TrueLiteral *) {} + virtual bool visit(TrueLiteral *) = 0; + virtual void endVisit(TrueLiteral *) = 0; - virtual bool visit(FalseLiteral *) { return true; } - virtual void endVisit(FalseLiteral *) {} + virtual bool visit(FalseLiteral *) = 0; + virtual void endVisit(FalseLiteral *) = 0; - virtual bool visit(SuperLiteral *) { return true; } - virtual void endVisit(SuperLiteral *) {} + virtual bool visit(SuperLiteral *) = 0; + virtual void endVisit(SuperLiteral *) = 0; - virtual bool visit(StringLiteral *) { return true; } - virtual void endVisit(StringLiteral *) {} + virtual bool visit(StringLiteral *) = 0; + virtual void endVisit(StringLiteral *) = 0; - virtual bool visit(TemplateLiteral *) { return true; } - virtual void endVisit(TemplateLiteral *) {} + virtual bool visit(TemplateLiteral *) = 0; + virtual void endVisit(TemplateLiteral *) = 0; - virtual bool visit(NumericLiteral *) { return true; } - virtual void endVisit(NumericLiteral *) {} + virtual bool visit(NumericLiteral *) = 0; + virtual void endVisit(NumericLiteral *) = 0; - virtual bool visit(RegExpLiteral *) { return true; } - virtual void endVisit(RegExpLiteral *) {} + virtual bool visit(RegExpLiteral *) = 0; + virtual void endVisit(RegExpLiteral *) = 0; - virtual bool visit(ArrayPattern *) { return true; } - virtual void endVisit(ArrayPattern *) {} + virtual bool visit(ArrayPattern *) = 0; + virtual void endVisit(ArrayPattern *) = 0; - virtual bool visit(ObjectPattern *) { return true; } - virtual void endVisit(ObjectPattern *) {} + virtual bool visit(ObjectPattern *) = 0; + virtual void endVisit(ObjectPattern *) = 0; - virtual bool visit(PatternElementList *) { return true; } - virtual void endVisit(PatternElementList *) {} + virtual bool visit(PatternElementList *) = 0; + virtual void endVisit(PatternElementList *) = 0; - virtual bool visit(PatternPropertyList *) { return true; } - virtual void endVisit(PatternPropertyList *) {} + virtual bool visit(PatternPropertyList *) = 0; + virtual void endVisit(PatternPropertyList *) = 0; - virtual bool visit(PatternElement *) { return true; } - virtual void endVisit(PatternElement *) {} + virtual bool visit(PatternElement *) = 0; + virtual void endVisit(PatternElement *) = 0; - virtual bool visit(PatternProperty *) { return true; } - virtual void endVisit(PatternProperty *) {} + virtual bool visit(PatternProperty *) = 0; + virtual void endVisit(PatternProperty *) = 0; - virtual bool visit(Elision *) { return true; } - virtual void endVisit(Elision *) {} + virtual bool visit(Elision *) = 0; + virtual void endVisit(Elision *) = 0; - virtual bool visit(NestedExpression *) { return true; } - virtual void endVisit(NestedExpression *) {} + virtual bool visit(NestedExpression *) = 0; + virtual void endVisit(NestedExpression *) = 0; - virtual bool visit(IdentifierPropertyName *) { return true; } - virtual void endVisit(IdentifierPropertyName *) {} + virtual bool visit(IdentifierPropertyName *) = 0; + virtual void endVisit(IdentifierPropertyName *) = 0; - virtual bool visit(StringLiteralPropertyName *) { return true; } - virtual void endVisit(StringLiteralPropertyName *) {} + virtual bool visit(StringLiteralPropertyName *) = 0; + virtual void endVisit(StringLiteralPropertyName *) = 0; - virtual bool visit(NumericLiteralPropertyName *) { return true; } - virtual void endVisit(NumericLiteralPropertyName *) {} + virtual bool visit(NumericLiteralPropertyName *) = 0; + virtual void endVisit(NumericLiteralPropertyName *) = 0; - virtual bool visit(ComputedPropertyName *) { return true; } - virtual void endVisit(ComputedPropertyName *) {} + virtual bool visit(ComputedPropertyName *) = 0; + virtual void endVisit(ComputedPropertyName *) = 0; - virtual bool visit(ArrayMemberExpression *) { return true; } - virtual void endVisit(ArrayMemberExpression *) {} + virtual bool visit(ArrayMemberExpression *) = 0; + virtual void endVisit(ArrayMemberExpression *) = 0; - virtual bool visit(FieldMemberExpression *) { return true; } - virtual void endVisit(FieldMemberExpression *) {} + virtual bool visit(FieldMemberExpression *) = 0; + virtual void endVisit(FieldMemberExpression *) = 0; - virtual bool visit(TaggedTemplate *) { return true; } - virtual void endVisit(TaggedTemplate *) {} + virtual bool visit(TaggedTemplate *) = 0; + virtual void endVisit(TaggedTemplate *) = 0; - virtual bool visit(NewMemberExpression *) { return true; } - virtual void endVisit(NewMemberExpression *) {} + virtual bool visit(NewMemberExpression *) = 0; + virtual void endVisit(NewMemberExpression *) = 0; - virtual bool visit(NewExpression *) { return true; } - virtual void endVisit(NewExpression *) {} + virtual bool visit(NewExpression *) = 0; + virtual void endVisit(NewExpression *) = 0; - virtual bool visit(CallExpression *) { return true; } - virtual void endVisit(CallExpression *) {} + virtual bool visit(CallExpression *) = 0; + virtual void endVisit(CallExpression *) = 0; - virtual bool visit(ArgumentList *) { return true; } - virtual void endVisit(ArgumentList *) {} + virtual bool visit(ArgumentList *) = 0; + virtual void endVisit(ArgumentList *) = 0; - virtual bool visit(PostIncrementExpression *) { return true; } - virtual void endVisit(PostIncrementExpression *) {} + virtual bool visit(PostIncrementExpression *) = 0; + virtual void endVisit(PostIncrementExpression *) = 0; - virtual bool visit(PostDecrementExpression *) { return true; } - virtual void endVisit(PostDecrementExpression *) {} + virtual bool visit(PostDecrementExpression *) = 0; + virtual void endVisit(PostDecrementExpression *) = 0; - virtual bool visit(DeleteExpression *) { return true; } - virtual void endVisit(DeleteExpression *) {} + virtual bool visit(DeleteExpression *) = 0; + virtual void endVisit(DeleteExpression *) = 0; - virtual bool visit(VoidExpression *) { return true; } - virtual void endVisit(VoidExpression *) {} + virtual bool visit(VoidExpression *) = 0; + virtual void endVisit(VoidExpression *) = 0; - virtual bool visit(TypeOfExpression *) { return true; } - virtual void endVisit(TypeOfExpression *) {} + virtual bool visit(TypeOfExpression *) = 0; + virtual void endVisit(TypeOfExpression *) = 0; - virtual bool visit(PreIncrementExpression *) { return true; } - virtual void endVisit(PreIncrementExpression *) {} + virtual bool visit(PreIncrementExpression *) = 0; + virtual void endVisit(PreIncrementExpression *) = 0; - virtual bool visit(PreDecrementExpression *) { return true; } - virtual void endVisit(PreDecrementExpression *) {} + virtual bool visit(PreDecrementExpression *) = 0; + virtual void endVisit(PreDecrementExpression *) = 0; - virtual bool visit(UnaryPlusExpression *) { return true; } - virtual void endVisit(UnaryPlusExpression *) {} + virtual bool visit(UnaryPlusExpression *) = 0; + virtual void endVisit(UnaryPlusExpression *) = 0; - virtual bool visit(UnaryMinusExpression *) { return true; } - virtual void endVisit(UnaryMinusExpression *) {} + virtual bool visit(UnaryMinusExpression *) = 0; + virtual void endVisit(UnaryMinusExpression *) = 0; - virtual bool visit(TildeExpression *) { return true; } - virtual void endVisit(TildeExpression *) {} + virtual bool visit(TildeExpression *) = 0; + virtual void endVisit(TildeExpression *) = 0; - virtual bool visit(NotExpression *) { return true; } - virtual void endVisit(NotExpression *) {} + virtual bool visit(NotExpression *) = 0; + virtual void endVisit(NotExpression *) = 0; - virtual bool visit(BinaryExpression *) { return true; } - virtual void endVisit(BinaryExpression *) {} + virtual bool visit(BinaryExpression *) = 0; + virtual void endVisit(BinaryExpression *) = 0; - virtual bool visit(ConditionalExpression *) { return true; } - virtual void endVisit(ConditionalExpression *) {} + virtual bool visit(ConditionalExpression *) = 0; + virtual void endVisit(ConditionalExpression *) = 0; - virtual bool visit(Expression *) { return true; } - virtual void endVisit(Expression *) {} + virtual bool visit(Expression *) = 0; + virtual void endVisit(Expression *) = 0; - virtual bool visit(Block *) { return true; } - virtual void endVisit(Block *) {} + virtual bool visit(Block *) = 0; + virtual void endVisit(Block *) = 0; - virtual bool visit(StatementList *) { return true; } - virtual void endVisit(StatementList *) {} + virtual bool visit(StatementList *) = 0; + virtual void endVisit(StatementList *) = 0; - virtual bool visit(VariableStatement *) { return true; } - virtual void endVisit(VariableStatement *) {} + virtual bool visit(VariableStatement *) = 0; + virtual void endVisit(VariableStatement *) = 0; - virtual bool visit(VariableDeclarationList *) { return true; } - virtual void endVisit(VariableDeclarationList *) {} + virtual bool visit(VariableDeclarationList *) = 0; + virtual void endVisit(VariableDeclarationList *) = 0; - virtual bool visit(EmptyStatement *) { return true; } - virtual void endVisit(EmptyStatement *) {} + virtual bool visit(EmptyStatement *) = 0; + virtual void endVisit(EmptyStatement *) = 0; - virtual bool visit(ExpressionStatement *) { return true; } - virtual void endVisit(ExpressionStatement *) {} + virtual bool visit(ExpressionStatement *) = 0; + virtual void endVisit(ExpressionStatement *) = 0; - virtual bool visit(IfStatement *) { return true; } - virtual void endVisit(IfStatement *) {} + virtual bool visit(IfStatement *) = 0; + virtual void endVisit(IfStatement *) = 0; - virtual bool visit(DoWhileStatement *) { return true; } - virtual void endVisit(DoWhileStatement *) {} + virtual bool visit(DoWhileStatement *) = 0; + virtual void endVisit(DoWhileStatement *) = 0; - virtual bool visit(WhileStatement *) { return true; } - virtual void endVisit(WhileStatement *) {} + virtual bool visit(WhileStatement *) = 0; + virtual void endVisit(WhileStatement *) = 0; - virtual bool visit(ForStatement *) { return true; } - virtual void endVisit(ForStatement *) {} + virtual bool visit(ForStatement *) = 0; + virtual void endVisit(ForStatement *) = 0; - virtual bool visit(ForEachStatement *) { return true; } - virtual void endVisit(ForEachStatement *) {} + virtual bool visit(ForEachStatement *) = 0; + virtual void endVisit(ForEachStatement *) = 0; - virtual bool visit(ContinueStatement *) { return true; } - virtual void endVisit(ContinueStatement *) {} + virtual bool visit(ContinueStatement *) = 0; + virtual void endVisit(ContinueStatement *) = 0; - virtual bool visit(BreakStatement *) { return true; } - virtual void endVisit(BreakStatement *) {} + virtual bool visit(BreakStatement *) = 0; + virtual void endVisit(BreakStatement *) = 0; - virtual bool visit(ReturnStatement *) { return true; } - virtual void endVisit(ReturnStatement *) {} + virtual bool visit(ReturnStatement *) = 0; + virtual void endVisit(ReturnStatement *) = 0; - virtual bool visit(YieldExpression *) { return true; } - virtual void endVisit(YieldExpression *) {} + virtual bool visit(YieldExpression *) = 0; + virtual void endVisit(YieldExpression *) = 0; - virtual bool visit(WithStatement *) { return true; } - virtual void endVisit(WithStatement *) {} + virtual bool visit(WithStatement *) = 0; + virtual void endVisit(WithStatement *) = 0; - virtual bool visit(SwitchStatement *) { return true; } - virtual void endVisit(SwitchStatement *) {} + virtual bool visit(SwitchStatement *) = 0; + virtual void endVisit(SwitchStatement *) = 0; - virtual bool visit(CaseBlock *) { return true; } - virtual void endVisit(CaseBlock *) {} + virtual bool visit(CaseBlock *) = 0; + virtual void endVisit(CaseBlock *) = 0; - virtual bool visit(CaseClauses *) { return true; } - virtual void endVisit(CaseClauses *) {} + virtual bool visit(CaseClauses *) = 0; + virtual void endVisit(CaseClauses *) = 0; - virtual bool visit(CaseClause *) { return true; } - virtual void endVisit(CaseClause *) {} + virtual bool visit(CaseClause *) = 0; + virtual void endVisit(CaseClause *) = 0; - virtual bool visit(DefaultClause *) { return true; } - virtual void endVisit(DefaultClause *) {} + virtual bool visit(DefaultClause *) = 0; + virtual void endVisit(DefaultClause *) = 0; - virtual bool visit(LabelledStatement *) { return true; } - virtual void endVisit(LabelledStatement *) {} + virtual bool visit(LabelledStatement *) = 0; + virtual void endVisit(LabelledStatement *) = 0; - virtual bool visit(ThrowStatement *) { return true; } - virtual void endVisit(ThrowStatement *) {} + virtual bool visit(ThrowStatement *) = 0; + virtual void endVisit(ThrowStatement *) = 0; - virtual bool visit(TryStatement *) { return true; } - virtual void endVisit(TryStatement *) {} + virtual bool visit(TryStatement *) = 0; + virtual void endVisit(TryStatement *) = 0; - virtual bool visit(Catch *) { return true; } - virtual void endVisit(Catch *) {} + virtual bool visit(Catch *) = 0; + virtual void endVisit(Catch *) = 0; - virtual bool visit(Finally *) { return true; } - virtual void endVisit(Finally *) {} + virtual bool visit(Finally *) = 0; + virtual void endVisit(Finally *) = 0; - virtual bool visit(FunctionDeclaration *) { return true; } - virtual void endVisit(FunctionDeclaration *) {} + virtual bool visit(FunctionDeclaration *) = 0; + virtual void endVisit(FunctionDeclaration *) = 0; - virtual bool visit(FunctionExpression *) { return true; } - virtual void endVisit(FunctionExpression *) {} + virtual bool visit(FunctionExpression *) = 0; + virtual void endVisit(FunctionExpression *) = 0; - virtual bool visit(FormalParameterList *) { return true; } - virtual void endVisit(FormalParameterList *) {} + virtual bool visit(FormalParameterList *) = 0; + virtual void endVisit(FormalParameterList *) = 0; - virtual bool visit(ClassExpression *) { return true; } - virtual void endVisit(ClassExpression *) {} + virtual bool visit(ClassExpression *) = 0; + virtual void endVisit(ClassExpression *) = 0; - virtual bool visit(ClassDeclaration *) { return true; } - virtual void endVisit(ClassDeclaration *) {} + virtual bool visit(ClassDeclaration *) = 0; + virtual void endVisit(ClassDeclaration *) = 0; - virtual bool visit(ClassElementList *) { return true; } - virtual void endVisit(ClassElementList *) {} + virtual bool visit(ClassElementList *) = 0; + virtual void endVisit(ClassElementList *) = 0; - virtual bool visit(Program *) { return true; } - virtual void endVisit(Program *) {} + virtual bool visit(Program *) = 0; + virtual void endVisit(Program *) = 0; - virtual bool visit(NameSpaceImport *) { return true; } - virtual void endVisit(NameSpaceImport *) {} + virtual bool visit(NameSpaceImport *) = 0; + virtual void endVisit(NameSpaceImport *) = 0; - virtual bool visit(ImportSpecifier *) { return true; } - virtual void endVisit(ImportSpecifier *) {} + virtual bool visit(ImportSpecifier *) = 0; + virtual void endVisit(ImportSpecifier *) = 0; - virtual bool visit(ImportsList *) { return true; } - virtual void endVisit(ImportsList *) {} + virtual bool visit(ImportsList *) = 0; + virtual void endVisit(ImportsList *) = 0; - virtual bool visit(NamedImports *) { return true; } - virtual void endVisit(NamedImports *) {} + virtual bool visit(NamedImports *) = 0; + virtual void endVisit(NamedImports *) = 0; - virtual bool visit(FromClause *) { return true; } - virtual void endVisit(FromClause *) {} + virtual bool visit(FromClause *) = 0; + virtual void endVisit(FromClause *) = 0; - virtual bool visit(ImportClause *) { return true; } - virtual void endVisit(ImportClause *) {} + virtual bool visit(ImportClause *) = 0; + virtual void endVisit(ImportClause *) = 0; - virtual bool visit(ImportDeclaration *) { return true; } - virtual void endVisit(ImportDeclaration *) {} + virtual bool visit(ImportDeclaration *) = 0; + virtual void endVisit(ImportDeclaration *) = 0; - virtual bool visit(ExportSpecifier *) { return true; } - virtual void endVisit(ExportSpecifier *) {} + virtual bool visit(ExportSpecifier *) = 0; + virtual void endVisit(ExportSpecifier *) = 0; - virtual bool visit(ExportsList *) { return true; } - virtual void endVisit(ExportsList *) {} + virtual bool visit(ExportsList *) = 0; + virtual void endVisit(ExportsList *) = 0; - virtual bool visit(ExportClause *) { return true; } - virtual void endVisit(ExportClause *) {} + virtual bool visit(ExportClause *) = 0; + virtual void endVisit(ExportClause *) = 0; - virtual bool visit(ExportDeclaration *) { return true; } - virtual void endVisit(ExportDeclaration *) {} + virtual bool visit(ExportDeclaration *) = 0; + virtual void endVisit(ExportDeclaration *) = 0; - virtual bool visit(ESModule *) { return true; } - virtual void endVisit(ESModule *) {} + virtual bool visit(ESModule *) = 0; + virtual void endVisit(ESModule *) = 0; - virtual bool visit(DebuggerStatement *) { return true; } - virtual void endVisit(DebuggerStatement *) {} + virtual bool visit(DebuggerStatement *) = 0; + virtual void endVisit(DebuggerStatement *) = 0; - virtual bool visit(Type *) { return true; } - virtual void endVisit(Type *) {} + virtual bool visit(Type *) = 0; + virtual void endVisit(Type *) = 0; - virtual bool visit(TypeArgumentList *) { return true; } - virtual void endVisit(TypeArgumentList *) {} + virtual bool visit(TypeArgumentList *) = 0; + virtual void endVisit(TypeArgumentList *) = 0; - virtual bool visit(TypeAnnotation *) { return true; } - virtual void endVisit(TypeAnnotation *) {} + virtual bool visit(TypeAnnotation *) = 0; + virtual void endVisit(TypeAnnotation *) = 0; virtual void throwRecursionDepthError() = 0; @@ -424,6 +424,337 @@ protected: friend class RecursionDepthCheck; }; +class QML_PARSER_EXPORT Visitor: public BaseVisitor +{ +public: + Visitor(quint16 parentRecursionDepth = 0); + + bool preVisit(Node *) override { return true; } + void postVisit(Node *) override {} + + // Ui + bool visit(UiProgram *) override { return true; } + bool visit(UiHeaderItemList *) override { return true; } + bool visit(UiPragma *) override { return true; } + bool visit(UiImport *) override { return true; } + bool visit(UiPublicMember *) override { return true; } + bool visit(UiSourceElement *) override { return true; } + bool visit(UiObjectDefinition *) override { return true; } + bool visit(UiObjectInitializer *) override { return true; } + bool visit(UiObjectBinding *) override { return true; } + bool visit(UiScriptBinding *) override { return true; } + bool visit(UiArrayBinding *) override { return true; } + bool visit(UiParameterList *) override { return true; } + bool visit(UiObjectMemberList *) override { return true; } + bool visit(UiArrayMemberList *) override { return true; } + bool visit(UiQualifiedId *) override { return true; } + bool visit(UiEnumDeclaration *) override { return true; } + bool visit(UiEnumMemberList *) override { return true; } + bool visit(UiVersionSpecifier *) override { return true; } + bool visit(UiInlineComponent *) override { return true; } + bool visit(UiAnnotationList *) override { return true; } + bool visit(UiRequired *) override { return true; } + + void endVisit(UiProgram *) override {} + void endVisit(UiImport *) override {} + void endVisit(UiHeaderItemList *) override {} + void endVisit(UiPragma *) override {} + void endVisit(UiPublicMember *) override {} + void endVisit(UiSourceElement *) override {} + void endVisit(UiObjectDefinition *) override {} + void endVisit(UiObjectInitializer *) override {} + void endVisit(UiObjectBinding *) override {} + void endVisit(UiScriptBinding *) override {} + void endVisit(UiArrayBinding *) override {} + void endVisit(UiParameterList *) override {} + void endVisit(UiObjectMemberList *) override {} + void endVisit(UiArrayMemberList *) override {} + void endVisit(UiQualifiedId *) override {} + void endVisit(UiEnumDeclaration *) override {} + void endVisit(UiEnumMemberList *) override {} + void endVisit(UiVersionSpecifier *) override {} + void endVisit(UiInlineComponent *) override {} + void endVisit(UiAnnotationList *) override {} + void endVisit(UiRequired *) override {} + + // QQmlJS + bool visit(ThisExpression *) override { return true; } + void endVisit(ThisExpression *) override {} + + bool visit(IdentifierExpression *) override { return true; } + void endVisit(IdentifierExpression *) override {} + + bool visit(NullExpression *) override { return true; } + void endVisit(NullExpression *) override {} + + bool visit(TrueLiteral *) override { return true; } + void endVisit(TrueLiteral *) override {} + + bool visit(FalseLiteral *) override { return true; } + void endVisit(FalseLiteral *) override {} + + bool visit(SuperLiteral *) override { return true; } + void endVisit(SuperLiteral *) override {} + + bool visit(StringLiteral *) override { return true; } + void endVisit(StringLiteral *) override {} + + bool visit(TemplateLiteral *) override { return true; } + void endVisit(TemplateLiteral *) override {} + + bool visit(NumericLiteral *) override { return true; } + void endVisit(NumericLiteral *) override {} + + bool visit(RegExpLiteral *) override { return true; } + void endVisit(RegExpLiteral *) override {} + + bool visit(ArrayPattern *) override { return true; } + void endVisit(ArrayPattern *) override {} + + bool visit(ObjectPattern *) override { return true; } + void endVisit(ObjectPattern *) override {} + + bool visit(PatternElementList *) override { return true; } + void endVisit(PatternElementList *) override {} + + bool visit(PatternPropertyList *) override { return true; } + void endVisit(PatternPropertyList *) override {} + + bool visit(PatternElement *) override { return true; } + void endVisit(PatternElement *) override {} + + bool visit(PatternProperty *) override { return true; } + void endVisit(PatternProperty *) override {} + + bool visit(Elision *) override { return true; } + void endVisit(Elision *) override {} + + bool visit(NestedExpression *) override { return true; } + void endVisit(NestedExpression *) override {} + + bool visit(IdentifierPropertyName *) override { return true; } + void endVisit(IdentifierPropertyName *) override {} + + bool visit(StringLiteralPropertyName *) override { return true; } + void endVisit(StringLiteralPropertyName *) override {} + + bool visit(NumericLiteralPropertyName *) override { return true; } + void endVisit(NumericLiteralPropertyName *) override {} + + bool visit(ComputedPropertyName *) override { return true; } + void endVisit(ComputedPropertyName *) override {} + + bool visit(ArrayMemberExpression *) override { return true; } + void endVisit(ArrayMemberExpression *) override {} + + bool visit(FieldMemberExpression *) override { return true; } + void endVisit(FieldMemberExpression *) override {} + + bool visit(TaggedTemplate *) override { return true; } + void endVisit(TaggedTemplate *) override {} + + bool visit(NewMemberExpression *) override { return true; } + void endVisit(NewMemberExpression *) override {} + + bool visit(NewExpression *) override { return true; } + void endVisit(NewExpression *) override {} + + bool visit(CallExpression *) override { return true; } + void endVisit(CallExpression *) override {} + + bool visit(ArgumentList *) override { return true; } + void endVisit(ArgumentList *) override {} + + bool visit(PostIncrementExpression *) override { return true; } + void endVisit(PostIncrementExpression *) override {} + + bool visit(PostDecrementExpression *) override { return true; } + void endVisit(PostDecrementExpression *) override {} + + bool visit(DeleteExpression *) override { return true; } + void endVisit(DeleteExpression *) override {} + + bool visit(VoidExpression *) override { return true; } + void endVisit(VoidExpression *) override {} + + bool visit(TypeOfExpression *) override { return true; } + void endVisit(TypeOfExpression *) override {} + + bool visit(PreIncrementExpression *) override { return true; } + void endVisit(PreIncrementExpression *) override {} + + bool visit(PreDecrementExpression *) override { return true; } + void endVisit(PreDecrementExpression *) override {} + + bool visit(UnaryPlusExpression *) override { return true; } + void endVisit(UnaryPlusExpression *) override {} + + bool visit(UnaryMinusExpression *) override { return true; } + void endVisit(UnaryMinusExpression *) override {} + + bool visit(TildeExpression *) override { return true; } + void endVisit(TildeExpression *) override {} + + bool visit(NotExpression *) override { return true; } + void endVisit(NotExpression *) override {} + + bool visit(BinaryExpression *) override { return true; } + void endVisit(BinaryExpression *) override {} + + bool visit(ConditionalExpression *) override { return true; } + void endVisit(ConditionalExpression *) override {} + + bool visit(Expression *) override { return true; } + void endVisit(Expression *) override {} + + bool visit(Block *) override { return true; } + void endVisit(Block *) override {} + + bool visit(StatementList *) override { return true; } + void endVisit(StatementList *) override {} + + bool visit(VariableStatement *) override { return true; } + void endVisit(VariableStatement *) override {} + + bool visit(VariableDeclarationList *) override { return true; } + void endVisit(VariableDeclarationList *) override {} + + bool visit(EmptyStatement *) override { return true; } + void endVisit(EmptyStatement *) override {} + + bool visit(ExpressionStatement *) override { return true; } + void endVisit(ExpressionStatement *) override {} + + bool visit(IfStatement *) override { return true; } + void endVisit(IfStatement *) override {} + + bool visit(DoWhileStatement *) override { return true; } + void endVisit(DoWhileStatement *) override {} + + bool visit(WhileStatement *) override { return true; } + void endVisit(WhileStatement *) override {} + + bool visit(ForStatement *) override { return true; } + void endVisit(ForStatement *) override {} + + bool visit(ForEachStatement *) override { return true; } + void endVisit(ForEachStatement *) override {} + + bool visit(ContinueStatement *) override { return true; } + void endVisit(ContinueStatement *) override {} + + bool visit(BreakStatement *) override { return true; } + void endVisit(BreakStatement *) override {} + + bool visit(ReturnStatement *) override { return true; } + void endVisit(ReturnStatement *) override {} + + bool visit(YieldExpression *) override { return true; } + void endVisit(YieldExpression *) override {} + + bool visit(WithStatement *) override { return true; } + void endVisit(WithStatement *) override {} + + bool visit(SwitchStatement *) override { return true; } + void endVisit(SwitchStatement *) override {} + + bool visit(CaseBlock *) override { return true; } + void endVisit(CaseBlock *) override {} + + bool visit(CaseClauses *) override { return true; } + void endVisit(CaseClauses *) override {} + + bool visit(CaseClause *) override { return true; } + void endVisit(CaseClause *) override {} + + bool visit(DefaultClause *) override { return true; } + void endVisit(DefaultClause *) override {} + + bool visit(LabelledStatement *) override { return true; } + void endVisit(LabelledStatement *) override {} + + bool visit(ThrowStatement *) override { return true; } + void endVisit(ThrowStatement *) override {} + + bool visit(TryStatement *) override { return true; } + void endVisit(TryStatement *) override {} + + bool visit(Catch *) override { return true; } + void endVisit(Catch *) override {} + + bool visit(Finally *) override { return true; } + void endVisit(Finally *) override {} + + bool visit(FunctionDeclaration *) override { return true; } + void endVisit(FunctionDeclaration *) override {} + + bool visit(FunctionExpression *) override { return true; } + void endVisit(FunctionExpression *) override {} + + bool visit(FormalParameterList *) override { return true; } + void endVisit(FormalParameterList *) override {} + + bool visit(ClassExpression *) override { return true; } + void endVisit(ClassExpression *) override {} + + bool visit(ClassDeclaration *) override { return true; } + void endVisit(ClassDeclaration *) override {} + + bool visit(ClassElementList *) override { return true; } + void endVisit(ClassElementList *) override {} + + bool visit(Program *) override { return true; } + void endVisit(Program *) override {} + + bool visit(NameSpaceImport *) override { return true; } + void endVisit(NameSpaceImport *) override {} + + bool visit(ImportSpecifier *) override { return true; } + void endVisit(ImportSpecifier *) override {} + + bool visit(ImportsList *) override { return true; } + void endVisit(ImportsList *) override {} + + bool visit(NamedImports *) override { return true; } + void endVisit(NamedImports *) override {} + + bool visit(FromClause *) override { return true; } + void endVisit(FromClause *) override {} + + bool visit(ImportClause *) override { return true; } + void endVisit(ImportClause *) override {} + + bool visit(ImportDeclaration *) override { return true; } + void endVisit(ImportDeclaration *) override {} + + bool visit(ExportSpecifier *) override { return true; } + void endVisit(ExportSpecifier *) override {} + + bool visit(ExportsList *) override { return true; } + void endVisit(ExportsList *) override {} + + bool visit(ExportClause *) override { return true; } + void endVisit(ExportClause *) override {} + + bool visit(ExportDeclaration *) override { return true; } + void endVisit(ExportDeclaration *) override {} + + bool visit(ESModule *) override { return true; } + void endVisit(ESModule *) override {} + + bool visit(DebuggerStatement *) override { return true; } + void endVisit(DebuggerStatement *) override {} + + bool visit(Type *) override { return true; } + void endVisit(Type *) override {} + + bool visit(TypeArgumentList *) override { return true; } + void endVisit(TypeArgumentList *) override {} + + bool visit(TypeAnnotation *) override { return true; } + void endVisit(TypeAnnotation *) override {} +}; + } } // namespace AST QT_END_NAMESPACE diff --git a/tests/auto/shared/qqmljsastdumper.cpp b/tests/auto/shared/qqmljsastdumper.cpp index 7c7485fd1f..92d95be80a 100644 --- a/tests/auto/shared/qqmljsastdumper.cpp +++ b/tests/auto/shared/qqmljsastdumper.cpp @@ -366,6 +366,12 @@ bool AstDumper::visit(UiRequired *el) return true; } +bool AstDumper::visit(UiAnnotationList *) +{ + start(QLatin1String("UiAnnotationList")); + return true; +} + void AstDumper::endVisit(AST::UiProgram *) { stop("UiProgram"); } void AstDumper::endVisit(AST::UiImport *el) { @@ -403,6 +409,7 @@ void AstDumper::endVisit(AST::UiEnumMemberList *el) { void AstDumper::endVisit(AST::UiVersionSpecifier *) { stop("UiVersionSpecifier"); } void AstDumper::endVisit(AST::UiInlineComponent *) { stop("UiInlineComponent"); } void AstDumper::endVisit(UiRequired *) { stop("UiRequired"); } +void AstDumper::endVisit(UiAnnotationList *) { stop("UiAnnotationList"); } // QQmlJS bool AstDumper::visit(AST::ThisExpression *el) { diff --git a/tests/auto/shared/qqmljsastdumper.h b/tests/auto/shared/qqmljsastdumper.h index 919b80f38c..cd52e96220 100644 --- a/tests/auto/shared/qqmljsastdumper.h +++ b/tests/auto/shared/qqmljsastdumper.h @@ -71,7 +71,7 @@ bool operator & (DumperOptions lhs, DumperOptions rhs); DumperOptions operator | (DumperOptions lhs, DumperOptions rhs); // no export, currently just a supporting file... -class AstDumper: public AST::Visitor +class AstDumper: public AST::BaseVisitor { public: static QString printNode2(AST::Node *); -- cgit v1.2.3 From 41e8f8a7c6aa4a530abdbc52f8014c4563e85417 Mon Sep 17 00:00:00 2001 From: Fawzi Mohamed Date: Tue, 11 Feb 2020 16:13:36 +0100 Subject: Add UiAnnotation for annotation objects This is a partial patch that is fuilly fixed with the following one (big restructure) because it needs extra visit methods, and that leads to conflicts, but I think it gets lost if merged with the next one. Change-Id: I54331a47a5c7faaf78a97e580825d1feec5adf92 Reviewed-by: Ulf Hermann --- src/qml/parser/qqmljs.g | 9 +++++---- src/qml/parser/qqmljsast.cpp | 13 ++++++++++++- src/qml/parser/qqmljsast_p.h | 30 +++++++++++++++++++++++++++--- src/qml/parser/qqmljsastfwd_p.h | 1 + src/qml/parser/qqmljsastvisitor_p.h | 4 ++++ tests/auto/shared/qqmljsastdumper.cpp | 7 +++++++ tests/auto/shared/qqmljsastdumper.h | 4 ++++ 7 files changed, 60 insertions(+), 8 deletions(-) diff --git a/src/qml/parser/qqmljs.g b/src/qml/parser/qqmljs.g index a5062aafc7..f6d8bcf9c3 100644 --- a/src/qml/parser/qqmljs.g +++ b/src/qml/parser/qqmljs.g @@ -326,6 +326,7 @@ public: AST::UiQualifiedId *UiQualifiedId; AST::UiEnumMemberList *UiEnumMemberList; AST::UiVersionSpecifier *UiVersionSpecifier; + AST::UiAnnotation *UiAnnotation; AST::UiAnnotationList *UiAnnotationList; }; @@ -953,7 +954,7 @@ UiAnnotationObjectDefinition: UiSimpleQualifiedId UiObjectInitializer; return false; } - AST::UiObjectDefinition *node = new (pool) AST::UiObjectDefinition(sym(1).UiQualifiedId, sym(2).UiObjectInitializer); + AST::UiAnnotation *node = new (pool) AST::UiAnnotation(sym(1).UiQualifiedId, sym(2).UiObjectInitializer); sym(1).Node = node; } break; ./ @@ -969,14 +970,14 @@ case $rule_number: { UiAnnotationList: UiAnnotation; /. case $rule_number: { - sym(1).Node = new (pool) AST::UiAnnotationList(sym(1).UiObjectDefinition); + sym(1).Node = new (pool) AST::UiAnnotationList(sym(1).UiAnnotation); } break; ./ UiAnnotationList: UiAnnotationList UiAnnotation; /. case $rule_number: { - AST::UiAnnotationList *node = new (pool) AST::UiAnnotationList(sym(1).UiAnnotationList, sym(2).UiObjectDefinition); + AST::UiAnnotationList *node = new (pool) AST::UiAnnotationList(sym(1).UiAnnotationList, sym(2).UiAnnotation); sym(1).Node = node; } break; ./ @@ -984,7 +985,7 @@ UiAnnotationList: UiAnnotationList UiAnnotation; UiAnnotatedObject: UiAnnotationList UiObjectDefinition; /. case $rule_number: { - AST::UiObjectMember *node = sym(2).UiObjectMember; + AST::UiObjectDefinition *node = sym(2).UiObjectDefinition; node->annotations = sym(1).UiAnnotationList->finish(); sym(1).Node = node; } break; diff --git a/src/qml/parser/qqmljsast.cpp b/src/qml/parser/qqmljsast.cpp index ef25427076..2a34c5a66c 100644 --- a/src/qml/parser/qqmljsast.cpp +++ b/src/qml/parser/qqmljsast.cpp @@ -1578,7 +1578,18 @@ void UiRequired::accept0(BaseVisitor *visitor) void UiAnnotationList::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { - accept(annotation, visitor); + for (UiAnnotationList *it = this; it; it = it->next) + accept(it->annotation, visitor); + } + + visitor->endVisit(this); +} + +void UiAnnotation::accept0(BaseVisitor *visitor) +{ + if (visitor->visit(this)) { + accept(qualifiedTypeNameId, visitor); + accept(initializer, visitor); } visitor->endVisit(this); diff --git a/src/qml/parser/qqmljsast_p.h b/src/qml/parser/qqmljsast_p.h index feabb5b22d..053e9fd2d3 100644 --- a/src/qml/parser/qqmljsast_p.h +++ b/src/qml/parser/qqmljsast_p.h @@ -260,6 +260,7 @@ public: Kind_UiEnumMemberList, Kind_UiVersionSpecifier, Kind_UiRequired, + Kind_UiAnnotation, Kind_UiAnnotationList }; @@ -3629,16 +3630,39 @@ public: UiEnumMemberList *members; }; +class QML_PARSER_EXPORT UiAnnotation: public Node +{ +public: + QQMLJS_DECLARE_AST_NODE(UiAnnotation) + + UiAnnotation(UiQualifiedId *qualifiedTypeNameId, + UiObjectInitializer *initializer) + : qualifiedTypeNameId(qualifiedTypeNameId), initializer(initializer) + { kind = K; } + + void accept0(BaseVisitor *visitor) override; + + SourceLocation firstSourceLocation() const override + { return qualifiedTypeNameId->identifierToken; } + + SourceLocation lastSourceLocation() const override + { return initializer->rbraceToken; } + +// attributes + UiQualifiedId *qualifiedTypeNameId; + UiObjectInitializer *initializer; +}; + class QML_PARSER_EXPORT UiAnnotationList: public Node { public: QQMLJS_DECLARE_AST_NODE(UiAnnotationList) - UiAnnotationList(UiObjectDefinition *annotation) + UiAnnotationList(UiAnnotation *annotation) : next(this), annotation(annotation) { kind = K; } - UiAnnotationList(UiAnnotationList *previous, UiObjectDefinition *annotation) + UiAnnotationList(UiAnnotationList *previous, UiAnnotation *annotation) : annotation(annotation) { kind = K; @@ -3663,7 +3687,7 @@ public: // attributes UiAnnotationList *next; - UiObjectDefinition *annotation; + UiAnnotation *annotation; }; } } // namespace AST diff --git a/src/qml/parser/qqmljsastfwd_p.h b/src/qml/parser/qqmljsastfwd_p.h index 49949cce61..8df0be7590 100644 --- a/src/qml/parser/qqmljsastfwd_p.h +++ b/src/qml/parser/qqmljsastfwd_p.h @@ -184,6 +184,7 @@ class UiEnumDeclaration; class UiEnumMemberList; class UiVersionSpecifier; class UiRequired; +class UiAnnotation; class UiAnnotationList; } // namespace AST diff --git a/src/qml/parser/qqmljsastvisitor_p.h b/src/qml/parser/qqmljsastvisitor_p.h index 2c17e9ba36..8fbdb97ee2 100644 --- a/src/qml/parser/qqmljsastvisitor_p.h +++ b/src/qml/parser/qqmljsastvisitor_p.h @@ -113,6 +113,7 @@ public: virtual bool visit(UiEnumMemberList *) = 0; virtual bool visit(UiVersionSpecifier *) = 0; virtual bool visit(UiInlineComponent *) = 0; + virtual bool visit(UiAnnotation *) = 0; virtual bool visit(UiAnnotationList *) = 0; virtual bool visit(UiRequired *) = 0; @@ -135,6 +136,7 @@ public: virtual void endVisit(UiEnumMemberList *) = 0; virtual void endVisit(UiVersionSpecifier *) = 0; virtual void endVisit(UiInlineComponent *) = 0; + virtual void endVisit(UiAnnotation *) = 0; virtual void endVisit(UiAnnotationList *) = 0; virtual void endVisit(UiRequired *) = 0; @@ -452,6 +454,7 @@ public: bool visit(UiEnumMemberList *) override { return true; } bool visit(UiVersionSpecifier *) override { return true; } bool visit(UiInlineComponent *) override { return true; } + bool visit(UiAnnotation *) override { return true; } bool visit(UiAnnotationList *) override { return true; } bool visit(UiRequired *) override { return true; } @@ -474,6 +477,7 @@ public: void endVisit(UiEnumMemberList *) override {} void endVisit(UiVersionSpecifier *) override {} void endVisit(UiInlineComponent *) override {} + void endVisit(UiAnnotation *) override {} void endVisit(UiAnnotationList *) override {} void endVisit(UiRequired *) override {} diff --git a/tests/auto/shared/qqmljsastdumper.cpp b/tests/auto/shared/qqmljsastdumper.cpp index 92d95be80a..8a50e021f6 100644 --- a/tests/auto/shared/qqmljsastdumper.cpp +++ b/tests/auto/shared/qqmljsastdumper.cpp @@ -366,6 +366,12 @@ bool AstDumper::visit(UiRequired *el) return true; } +bool AstDumper::visit(UiAnnotation *) +{ + start(QLatin1String("UiAnnotation")); + return true; +} + bool AstDumper::visit(UiAnnotationList *) { start(QLatin1String("UiAnnotationList")); @@ -409,6 +415,7 @@ void AstDumper::endVisit(AST::UiEnumMemberList *el) { void AstDumper::endVisit(AST::UiVersionSpecifier *) { stop("UiVersionSpecifier"); } void AstDumper::endVisit(AST::UiInlineComponent *) { stop("UiInlineComponent"); } void AstDumper::endVisit(UiRequired *) { stop("UiRequired"); } +void AstDumper::endVisit(UiAnnotation *) { stop("UiAnnotation"); } void AstDumper::endVisit(UiAnnotationList *) { stop("UiAnnotationList"); } // QQmlJS diff --git a/tests/auto/shared/qqmljsastdumper.h b/tests/auto/shared/qqmljsastdumper.h index cd52e96220..d8d19e351d 100644 --- a/tests/auto/shared/qqmljsastdumper.h +++ b/tests/auto/shared/qqmljsastdumper.h @@ -119,6 +119,8 @@ public: bool visit(AST::UiVersionSpecifier *) override; bool visit(AST::UiInlineComponent *) override; bool visit(AST::UiRequired *) override; + bool visit(AST::UiAnnotation *) override; + bool visit(AST::UiAnnotationList *) override; void endVisit(AST::UiProgram *) override; void endVisit(AST::UiImport *) override; @@ -140,6 +142,8 @@ public: void endVisit(AST::UiVersionSpecifier *) override; void endVisit(AST::UiInlineComponent *) override; void endVisit(AST::UiRequired *) override; + void endVisit(AST::UiAnnotation *) override; + void endVisit(AST::UiAnnotationList *) override; // QQmlJS bool visit(AST::ThisExpression *) override; -- cgit v1.2.3 From 229e3220ef521dd4389808fd311ea5ae33ab0cae Mon Sep 17 00:00:00 2001 From: Fawzi Mohamed Date: Tue, 11 Feb 2020 16:32:04 +0100 Subject: qmlformat: preserve annotations Change-Id: I22e72d91f6d422e93a7ebc642a8449cb490aec20 Reviewed-by: Ulf Hermann Reviewed-by: Maximilian Goldstein --- .../data/Annotations.formatted.nosort.qml | 106 +++++++++++++++++++++ .../qml/qmlformat/data/Annotations.formatted.qml | 106 +++++++++++++++++++++ tests/auto/qml/qmlformat/data/Annotations.qml | 76 +++++++++++++++ tests/auto/qml/qmlformat/tst_qmlformat.cpp | 12 +++ tools/qmlformat/dumpastvisitor.cpp | 42 ++++++++ tools/qmlformat/dumpastvisitor.h | 5 + 6 files changed, 347 insertions(+) create mode 100644 tests/auto/qml/qmlformat/data/Annotations.formatted.nosort.qml create mode 100644 tests/auto/qml/qmlformat/data/Annotations.formatted.qml create mode 100644 tests/auto/qml/qmlformat/data/Annotations.qml diff --git a/tests/auto/qml/qmlformat/data/Annotations.formatted.nosort.qml b/tests/auto/qml/qmlformat/data/Annotations.formatted.nosort.qml new file mode 100644 index 0000000000..a05c2125dc --- /dev/null +++ b/tests/auto/qml/qmlformat/data/Annotations.formatted.nosort.qml @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Charts module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//![2] +import QtQuick 2.0 +//![2] +import QtCharts 2.0 + +@Pippo { + atg1: 3 +} +@Annotation2 { +} +Item { + //![1] + + @AnnotateMore { + property int x: 5 + } + @AnnotateALot { + } + + property variant othersSlice: 0 + @Annotate { + } + + anchors.fill: parent + @SuperComplete { + binding: late + } + Component.onCompleted: { + // You can also manipulate slices dynamically, like append a slice or set a slice exploded + othersSlice = pieSeries.append("Others", 52); + pieSeries.find("Volkswagen").exploded = true; + } + //![1] + ChartView { + id: chart + + title: "Top-5 car brand shares in Finland" + anchors.fill: parent + legend.alignment: Qt.AlignBottom + antialiasing: true + + @ExtraAnnotation { + signal pippo() + } + PieSeries { + id: pieSeries + + PieSlice { + label: "Volkswagen" + value: 13.5 + } + + PieSlice { + label: "Toyota" + value: 10.9 + } + + PieSlice { + label: "Ford" + value: 8.6 + } + + PieSlice { + label: "Skoda" + value: 8.2 + } + + PieSlice { + label: "Volvo" + value: 6.8 + } + + } + + } + +} diff --git a/tests/auto/qml/qmlformat/data/Annotations.formatted.qml b/tests/auto/qml/qmlformat/data/Annotations.formatted.qml new file mode 100644 index 0000000000..a142d4cb74 --- /dev/null +++ b/tests/auto/qml/qmlformat/data/Annotations.formatted.qml @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Charts module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//![2] +import QtCharts 2.0 +//![2] +import QtQuick 2.0 + +@Pippo { + atg1: 3 +} +@Annotation2 { +} +Item { + //![1] + + @AnnotateMore { + property int x: 5 + } + @AnnotateALot { + } + + property variant othersSlice: 0 + @Annotate { + } + + anchors.fill: parent + @SuperComplete { + binding: late + } + Component.onCompleted: { + // You can also manipulate slices dynamically, like append a slice or set a slice exploded + othersSlice = pieSeries.append("Others", 52); + pieSeries.find("Volkswagen").exploded = true; + } + //![1] + ChartView { + id: chart + + title: "Top-5 car brand shares in Finland" + anchors.fill: parent + legend.alignment: Qt.AlignBottom + antialiasing: true + + @ExtraAnnotation { + signal pippo() + } + PieSeries { + id: pieSeries + + PieSlice { + label: "Volkswagen" + value: 13.5 + } + + PieSlice { + label: "Toyota" + value: 10.9 + } + + PieSlice { + label: "Ford" + value: 8.6 + } + + PieSlice { + label: "Skoda" + value: 8.2 + } + + PieSlice { + label: "Volvo" + value: 6.8 + } + + } + + } + +} diff --git a/tests/auto/qml/qmlformat/data/Annotations.qml b/tests/auto/qml/qmlformat/data/Annotations.qml new file mode 100644 index 0000000000..2d3d7d2cfd --- /dev/null +++ b/tests/auto/qml/qmlformat/data/Annotations.qml @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Charts module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//![2] +import QtQuick 2.0 +//![2] +import QtCharts 2.0 + +@Pippo{ atg1:3 } +@Annotation2{} +Item { + @Annotate{} + anchors.fill: parent + @AnnotateMore{ + property int x: 5 + } + @AnnotateALot{} + property variant othersSlice: 0 + + //![1] + ChartView { + id: chart + title: "Top-5 car brand shares in Finland" + anchors.fill: parent + legend.alignment: Qt.AlignBottom + antialiasing: true + +@ExtraAnnotation{ + signal pippo +} + PieSeries { + id: pieSeries + PieSlice { label: "Volkswagen"; value: 13.5 } + PieSlice { label: "Toyota"; value: 10.9 } + PieSlice { label: "Ford"; value: 8.6 } + PieSlice { label: "Skoda"; value: 8.2 } + PieSlice { label: "Volvo"; value: 6.8 } + } + } + +@SuperComplete{ +binding: late +} + Component.onCompleted: { + // You can also manipulate slices dynamically, like append a slice or set a slice exploded + othersSlice = pieSeries.append("Others", 52.0); + pieSeries.find("Volkswagen").exploded = true; + } + //![1] +} diff --git a/tests/auto/qml/qmlformat/tst_qmlformat.cpp b/tests/auto/qml/qmlformat/tst_qmlformat.cpp index b10eaf26f1..47255d7745 100644 --- a/tests/auto/qml/qmlformat/tst_qmlformat.cpp +++ b/tests/auto/qml/qmlformat/tst_qmlformat.cpp @@ -41,6 +41,8 @@ private Q_SLOTS: void testFormat(); void testFormatNoSort(); + void testAnnotations(); + void testAnnotationsNoSort(); void testReadOnlyProps(); @@ -183,6 +185,16 @@ void TestQmlformat::testFormatNoSort() QCOMPARE(runQmlformat(testFile("Example1.qml"), false, true), readTestFile("Example1.formatted.nosort.qml")); } +void TestQmlformat::testAnnotations() +{ + QCOMPARE(runQmlformat(testFile("Annotations.qml"), true, true), readTestFile("Annotations.formatted.qml")); +} + +void TestQmlformat::testAnnotationsNoSort() +{ + QCOMPARE(runQmlformat(testFile("Annotations.qml"), false, true), readTestFile("Annotations.formatted.nosort.qml")); +} + void TestQmlformat::testReadOnlyProps() { QCOMPARE(runQmlformat(testFile("readOnlyProps.qml"), false, true), readTestFile("readOnlyProps.formatted.qml")); diff --git a/tools/qmlformat/dumpastvisitor.cpp b/tools/qmlformat/dumpastvisitor.cpp index 75d9fa8a4f..7f1e285423 100644 --- a/tools/qmlformat/dumpastvisitor.cpp +++ b/tools/qmlformat/dumpastvisitor.cpp @@ -52,6 +52,14 @@ DumpAstVisitor::DumpAstVisitor(Node *rootNode, CommentAstVisitor *comment): m_co m_result = lines.join("\n"); } +bool DumpAstVisitor::preVisit(Node *el) +{ + UiObjectMember *m = el->uiObjectMemberCast(); + if (m != 0) + Node::accept(m->annotations, this); + return true; +} + static QString parseUiQualifiedId(UiQualifiedId *id) { QString name = id->name.toString(); @@ -1247,3 +1255,37 @@ bool DumpAstVisitor::visit(UiPragma *node) { return true; } + +bool DumpAstVisitor::visit(UiAnnotation *node) +{ + if (scope().m_firstObject) { + if (scope().m_firstOfAll) + scope().m_firstOfAll = false; + else + addNewLine(); + + scope().m_firstObject = false; + } + + addLine(getComment(node, Comment::Location::Front)); + addLine(QLatin1String("@") + parseUiQualifiedId(node->qualifiedTypeNameId) + " {"); + + m_indentLevel++; + + ScopeProperties props; + props.m_bindings = findBindings(node->initializer->members); + m_scope_properties.push(props); + + m_result += getOrphanedComments(node); + + return true; +} + +void DumpAstVisitor::endVisit(UiAnnotation *node) { + m_indentLevel--; + + m_scope_properties.pop(); + + addLine("}"); + addLine(getComment(node, Comment::Location::Back)); +} diff --git a/tools/qmlformat/dumpastvisitor.h b/tools/qmlformat/dumpastvisitor.h index 8c34e01960..1e25bd9190 100644 --- a/tools/qmlformat/dumpastvisitor.h +++ b/tools/qmlformat/dumpastvisitor.h @@ -46,6 +46,8 @@ public: QString toString() const { return m_result; } + bool preVisit(Node *) override; + bool visit(UiScriptBinding *node) override; bool visit(UiArrayBinding *node) override; @@ -67,6 +69,9 @@ public: bool visit(UiImport *node) override; bool visit(UiPragma *node) override; + bool visit(UiAnnotation *node) override; + void endVisit(UiAnnotation *node) override; + void throwRecursionDepthError() override {} bool error() const { return m_error; } -- cgit v1.2.3 From 5445fcac36d7122d533a2bdf0fcfe6206b7f3ff4 Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Wed, 12 Feb 2020 09:21:50 +0100 Subject: QQuickItemView: do not set parent to nullptr upon destruction Setting a delegate item's parent to nullptr will make any bindings to the parent inside the item invalid, and warnings will as such be printed (first seen after 8c72e634b3b0eacbfdee883bfc34994d3c19ed77). I assume the reason for setting the (visual) parent to nullptr is to immediately hide it. So to avoid trigger any bindings, we instead just cull if from the scene graph. It's also dubious why a delegate should have bindings to its parent in the first place, since what ends up being the parent is an implementation detail, and probably not be the item the user expects it to be. Fixes: QTBUG-81976 Change-Id: I7bd8ab91461504b6e79d4aa2ab832be087245c3e Reviewed-by: Mitch Curtis --- src/quick/items/qquickitemview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp index 7fb392233e..3e3a2c262b 100644 --- a/src/quick/items/qquickitemview.cpp +++ b/src/quick/items/qquickitemview.cpp @@ -2419,7 +2419,7 @@ void QQuickItemView::destroyingItem(QObject *object) Q_D(QQuickItemView); QQuickItem* item = qmlobject_cast(object); if (item) { - item->setParentItem(nullptr); + QQuickItemPrivate::get(item)->setCulled(true); d->unrequestedItems.remove(item); } } -- cgit v1.2.3 From 57a7ec1c9d226e05e9453e17c582dc71c01185a0 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Thu, 13 Feb 2020 12:53:28 +0100 Subject: TestCase: deprecate mouseDoubleClick() in favor of mouseDoubleClickSequence(), which has a much more realistic event sequence. mouseDoubleClick() only sends a MouseDoubleClick event, without any press, release, etc. Change-Id: Ifa57cfe678c5f0aef7ee35dab8a1a97ce9a06de0 Fixes: QTBUG-82138 Reviewed-by: Shawn Rutledge Reviewed-by: Fabian Kosmale Reviewed-by: Ulf Hermann --- src/imports/testlib/TestCase.qml | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/imports/testlib/TestCase.qml b/src/imports/testlib/TestCase.qml index 20c5ce6418..380b7e38d7 100644 --- a/src/imports/testlib/TestCase.qml +++ b/src/imports/testlib/TestCase.qml @@ -198,7 +198,7 @@ import Qt.test.qtestroot 1.0 } \endcode - The mousePress(), mouseRelease(), mouseClick(), mouseDoubleClick(), mouseDoubleClickSequence() + The mousePress(), mouseRelease(), mouseClick(), mouseDoubleClickSequence() and mouseMove() methods can be used to simulate mouse events in a similar fashion. @@ -1331,7 +1331,7 @@ Item { If \a item is obscured by another item, or a child of \a item occupies that position, then the event will be delivered to the other item instead. - \sa mouseRelease(), mouseClick(), mouseDoubleClick(), mouseDoubleClickSequence(), mouseMove(), mouseDrag(), mouseWheel() + \sa mouseRelease(), mouseClick(), mouseDoubleClickSequence(), mouseMove(), mouseDrag(), mouseWheel() */ function mousePress(item, x, y, button, modifiers, delay) { if (!qtest_verifyItem(item, "mousePress")) @@ -1365,7 +1365,7 @@ Item { If \a item is obscured by another item, or a child of \a item occupies that position, then the event will be delivered to the other item instead. - \sa mousePress(), mouseClick(), mouseDoubleClick(), mouseDoubleClickSequence(), mouseMove(), mouseDrag(), mouseWheel() + \sa mousePress(), mouseClick(), mouseDoubleClickSequence(), mouseMove(), mouseDrag(), mouseWheel() */ function mouseRelease(item, x, y, button, modifiers, delay) { if (!qtest_verifyItem(item, "mouseRelease")) @@ -1398,7 +1398,7 @@ Item { If \a item is obscured by another item, or a child of \a item occupies that position, then the event will be delivered to the other item instead. - \sa mousePress(), mouseClick(), mouseDoubleClick(), mouseDoubleClickSequence(), mouseMove(), mouseRelease(), mouseWheel() + \sa mousePress(), mouseClick(), mouseDoubleClickSequence(), mouseMove(), mouseRelease(), mouseWheel() */ function mouseDrag(item, x, y, dx, dy, button, modifiers, delay) { if (!qtest_verifyItem(item, "mouseDrag")) @@ -1453,7 +1453,7 @@ Item { If \a item is obscured by another item, or a child of \a item occupies that position, then the event will be delivered to the other item instead. - \sa mousePress(), mouseRelease(), mouseDoubleClick(), mouseDoubleClickSequence(), mouseMove(), mouseDrag(), mouseWheel() + \sa mousePress(), mouseRelease(), mouseDoubleClickSequence(), mouseMove(), mouseDrag(), mouseWheel() */ function mouseClick(item, x, y, button, modifiers, delay) { if (!qtest_verifyItem(item, "mouseClick")) @@ -1475,6 +1475,7 @@ Item { /*! \qmlmethod TestCase::mouseDoubleClick(item, x = item.width / 2, y = item.height / 2, button = Qt.LeftButton, modifiers = Qt.NoModifier, delay = -1) + \deprecated Simulates double-clicking a mouse \a button with optional \a modifiers on an \a item. The position of the click is defined by \a x and \a y. @@ -1528,7 +1529,7 @@ Item { This QML method was introduced in Qt 5.5. - \sa mouseDoubleClick(), mousePress(), mouseRelease(), mouseClick(), mouseMove(), mouseDrag(), mouseWheel() + \sa mousePress(), mouseRelease(), mouseClick(), mouseMove(), mouseDrag(), mouseWheel() */ function mouseDoubleClickSequence(item, x, y, button, modifiers, delay) { if (!qtest_verifyItem(item, "mouseDoubleClickSequence")) @@ -1560,7 +1561,7 @@ Item { If \a item is obscured by another item, or a child of \a item occupies that position, then the event will be delivered to the other item instead. - \sa mousePress(), mouseRelease(), mouseClick(), mouseDoubleClick(), mouseDoubleClickSequence(), mouseDrag(), mouseWheel() + \sa mousePress(), mouseRelease(), mouseClick(), mouseDoubleClickSequence(), mouseDrag(), mouseWheel() */ function mouseMove(item, x, y, delay, buttons) { if (!qtest_verifyItem(item, "mouseMove")) @@ -1588,7 +1589,7 @@ Item { The \a xDelta and \a yDelta contain the wheel rotation distance in eighths of a degree. see \l QWheelEvent::angleDelta() for more details. - \sa mousePress(), mouseClick(), mouseDoubleClick(), mouseDoubleClickSequence(), mouseMove(), mouseRelease(), mouseDrag(), QWheelEvent::angleDelta() + \sa mousePress(), mouseClick(), mouseDoubleClickSequence(), mouseMove(), mouseRelease(), mouseDrag(), QWheelEvent::angleDelta() */ function mouseWheel(item, x, y, xDelta, yDelta, buttons, modifiers, delay) { if (!qtest_verifyItem(item, "mouseWheel")) -- cgit v1.2.3 From dd6ffbec2496920b1bfe4f29cca1eba82e959869 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Fri, 14 Feb 2020 14:04:14 +0100 Subject: Optimize QQuickPixmapCache readImage() slightly Calling QImageReader::size() twice means calling the image format plugin twice, so it's best to avoid that. Change-Id: I4741e87c7c95252904d0dd9f484a57d953670559 Reviewed-by: Shawn Rutledge --- src/quick/util/qquickpixmapcache.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/quick/util/qquickpixmapcache.cpp b/src/quick/util/qquickpixmapcache.cpp index 2ae9debbc9..6a34169fce 100644 --- a/src/quick/util/qquickpixmapcache.cpp +++ b/src/quick/util/qquickpixmapcache.cpp @@ -427,11 +427,12 @@ static bool readImage(const QUrl& url, QIODevice *dev, QImage *image, QString *e imgio.setScaledSize(scSize); if (!requestRegion.isNull()) imgio.setScaledClipRect(requestRegion); + const QSize originalSize = imgio.size(); qCDebug(lcImg) << url << "frame" << frame << "of" << imgio.imageCount() - << "requestRegion" << requestRegion << "QImageReader size" << imgio.size() << "-> scSize" << scSize; + << "requestRegion" << requestRegion << "QImageReader size" << originalSize << "-> scSize" << scSize; if (impsize) - *impsize = imgio.size(); + *impsize = originalSize; if (imgio.read(image)) { maybeRemoveAlpha(image); -- cgit v1.2.3 From 751e92d50a23d1273af42a7a7836bb2eb336eced Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Thu, 13 Feb 2020 19:03:40 +0100 Subject: V4 Debugger: Properly set up context object for expressions We need to use the object in question as context object in order to access its properties. Otherwise we can only access the context properties and, incidentally, the root scope's properties. The latter is why the test didn't fail. Fixes: QTBUG-82150 Change-Id: I1f18f9e78dd61786310fd75e0695929522a4c90c Reviewed-by: Simon Hausmann --- src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp | 8 ++++---- tests/auto/qml/debugger/qqmldebugjs/data/oncompleted.qml | 4 ++++ tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp | 10 ++++++++++ 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp index 61fea96e2f..333ce4b26f 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp @@ -66,7 +66,6 @@ void JavaScriptJob::run() QV4::ScopedContext ctx(scope, engine->currentStackFrame ? engine->currentContext() : engine->scriptContext()); - QObject scopeObject; QV4::CppStackFrame *frame = engine->currentStackFrame; @@ -76,9 +75,10 @@ void JavaScriptJob::run() ctx = static_cast(&frame->jsFrame->context); if (context >= 0) { - QQmlContext *extraContext = qmlContext(QQmlDebugService::objectForId(context)); + QObject *forId = QQmlDebugService::objectForId(context); + QQmlContext *extraContext = qmlContext(forId); if (extraContext) - ctx = QV4::QmlContext::create(ctx, QQmlContextData::get(extraContext), &scopeObject); + ctx = QV4::QmlContext::create(ctx, QQmlContextData::get(extraContext), forId); } else if (frameNr < 0) { // Use QML context if available QQmlEngine *qmlEngine = engine->qmlEngine(); if (qmlEngine) { @@ -99,7 +99,7 @@ void JavaScriptJob::run() } } if (!engine->qmlContext()) - ctx = QV4::QmlContext::create(ctx, QQmlContextData::get(qmlRootContext), &scopeObject); + ctx = QV4::QmlContext::create(ctx, QQmlContextData::get(qmlRootContext), nullptr); } } diff --git a/tests/auto/qml/debugger/qqmldebugjs/data/oncompleted.qml b/tests/auto/qml/debugger/qqmldebugjs/data/oncompleted.qml index deba24cf91..a7231df48b 100644 --- a/tests/auto/qml/debugger/qqmldebugjs/data/oncompleted.qml +++ b/tests/auto/qml/debugger/qqmldebugjs/data/oncompleted.qml @@ -36,5 +36,9 @@ Item { } id: root property int a: 10 + + Item { + property int b: 11 + } } diff --git a/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp b/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp index 3f424d16f2..91470e0651 100644 --- a/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp +++ b/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp @@ -896,6 +896,16 @@ void tst_QQmlDebugJS::evaluateInContext() QVERIFY(waitForClientSignal(SIGNAL(result()))); QTRY_COMPARE(responseBody(m_client).value("value").toInt(), 20); + + auto childObjects = object.children; + QVERIFY(childObjects.count() > 0); // QQmlComponentAttached is also in there + QCOMPARE(childObjects[0].className, QString::fromLatin1("Item")); + + // "b" accessible in context of surrounding (child) object + m_client->evaluate(QLatin1String("b"), -1, childObjects[0].debugId); + QVERIFY(waitForClientSignal(SIGNAL(result()))); + + QTRY_COMPARE(responseBody(m_client).value("value").toInt(), 11); } void tst_QQmlDebugJS::getScripts() -- cgit v1.2.3 From ee95f0e6830a504574ef5fa54b44a11b13d5a8ae Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Wed, 12 Feb 2020 17:36:14 +0100 Subject: MultiPointTouchArea: update the TouchPoint.x and y properties together Letting them change sequentially is inconvenient when they are used to drive some sort of smooth stroke (drawing or motion). Fixes: QTBUG-81944 Change-Id: I46c5948dbec927682244daf00a0df3453a0d92a6 Reviewed-by: Michael Brasser --- src/quick/items/qquickmultipointtoucharea.cpp | 28 ++++++++++++--------------- src/quick/items/qquickmultipointtoucharea_p.h | 4 +--- 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/src/quick/items/qquickmultipointtoucharea.cpp b/src/quick/items/qquickmultipointtoucharea.cpp index 9a371207ce..3a807d3c66 100644 --- a/src/quick/items/qquickmultipointtoucharea.cpp +++ b/src/quick/items/qquickmultipointtoucharea.cpp @@ -88,20 +88,18 @@ void QQuickTouchPoint::setPointId(int id) These properties hold the current position of the touch point. */ -void QQuickTouchPoint::setX(qreal x) +void QQuickTouchPoint::setPosition(QPointF p) { - if (_x == x) + bool xch = (_x != p.x()); + bool ych = (_y != p.y()); + if (!xch && !ych) return; - _x = x; - emit xChanged(); -} - -void QQuickTouchPoint::setY(qreal y) -{ - if (_y == y) - return; - _y = y; - emit yChanged(); + _x = p.x(); + _y = p.y(); + if (xch) + emit xChanged(); + if (ych) + emit yChanged(); } /*! @@ -798,8 +796,7 @@ void QQuickMultiPointTouchArea::updateTouchPoint(QQuickTouchPoint *dtp, const QT //TODO: if !qmlDefined, could bypass setters. // also, should only emit signals after all values have been set dtp->setUniqueId(p->uniqueId()); - dtp->setX(p->pos().x()); - dtp->setY(p->pos().y()); + dtp->setPosition(p->pos()); dtp->setEllipseDiameters(p->ellipseDiameters()); dtp->setPressure(p->pressure()); dtp->setRotation(p->rotation()); @@ -817,8 +814,7 @@ void QQuickMultiPointTouchArea::updateTouchPoint(QQuickTouchPoint *dtp, const QM { dtp->setPreviousX(dtp->x()); dtp->setPreviousY(dtp->y()); - dtp->setX(e->localPos().x()); - dtp->setY(e->localPos().y()); + dtp->setPosition(e->localPos()); if (e->type() == QEvent::MouseButtonPress) { dtp->setStartX(e->localPos().x()); dtp->setStartY(e->localPos().y()); diff --git a/src/quick/items/qquickmultipointtoucharea_p.h b/src/quick/items/qquickmultipointtoucharea_p.h index 363e62593b..e34a3faad6 100644 --- a/src/quick/items/qquickmultipointtoucharea_p.h +++ b/src/quick/items/qquickmultipointtoucharea_p.h @@ -97,10 +97,8 @@ public: void setUniqueId(const QPointingDeviceUniqueId &id); qreal x() const { return _x; } - void setX(qreal x); - qreal y() const { return _y; } - void setY(qreal y); + void setPosition(QPointF pos); QSizeF ellipseDiameters() const { return _ellipseDiameters; } void setEllipseDiameters(const QSizeF &d); -- cgit v1.2.3 From 55546991e24ca6799709cbe0171b9ab87216c35f Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Fri, 14 Feb 2020 16:41:28 +0100 Subject: Rearrange QQuickPixmapKey operator== ...to do the comparisons in the same order as the variables are stored. Change-Id: I5faa1daa84757b94993c3135ddfc9a3fd6c10ea6 Reviewed-by: Shawn Rutledge --- src/quick/util/qquickpixmapcache.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/quick/util/qquickpixmapcache.cpp b/src/quick/util/qquickpixmapcache.cpp index 6a34169fce..8846edcd44 100644 --- a/src/quick/util/qquickpixmapcache.cpp +++ b/src/quick/util/qquickpixmapcache.cpp @@ -1026,8 +1026,11 @@ public: inline bool operator==(const QQuickPixmapKey &lhs, const QQuickPixmapKey &rhs) { - return *lhs.region == *rhs.region && *lhs.size == *rhs.size && *lhs.url == *rhs.url && - lhs.options == rhs.options && lhs.frame == rhs.frame; + return *lhs.url == *rhs.url && + *lhs.region == *rhs.region && + *lhs.size == *rhs.size && + lhs.frame == rhs.frame && + lhs.options == rhs.options; } inline uint qHash(const QQuickPixmapKey &key) -- cgit v1.2.3