diff options
author | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2019-10-12 01:00:20 +0200 |
---|---|---|
committer | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2019-10-12 01:00:20 +0200 |
commit | d6cbf42e3720f0bdb1d6dc328ec8b8ac0ffb13ca (patch) | |
tree | 0326fbd4f1d54beba03399701e91c91b2c6195ae | |
parent | 1d2cf00cecd537cc1dfdedda776897c0dc23e229 (diff) | |
parent | 8cb08ca42157bb43b523103a6d1be94534be0597 (diff) |
Merge remote-tracking branch 'origin/5.15' into dev
Change-Id: I3a13e84b77e1c6c3a85ef000d2bfbadbc72651bb
42 files changed, 572 insertions, 90 deletions
diff --git a/examples/quick/scenegraph/d3d11underqml/d3d11underqml.pro b/examples/quick/scenegraph/d3d11underqml/d3d11underqml.pro index 3c94d48ac4..7658a9a813 100644 --- a/examples/quick/scenegraph/d3d11underqml/d3d11underqml.pro +++ b/examples/quick/scenegraph/d3d11underqml/d3d11underqml.pro @@ -1,3 +1,5 @@ +!win32: error("This example requires Windows") + QT += qml quick HEADERS += d3d11squircle.h diff --git a/examples/quick/scenegraph/metaltextureimport/metaltextureimport.pro b/examples/quick/scenegraph/metaltextureimport/metaltextureimport.pro index c8ea7ce478..5b11606946 100644 --- a/examples/quick/scenegraph/metaltextureimport/metaltextureimport.pro +++ b/examples/quick/scenegraph/metaltextureimport/metaltextureimport.pro @@ -1,3 +1,5 @@ +!macos: error("This example requires macOS") + QT += qml quick HEADERS += metaltextureimport.h diff --git a/examples/quick/scenegraph/metalunderqml/metalunderqml.pro b/examples/quick/scenegraph/metalunderqml/metalunderqml.pro index 9b27638a6d..9fd131fe1b 100644 --- a/examples/quick/scenegraph/metalunderqml/metalunderqml.pro +++ b/examples/quick/scenegraph/metalunderqml/metalunderqml.pro @@ -1,3 +1,5 @@ +!macos: error("This example requires macOS") + QT += qml quick HEADERS += metalsquircle.h diff --git a/examples/quick/scenegraph/vulkanunderqml/vulkanunderqml.pro b/examples/quick/scenegraph/vulkanunderqml/vulkanunderqml.pro index 9a0a87c9f0..9ea57b91c3 100644 --- a/examples/quick/scenegraph/vulkanunderqml/vulkanunderqml.pro +++ b/examples/quick/scenegraph/vulkanunderqml/vulkanunderqml.pro @@ -1,3 +1,5 @@ +!qtConfig(vulkan): error("This example requires Qt built with Vulkan support") + QT += qml quick HEADERS += vulkansquircle.h diff --git a/examples/quick/views/doc/src/views.qdoc b/examples/quick/views/doc/src/views.qdoc index 294b88542b..16237a68e0 100644 --- a/examples/quick/views/doc/src/views.qdoc +++ b/examples/quick/views/doc/src/views.qdoc @@ -87,7 +87,7 @@ \section1 Packages - \e Packages uses the \l Package type to transition delegates between + \e Packages use the \l [QML]{Package} type to transition delegates between two views. It has a Package object which defines delegate items for each view and an diff --git a/src/imports/layouts/qquickstacklayout.cpp b/src/imports/layouts/qquickstacklayout.cpp index 116e162aa9..4c1d611409 100644 --- a/src/imports/layouts/qquickstacklayout.cpp +++ b/src/imports/layouts/qquickstacklayout.cpp @@ -94,7 +94,7 @@ \sa ColumnLayout \sa GridLayout \sa RowLayout - \sa StackView + \sa {QtQuick.Controls::StackView}{StackView} */ QT_BEGIN_NAMESPACE diff --git a/src/plugins/scenegraph/openvg/qsgopenvgcontext.cpp b/src/plugins/scenegraph/openvg/qsgopenvgcontext.cpp index 1736a2098e..a5231e15d1 100644 --- a/src/plugins/scenegraph/openvg/qsgopenvgcontext.cpp +++ b/src/plugins/scenegraph/openvg/qsgopenvgcontext.cpp @@ -76,6 +76,7 @@ void QSGOpenVGRenderContext::initialize(const QSGRenderContext::InitParams *para m_vgContext = vgparams->context; QSGRenderContext::initialize(params); + emit initialized(); } void QSGOpenVGRenderContext::invalidate() @@ -84,6 +85,7 @@ void QSGOpenVGRenderContext::invalidate() delete m_glyphCacheManager; m_glyphCacheManager = nullptr; QSGRenderContext::invalidate(); + emit invalidated(); } void QSGOpenVGRenderContext::renderNextFrame(QSGRenderer *renderer, uint fboId) diff --git a/src/plugins/scenegraph/openvg/qsgopenvginternalrectanglenode.cpp b/src/plugins/scenegraph/openvg/qsgopenvginternalrectanglenode.cpp index d728686248..2c71c1610a 100644 --- a/src/plugins/scenegraph/openvg/qsgopenvginternalrectanglenode.cpp +++ b/src/plugins/scenegraph/openvg/qsgopenvginternalrectanglenode.cpp @@ -211,21 +211,14 @@ void QSGOpenVGInternalRectangleNode::render() } else { vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE); vgLoadIdentity(); - if (m_radius > 0) { - // Fallback to rendering to an image for rounded rects with perspective transforms - if (m_offscreenSurface == nullptr || m_offscreenSurface->size() != QSize(std::ceil(m_rect.width()), std::ceil(m_rect.height()))) { - delete m_offscreenSurface; - m_offscreenSurface = new QOpenVGOffscreenSurface(QSize(std::ceil(m_rect.width()), std::ceil(m_rect.height()))); - } - - m_offscreenSurface->makeCurrent(); - } else if (m_offscreenSurface) { + // Fallback to rendering to an image for rounded rects with perspective transforms + if (m_offscreenSurface == nullptr || m_offscreenSurface->size() != QSize(std::ceil(m_rect.width()), std::ceil(m_rect.height()))) { delete m_offscreenSurface; - m_offscreenSurface = nullptr; + m_offscreenSurface = new QOpenVGOffscreenSurface(QSize(std::ceil(m_rect.width()), std::ceil(m_rect.height()))); } + m_offscreenSurface->makeCurrent(); } - // If path is dirty if (m_pathDirty) { vgClearPath(m_rectanglePath, VG_PATH_CAPABILITY_APPEND_TO); @@ -291,7 +284,7 @@ void QSGOpenVGInternalRectangleNode::render() vgDrawPath(m_rectanglePath, VG_FILL_PATH); } - if (!transform().isAffine() && m_radius > 0) { + if (!transform().isAffine()) { m_offscreenSurface->doneCurrent(); // Render offscreen surface vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE); diff --git a/src/plugins/scenegraph/openvg/qsgopenvgrenderloop.cpp b/src/plugins/scenegraph/openvg/qsgopenvgrenderloop.cpp index 69b10fcdee..85651ece9d 100644 --- a/src/plugins/scenegraph/openvg/qsgopenvgrenderloop.cpp +++ b/src/plugins/scenegraph/openvg/qsgopenvgrenderloop.cpp @@ -187,6 +187,7 @@ void QSGOpenVGRenderLoop::renderWindow(QQuickWindow *window) data.updatePending = false; if (!data.grabOnly) { + cd->flushFrameSynchronousEvents(); // Event delivery/processing triggered the window to be deleted or stop rendering. if (!m_windows.contains(window)) return; diff --git a/src/plugins/scenegraph/openvg/qsgopenvgspritenode.cpp b/src/plugins/scenegraph/openvg/qsgopenvgspritenode.cpp index fb24df7471..1b75d450aa 100644 --- a/src/plugins/scenegraph/openvg/qsgopenvgspritenode.cpp +++ b/src/plugins/scenegraph/openvg/qsgopenvgspritenode.cpp @@ -52,7 +52,7 @@ QSGOpenVGSpriteNode::QSGOpenVGSpriteNode() QSGOpenVGSpriteNode::~QSGOpenVGSpriteNode() { - + delete m_texture; } void QSGOpenVGSpriteNode::setTexture(QSGTexture *texture) diff --git a/src/plugins/scenegraph/openvg/qsgopenvgspritenode.h b/src/plugins/scenegraph/openvg/qsgopenvgspritenode.h index d47b389a0b..dba4e663be 100644 --- a/src/plugins/scenegraph/openvg/qsgopenvgspritenode.h +++ b/src/plugins/scenegraph/openvg/qsgopenvgspritenode.h @@ -66,7 +66,7 @@ public: void render() override; private: - QSGOpenVGTexture *m_texture; + QSGOpenVGTexture *m_texture = nullptr; float m_time; QPoint m_sourceA; QPoint m_sourceB; diff --git a/src/qml/doc/src/javascript/imports.qdoc b/src/qml/doc/src/javascript/imports.qdoc index 974f2e154f..8e26c4aadd 100644 --- a/src/qml/doc/src/javascript/imports.qdoc +++ b/src/qml/doc/src/javascript/imports.qdoc @@ -144,14 +144,17 @@ A JavaScript resource may import a QML module in the following fashion: .import TypeNamespace MajorVersion.MinorVersion as Qualifier \endcode -For example: +Below you can see an example that also shows how to use the QML types from a +module imported in javascript: + \code .import Qt.test 1.0 as JsQtTest + +var importedEnumValue = JsQtTest.MyQmlObject.EnumValue3 \endcode In particular, this may be useful in order to access functionality provided via a singleton type; see qmlRegisterSingletonType() for more information. \note The .import syntax doesn't work for scripts used in the \l {WorkerScript} - */ diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp index 520b715189..cc89947cec 100644 --- a/src/qml/jsruntime/qv4dateobject.cpp +++ b/src/qml/jsruntime/qv4dateobject.cpp @@ -294,13 +294,28 @@ static double MakeDay(double year, double month, double day) if (month < 0) month += 12.0; - double d = DayFromYear(year); - bool leap = InLeapYear(d*msPerDay); + /* Quoting the spec: - d += DayFromMonth(month, leap); - d += day - 1; + Find a value t such that YearFromTime(t) is ym and MonthFromTime(t) is mn + and DateFromTime(t) is 1; but if this is not possible (because some + argument is out of range), return NaN. + */ + double first = DayFromYear(year); + /* Beware floating-point glitches: don't test the first millisecond of a + * year, month or day when we could test a moment firmly in the interior of + * the interval. A rounding glitch might give the first millisecond to the + * preceding interval. + */ + bool leap = InLeapYear((first + 60) * msPerDay); - return d; + first += DayFromMonth(month, leap); + const double t = first * msPerDay + msPerDay / 2; // Noon on the first of the month + Q_ASSERT(Day(t) == first); + if (YearFromTime(t) != year || MonthFromTime(t) != month || DateFromTime(t) != 1) { + qWarning("Apparently out-of-range date %.0f-%02.0f-%02.0f", year, month, day); + return qt_qnan(); + } + return first + day - 1; } static inline double MakeDate(double day, double time) diff --git a/src/qmlmodels/qqmllistmodel.cpp b/src/qmlmodels/qqmllistmodel.cpp index d68815cbc1..e0a66e7170 100644 --- a/src/qmlmodels/qqmllistmodel.cpp +++ b/src/qmlmodels/qqmllistmodel.cpp @@ -634,7 +634,7 @@ void ListModel::set(int elementIndex, QV4::Object *object, QVector<int> *roles) mo->updateValues(*roles); } -void ListModel::set(int elementIndex, QV4::Object *object) +void ListModel::set(int elementIndex, QV4::Object *object, ListModel::SetElement reason) { if (!object) return; @@ -684,7 +684,7 @@ void ListModel::set(int elementIndex, QV4::Object *object) } else if (QV4::DateObject *date = propertyValue->as<QV4::DateObject>()) { const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::DateTime); if (r.type == ListLayout::Role::DateTime) { - QDateTime dt = date->toQDateTime();; + QDateTime dt = date->toQDateTime(); e->setDateTimePropertyFast(r, dt); } } else if (QV4::Object *o = propertyValue->as<QV4::Object>()) { @@ -699,9 +699,16 @@ void ListModel::set(int elementIndex, QV4::Object *object) e->setVariantMapFast(role, o); } } else if (propertyValue->isNullOrUndefined()) { - const ListLayout::Role *r = m_layout->getExistingRole(propertyName); - if (r) - e->clearProperty(*r); + if (reason == SetElement::WasJustInserted) { + QQmlError err; + auto memberName = propertyName->toString(m_modelCache->engine())->toQString(); + err.setDescription(QString::fromLatin1("%1 is %2. Adding an object with a %2 member does not create a role for it.").arg(memberName, propertyValue->isNull() ? QLatin1String("null") : QLatin1String("undefined"))); + qmlWarning(nullptr, err); + } else { + const ListLayout::Role *r = m_layout->getExistingRole(propertyName); + if (r) + e->clearProperty(*r); + } } } } @@ -725,13 +732,13 @@ QVector<std::function<void()>> ListModel::remove(int index, int count) void ListModel::insert(int elementIndex, QV4::Object *object) { insertElement(elementIndex); - set(elementIndex, object); + set(elementIndex, object, SetElement::WasJustInserted); } int ListModel::append(QV4::Object *object) { int elementIndex = appendElement(); - set(elementIndex, object); + set(elementIndex, object, SetElement::WasJustInserted); return elementIndex; } diff --git a/src/qmlmodels/qqmllistmodel_p_p.h b/src/qmlmodels/qqmllistmodel_p_p.h index a0d0e9ad89..2ad5158050 100644 --- a/src/qmlmodels/qqmllistmodel_p_p.h +++ b/src/qmlmodels/qqmllistmodel_p_p.h @@ -381,8 +381,10 @@ public: return elements.count(); } + enum class SetElement {WasJustInserted, IsCurrentlyUpdated}; + void set(int elementIndex, QV4::Object *object, QVector<int> *roles); - void set(int elementIndex, QV4::Object *object); + void set(int elementIndex, QV4::Object *object, SetElement reason = SetElement::IsCurrentlyUpdated); int append(QV4::Object *object); void insert(int elementIndex, QV4::Object *object); diff --git a/src/qmltest/quicktestutil.cpp b/src/qmltest/quicktestutil.cpp index 682c56400e..d9e6a2fba5 100644 --- a/src/qmltest/quicktestutil.cpp +++ b/src/qmltest/quicktestutil.cpp @@ -63,7 +63,7 @@ int QuickTestUtil::dragThreshold() const QJSValue QuickTestUtil::typeName(const QVariant &v) const { - QString name(v.typeName()); + QString name = QString::fromUtf8(v.typeName()); if (v.canConvert<QObject*>()) { QQmlType type; const QMetaObject *mo = v.value<QObject*>()->metaObject(); diff --git a/src/quick/doc/qtquick.qdocconf b/src/quick/doc/qtquick.qdocconf index 6a4300c1bd..91458527dd 100644 --- a/src/quick/doc/qtquick.qdocconf +++ b/src/quick/doc/qtquick.qdocconf @@ -38,7 +38,7 @@ qhp.QtQuick.subprojects.examples.selectors = fake:example tagfile = ../../../doc/qtquick/qtquick.tags -depends += qtcore qtqml qtqmltest qtgui qtlinguist qtquickcontrols1 qtquickcontrols qtdoc qtquickdialogs qtsensors qtwidgets qmake qtmultimedia qtgraphicaleffects qtsql qtxmlpatterns +depends += qtcore qtqml qtqmltest qtgui qtlinguist qtquickcontrols qtquickcontrols1 qtdoc qtquickdialogs qtsensors qtwidgets qmake qtmultimedia qtgraphicaleffects qtsql qtxmlpatterns headerdirs += ..\ ../../quick \ diff --git a/src/quick/items/qquickimage.cpp b/src/quick/items/qquickimage.cpp index c7e7ccea55..840cfe15da 100644 --- a/src/quick/items/qquickimage.cpp +++ b/src/quick/items/qquickimage.cpp @@ -676,13 +676,13 @@ QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) int xOffset = 0; if (d->hAlign == QQuickImage::AlignHCenter) - xOffset = qCeil((width() - pixWidth) / 2.); + xOffset = (width() - pixWidth) / 2; else if (d->hAlign == QQuickImage::AlignRight) xOffset = qCeil(width() - pixWidth); int yOffset = 0; if (d->vAlign == QQuickImage::AlignVCenter) - yOffset = qCeil((height() - pixHeight) / 2.); + yOffset = (height() - pixHeight) / 2; else if (d->vAlign == QQuickImage::AlignBottom) yOffset = qCeil(height() - pixHeight); diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp index e1af65c986..fccd467274 100644 --- a/src/quick/items/qquickitemview.cpp +++ b/src/quick/items/qquickitemview.cpp @@ -587,6 +587,7 @@ void QQuickItemView::setHighlightRangeMode(HighlightRangeMode mode) d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd; if (isComponentComplete()) { d->updateViewport(); + d->moveReason = QQuickItemViewPrivate::Other; d->fixupPosition(); } emit highlightRangeModeChanged(); @@ -609,8 +610,10 @@ void QQuickItemView::setPreferredHighlightBegin(qreal start) d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd; if (isComponentComplete()) { d->updateViewport(); - if (!isMoving() && !isFlicking()) + if (!isMoving() && !isFlicking()) { + d->moveReason = QQuickItemViewPrivate::Other; d->fixupPosition(); + } } emit preferredHighlightBeginChanged(); } @@ -624,8 +627,10 @@ void QQuickItemView::resetPreferredHighlightBegin() d->highlightRangeStart = 0; if (isComponentComplete()) { d->updateViewport(); - if (!isMoving() && !isFlicking()) + if (!isMoving() && !isFlicking()) { + d->moveReason = QQuickItemViewPrivate::Other; d->fixupPosition(); + } } emit preferredHighlightBeginChanged(); } @@ -646,8 +651,10 @@ void QQuickItemView::setPreferredHighlightEnd(qreal end) d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd; if (isComponentComplete()) { d->updateViewport(); - if (!isMoving() && !isFlicking()) + if (!isMoving() && !isFlicking()) { + d->moveReason = QQuickItemViewPrivate::Other; d->fixupPosition(); + } } emit preferredHighlightEndChanged(); } @@ -661,8 +668,10 @@ void QQuickItemView::resetPreferredHighlightEnd() d->highlightRangeEnd = 0; if (isComponentComplete()) { d->updateViewport(); - if (!isMoving() && !isFlicking()) + if (!isMoving() && !isFlicking()) { + d->moveReason = QQuickItemViewPrivate::Other; d->fixupPosition(); + } } emit preferredHighlightEndChanged(); } diff --git a/src/quick/items/qquickrendercontrol.cpp b/src/quick/items/qquickrendercontrol.cpp index addd52cb1d..9f9777f199 100644 --- a/src/quick/items/qquickrendercontrol.cpp +++ b/src/quick/items/qquickrendercontrol.cpp @@ -275,6 +275,7 @@ void QQuickRenderControl::polishItems() if (!d->window) return; cd->polishItems(); + emit d->window->afterAnimating(); } /*! diff --git a/src/quick/items/qquickstateoperations.cpp b/src/quick/items/qquickstateoperations.cpp index 31d1c91649..07767d377d 100644 --- a/src/quick/items/qquickstateoperations.cpp +++ b/src/quick/items/qquickstateoperations.cpp @@ -44,6 +44,7 @@ #include <QtQml/qqmlinfo.h> #include <QtCore/qmath.h> +#include <memory> QT_BEGIN_NAMESPACE @@ -51,15 +52,17 @@ class QQuickParentChangePrivate : public QQuickStateOperationPrivate { Q_DECLARE_PUBLIC(QQuickParentChange) public: - QQuickParentChangePrivate() : target(nullptr), parent(nullptr), origParent(nullptr), origStackBefore(nullptr), - rewindParent(nullptr), rewindStackBefore(nullptr) {} - - QQuickItem *target; + QQuickItem *target = nullptr; QPointer<QQuickItem> parent; - QPointer<QQuickItem> origParent; - QPointer<QQuickItem> origStackBefore; - QQuickItem *rewindParent; - QQuickItem *rewindStackBefore; + + struct StateSnapshot { + QPointer<QQuickItem> parent; + QPointer<QQuickItem> stackBefore; + qreal x = 0, y = 0, width = 0, height = 0, scale = 0, rotation = 0; + }; + + std::unique_ptr<StateSnapshot> orig; + std::unique_ptr<StateSnapshot> rewind; QQmlNullableValue<QQmlScriptString> xString; QQmlNullableValue<QQmlScriptString> yString; @@ -68,10 +71,11 @@ public: QQmlNullableValue<QQmlScriptString> scaleString; QQmlNullableValue<QQmlScriptString> rotationString; - void doChange(QQuickItem *targetParent, QQuickItem *stackBefore = nullptr); + void doChange(QQuickItem *targetParent); + void reverseRewindHelper(const std::unique_ptr<StateSnapshot> &snapshot); }; -void QQuickParentChangePrivate::doChange(QQuickItem *targetParent, QQuickItem *stackBefore) +void QQuickParentChangePrivate::doChange(QQuickItem *targetParent) { if (targetParent && target && target->parentItem()) { Q_Q(QQuickParentChange); @@ -137,11 +141,6 @@ void QQuickParentChangePrivate::doChange(QQuickItem *targetParent, QQuickItem *s } else if (target) { target->setParentItem(targetParent); } - - //restore the original stack position. - //### if stackBefore has also been reparented this won't work - if (target && stackBefore) - target->stackBefore(stackBefore); } /*! @@ -305,7 +304,7 @@ bool QQuickParentChange::rotationIsSet() const QQuickItem *QQuickParentChange::originalParent() const { Q_D(const QQuickParentChange); - return d->origParent; + return d->orig ? d->orig->parent : nullptr; } /*! @@ -473,21 +472,11 @@ void QQuickParentChange::saveOriginals() { Q_D(QQuickParentChange); saveCurrentValues(); - d->origParent = d->rewindParent; - d->origStackBefore = d->rewindStackBefore; + if (!d->orig) + d->orig.reset(new QQuickParentChangePrivate::StateSnapshot); + *d->orig = *d->rewind; } -/*void QQuickParentChange::copyOriginals(QQuickStateActionEvent *other) -{ - Q_D(QQuickParentChange); - QQuickParentChange *pc = static_cast<QQuickParentChange*>(other); - - d->origParent = pc->d_func()->rewindParent; - d->origStackBefore = pc->d_func()->rewindStackBefore; - - saveCurrentValues(); -}*/ - void QQuickParentChange::execute() { Q_D(QQuickParentChange); @@ -499,10 +488,26 @@ bool QQuickParentChange::isReversable() return true; } +void QQuickParentChangePrivate::reverseRewindHelper(const std::unique_ptr<QQuickParentChangePrivate::StateSnapshot> &snapshot) +{ + if (!target || !snapshot) + return; + target->setX(snapshot->x); + target->setY(snapshot->y); + target->setScale(snapshot->scale); + target->setWidth(snapshot->width); + target->setHeight(snapshot->height); + target->setRotation(snapshot->rotation); + target->setParentItem(snapshot->parent); + if (snapshot->stackBefore) + target->stackBefore(snapshot->stackBefore); +} + + void QQuickParentChange::reverse() { Q_D(QQuickParentChange); - d->doChange(d->origParent, d->origStackBefore); + d->reverseRewindHelper(d->orig); } QQuickStateActionEvent::EventType QQuickParentChange::type() const @@ -524,21 +529,28 @@ void QQuickParentChange::saveCurrentValues() { Q_D(QQuickParentChange); if (!d->target) { - d->rewindParent = nullptr; - d->rewindStackBefore = nullptr; + d->rewind = nullptr; return; } - d->rewindParent = d->target->parentItem(); - d->rewindStackBefore = nullptr; + d->rewind.reset(new QQuickParentChangePrivate::StateSnapshot); + d->rewind->x = d->target->x(); + d->rewind->y = d->target->y(); + d->rewind->scale = d->target->scale(); + d->rewind->width = d->target->width(); + d->rewind->height = d->target->height(); + d->rewind->rotation = d->target->rotation(); + + d->rewind->parent = d->target->parentItem(); + d->rewind->stackBefore = nullptr; - if (!d->rewindParent) + if (!d->rewind->parent) return; - QList<QQuickItem *> children = d->rewindParent->childItems(); + QList<QQuickItem *> children = d->rewind->parent->childItems(); for (int ii = 0; ii < children.count() - 1; ++ii) { if (children.at(ii) == d->target) { - d->rewindStackBefore = children.at(ii + 1); + d->rewind->stackBefore = children.at(ii + 1); break; } } @@ -547,7 +559,8 @@ void QQuickParentChange::saveCurrentValues() void QQuickParentChange::rewind() { Q_D(QQuickParentChange); - d->doChange(d->rewindParent, d->rewindStackBefore); + d->reverseRewindHelper(d->rewind); + d->rewind.reset(); } /*! diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarespritenode.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarespritenode.cpp index d4e5e98d68..17e8bdc2f9 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarespritenode.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarespritenode.cpp @@ -49,6 +49,11 @@ QSGSoftwareSpriteNode::QSGSoftwareSpriteNode() setGeometry((QSGGeometry*)1); } +QSGSoftwareSpriteNode::~QSGSoftwareSpriteNode() +{ + delete m_texture; +} + void QSGSoftwareSpriteNode::setTexture(QSGTexture *texture) { m_texture = qobject_cast<QSGSoftwarePixmapTexture*>(texture); diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarespritenode_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarespritenode_p.h index 577a30c051..4015537395 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarespritenode_p.h +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarespritenode_p.h @@ -64,6 +64,7 @@ class QSGSoftwareSpriteNode : public QSGSpriteNode { public: QSGSoftwareSpriteNode(); + ~QSGSoftwareSpriteNode() override; void setTexture(QSGTexture *texture) override; void setTime(float time) override; @@ -81,7 +82,7 @@ public: private: - QSGSoftwarePixmapTexture *m_texture; + QSGSoftwarePixmapTexture *m_texture = nullptr; float m_time; QPoint m_sourceA; QPoint m_sourceB; diff --git a/tests/auto/qml/qqmlecmascript/data/checkDate-October.qml b/tests/auto/qml/qqmlecmascript/data/checkDate-October.qml new file mode 100644 index 0000000000..6686831e1c --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/checkDate-October.qml @@ -0,0 +1,12 @@ +import Qt.test 1.0 +import QtQuick 2.0 + +MyTypeObject { + Component.onCompleted: { + // QTBUG-78996 + dateProperty = new Date(2019, 9, 3) + boolProperty = (dateProperty.getFullYear() == 2019 + && dateProperty.getMonth() == 9 + && dateProperty.getDate() == 3) + } +} diff --git a/tests/auto/qml/qqmlecmascript/data/checkDate-denormal-Feb.qml b/tests/auto/qml/qqmlecmascript/data/checkDate-denormal-Feb.qml new file mode 100644 index 0000000000..29ec40ffbd --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/checkDate-denormal-Feb.qml @@ -0,0 +1,11 @@ +import Qt.test 1.0 +import QtQuick 2.0 + +MyTypeObject { + Component.onCompleted: { + dateProperty = new Date(2019, 2, 0) // Feb 28th + boolProperty = (dateProperty.getFullYear() == 2019 + && dateProperty.getMonth() == 1 + && dateProperty.getDate() == 28) + } +} diff --git a/tests/auto/qml/qqmlecmascript/data/checkDate-denormal-March.qml b/tests/auto/qml/qqmlecmascript/data/checkDate-denormal-March.qml new file mode 100644 index 0000000000..7fc8bf43bd --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/checkDate-denormal-March.qml @@ -0,0 +1,11 @@ +import Qt.test 1.0 +import QtQuick 2.0 + +MyTypeObject { + Component.onCompleted: { + dateProperty = new Date(2019, 1, 29) // March 1st + boolProperty = (dateProperty.getFullYear() == 2019 + && dateProperty.getMonth() == 2 + && dateProperty.getDate() == 1) + } +} diff --git a/tests/auto/qml/qqmlecmascript/data/checkDate-denormal-leap.qml b/tests/auto/qml/qqmlecmascript/data/checkDate-denormal-leap.qml new file mode 100644 index 0000000000..6dd84810e6 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/checkDate-denormal-leap.qml @@ -0,0 +1,11 @@ +import Qt.test 1.0 +import QtQuick 2.0 + +MyTypeObject { + Component.onCompleted: { + dateProperty = new Date(2020, 2, 0) // Feb 29th + boolProperty = (dateProperty.getFullYear() == 2020 + && dateProperty.getMonth() == 1 + && dateProperty.getDate() == 29) + } +} diff --git a/tests/auto/qml/qqmlecmascript/data/checkDate-denormal-wrap.qml b/tests/auto/qml/qqmlecmascript/data/checkDate-denormal-wrap.qml new file mode 100644 index 0000000000..ddb79727ef --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/checkDate-denormal-wrap.qml @@ -0,0 +1,11 @@ +import Qt.test 1.0 +import QtQuick 2.0 + +MyTypeObject { + Component.onCompleted: { + dateProperty = new Date(2017, 40, -61) // 2020, Feb 29th + boolProperty = (dateProperty.getFullYear() == 2020 + && dateProperty.getMonth() == 1 + && dateProperty.getDate() == 29) + } +} diff --git a/tests/auto/qml/qqmlecmascript/data/checkDate-denormal-year.qml b/tests/auto/qml/qqmlecmascript/data/checkDate-denormal-year.qml new file mode 100644 index 0000000000..90514c39c8 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/checkDate-denormal-year.qml @@ -0,0 +1,11 @@ +import Qt.test 1.0 +import QtQuick 2.0 + +MyTypeObject { + Component.onCompleted: { + dateProperty = new Date(2019, 12, 0) // Dec 31 + boolProperty = (dateProperty.getFullYear() == 2019 + && dateProperty.getMonth() == 11 + && dateProperty.getDate() == 31) + } +} diff --git a/tests/auto/qml/qqmlecmascript/data/checkDateTime-October.qml b/tests/auto/qml/qqmlecmascript/data/checkDateTime-October.qml new file mode 100644 index 0000000000..c97076f887 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/checkDateTime-October.qml @@ -0,0 +1,16 @@ +import Qt.test 1.0 +import QtQuick 2.0 + +MyTypeObject { + Component.onCompleted: { + // QTBUG-78996 + dateTimeProperty = new Date(2019, 9, 3, 12) + boolProperty = (dateTimeProperty.getFullYear() == 2019 + && dateTimeProperty.getMonth() == 9 + && dateTimeProperty.getDate() == 3 + && dateTimeProperty.getHours() == 12 + && dateTimeProperty.getMinutes() == 0 + && dateTimeProperty.getSeconds() == 0 + && dateTimeProperty.getMilliseconds() == 0) + } +} diff --git a/tests/auto/qml/qqmlecmascript/data/checkDateTime-denormal-March.qml b/tests/auto/qml/qqmlecmascript/data/checkDateTime-denormal-March.qml new file mode 100644 index 0000000000..2b6b9af3e1 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/checkDateTime-denormal-March.qml @@ -0,0 +1,15 @@ +import Qt.test 1.0 +import QtQuick 2.0 + +MyTypeObject { + Component.onCompleted: { + dateTimeProperty = new Date(2019, 1, 28, 23, 59, 59, 1001) // 2019-3-1 0:0:0.001 + boolProperty = (dateTimeProperty.getFullYear() == 2019 + && dateTimeProperty.getMonth() == 2 + && dateTimeProperty.getDate() == 1 + && dateTimeProperty.getHours() == 0 + && dateTimeProperty.getMinutes() == 0 + && dateTimeProperty.getSeconds() == 0 + && dateTimeProperty.getMilliseconds() == 1) + } +} diff --git a/tests/auto/qml/qqmlecmascript/data/checkDateTime-denormal-hours.qml b/tests/auto/qml/qqmlecmascript/data/checkDateTime-denormal-hours.qml new file mode 100644 index 0000000000..7d018e2904 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/checkDateTime-denormal-hours.qml @@ -0,0 +1,15 @@ +import Qt.test 1.0 +import QtQuick 2.0 + +MyTypeObject { + Component.onCompleted: { + dateTimeProperty = new Date(2019, 11, 31, 1440) // 2020-2-29 0:0:0 + boolProperty = (dateTimeProperty.getFullYear() == 2020 + && dateTimeProperty.getMonth() == 1 + && dateTimeProperty.getDate() == 29 + && dateTimeProperty.getHours() == 0 + && dateTimeProperty.getMinutes() == 0 + && dateTimeProperty.getSeconds() == 0 + && dateTimeProperty.getMilliseconds() == 0) + } +} diff --git a/tests/auto/qml/qqmlecmascript/data/checkDateTime-denormal-leap.qml b/tests/auto/qml/qqmlecmascript/data/checkDateTime-denormal-leap.qml new file mode 100644 index 0000000000..0a7687c669 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/checkDateTime-denormal-leap.qml @@ -0,0 +1,15 @@ +import Qt.test 1.0 +import QtQuick 2.0 + +MyTypeObject { + Component.onCompleted: { + dateTimeProperty = new Date(2020, 2, 1, 0, 0, 0, -1) // 2020-2-29 23:59:59.999 + boolProperty = (dateTimeProperty.getFullYear() == 2020 + && dateTimeProperty.getMonth() == 1 + && dateTimeProperty.getDate() == 29 + && dateTimeProperty.getHours() == 23 + && dateTimeProperty.getMinutes() == 59 + && dateTimeProperty.getSeconds() == 59 + && dateTimeProperty.getMilliseconds() == 999) + } +} diff --git a/tests/auto/qml/qqmlecmascript/data/checkDateTime-denormal-minutes.qml b/tests/auto/qml/qqmlecmascript/data/checkDateTime-denormal-minutes.qml new file mode 100644 index 0000000000..738d603b4b --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/checkDateTime-denormal-minutes.qml @@ -0,0 +1,15 @@ +import Qt.test 1.0 +import QtQuick 2.0 + +MyTypeObject { + Component.onCompleted: { + dateTimeProperty = new Date(2020, 1, 28, 0, 1440) // 2020-2-29 0:0:0 + boolProperty = (dateTimeProperty.getFullYear() == 2020 + && dateTimeProperty.getMonth() == 1 + && dateTimeProperty.getDate() == 29 + && dateTimeProperty.getHours() == 0 + && dateTimeProperty.getMinutes() == 0 + && dateTimeProperty.getSeconds() == 0 + && dateTimeProperty.getMilliseconds() == 0) + } +} diff --git a/tests/auto/qml/qqmlecmascript/data/checkDateTime-denormal-seconds.qml b/tests/auto/qml/qqmlecmascript/data/checkDateTime-denormal-seconds.qml new file mode 100644 index 0000000000..d48534f0d0 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/checkDateTime-denormal-seconds.qml @@ -0,0 +1,15 @@ +import Qt.test 1.0 +import QtQuick 2.0 + +MyTypeObject { + Component.onCompleted: { + dateTimeProperty = new Date(2020, 1, 28, 23, 0, 3600) // 2020-2-29 0:0:0 + boolProperty = (dateTimeProperty.getFullYear() == 2020 + && dateTimeProperty.getMonth() == 1 + && dateTimeProperty.getDate() == 29 + && dateTimeProperty.getHours() == 0 + && dateTimeProperty.getMinutes() == 0 + && dateTimeProperty.getSeconds() == 0 + && dateTimeProperty.getMilliseconds() == 0) + } +} diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index 160546fc64..f4de83eb87 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -79,6 +79,10 @@ private slots: void assignDate(); void exportDate_data(); void exportDate(); + void checkDate_data(); + void checkDate(); + void checkDateTime_data(); + void checkDateTime(); void idShortcutInvalidates(); void boolPropertiesEvaluateAsBool(); void methods(); @@ -568,6 +572,82 @@ void tst_qqmlecmascript::exportDate() QCOMPARE(object->boolProperty(), true); } +void tst_qqmlecmascript::checkDate_data() +{ + QTest::addColumn<QUrl>("source"); + QTest::addColumn<QDate>("date"); + // NB: JavaScript month-indices are Jan = 0 to Dec = 11; QDate's are Jan = 1 to Dec = 12. + QTest::newRow("denormal-March") + << testFileUrl("checkDate-denormal-March.qml") + << QDate(2019, 3, 1); + QTest::newRow("denormal-leap") + << testFileUrl("checkDate-denormal-leap.qml") + << QDate(2020, 2, 29); + QTest::newRow("denormal-Feb") + << testFileUrl("checkDate-denormal-Feb.qml") + << QDate(2019, 2, 28); + QTest::newRow("denormal-year") + << testFileUrl("checkDate-denormal-year.qml") + << QDate(2019, 12, 31); + QTest::newRow("denormal-wrap") + << testFileUrl("checkDate-denormal-wrap.qml") + << QDate(2020, 2, 29); + QTest::newRow("October") + << testFileUrl("checkDate-October.qml") + << QDate(2019, 10, 3); +} + +void tst_qqmlecmascript::checkDate() +{ + QFETCH(const QUrl, source); + QFETCH(const QDate, date); + QQmlEngine e; + QQmlComponent component(&e, source); + QScopedPointer<QObject> obj(component.create()); + MyTypeObject *object = qobject_cast<MyTypeObject *>(obj.data()); + QVERIFY(object != nullptr); + QCOMPARE(object->dateProperty(), date); + QVERIFY(object->boolProperty()); +} + +void tst_qqmlecmascript::checkDateTime_data() +{ + QTest::addColumn<QUrl>("source"); + QTest::addColumn<QDateTime>("when"); + // NB: JavaScript month-indices are Jan = 0 to Dec = 11; QDate's are Jan = 1 to Dec = 12. + QTest::newRow("denormal-March") + << testFileUrl("checkDateTime-denormal-March.qml") + << QDateTime(QDate(2019, 3, 1), QTime(0, 0, 0, 1), Qt::LocalTime); + QTest::newRow("denormal-leap") + << testFileUrl("checkDateTime-denormal-leap.qml") + << QDateTime(QDate(2020, 2, 29), QTime(23, 59, 59, 999), Qt::LocalTime); + QTest::newRow("denormal-hours") + << testFileUrl("checkDateTime-denormal-hours.qml") + << QDateTime(QDate(2020, 2, 29), QTime(0, 0), Qt::LocalTime); + QTest::newRow("denormal-minutes") + << testFileUrl("checkDateTime-denormal-minutes.qml") + << QDateTime(QDate(2020, 2, 29), QTime(0, 0), Qt::LocalTime); + QTest::newRow("denormal-seconds") + << testFileUrl("checkDateTime-denormal-seconds.qml") + << QDateTime(QDate(2020, 2, 29), QTime(0, 0), Qt::LocalTime); + QTest::newRow("October") + << testFileUrl("checkDateTime-October.qml") + << QDateTime(QDate(2019, 10, 3), QTime(12, 0), Qt::LocalTime); +} + +void tst_qqmlecmascript::checkDateTime() +{ + QFETCH(const QUrl, source); + QFETCH(const QDateTime, when); + QQmlEngine e; + QQmlComponent component(&e, source); + QScopedPointer<QObject> obj(component.create()); + MyTypeObject *object = qobject_cast<MyTypeObject *>(obj.data()); + QVERIFY(object != nullptr); + QCOMPARE(object->dateTimeProperty(), when); + QVERIFY(object->boolProperty()); +} + void tst_qqmlecmascript::idShortcutInvalidates() { QQmlEngine engine; diff --git a/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp b/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp index b47062ee94..75a932b6f4 100644 --- a/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp +++ b/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp @@ -129,6 +129,7 @@ private slots: void crash_append_empty_array(); void dynamic_roles_crash_QTBUG_38907(); void nestedListModelIteration(); + void undefinedAppendShouldCauseError(); }; bool tst_qqmllistmodel::compareVariantList(const QVariantList &testList, QVariant object) @@ -1694,6 +1695,35 @@ void tst_qqmllistmodel::nestedListModelIteration() QScopedPointer<QObject>(component.create()); } +// QTBUG-63569 +void tst_qqmllistmodel::undefinedAppendShouldCauseError() +{ + QQmlEngine engine; + QQmlComponent component(&engine); + component.setData( + R"(import QtQuick 2.5 + Item { + width: 640 + height: 480 + ListModel { + id : model + } + Component.onCompleted: { + var tempData = { + faulty: undefined + } + model.insert(0, tempData) + tempData.faulty = null + model.insert(0, tempData) + } + })", + QUrl()); + QTest::ignoreMessage(QtMsgType::QtWarningMsg, "<Unknown File>: faulty is undefined. Adding an object with a undefined member does not create a role for it."); + QTest::ignoreMessage(QtMsgType::QtWarningMsg, "<Unknown File>: faulty is null. Adding an object with a null member does not create a role for it."); + QScopedPointer<QObject>(component.create()); +} + + QTEST_MAIN(tst_qqmllistmodel) #include "tst_qqmllistmodel.moc" diff --git a/tests/auto/qml/qv4identifiertable/tst_qv4identifiertable.cpp b/tests/auto/qml/qv4identifiertable/tst_qv4identifiertable.cpp index 308fba9049..157d0f2a62 100644 --- a/tests/auto/qml/qv4identifiertable/tst_qv4identifiertable.cpp +++ b/tests/auto/qml/qv4identifiertable/tst_qv4identifiertable.cpp @@ -1,5 +1,6 @@ /**************************************************************************** ** +** Copyright (C) 2019 The Qt Company Ltd. ** Copyright (C) 2016 basysKom GmbH. ** Contact: https://www.qt.io/licensing/ ** @@ -110,8 +111,8 @@ void tst_qv4identifiertable::sweepCenterEntryInBucket() table.asPropertyKey(entry2); table.asPropertyKey(entry3); - QCOMPARE(table.size, 3); - QCOMPARE(table.alloc, 5); + QCOMPARE(table.size, 3u); + QCOMPARE(table.alloc, 5u); QCOMPARE(table.entriesByHash[0], entry1); QCOMPARE(table.entriesByHash[1], entry2); @@ -153,8 +154,8 @@ void tst_qv4identifiertable::sweepLastEntryInBucket() table.asPropertyKey(entry2); table.asPropertyKey(entry3); - QCOMPARE(table.size, 3); - QCOMPARE(table.alloc, 5); + QCOMPARE(table.size, 3u); + QCOMPARE(table.alloc, 5u); QCOMPARE(table.entriesByHash[0], entry1); QCOMPARE(table.entriesByHash[1], entry2); @@ -193,8 +194,8 @@ void tst_qv4identifiertable::sweepFirstEntryInSameBucketWithDifferingHash() table.asPropertyKey(entry1); table.asPropertyKey(entry2); - QCOMPARE(table.size, 2); - QCOMPARE(table.alloc, 5); + QCOMPARE(table.size, 2u); + QCOMPARE(table.alloc, 5u); QCOMPARE(table.entriesByHash[0], entry1); QCOMPARE(table.entriesByHash[1], entry2); @@ -231,8 +232,8 @@ void tst_qv4identifiertable::dontSweepAcrossBucketBoundaries() table.asPropertyKey(entry1); table.asPropertyKey(entry2); - QCOMPARE(table.size, 2); - QCOMPARE(table.alloc, 5); + QCOMPARE(table.size, 2u); + QCOMPARE(table.alloc, 5u); QCOMPARE(table.entriesByHash[0], entry1); QCOMPARE(table.entriesByHash[1], entry2); @@ -279,8 +280,8 @@ void tst_qv4identifiertable::sweepAcrossBucketBoundariesIfFirstBucketFull() table.asPropertyKey(entry3); table.asPropertyKey(entry4); - QCOMPARE(table.size, 4); - QCOMPARE(table.alloc, 11); + QCOMPARE(table.size, 4u); + QCOMPARE(table.alloc, 11u); QCOMPARE(table.entriesByHash[0], entry1); QCOMPARE(table.entriesByHash[1], entry2); @@ -336,8 +337,8 @@ void tst_qv4identifiertable::sweepBucketGap() table.asPropertyKey(entry3); table.asPropertyKey(entry4); - QCOMPARE(table.size, 4); - QCOMPARE(table.alloc, 11); + QCOMPARE(table.size, 4u); + QCOMPARE(table.alloc, 11u); QCOMPARE(table.entriesByHash[0], entry1); QCOMPARE(table.entriesByHash[1], entry2); diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp index 3ddfe1b923..fb5ae168e8 100644 --- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp +++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp @@ -1946,6 +1946,31 @@ void tst_QQuickListView::enforceRange() QTRY_COMPARE(listview->currentIndex(), 6); + // Test for [QTBUG-77418] { + // explicit set current index + listview->setCurrentIndex(5); + QTRY_COMPARE(listview->contentY(), 0); + + // then check if contentY changes if the highlight range is changed + listview->setPreferredHighlightBegin(80); + listview->setPreferredHighlightEnd(80); + QTRY_COMPARE(listview->contentY(), 20); + + // verify that current index does not change with no highlight + listview->setHighlightRangeMode(QQuickListView::NoHighlightRange); + listview->setContentY(100); + QTRY_COMPARE(listview->currentIndex(), 5); + + // explicit set current index, contentY should not change now + listview->setCurrentIndex(6); + QTRY_COMPARE(listview->contentY(), 100); + QTest::qWait(50); // This was needed in order to reproduce a failure for the following test + + // verify that contentY changes if we turn on highlight again + listview->setHighlightRangeMode(QQuickListView::StrictlyEnforceRange); + QTRY_COMPARE(listview->contentY(), 40); + // } Test for [QTBUG-77418] + // change model QaimModel model2; for (int i = 0; i < 5; i++) diff --git a/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp b/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp index 48d6c257a6..a8e847a5c7 100644 --- a/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp +++ b/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp @@ -1616,16 +1616,55 @@ void tst_QQuickPathView::flickNClick() // QTBUG-77173 QQuickPathView *pathview = qobject_cast<QQuickPathView*>(window->rootObject()); QVERIFY(pathview != nullptr); + QSignalSpy movingChangedSpy(pathview, SIGNAL(movingChanged())); + QSignalSpy draggingSpy(pathview, SIGNAL(draggingChanged())); + QSignalSpy dragStartedSpy(pathview, SIGNAL(dragStarted())); + QSignalSpy dragEndedSpy(pathview, SIGNAL(dragEnded())); + QSignalSpy currentIndexSpy(pathview, SIGNAL(currentIndexChanged())); + QSignalSpy moveStartedSpy(pathview, SIGNAL(movementStarted())); + QSignalSpy moveEndedSpy(pathview, SIGNAL(movementEnded())); + QSignalSpy flickingSpy(pathview, SIGNAL(flickingChanged())); + QSignalSpy flickStartedSpy(pathview, SIGNAL(flickStarted())); + QSignalSpy flickEndedSpy(pathview, SIGNAL(flickEnded())); for (int duration = 100; duration > 0; duration -= 20) { + movingChangedSpy.clear(); + draggingSpy.clear(); + dragStartedSpy.clear(); + dragEndedSpy.clear(); + currentIndexSpy.clear(); + moveStartedSpy.clear(); + moveEndedSpy.clear(); + flickingSpy.clear(); + flickStartedSpy.clear(); + flickEndedSpy.clear(); // Dragging the child mouse area should animate the PathView (MA has no drag target) flick(window.data(), QPoint(200,200), QPoint(400,200), duration); QVERIFY(pathview->isMoving()); + QCOMPARE(movingChangedSpy.count(), 1); + QCOMPARE(draggingSpy.count(), 2); + QCOMPARE(dragStartedSpy.count(), 1); + QCOMPARE(dragEndedSpy.count(), 1); + QVERIFY(currentIndexSpy.count() > 0); + QCOMPARE(moveStartedSpy.count(), 1); + QCOMPARE(moveEndedSpy.count(), 0); + QCOMPARE(flickingSpy.count(), 1); + QCOMPARE(flickStartedSpy.count(), 1); + QCOMPARE(flickEndedSpy.count(), 0); // Now while it's still moving, click it. // The PathView should stop at a position such that offset is a whole number. QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(200, 200)); QTRY_VERIFY(!pathview->isMoving()); + QCOMPARE(movingChangedSpy.count(), 2); // QTBUG-78926 + QCOMPARE(draggingSpy.count(), 2); + QCOMPARE(dragStartedSpy.count(), 1); + QCOMPARE(dragEndedSpy.count(), 1); + QCOMPARE(moveStartedSpy.count(), 1); + QCOMPARE(moveEndedSpy.count(), 1); + QCOMPARE(flickingSpy.count(), 2); + QCOMPARE(flickStartedSpy.count(), 1); + QCOMPARE(flickEndedSpy.count(), 1); QVERIFY(qFuzzyIsNull(pathview->offset() - int(pathview->offset()))); } } diff --git a/tests/auto/quick/qquickstates/data/parentChangeCorrectReversal.qml b/tests/auto/quick/qquickstates/data/parentChangeCorrectReversal.qml new file mode 100644 index 0000000000..3d38fa4046 --- /dev/null +++ b/tests/auto/quick/qquickstates/data/parentChangeCorrectReversal.qml @@ -0,0 +1,72 @@ +import QtQuick 2.10 +import QtQuick.Layouts 1.3 + +Item { + id: root + + visible: true + + width: 400 + height: 200 + property bool switchToRight: false + property alias stayingRectX: stayingRect.x + + RowLayout { + id: topLayout + + anchors.fill: parent + + Item { + Layout.fillWidth: true + Layout.fillHeight: true + + Rectangle { + id: leftRect + + width: parent.width*(2/3) + height: width + anchors.centerIn: parent + + color: "red" + + Rectangle { + id: stayingRect + + x: 70; y: 70 + width: 50; height: 50 + + color: "yellow" + } + } + } + + Item { + Layout.fillWidth: true + Layout.fillHeight: true + + Rectangle { + id: rightRect + + width: parent.height*(2/3) + height: width + anchors.centerIn: parent + + color: "green" + rotation: 45 + } + } + } + + states: State { + name: "switchToRight" + + ParentChange { + target: stayingRect + parent: rightRect + width: 70 + } + + } + + state: root.switchToRight ? "switchToRight" : "" +} diff --git a/tests/auto/quick/qquickstates/tst_qquickstates.cpp b/tests/auto/quick/qquickstates/tst_qquickstates.cpp index 1eb797f54f..d5fea3cb28 100644 --- a/tests/auto/quick/qquickstates/tst_qquickstates.cpp +++ b/tests/auto/quick/qquickstates/tst_qquickstates.cpp @@ -139,6 +139,7 @@ private slots: void revertListMemoryLeak(); void duplicateStateName(); void trivialWhen(); + void parentChangeCorrectReversal(); }; void tst_qquickstates::initTestCase() @@ -1675,6 +1676,22 @@ void tst_qquickstates::trivialWhen() QVERIFY(c.create()); } +void tst_qquickstates::parentChangeCorrectReversal() +{ + QQmlEngine engine; + QQmlComponent c(&engine, testFileUrl("parentChangeCorrectReversal.qml")); + QScopedPointer<QObject> root {c.create()}; + QVERIFY(root); + QQmlProperty stayingRectX(root.get(), "stayingRectX"); + qreal oldX = stayingRectX.read().toDouble(); + QQmlProperty switchToRight(root.get(), "switchToRight"); + switchToRight.write(true); + qreal newX = stayingRectX.read().toDouble(); + QVERIFY(newX != oldX); + switchToRight.write(false); + QCOMPARE(oldX, stayingRectX.read().toDouble()); +} + QTEST_MAIN(tst_qquickstates) |