diff options
Diffstat (limited to 'src/quick')
39 files changed, 610 insertions, 190 deletions
diff --git a/src/quick/accessible/qaccessiblequickitem.cpp b/src/quick/accessible/qaccessiblequickitem.cpp index 98e7663c96..b87203c3ef 100644 --- a/src/quick/accessible/qaccessiblequickitem.cpp +++ b/src/quick/accessible/qaccessiblequickitem.cpp @@ -382,6 +382,22 @@ QString QAccessibleQuickItem::text(QAccessible::Text textType) const return QString(); } +void QAccessibleQuickItem::setText(QAccessible::Text textType, const QString &text) +{ + if (role() != QAccessible::EditableText) + return; + if (textType != QAccessible::Value) + return; + + if (QTextDocument *doc = textDocument()) { + doc->setPlainText(text); + return; + } + auto textPropertyName = "text"; + if (object()->metaObject()->indexOfProperty(textPropertyName) >= 0) + object()->setProperty(textPropertyName, text); +} + void *QAccessibleQuickItem::interface_cast(QAccessible::InterfaceType t) { QAccessible::Role r = role(); diff --git a/src/quick/accessible/qaccessiblequickitem_p.h b/src/quick/accessible/qaccessiblequickitem_p.h index 5375d37bf0..931e995f0f 100644 --- a/src/quick/accessible/qaccessiblequickitem_p.h +++ b/src/quick/accessible/qaccessiblequickitem_p.h @@ -83,6 +83,7 @@ public: QAccessible::State state() const override; QAccessible::Role role() const override; QString text(QAccessible::Text) const override; + void setText(QAccessible::Text, const QString &text) override; bool isAccessible() const; diff --git a/src/quick/configure.json b/src/quick/configure.json index 70fe6d2129..4098db87aa 100644 --- a/src/quick/configure.json +++ b/src/quick/configure.json @@ -113,6 +113,7 @@ "label": "TableView item", "purpose": "Provides the TableView item.", "section": "Qt Quick", + "condition": "features.qml-table-model", "output": [ "privateFeature" ] diff --git a/src/quick/designer/qquickdesignercustomparserobject.cpp b/src/quick/designer/qquickdesignercustomparserobject.cpp index 50a8b6a25b..841aae5bc3 100644 --- a/src/quick/designer/qquickdesignercustomparserobject.cpp +++ b/src/quick/designer/qquickdesignercustomparserobject.cpp @@ -46,12 +46,12 @@ QQuickDesignerCustomParserObject::QQuickDesignerCustomParserObject() } -void QQuickDesignerCustomParser::verifyBindings(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &, const QList<const QV4::CompiledData::Binding *> &) +void QQuickDesignerCustomParser::verifyBindings(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &, const QList<const QV4::CompiledData::Binding *> &) { /* Nothing to do we accept anything */ } -void QQuickDesignerCustomParser::applyBindings(QObject *, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &, const QList<const QV4::CompiledData::Binding *> &) +void QQuickDesignerCustomParser::applyBindings(QObject *, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &, const QList<const QV4::CompiledData::Binding *> &) { /* Nothing to do we accept anything */ } diff --git a/src/quick/designer/qquickdesignercustomparserobject_p.h b/src/quick/designer/qquickdesignercustomparserobject_p.h index b38417d102..4da00ea841 100644 --- a/src/quick/designer/qquickdesignercustomparserobject_p.h +++ b/src/quick/designer/qquickdesignercustomparserobject_p.h @@ -70,8 +70,8 @@ public: QQuickDesignerCustomParser() : QQmlCustomParser(AcceptsAttachedProperties | AcceptsSignalHandlers) {} - void verifyBindings(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &props) override; - void applyBindings(QObject *obj, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings) override; + void verifyBindings(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &props) override; + void applyBindings(QObject *obj, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings) override; }; QT_END_NAMESPACE diff --git a/src/quick/doc/snippets/pointerHandlers/tapHandlerOnTapped.qml b/src/quick/doc/snippets/pointerHandlers/tapHandlerOnTapped.qml new file mode 100644 index 0000000000..f556c238da --- /dev/null +++ b/src/quick/doc/snippets/pointerHandlers/tapHandlerOnTapped.qml @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +//![0] +import QtQuick 2.12 + +Rectangle { + width: 100 + height: 100 + + TapHandler { + acceptedButtons: Qt.LeftButton | Qt.RightButton + onTapped: console.log("tapped", eventPoint.event.device.name, + "button", eventPoint.event.button, + "@", eventPoint.scenePosition) + } +} +//![0] diff --git a/src/quick/handlers/qquickdraghandler.cpp b/src/quick/handlers/qquickdraghandler.cpp index 22fe3df4d0..61b66beff4 100644 --- a/src/quick/handlers/qquickdraghandler.cpp +++ b/src/quick/handlers/qquickdraghandler.cpp @@ -114,8 +114,14 @@ void QQuickDragHandler::onGrabChanged(QQuickPointerHandler *grabber, QQuickEvent QQuickMultiPointHandler::onGrabChanged(grabber, transition, point); if (grabber == this && transition == QQuickEventPoint::GrabExclusive && target()) { // In case the grab got handed over from another grabber, we might not get the Press. - if (!m_pressedInsideTarget) { - if (target() != parentItem()) + + auto isDescendant = [](QQuickItem *parent, QQuickItem *target) { + return (target != parent) && !target->isAncestorOf(parent); + }; + if (m_snapMode == SnapAlways + || (m_snapMode == SnapIfPressedOutsideTarget && !m_pressedInsideTarget) + || (m_snapMode == SnapAuto && !m_pressedInsideTarget && isDescendant(parentItem(), target())) + ) { m_pressTargetPos = QPointF(target()->width(), target()->height()) / 2; } else if (m_pressTargetPos.isNull()) { m_pressTargetPos = targetCentroidPosition(); @@ -123,6 +129,33 @@ void QQuickDragHandler::onGrabChanged(QQuickPointerHandler *grabber, QQuickEvent } } +/*! + \qmlproperty enumeration QtQuick.DragHandler::snapMode + + This property holds the snap mode. + + The snap mode configures snapping of the \l target item's center to the event point. + + Possible values: + \value DragHandler.SnapNever Never snap + \value DragHandler.SnapAuto The \l target snaps if the event point was pressed outside of the \l target + item \e and the \l target is a descendant of \l parentItem (default) + \value DragHandler.SnapWhenPressedOutsideTarget The \l target snaps if the event point was pressed outside of the \l target + \value DragHandler.SnapAlways Always snap +*/ +QQuickDragHandler::SnapMode QQuickDragHandler::snapMode() const +{ + return m_snapMode; +} + +void QQuickDragHandler::setSnapMode(QQuickDragHandler::SnapMode mode) +{ + if (mode == m_snapMode) + return; + m_snapMode = mode; + emit snapModeChanged(); +} + void QQuickDragHandler::onActiveChanged() { QQuickMultiPointHandler::onActiveChanged(); diff --git a/src/quick/handlers/qquickdraghandler_p.h b/src/quick/handlers/qquickdraghandler_p.h index 748026488a..18c1fd841d 100644 --- a/src/quick/handlers/qquickdraghandler_p.h +++ b/src/quick/handlers/qquickdraghandler_p.h @@ -62,8 +62,17 @@ class Q_QUICK_PRIVATE_EXPORT QQuickDragHandler : public QQuickMultiPointHandler Q_PROPERTY(QQuickDragAxis * xAxis READ xAxis CONSTANT) Q_PROPERTY(QQuickDragAxis * yAxis READ yAxis CONSTANT) Q_PROPERTY(QVector2D translation READ translation NOTIFY translationChanged) + Q_PROPERTY(SnapMode snapMode READ snapMode WRITE setSnapMode NOTIFY snapModeChanged) public: + enum SnapMode { + NoSnap = 0, + SnapAuto, + SnapIfPressedOutsideTarget, + SnapAlways + }; + Q_ENUM(SnapMode) + explicit QQuickDragHandler(QQuickItem *parent = nullptr); void handlePointerEventImpl(QQuickPointerEvent *event) override; @@ -73,11 +82,14 @@ public: QVector2D translation() const { return m_translation; } void setTranslation(const QVector2D &trans); + QQuickDragHandler::SnapMode snapMode() const; + void setSnapMode(QQuickDragHandler::SnapMode mode); void enforceConstraints(); Q_SIGNALS: void translationChanged(); + void snapModeChanged(); protected: void onActiveChanged() override; @@ -97,6 +109,7 @@ private: QQuickDragAxis m_xAxis; QQuickDragAxis m_yAxis; + QQuickDragHandler::SnapMode m_snapMode = SnapAuto; bool m_pressedInsideTarget = false; friend class QQuickDragAxis; diff --git a/src/quick/handlers/qquicktaphandler.cpp b/src/quick/handlers/qquicktaphandler.cpp index 081645da71..40a4813527 100644 --- a/src/quick/handlers/qquicktaphandler.cpp +++ b/src/quick/handlers/qquicktaphandler.cpp @@ -381,35 +381,50 @@ void QQuickTapHandler::updateTimeHeld() */ /*! - \qmlsignal QtQuick::TapHandler::tapped + \qmlsignal QtQuick::TapHandler::tapped(EventPoint eventPoint) This signal is emitted each time the \c parent Item is tapped. That is, if you press and release a touchpoint or button within a time period less than \l longPressThreshold, while any movement does not exceed the drag threshold, then the \c tapped signal will be emitted at the time - of release. + of release. The \c eventPoint signal parameter contains information + from the release event about the point that was tapped: + + \snippet pointerHandlers/tapHandlerOnTapped.qml 0 + + \note At the time this signal is emitted, \l point has been reset + (all coordinates are \c 0). */ /*! - \qmlsignal QtQuick::TapHandler::singleTapped + \qmlsignal QtQuick::TapHandler::singleTapped(EventPoint eventPoint) \since 5.11 This signal is emitted when the \c parent Item is tapped once. After an amount of time greater than QStyleHints::mouseDoubleClickInterval, it can be tapped again; but if the time until the next tap is less, - \l tapCount will increase. + \l tapCount will increase. The \c eventPoint signal parameter contains + information from the release event about the point that was tapped. + + \note At the time this signal is emitted, \l point has been reset + (all coordinates are \c 0). */ /*! - \qmlsignal QtQuick::TapHandler::doubleTapped + \qmlsignal QtQuick::TapHandler::doubleTapped(EventPoint eventPoint) \since 5.11 This signal is emitted when the \c parent Item is tapped twice within a short span of time (QStyleHints::mouseDoubleClickInterval) and distance (QPlatformTheme::MouseDoubleClickDistance or QPlatformTheme::TouchDoubleTapDistance). This signal always occurs after - \l singleTapped, \l tapped, and \l tapCountChanged. + \l singleTapped, \l tapped, and \l tapCountChanged. The \c eventPoint + signal parameter contains information from the release event about the + point that was tapped. + + \note At the time this signal is emitted, \l point has been reset + (all coordinates are \c 0). */ /*! diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp index 58bc12a221..0f104a122f 100644 --- a/src/quick/items/context2d/qquickcontext2d.cpp +++ b/src/quick/items/context2d/qquickcontext2d.cpp @@ -473,7 +473,7 @@ static QFont qt_font_from_string(const QString& fontString, const QFont ¤t return newFont; } -class QQuickContext2DEngineData : public QV8Engine::Deletable +class QQuickContext2DEngineData : public QV4::ExecutionEngine::Deletable { public: QQuickContext2DEngineData(QV4::ExecutionEngine *engine); @@ -2000,7 +2000,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_miterLimit(const QV4::FunctionO \since QtQuick 2.11 Returns an array of qreals representing the dash pattern of the line. - \sa setLineDash() + \sa setLineDash(), lineDashOffset */ QV4::ReturnedValue QQuickJSContext2DPrototype::method_getLineDash(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int) { @@ -2022,7 +2022,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_getLineDash(const QV4::Fun /*! \qmlmethod QtQuick::Context2D::setLineDash(array pattern) \since QtQuick 2.11 - Sets the dash pattern to the given pattern + Sets the dash pattern to the given pattern. \a pattern a list of numbers that specifies distances to alternately draw a line and a gap. @@ -2041,7 +2041,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_getLineDash(const QV4::Fun \endcode \endtable - \sa setLineDash + \sa getLineDash(), lineDashOffset */ QV4::ReturnedValue QQuickJSContext2DPrototype::method_setLineDash(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc) { @@ -2083,8 +2083,10 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_setLineDash(const QV4::Fun \qmlproperty real QtQuick::Context2D::lineDashOffset \since QtQuick 2.11 - Holds the current line dash offset - The default line dash ofset value is 0 + Holds the current line dash offset. + The default line dash offset value is \c 0. + + \sa getLineDash(), setLineDash() */ QV4::ReturnedValue QQuickJSContext2D::method_get_lineDashOffset(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int) { diff --git a/src/quick/items/qquickaccessibleattached.cpp b/src/quick/items/qquickaccessibleattached.cpp index 0168c3160c..c150e4efa2 100644 --- a/src/quick/items/qquickaccessibleattached.cpp +++ b/src/quick/items/qquickaccessibleattached.cpp @@ -390,6 +390,49 @@ QQuickAccessibleAttached::~QQuickAccessibleAttached() { } +void QQuickAccessibleAttached::setRole(QAccessible::Role role) +{ + if (role != m_role) { + m_role = role; + Q_EMIT roleChanged(); + // There is no way to signify role changes at the moment. + // QAccessible::updateAccessibility(parent(), 0, QAccessible::); + + switch (role) { + case QAccessible::CheckBox: + case QAccessible::RadioButton: + if (!m_stateExplicitlySet.focusable) + m_state.focusable = true; + if (!m_stateExplicitlySet.checkable) + m_state.checkable = true; + break; + case QAccessible::Button: + case QAccessible::MenuItem: + case QAccessible::PageTab: + case QAccessible::SpinBox: + case QAccessible::ComboBox: + case QAccessible::Terminal: + case QAccessible::ScrollBar: + if (!m_stateExplicitlySet.focusable) + m_state.focusable = true; + break; + case QAccessible::EditableText: + if (!m_stateExplicitlySet.editable) + m_state.editable = true; + if (!m_stateExplicitlySet.focusable) + m_state.focusable = true; + break; + case QAccessible::StaticText: + if (!m_stateExplicitlySet.readOnly) { + m_state.readOnly = true; + } + break; + default: + break; + } + } +} + QQuickAccessibleAttached *QQuickAccessibleAttached::qmlAttachedProperties(QObject *obj) { return new QQuickAccessibleAttached(obj); diff --git a/src/quick/items/qquickaccessibleattached_p.h b/src/quick/items/qquickaccessibleattached_p.h index 215a1e5db6..f4194ef13d 100644 --- a/src/quick/items/qquickaccessibleattached_p.h +++ b/src/quick/items/qquickaccessibleattached_p.h @@ -69,6 +69,7 @@ QT_BEGIN_NAMESPACE bool P() const { return m_state.P ; } \ void set_ ## P(bool arg) \ { \ + m_stateExplicitlySet.P = true; \ if (m_state.P == arg) \ return; \ m_state.P = arg; \ @@ -111,35 +112,7 @@ public: ~QQuickAccessibleAttached(); QAccessible::Role role() const { return m_role; } - void setRole(QAccessible::Role role) - { - if (role != m_role) { - m_role = role; - Q_EMIT roleChanged(); - // There is no way to signify role changes at the moment. - // QAccessible::updateAccessibility(parent(), 0, QAccessible::); - - switch (role) { - case QAccessible::CheckBox: - case QAccessible::RadioButton: - m_state.focusable = true; - m_state.checkable = true; - break; - case QAccessible::Button: - case QAccessible::MenuItem: - case QAccessible::PageTab: - case QAccessible::EditableText: - case QAccessible::SpinBox: - case QAccessible::ComboBox: - case QAccessible::Terminal: - case QAccessible::ScrollBar: - m_state.focusable = true; - break; - default: - break; - } - } - } + void setRole(QAccessible::Role role); QString name() const { if (m_state.passwordEdit) return QString(); @@ -241,6 +214,7 @@ private: QAccessible::Role m_role; QAccessible::State m_state; + QAccessible::State m_stateExplicitlySet; QString m_name; QString m_description; diff --git a/src/quick/items/qquickopenglshadereffect.cpp b/src/quick/items/qquickopenglshadereffect.cpp index bc1f787b81..0cbabaa170 100644 --- a/src/quick/items/qquickopenglshadereffect.cpp +++ b/src/quick/items/qquickopenglshadereffect.cpp @@ -221,7 +221,7 @@ QQuickOpenGLShaderEffectCommon::~QQuickOpenGLShaderEffectCommon() clearSignalMappers(shaderType); } -void QQuickOpenGLShaderEffectCommon::disconnectPropertySignals(QQuickItem *item, Key::ShaderType shaderType) +void QQuickOpenGLShaderEffectCommon::disconnectPropertySignals(QObject *obj, Key::ShaderType shaderType) { for (int i = 0; i < uniformData[shaderType].size(); ++i) { if (signalMappers[shaderType].at(i) == 0) @@ -229,12 +229,11 @@ void QQuickOpenGLShaderEffectCommon::disconnectPropertySignals(QQuickItem *item, const UniformData &d = uniformData[shaderType].at(i); auto mapper = signalMappers[shaderType].at(i); void *a = mapper; - QObjectPrivate::disconnect(item, mapper->signalIndex(), &a); + QObjectPrivate::disconnect(obj, mapper->signalIndex(), &a); if (d.specialType == UniformData::Sampler || d.specialType == UniformData::SamplerExternal) { QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(d.value)); if (source) { - if (item->window()) - QQuickItemPrivate::get(source)->derefWindow(); + QQuickItemPrivate::get(source)->derefWindow(); QObject::disconnect(source, SIGNAL(destroyed(QObject*)), host, SLOT(sourceDestroyed(QObject*))); } } diff --git a/src/quick/items/qquickopenglshadereffect_p.h b/src/quick/items/qquickopenglshadereffect_p.h index 0c2adadc62..3087c1eb0b 100644 --- a/src/quick/items/qquickopenglshadereffect_p.h +++ b/src/quick/items/qquickopenglshadereffect_p.h @@ -89,7 +89,7 @@ struct Q_QUICK_PRIVATE_EXPORT QQuickOpenGLShaderEffectCommon ~QQuickOpenGLShaderEffectCommon(); - void disconnectPropertySignals(QQuickItem *item, Key::ShaderType shaderType); + void disconnectPropertySignals(QObject *item, Key::ShaderType shaderType); void connectPropertySignals(QQuickItem *item, const QMetaObject *itemMetaObject, Key::ShaderType shaderType); void updateParseLog(bool ignoreAttributes); void lookThroughShaderCode(QQuickItem *item, const QMetaObject *itemMetaObject, Key::ShaderType shaderType, const QByteArray &code); diff --git a/src/quick/items/qquickopenglshadereffectnode.cpp b/src/quick/items/qquickopenglshadereffectnode.cpp index f32b32491b..f96ebebcd6 100644 --- a/src/quick/items/qquickopenglshadereffectnode.cpp +++ b/src/quick/items/qquickopenglshadereffectnode.cpp @@ -477,11 +477,11 @@ void QQuickOpenGLShaderEffectMaterial::updateTextures() const } } -void QQuickOpenGLShaderEffectMaterial::invalidateTextureProvider(QSGTextureProvider *provider) +void QQuickOpenGLShaderEffectMaterial::invalidateTextureProvider(const QObject *provider) { for (int i = 0; i < textureProviders.size(); ++i) { if (provider == textureProviders.at(i)) - textureProviders[i] = 0; + textureProviders[i] = nullptr; } } @@ -505,10 +505,10 @@ void QQuickOpenGLShaderEffectNode::markDirtyTexture() Q_EMIT dirtyTexture(); } -void QQuickOpenGLShaderEffectNode::textureProviderDestroyed(QObject *object) +void QQuickOpenGLShaderEffectNode::textureProviderDestroyed(const QObject *object) { Q_ASSERT(material()); - static_cast<QQuickOpenGLShaderEffectMaterial *>(material())->invalidateTextureProvider(static_cast<QSGTextureProvider *>(object)); + static_cast<QQuickOpenGLShaderEffectMaterial *>(material())->invalidateTextureProvider(object); } void QQuickOpenGLShaderEffectNode::preprocess() diff --git a/src/quick/items/qquickopenglshadereffectnode_p.h b/src/quick/items/qquickopenglshadereffectnode_p.h index 7c75bb3126..6d68ba87b9 100644 --- a/src/quick/items/qquickopenglshadereffectnode_p.h +++ b/src/quick/items/qquickopenglshadereffectnode_p.h @@ -122,7 +122,7 @@ public: void setProgramSource(const QQuickOpenGLShaderEffectMaterialKey &source); void updateTextures() const; - void invalidateTextureProvider(QSGTextureProvider *provider); + void invalidateTextureProvider(const QObject *provider); static void cleanupMaterialCache(); @@ -159,7 +159,7 @@ Q_SIGNALS: private Q_SLOTS: void markDirtyTexture(); - void textureProviderDestroyed(QObject *object); + void textureProviderDestroyed(const QObject *object); }; QT_END_NAMESPACE diff --git a/src/quick/items/qquickshadereffect.cpp b/src/quick/items/qquickshadereffect.cpp index ab79b69c8c..05d9e5e36d 100644 --- a/src/quick/items/qquickshadereffect.cpp +++ b/src/quick/items/qquickshadereffect.cpp @@ -795,7 +795,8 @@ bool QQuickShaderEffect::event(QEvent *e) return QQuickItem::event(e); } #endif - m_impl->handleEvent(e); + if (m_impl) + m_impl->handleEvent(e); return QQuickItem::event(e); } diff --git a/src/quick/items/qquicktableview.cpp b/src/quick/items/qquicktableview.cpp index 8f5130fc17..9583ef4231 100644 --- a/src/quick/items/qquicktableview.cpp +++ b/src/quick/items/qquicktableview.cpp @@ -305,9 +305,7 @@ \l view, which means that the table's width could be larger or smaller than the viewport width. As a TableView cannot always know the exact width of the table without loading all columns in the model, the \c contentWidth is - usually an estimate based on the columns it has seen so far. This estimate - is recalculated whenever new columns are flicked into view, which means - that the content width can change dynamically. + usually an estimate based on the initially loaded table. If you know what the width of the table will be, assign a value to \c contentWidth, to avoid unnecessary calculations and updates to the @@ -324,9 +322,7 @@ \c view, which means that the table's height could be larger or smaller than the viewport height. As a TableView cannot always know the exact height of the table without loading all rows in the model, the \c contentHeight is - usually an estimate based on the rows it has seen so far. This estimate is - recalculated whenever new rows are flicked into view, which means that - the content height can change dynamically. + usually an estimate based on the initially loaded table. If you know what the height of the table will be, assign a value to \c contentHeight, to avoid unnecessary calculations and updates to @@ -616,6 +612,7 @@ void QQuickTableViewPrivate::updateContentWidth() Q_Q(QQuickTableView); if (syncHorizontally) { + QBoolBlocker fixupGuard(inUpdateContentSize, true); q->QQuickFlickable::setContentWidth(syncView->contentWidth()); return; } @@ -632,6 +629,8 @@ void QQuickTableViewPrivate::updateContentWidth() const qreal remainingSpacing = columnsRemaining * cellSpacing.width(); const qreal estimatedRemainingWidth = remainingColumnWidths + remainingSpacing; const qreal estimatedWidth = loadedTableOuterRect.right() + estimatedRemainingWidth; + + QBoolBlocker fixupGuard(inUpdateContentSize, true); q->QQuickFlickable::setContentWidth(estimatedWidth); } @@ -640,6 +639,7 @@ void QQuickTableViewPrivate::updateContentHeight() Q_Q(QQuickTableView); if (syncVertically) { + QBoolBlocker fixupGuard(inUpdateContentSize, true); q->QQuickFlickable::setContentHeight(syncView->contentHeight()); return; } @@ -656,64 +656,204 @@ void QQuickTableViewPrivate::updateContentHeight() const qreal remainingSpacing = rowsRemaining * cellSpacing.height(); const qreal estimatedRemainingHeight = remainingRowHeights + remainingSpacing; const qreal estimatedHeight = loadedTableOuterRect.bottom() + estimatedRemainingHeight; + + QBoolBlocker fixupGuard(inUpdateContentSize, true); q->QQuickFlickable::setContentHeight(estimatedHeight); } -void QQuickTableViewPrivate::enforceTableAtOrigin() +void QQuickTableViewPrivate::updateExtents() { - // Gaps before the first row/column can happen if rows/columns - // changes size while flicking e.g because of spacing changes or - // changes to a column maxWidth/row maxHeight. Check for this, and - // move the whole table rect accordingly. - bool layoutNeeded = false; - const qreal flickMargin = 50; + // When rows or columns outside the viewport are removed or added, or a rebuild + // forces us to guesstimate a new top-left, the edges of the table might end up + // out of sync with the edges of the content view. We detect this situation here, and + // move the origin to ensure that there will never be gaps at the end of the table. + // Normally we detect that the size of the whole table is not going to be equal to the + // size of the content view already when we load the last row/column, and especially + // before it's flicked completely inside the viewport. For those cases we simply adjust + // the origin/endExtent, to give a smooth flicking experience. + // But if flicking fast (e.g with a scrollbar), it can happen that the viewport ends up + // outside the end of the table in just one viewport update. To avoid a "blink" in the + // viewport when that happens, we "move" the loaded table into the viewport to cover it. + Q_Q(QQuickTableView); - const bool noMoreColumns = nextVisibleEdgeIndexAroundLoadedTable(Qt::LeftEdge) == kEdgeIndexAtEnd; - const bool noMoreRows = nextVisibleEdgeIndexAroundLoadedTable(Qt::TopEdge) == kEdgeIndexAtEnd; + bool tableMovedHorizontally = false; + bool tableMovedVertically = false; - if (noMoreColumns) { - if (!qFuzzyIsNull(loadedTableOuterRect.left())) { - // There are no more columns, but the table rect - // is not at origin. So we move it there. - loadedTableOuterRect.moveLeft(0); - layoutNeeded = true; + const int nextLeftColumn = nextVisibleEdgeIndexAroundLoadedTable(Qt::LeftEdge); + const int nextRightColumn = nextVisibleEdgeIndexAroundLoadedTable(Qt::RightEdge); + const int nextTopRow = nextVisibleEdgeIndexAroundLoadedTable(Qt::TopEdge); + const int nextBottomRow = nextVisibleEdgeIndexAroundLoadedTable(Qt::BottomEdge); + + if (syncHorizontally) { + const auto syncView_d = syncView->d_func(); + origin.rx() = syncView_d->origin.x(); + endExtent.rwidth() = syncView_d->endExtent.width(); + hData.markExtentsDirty(); + } else if (nextLeftColumn == kEdgeIndexAtEnd) { + // There are no more columns to load on the left side of the table. + // In that case, we ensure that the origin match the beginning of the table. + if (loadedTableOuterRect.left() > viewportRect.left()) { + // We have a blank area at the left end of the viewport. In that case we don't have time to + // wait for the viewport to move (after changing origin), since that will take an extra + // update cycle, which will be visible as a blink. Instead, unless the blank spot is just + // us overshooting, we brute force the loaded table inside the already existing viewport. + if (loadedTableOuterRect.left() > origin.x()) { + const qreal diff = loadedTableOuterRect.left() - origin.x(); + loadedTableOuterRect.moveLeft(loadedTableOuterRect.left() - diff); + loadedTableInnerRect.moveLeft(loadedTableInnerRect.left() - diff); + tableMovedHorizontally = true; + } } - } else { - if (loadedTableOuterRect.left() <= 0) { - // The table rect is at origin, or outside. But we still have - // more visible columns to the left. So we need to make some - // space so that they can be flicked in. - loadedTableOuterRect.moveLeft(flickMargin); - layoutNeeded = true; + origin.rx() = loadedTableOuterRect.left(); + hData.markExtentsDirty(); + } else if (loadedTableOuterRect.left() <= origin.x() + cellSpacing.width()) { + // The table rect is at the origin, or outside, but we still have more + // visible columns to the left. So we try to guesstimate how much space + // the rest of the columns will occupy, and move the origin accordingly. + const int columnsRemaining = nextLeftColumn + 1; + const qreal remainingColumnWidths = columnsRemaining * averageEdgeSize.width(); + const qreal remainingSpacing = columnsRemaining * cellSpacing.width(); + const qreal estimatedRemainingWidth = remainingColumnWidths + remainingSpacing; + origin.rx() = loadedTableOuterRect.left() - estimatedRemainingWidth; + hData.markExtentsDirty(); + } else if (nextRightColumn == kEdgeIndexAtEnd) { + // There are no more columns to load on the right side of the table. + // In that case, we ensure that the end of the content view match the end of the table. + if (loadedTableOuterRect.right() < viewportRect.right()) { + // We have a blank area at the right end of the viewport. In that case we don't have time to + // wait for the viewport to move (after changing endExtent), since that will take an extra + // update cycle, which will be visible as a blink. Instead, unless the blank spot is just + // us overshooting, we brute force the loaded table inside the already existing viewport. + const qreal w = qMin(viewportRect.right(), q->contentWidth() + endExtent.width()); + if (loadedTableOuterRect.right() < w) { + const qreal diff = loadedTableOuterRect.right() - w; + loadedTableOuterRect.moveRight(loadedTableOuterRect.right() - diff); + loadedTableInnerRect.moveRight(loadedTableInnerRect.right() - diff); + tableMovedHorizontally = true; + } } + endExtent.rwidth() = loadedTableOuterRect.right() - q->contentWidth(); + hData.markExtentsDirty(); + } else if (loadedTableOuterRect.right() >= q->contentWidth() + endExtent.width() - cellSpacing.width()) { + // The right-most column is outside the end of the content view, and we + // still have more visible columns in the model. This can happen if the application + // has set a fixed content width. + const int columnsRemaining = tableSize.width() - nextRightColumn; + const qreal remainingColumnWidths = columnsRemaining * averageEdgeSize.width(); + const qreal remainingSpacing = columnsRemaining * cellSpacing.width(); + const qreal estimatedRemainingWidth = remainingColumnWidths + remainingSpacing; + const qreal pixelsOutsideContentWidth = loadedTableOuterRect.right() - q->contentWidth(); + endExtent.rwidth() = pixelsOutsideContentWidth + estimatedRemainingWidth; + hData.markExtentsDirty(); } - if (noMoreRows) { - if (!qFuzzyIsNull(loadedTableOuterRect.top())) { - loadedTableOuterRect.moveTop(0); - layoutNeeded = true; + if (syncVertically) { + const auto syncView_d = syncView->d_func(); + origin.ry() = syncView_d->origin.y(); + endExtent.rheight() = syncView_d->endExtent.height(); + vData.markExtentsDirty(); + } else if (nextTopRow == kEdgeIndexAtEnd) { + // There are no more rows to load on the top side of the table. + // In that case, we ensure that the origin match the beginning of the table. + if (loadedTableOuterRect.top() > viewportRect.top()) { + // We have a blank area at the top of the viewport. In that case we don't have time to + // wait for the viewport to move (after changing origin), since that will take an extra + // update cycle, which will be visible as a blink. Instead, unless the blank spot is just + // us overshooting, we brute force the loaded table inside the already existing viewport. + if (loadedTableOuterRect.top() > origin.y()) { + const qreal diff = loadedTableOuterRect.top() - origin.y(); + loadedTableOuterRect.moveTop(loadedTableOuterRect.top() - diff); + loadedTableInnerRect.moveTop(loadedTableInnerRect.top() - diff); + tableMovedVertically = true; + } } - } else { - if (loadedTableOuterRect.top() <= 0) { - loadedTableOuterRect.moveTop(flickMargin); - layoutNeeded = true; + origin.ry() = loadedTableOuterRect.top(); + vData.markExtentsDirty(); + } else if (loadedTableOuterRect.top() <= origin.y() + cellSpacing.height()) { + // The table rect is at the origin, or outside, but we still have more + // visible rows at the top. So we try to guesstimate how much space + // the rest of the rows will occupy, and move the origin accordingly. + const int rowsRemaining = nextTopRow + 1; + const qreal remainingRowHeights = rowsRemaining * averageEdgeSize.height(); + const qreal remainingSpacing = rowsRemaining * cellSpacing.height(); + const qreal estimatedRemainingHeight = remainingRowHeights + remainingSpacing; + origin.ry() = loadedTableOuterRect.top() - estimatedRemainingHeight; + vData.markExtentsDirty(); + } else if (nextBottomRow == kEdgeIndexAtEnd) { + // There are no more rows to load on the bottom side of the table. + // In that case, we ensure that the end of the content view match the end of the table. + if (loadedTableOuterRect.bottom() < viewportRect.bottom()) { + // We have a blank area at the bottom of the viewport. In that case we don't have time to + // wait for the viewport to move (after changing endExtent), since that will take an extra + // update cycle, which will be visible as a blink. Instead, unless the blank spot is just + // us overshooting, we brute force the loaded table inside the already existing viewport. + const qreal h = qMin(viewportRect.bottom(), q->contentHeight() + endExtent.height()); + if (loadedTableOuterRect.bottom() < h) { + const qreal diff = loadedTableOuterRect.bottom() - h; + loadedTableOuterRect.moveBottom(loadedTableOuterRect.bottom() - diff); + loadedTableInnerRect.moveBottom(loadedTableInnerRect.bottom() - diff); + tableMovedVertically = true; + } + } + endExtent.rheight() = loadedTableOuterRect.bottom() - q->contentHeight(); + vData.markExtentsDirty(); + } else if (loadedTableOuterRect.bottom() >= q->contentHeight() + endExtent.height() - cellSpacing.height()) { + // The bottom-most row is outside the end of the content view, and we + // still have more visible rows in the model. This can happen if the application + // has set a fixed content height. + const int rowsRemaining = tableSize.height() - nextBottomRow; + const qreal remainingRowHeigts = rowsRemaining * averageEdgeSize.height(); + const qreal remainingSpacing = rowsRemaining * cellSpacing.height(); + const qreal estimatedRemainingHeight = remainingRowHeigts + remainingSpacing; + const qreal pixelsOutsideContentHeight = loadedTableOuterRect.bottom() - q->contentHeight(); + endExtent.rheight() = pixelsOutsideContentHeight + estimatedRemainingHeight; + vData.markExtentsDirty(); + } + + if (tableMovedHorizontally || tableMovedVertically) { + qCDebug(lcTableViewDelegateLifecycle) << "move table to" << loadedTableOuterRect; + + // relayoutTableItems() will take care of moving the existing + // delegate items into the new loadedTableOuterRect. + relayoutTableItems(); + + // Inform the sync children that they need to rebuild to stay in sync + for (auto syncChild : qAsConst(syncChildren)) { + auto syncChild_d = syncChild->d_func(); + syncChild_d->scheduledRebuildOptions |= RebuildOption::ViewportOnly; + if (tableMovedHorizontally) + syncChild_d->scheduledRebuildOptions |= RebuildOption::CalculateNewTopLeftColumn; + if (tableMovedVertically) + syncChild_d->scheduledRebuildOptions |= RebuildOption::CalculateNewTopLeftRow; } } - if (layoutNeeded) { - qCDebug(lcTableViewDelegateLifecycle); - relayoutTableItems(); + if (hData.minExtentDirty || vData.minExtentDirty) { + qCDebug(lcTableViewDelegateLifecycle) << "move origin and endExtent to:" << origin << endExtent; + // updateBeginningEnd() will let the new extents take effect. This will also change the + // visualArea of the flickable, which again will cause any attached scrollbars to adjust + // the position of the handle. Note the latter will cause the viewport to move once more. + updateBeginningEnd(); } } void QQuickTableViewPrivate::updateAverageEdgeSize() { - const int loadedRowCount = loadedRows.count(); - const int loadedColumnCount = loadedColumns.count(); - const qreal accRowSpacing = (loadedRowCount - 1) * cellSpacing.height(); - const qreal accColumnSpacing = (loadedColumnCount - 1) * cellSpacing.width(); - averageEdgeSize.setHeight((loadedTableOuterRect.height() - accRowSpacing) / loadedRowCount); - averageEdgeSize.setWidth((loadedTableOuterRect.width() - accColumnSpacing) / loadedColumnCount); + if (explicitContentWidth.isValid()) { + const qreal accColumnSpacing = (tableSize.width() - 1) * cellSpacing.width(); + averageEdgeSize.setWidth((explicitContentWidth - accColumnSpacing) / tableSize.width()); + } else { + const qreal accColumnSpacing = (loadedColumns.count() - 1) * cellSpacing.width(); + averageEdgeSize.setWidth((loadedTableOuterRect.width() - accColumnSpacing) / loadedColumns.count()); + } + + if (explicitContentHeight.isValid()) { + const qreal accRowSpacing = (tableSize.height() - 1) * cellSpacing.height(); + averageEdgeSize.setHeight((explicitContentHeight - accRowSpacing) / tableSize.height()); + } else { + const qreal accRowSpacing = (loadedRows.count() - 1) * cellSpacing.height(); + averageEdgeSize.setHeight((loadedTableOuterRect.height() - accRowSpacing) / loadedRows.count()); + } } void QQuickTableViewPrivate::syncLoadedTableRectFromLoadedTable() @@ -770,13 +910,12 @@ void QQuickTableViewPrivate::forceLayout() scheduleRebuildTable(rebuildOptions); - if (polishing) { + auto rootView = rootSyncView(); + const bool updated = rootView->d_func()->updateTableRecursive(); + if (!updated) { qWarning() << "TableView::forceLayout(): Cannot do an immediate re-layout during an ongoing layout!"; - q_func()->polish(); - return; + rootView->polish(); } - - updatePolish(); } void QQuickTableViewPrivate::syncLoadedTableFromLoadRequest() @@ -1212,19 +1351,6 @@ bool QQuickTableViewPrivate::isRowHidden(int row) return qFuzzyIsNull(getRowHeight(row)); } -void QQuickTableViewPrivate::relayoutTable() -{ - clearEdgeSizeCache(); - relayoutTableItems(); - syncLoadedTableRectFromLoadedTable(); - enforceTableAtOrigin(); - updateContentWidth(); - updateContentHeight(); - // Return back to updatePolish to loadAndUnloadVisibleEdges() - // since the re-layout might have caused some edges to be pushed - // out, while others might have been pushed in. -} - void QQuickTableViewPrivate::relayoutTableItems() { qCDebug(lcTableViewDelegateLifecycle); @@ -1409,20 +1535,7 @@ void QQuickTableViewPrivate::processLoadRequest() if (rebuildState == RebuildState::Done) { // Loading of this edge was not done as a part of a rebuild, but // instead as an incremental build after e.g a flick. - switch (loadRequest.edge()) { - case Qt::LeftEdge: - case Qt::TopEdge: - enforceTableAtOrigin(); - break; - case Qt::RightEdge: - updateAverageEdgeSize(); - updateContentWidth(); - break; - case Qt::BottomEdge: - updateAverageEdgeSize(); - updateContentHeight(); - break; - } + updateExtents(); drainReusePoolAfterLoadRequest(); } @@ -1637,16 +1750,29 @@ void QQuickTableViewPrivate::beginRebuildTable() else if (rebuildOptions & RebuildOption::ViewportOnly) releaseLoadedItems(reusableFlag); + if (rebuildOptions & RebuildOption::All) { + origin = QPointF(0, 0); + endExtent = QSizeF(0, 0); + hData.markExtentsDirty(); + vData.markExtentsDirty(); + updateBeginningEnd(); + } + loadedColumns.clear(); loadedRows.clear(); loadedTableOuterRect = QRect(); loadedTableInnerRect = QRect(); clearEdgeSizeCache(); - if (syncHorizontally) + if (syncHorizontally) { setLocalViewportX(syncView->contentX()); - if (syncVertically) + viewportRect.moveLeft(syncView->d_func()->viewportRect.left()); + } + + if (syncVertically) { setLocalViewportY(syncView->contentY()); + viewportRect.moveTop(syncView->d_func()->viewportRect.top()); + } if (!model) { qCDebug(lcTableViewDelegateLifecycle()) << "no model found, leaving table empty"; @@ -1690,12 +1816,29 @@ void QQuickTableViewPrivate::layoutAfterLoadingInitialTable() // columns, since during the process, we didn't have all the items // available yet for the calculation. So we do it now. The exception // is if we specifically only requested a relayout. - relayoutTable(); + clearEdgeSizeCache(); + relayoutTableItems(); + syncLoadedTableRectFromLoadedTable(); + } + + if (syncView || rebuildOptions.testFlag(RebuildOption::All)) { + // We try to limit how often we update the content size. The main reason is that is has a + // tendency to cause flicker in the viewport if it happens while flicking. But another just + // as valid reason is that we actually never really know what the size of the full table will + // ever be. Even if e.g spacing changes, and we normally would assume that the size of the table + // would increase accordingly, the model might also at some point have removed/hidden/resized + // rows/columns outside the viewport. This would also affect the size, but since we don't load + // rows or columns outside the viewport, this information is ignored. And even if we did, we + // might also have been fast-flicked to a new location at some point, and started a new rebuild + // there based on a new guesstimated top-left cell. Either way, changing the content size + // based on the currently visible row/columns/spacing can be really off. So instead of pretending + // that we know what the actual size of the table is, we just keep the first guesstimate. + updateAverageEdgeSize(); + updateContentWidth(); + updateContentHeight(); } - updateAverageEdgeSize(); - updateContentWidth(); - updateContentHeight(); + updateExtents(); } void QQuickTableViewPrivate::unloadEdge(Qt::Edge edge) @@ -1710,8 +1853,6 @@ void QQuickTableViewPrivate::unloadEdge(Qt::Edge edge) unloadItem(QPoint(column, r.key())); loadedColumns.remove(column); syncLoadedTableRectFromLoadedTable(); - updateAverageEdgeSize(); - updateContentWidth(); break; } case Qt::TopEdge: case Qt::BottomEdge: { @@ -1720,8 +1861,6 @@ void QQuickTableViewPrivate::unloadEdge(Qt::Edge edge) unloadItem(QPoint(c.key(), row)); loadedRows.remove(row); syncLoadedTableRectFromLoadedTable(); - updateAverageEdgeSize(); - updateContentHeight(); break; } } @@ -1925,8 +2064,17 @@ bool QQuickTableViewPrivate::updateTable() void QQuickTableViewPrivate::fixup(QQuickFlickablePrivate::AxisData &data, qreal minExtent, qreal maxExtent) { - if (scheduledRebuildOptions || rebuildState != RebuildState::Done) + if (inUpdateContentSize) { + // We update the content size dynamically as we load and unload edges. + // Unfortunately, this also triggers a call to this function. The base + // implementation will do things like start a momentum animation or move + // the content view somewhere else, which causes glitches. This can + // especially happen if flicking on one of the syncView children, which triggers + // an update to our content size. In that case, the base implementation don't know + // that the view is being indirectly dragged, and will therefore do strange things as + // it tries to 'fixup' the geometry. So we use a guard to prevent this from happening. return; + } QQuickFlickablePrivate::fixup(data, minExtent, maxExtent); } @@ -2011,13 +2159,11 @@ void QQuickTableViewPrivate::syncWithPendingChanges() Q_Q(QQuickTableView); viewportRect = QRectF(q->contentX(), q->contentY(), q->width(), q->height()); - // Sync rebuild options first, in case we schedule a rebuild from one of the - // other sync calls above. If so, we need to start a new rebuild from the top. - syncRebuildOptions(); - syncModel(); syncDelegate(); syncSyncView(); + + syncRebuildOptions(); } void QQuickTableViewPrivate::syncRebuildOptions() @@ -2107,7 +2253,6 @@ void QQuickTableViewPrivate::syncSyncView() assignedSyncView->d_func()->syncChildren.append(q); scheduledRebuildOptions |= RebuildOption::ViewportOnly; - q->polish(); } syncView = assignedSyncView; @@ -2120,6 +2265,21 @@ void QQuickTableViewPrivate::syncSyncView() q->setColumnSpacing(syncView->columnSpacing()); if (syncVertically) q->setRowSpacing(syncView->rowSpacing()); + + if (syncView && loadedItems.isEmpty() && !tableSize.isEmpty()) { + // When we have a syncView, we can sometimes temporarily end up with no loaded items. + // This can happen if the syncView has a model with more rows or columns than us, in + // which case the viewport can end up in a place where we have no rows or columns to + // show. In that case, check now if the viewport has been flicked back again, and + // that we can rebuild the table with a visible top-left cell. + const auto syncView_d = syncView->d_func(); + if (!syncView_d->loadedItems.isEmpty()) { + if (syncHorizontally && syncView_d->leftColumn() <= tableSize.width() - 1) + scheduledRebuildOptions |= QQuickTableViewPrivate::RebuildOption::ViewportOnly; + else if (syncVertically && syncView_d->topRow() <= tableSize.height() - 1) + scheduledRebuildOptions |= QQuickTableViewPrivate::RebuildOption::ViewportOnly; + } + } } void QQuickTableViewPrivate::connectToModel() @@ -2254,7 +2414,6 @@ void QQuickTableViewPrivate::modelResetCallback() void QQuickTableViewPrivate::scheduleRebuildIfFastFlick() { Q_Q(QQuickTableView); - // If the viewport has moved more than one page vertically or horizontally, we switch // strategy from refilling edges around the current table to instead rebuild the table // from scratch inside the new viewport. This will greatly improve performance when flicking @@ -2345,6 +2504,26 @@ QQuickTableView::QQuickTableView(QQuickTableViewPrivate &dd, QQuickItem *parent) setFlag(QQuickItem::ItemIsFocusScope); } +qreal QQuickTableView::minXExtent() const +{ + return QQuickFlickable::minXExtent() - d_func()->origin.x(); +} + +qreal QQuickTableView::maxXExtent() const +{ + return QQuickFlickable::maxXExtent() - d_func()->endExtent.width(); +} + +qreal QQuickTableView::minYExtent() const +{ + return QQuickFlickable::minYExtent() - d_func()->origin.y(); +} + +qreal QQuickTableView::maxYExtent() const +{ + return QQuickFlickable::maxYExtent() - d_func()->endExtent.height(); +} + int QQuickTableView::rows() const { return d_func()->tableSize.height(); diff --git a/src/quick/items/qquicktableview_p.h b/src/quick/items/qquicktableview_p.h index 3d46221574..3b113efa4f 100644 --- a/src/quick/items/qquicktableview_p.h +++ b/src/quick/items/qquicktableview_p.h @@ -147,6 +147,11 @@ private: Q_DISABLE_COPY(QQuickTableView) Q_DECLARE_PRIVATE(QQuickTableView) + qreal minXExtent() const override; + qreal maxXExtent() const override; + qreal minYExtent() const override; + qreal maxYExtent() const override; + Q_PRIVATE_SLOT(d_func(), void _q_componentFinalized()) }; diff --git a/src/quick/items/qquicktableview_p_p.h b/src/quick/items/qquicktableview_p_p.h index 7f2aee9105..b66ac66dec 100644 --- a/src/quick/items/qquicktableview_p_p.h +++ b/src/quick/items/qquicktableview_p_p.h @@ -251,6 +251,9 @@ public: QRectF loadedTableOuterRect; QRectF loadedTableInnerRect; + QPointF origin = QPointF(0, 0); + QSizeF endExtent = QSizeF(0, 0); + QRectF viewportRect = QRectF(0, 0, -1, -1); QSize tableSize; @@ -272,6 +275,7 @@ public: bool syncHorizontally = false; bool inSetLocalViewportPos = false; bool inSyncViewportPosRecursive = false; + bool inUpdateContentSize = false; QJSValue rowHeightProvider; QJSValue columnWidthProvider; @@ -337,7 +341,6 @@ public: bool updateTableRecursive(); bool updateTable(); - void relayoutTable(); void relayoutTableItems(); void layoutVerticalEdge(Qt::Edge tableEdge); @@ -350,7 +353,7 @@ public: void updateAverageEdgeSize(); void forceLayout(); - void enforceTableAtOrigin(); + void updateExtents(); void syncLoadedTableRectFromLoadedTable(); void syncLoadedTableFromLoadRequest(); diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp index 6d343a91ce..ae849aeb4b 100644 --- a/src/quick/items/qquicktext.cpp +++ b/src/quick/items/qquicktext.cpp @@ -1653,13 +1653,17 @@ void QQuickText::setText(const QString &n) if (d->text == n) return; - d->richText = d->format == RichText; + d->markdownText = d->format == MarkdownText; + d->richText = d->format == RichText || d->markdownText; d->styledText = d->format == StyledText || (d->format == AutoText && Qt::mightBeRichText(n)); d->text = n; if (isComponentComplete()) { if (d->richText) { d->ensureDoc(); - d->extra->doc->setText(n); + if (d->markdownText) + d->extra->doc->setMarkdownText(n); + else + d->extra->doc->setText(n); d->rightToLeftText = d->extra->doc->toPlainText().isRightToLeft(); } else { d->clearFormats(); @@ -2146,7 +2150,8 @@ void QQuickText::setTextFormat(TextFormat format) return; d->format = format; bool wasRich = d->richText; - d->richText = format == RichText; + d->markdownText = format == MarkdownText; + d->richText = format == RichText || d->markdownText; d->styledText = format == StyledText || (format == AutoText && Qt::mightBeRichText(d->text)); if (isComponentComplete()) { @@ -2687,7 +2692,10 @@ void QQuickText::componentComplete() if (d->updateOnComponentComplete) { if (d->richText) { d->ensureDoc(); - d->extra->doc->setText(d->text); + if (d->markdownText) + d->extra->doc->setMarkdownText(d->text); + else + d->extra->doc->setText(d->text); d->rightToLeftText = d->extra->doc->toPlainText().isRightToLeft(); } else { d->rightToLeftText = d->text.isRightToLeft(); diff --git a/src/quick/items/qquicktext_p.h b/src/quick/items/qquicktext_p.h index 1af60051fb..45f387cb12 100644 --- a/src/quick/items/qquicktext_p.h +++ b/src/quick/items/qquicktext_p.h @@ -121,6 +121,7 @@ public: Q_ENUM(TextStyle) enum TextFormat { PlainText = Qt::PlainText, RichText = Qt::RichText, + MarkdownText = Qt::MarkdownText, AutoText = Qt::AutoText, StyledText = 4 }; Q_ENUM(TextFormat) diff --git a/src/quick/items/qquicktext_p_p.h b/src/quick/items/qquicktext_p_p.h index efa45e0958..c01998b100 100644 --- a/src/quick/items/qquicktext_p_p.h +++ b/src/quick/items/qquicktext_p_p.h @@ -161,6 +161,7 @@ public: bool updateOnComponentComplete:1; bool richText:1; bool styledText:1; + bool markdownText:1; bool widthExceeded:1; bool heightExceeded:1; bool internalWidthUpdate:1; diff --git a/src/quick/items/qquicktextcontrol.cpp b/src/quick/items/qquicktextcontrol.cpp index a7a90c9134..caef24293a 100644 --- a/src/quick/items/qquicktextcontrol.cpp +++ b/src/quick/items/qquicktextcontrol.cpp @@ -1297,6 +1297,7 @@ void QQuickTextControlPrivate::inputMethodEvent(QInputMethodEvent *e) || e->preeditString() != cursor.block().layout()->preeditAreaText() || e->replacementLength() > 0; bool forceSelectionChanged = false; + int oldCursorPos = cursor.position(); cursor.beginEditBlock(); if (isGettingInput) { @@ -1365,6 +1366,8 @@ void QQuickTextControlPrivate::inputMethodEvent(QInputMethodEvent *e) QTextCursorPrivate *cursor_d = QTextCursorPrivate::getPrivate(&cursor); if (cursor_d) cursor_d->setX(); + if (cursor.position() != oldCursorPos) + emit q->cursorPositionChanged(); q->updateCursorRectangle(oldPreeditCursor != preeditCursor || forceSelectionChanged || isGettingInput); selectionChanged(forceSelectionChanged); } diff --git a/src/quick/items/qquicktextdocument.cpp b/src/quick/items/qquicktextdocument.cpp index 06ac5804c4..021bbca0f6 100644 --- a/src/quick/items/qquicktextdocument.cpp +++ b/src/quick/items/qquicktextdocument.cpp @@ -237,6 +237,14 @@ void QQuickTextDocumentWithImageResources::setText(const QString &text) #endif } +#if QT_CONFIG(textmarkdownreader) +void QQuickTextDocumentWithImageResources::setMarkdownText(const QString &text) +{ + clearResources(); + QTextDocument::setMarkdown(text); +} +#endif + QSet<QUrl> QQuickTextDocumentWithImageResources::errors; QT_END_NAMESPACE diff --git a/src/quick/items/qquicktextdocument_p.h b/src/quick/items/qquicktextdocument_p.h index 1218b12b89..9c5152d442 100644 --- a/src/quick/items/qquicktextdocument_p.h +++ b/src/quick/items/qquicktextdocument_p.h @@ -73,6 +73,9 @@ public: virtual ~QQuickTextDocumentWithImageResources(); void setText(const QString &); +#if QT_CONFIG(textmarkdownreader) + void setMarkdownText(const QString &); +#endif int resourcesLoading() const { return outstanding; } QSizeF intrinsicSize(QTextDocument *doc, int posInDocument, const QTextFormat &format) override; diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp index 6b4b118eb7..b299e7c92f 100644 --- a/src/quick/items/qquicktextedit.cpp +++ b/src/quick/items/qquicktextedit.cpp @@ -2298,7 +2298,6 @@ void QQuickTextEditPrivate::init() qmlobject_connect(control, QQuickTextControl, SIGNAL(cursorPositionChanged()), q, QQuickTextEdit, SIGNAL(cursorPositionChanged())); qmlobject_connect(control, QQuickTextControl, SIGNAL(cursorRectangleChanged()), q, QQuickTextEdit, SLOT(moveCursorDelegate())); qmlobject_connect(control, QQuickTextControl, SIGNAL(linkActivated(QString)), q, QQuickTextEdit, SIGNAL(linkActivated(QString))); - qmlobject_connect(control, QQuickTextControl, SIGNAL(linkHovered(QString)), q, QQuickTextEdit, SIGNAL(linkHovered(QString))); qmlobject_connect(control, QQuickTextControl, SIGNAL(overwriteModeChanged(bool)), q, QQuickTextEdit, SIGNAL(overwriteModeChanged(bool))); qmlobject_connect(control, QQuickTextControl, SIGNAL(textChanged()), q, QQuickTextEdit, SLOT(q_textChanged())); qmlobject_connect(control, QQuickTextControl, SIGNAL(preeditTextChanged()), q, QQuickTextEdit, SIGNAL(preeditTextChanged())); @@ -2310,6 +2309,7 @@ void QQuickTextEditPrivate::init() qmlobject_connect(document, QQuickTextDocumentWithImageResources, SIGNAL(imagesLoaded()), q, QQuickTextEdit, SLOT(updateSize())); QObject::connect(document, &QQuickTextDocumentWithImageResources::contentsChange, q, &QQuickTextEdit::q_contentsChange); QObject::connect(document->documentLayout(), &QAbstractTextDocumentLayout::updateBlock, q, &QQuickTextEdit::invalidateBlock); + QObject::connect(control, &QQuickTextControl::linkHovered, q, &QQuickTextEdit::q_linkHovered); document->setDefaultFont(font); document->setDocumentMargin(textMargin); @@ -2317,6 +2317,9 @@ void QQuickTextEditPrivate::init() document->setUndoRedoEnabled(true); updateDefaultTextOption(); q->updateSize(); +#if QT_CONFIG(cursor) + q->setCursor(Qt::IBeamCursor); +#endif } void QQuickTextEditPrivate::resetInputMethod() @@ -2584,6 +2587,20 @@ void QQuickTextEdit::updateCursor() } } +void QQuickTextEdit::q_linkHovered(const QString &link) +{ + Q_D(QQuickTextEdit); + emit linkHovered(link); +#if QT_CONFIG(cursor) + if (link.isEmpty()) { + setCursor(d->cursorToRestoreAfterHover); + } else if (cursor().shape() != Qt::PointingHandCursor) { + d->cursorToRestoreAfterHover = cursor().shape(); + setCursor(Qt::PointingHandCursor); + } +#endif +} + void QQuickTextEdit::q_updateAlignment() { Q_D(QQuickTextEdit); diff --git a/src/quick/items/qquicktextedit_p.h b/src/quick/items/qquicktextedit_p.h index 7a847ffeae..259a614d6b 100644 --- a/src/quick/items/qquicktextedit_p.h +++ b/src/quick/items/qquicktextedit_p.h @@ -374,6 +374,7 @@ private Q_SLOTS: void updateWholeDocument(); void invalidateBlock(const QTextBlock &block); void updateCursor(); + void q_linkHovered(const QString &link); void q_updateAlignment(); void updateSize(); void triggerPreprocess(); diff --git a/src/quick/items/qquicktextedit_p_p.h b/src/quick/items/qquicktextedit_p_p.h index 46d3d5ff6b..389ce3175c 100644 --- a/src/quick/items/qquicktextedit_p_p.h +++ b/src/quick/items/qquicktextedit_p_p.h @@ -207,6 +207,7 @@ public: Qt::InputMethodHints inputMethodHints; #endif UpdateType updateType; + Qt::CursorShape cursorToRestoreAfterHover = Qt::IBeamCursor; bool dirty : 1; bool richText : 1; diff --git a/src/quick/items/qquicktextnodeengine.cpp b/src/quick/items/qquicktextnodeengine.cpp index a1b5eb1faf..32478ba375 100644 --- a/src/quick/items/qquicktextnodeengine.cpp +++ b/src/quick/items/qquicktextnodeengine.cpp @@ -1011,6 +1011,17 @@ void QQuickTextNodeEngine::addTextBlock(QTextDocument *textDocument, const QText break; }; + switch (block.blockFormat().marker()) { + case QTextBlockFormat::Checked: + listItemBullet = QChar(0x2612); // Checked checkbox + break; + case QTextBlockFormat::Unchecked: + listItemBullet = QChar(0x2610); // Unchecked checkbox + break; + case QTextBlockFormat::NoMarker: + break; + } + QSizeF size(fontMetrics.horizontalAdvance(listItemBullet), fontMetrics.height()); qreal xoff = fontMetrics.horizontalAdvance(QLatin1Char(' ')); if (block.textDirection() == Qt::LeftToRight) diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index f3a2b07620..5dcd101462 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -64,6 +64,7 @@ #include <QtGui/qpainter.h> #include <QtGui/qevent.h> #include <QtGui/qmatrix4x4.h> +#include <QtGui/qpa/qplatformtheme.h> #include <QtCore/qvarlengtharray.h> #include <QtCore/qabstractanimation.h> #include <QtCore/QLibraryInfo> @@ -632,25 +633,28 @@ static QMouseEvent *touchToMouseEvent(QEvent::Type type, const QTouchEvent::Touc return me; } -bool QQuickWindowPrivate::checkIfDoubleClicked(ulong newPressEventTimestamp) +bool QQuickWindowPrivate::checkIfDoubleTapped(ulong newPressEventTimestamp, QPoint newPressPos) { - bool doubleClicked; + bool doubleClicked = false; + + if (touchMousePressTimestamp > 0) { + QPoint distanceBetweenPresses = newPressPos - touchMousePressPos; + const int doubleTapDistance = QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::TouchDoubleTapDistance).toInt(); + doubleClicked = (qAbs(distanceBetweenPresses.x()) <= doubleTapDistance) && (qAbs(distanceBetweenPresses.y()) <= doubleTapDistance); - if (touchMousePressTimestamp == 0) { - // just initialize the variable - touchMousePressTimestamp = newPressEventTimestamp; - doubleClicked = false; - } else { - ulong timeBetweenPresses = newPressEventTimestamp - touchMousePressTimestamp; - ulong doubleClickInterval = static_cast<ulong>(QGuiApplication::styleHints()-> - mouseDoubleClickInterval()); - doubleClicked = timeBetweenPresses < doubleClickInterval; if (doubleClicked) { - touchMousePressTimestamp = 0; - } else { - touchMousePressTimestamp = newPressEventTimestamp; + ulong timeBetweenPresses = newPressEventTimestamp - touchMousePressTimestamp; + ulong doubleClickInterval = static_cast<ulong>(QGuiApplication::styleHints()-> + mouseDoubleClickInterval()); + doubleClicked = timeBetweenPresses < doubleClickInterval; } } + if (doubleClicked) { + touchMousePressTimestamp = 0; + } else { + touchMousePressTimestamp = newPressEventTimestamp; + touchMousePressPos = newPressPos; + } return doubleClicked; } @@ -707,7 +711,9 @@ bool QQuickWindowPrivate::deliverTouchAsMouse(QQuickItem *item, QQuickPointerEve if (auto pointerEventPoint = pointerEvent->pointById(p.id())) pointerEventPoint->setGrabberItem(item); - if (checkIfDoubleClicked(event->timestamp())) { + if (checkIfDoubleTapped(event->timestamp(), p.screenPos().toPoint())) { + // since we synth the mouse event from from touch, we respect the + // QPlatformTheme::TouchDoubleTapDistance instead of QPlatformTheme::MouseDoubleClickDistance QScopedPointer<QMouseEvent> mouseDoubleClick(touchToMouseEvent(QEvent::MouseButtonDblClick, p, event.data(), item, false)); QCoreApplication::sendEvent(item, mouseDoubleClick.data()); event->setAccepted(mouseDoubleClick->isAccepted()); @@ -722,6 +728,12 @@ bool QQuickWindowPrivate::deliverTouchAsMouse(QQuickItem *item, QQuickPointerEve // Touch point was there before and moved } else if (touchMouseDevice == device && p.id() == touchMouseId) { if (p.state() & Qt::TouchPointMoved) { + if (touchMousePressTimestamp != 0) { + const int doubleTapDistance = QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::TouchDoubleTapDistance).toInt(); + const QPoint moveDelta = p.screenPos().toPoint() - touchMousePressPos; + if (moveDelta.x() >= doubleTapDistance || moveDelta.y() >= doubleTapDistance) + touchMousePressTimestamp = 0; // Got dragged too far, dismiss the double tap + } if (QQuickItem *mouseGrabberItem = q->mouseGrabberItem()) { QScopedPointer<QMouseEvent> me(touchToMouseEvent(QEvent::MouseMove, p, event.data(), mouseGrabberItem, false)); QCoreApplication::sendEvent(item, me.data()); diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h index 5a3807b24f..63760a3b68 100644 --- a/src/quick/items/qquickwindow_p.h +++ b/src/quick/items/qquickwindow_p.h @@ -135,8 +135,9 @@ public: #endif int touchMouseId; QQuickPointerDevice *touchMouseDevice; - bool checkIfDoubleClicked(ulong newPressEventTimestamp); + bool checkIfDoubleTapped(ulong newPressEventTimestamp, QPoint newPressPos); ulong touchMousePressTimestamp; + QPoint touchMousePressPos; // in screen coordiantes void cancelTouchMouseSynthesis(); // Mouse positions are saved in widget coordinates diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp index d9ed25c099..53648e352a 100644 --- a/src/quick/scenegraph/qsgcontext.cpp +++ b/src/quick/scenegraph/qsgcontext.cpp @@ -393,7 +393,7 @@ QSGTexture *QSGRenderContext::textureForFactory(QQuickTextureFactory *factory, Q void QSGRenderContext::textureFactoryDestroyed(QObject *o) { m_mutex.lock(); - m_texturesToDelete << m_textures.take(static_cast<QQuickTextureFactory *>(o)); + m_texturesToDelete << m_textures.take(o); m_mutex.unlock(); } diff --git a/src/quick/scenegraph/qsgcontext_p.h b/src/quick/scenegraph/qsgcontext_p.h index 6d70d7ef6b..282ce828af 100644 --- a/src/quick/scenegraph/qsgcontext_p.h +++ b/src/quick/scenegraph/qsgcontext_p.h @@ -194,7 +194,7 @@ protected: QPointer<QSGContext> m_sg; QMutex m_mutex; - QHash<QQuickTextureFactory *, QSGTexture *> m_textures; + QHash<QObject *, QSGTexture *> m_textures; QSet<QSGTexture *> m_texturesToDelete; QHash<QString, QSGDistanceFieldGlyphCache *> m_glyphCaches; diff --git a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp index 8121b4559e..9ad0a77318 100644 --- a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp +++ b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp @@ -41,6 +41,7 @@ #include <QtCore/qelapsedtimer.h> #include <QtCore/qbuffer.h> +#include <QtCore/qendian.h> #include <QtQml/qqmlfile.h> #include <QtGui/private/qdistancefield_p.h> diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p.h b/src/quick/scenegraph/qsgdefaultglyphnode_p.h index 37a89c70b9..cfa1c1dad2 100644 --- a/src/quick/scenegraph/qsgdefaultglyphnode_p.h +++ b/src/quick/scenegraph/qsgdefaultglyphnode_p.h @@ -53,6 +53,7 @@ #include <private/qsgadaptationlayer_p.h> #include <private/qsgbasicglyphnode_p.h> +#include <qlinkedlist.h> QT_BEGIN_NAMESPACE diff --git a/src/quick/util/qquickpropertychanges.cpp b/src/quick/util/qquickpropertychanges.cpp index d739c8a017..776e7ab59a 100644 --- a/src/quick/util/qquickpropertychanges.cpp +++ b/src/quick/util/qquickpropertychanges.cpp @@ -201,14 +201,14 @@ public: QPointer<QObject> object; QList<const QV4::CompiledData::Binding *> bindings; - QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit; + QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit; bool decoded : 1; bool restore : 1; bool isExplicit : 1; void decode(); - void decodeBinding(const QString &propertyPrefix, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &qmlUnit, const QV4::CompiledData::Binding *binding); + void decodeBinding(const QString &propertyPrefix, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &qmlUnit, const QV4::CompiledData::Binding *binding); class ExpressionChange { public: @@ -236,7 +236,7 @@ public: QQmlProperty property(const QString &); }; -void QQuickPropertyChangesParser::verifyList(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, const QV4::CompiledData::Binding *binding) +void QQuickPropertyChangesParser::verifyList(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QV4::CompiledData::Binding *binding) { if (binding->type == QV4::CompiledData::Binding::Type_Object) { error(compilationUnit->objectAt(binding->value.objectIndex), QQuickPropertyChanges::tr("PropertyChanges does not support creating state-specific objects.")); @@ -266,7 +266,7 @@ void QQuickPropertyChangesPrivate::decode() decoded = true; } -void QQuickPropertyChangesPrivate::decodeBinding(const QString &propertyPrefix, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, const QV4::CompiledData::Binding *binding) +void QQuickPropertyChangesPrivate::decodeBinding(const QString &propertyPrefix, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QV4::CompiledData::Binding *binding) { Q_Q(QQuickPropertyChanges); @@ -314,7 +314,7 @@ void QQuickPropertyChangesPrivate::decodeBinding(const QString &propertyPrefix, QQmlBinding::Identifier id = QQmlBinding::Invalid; if (!binding->isTranslationBinding()) { - expression = binding->valueAsString(compilationUnit.data()); + expression = compilationUnit->bindingValueAsString(binding); id = binding->value.compiledScriptIndex; } expressions << ExpressionChange(propertyName, binding, id, expression, url, line, column); @@ -328,10 +328,10 @@ void QQuickPropertyChangesPrivate::decodeBinding(const QString &propertyPrefix, case QV4::CompiledData::Binding::Type_TranslationById: Q_UNREACHABLE(); case QV4::CompiledData::Binding::Type_String: - var = binding->valueAsString(compilationUnit.data()); + var = compilationUnit->bindingValueAsString(binding); break; case QV4::CompiledData::Binding::Type_Number: - var = binding->valueAsNumber(compilationUnit->constants); + var = compilationUnit->bindingValueAsNumber(binding); break; case QV4::CompiledData::Binding::Type_Boolean: var = binding->valueAsBoolean(); @@ -346,13 +346,13 @@ void QQuickPropertyChangesPrivate::decodeBinding(const QString &propertyPrefix, properties << qMakePair(propertyName, var); } -void QQuickPropertyChangesParser::verifyBindings(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &props) +void QQuickPropertyChangesParser::verifyBindings(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &props) { for (int ii = 0; ii < props.count(); ++ii) verifyList(compilationUnit, props.at(ii)); } -void QQuickPropertyChangesParser::applyBindings(QObject *obj, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings) +void QQuickPropertyChangesParser::applyBindings(QObject *obj, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings) { QQuickPropertyChangesPrivate *p = static_cast<QQuickPropertyChangesPrivate *>(QObjectPrivate::get(obj)); diff --git a/src/quick/util/qquickpropertychanges_p.h b/src/quick/util/qquickpropertychanges_p.h index 74fe511d6e..82a6ebffac 100644 --- a/src/quick/util/qquickpropertychanges_p.h +++ b/src/quick/util/qquickpropertychanges_p.h @@ -101,10 +101,10 @@ public: QQuickPropertyChangesParser() : QQmlCustomParser(AcceptsAttachedProperties) {} - void verifyList(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, const QV4::CompiledData::Binding *binding); + void verifyList(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QV4::CompiledData::Binding *binding); - void verifyBindings(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &props) override; - void applyBindings(QObject *obj, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings) override; + void verifyBindings(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &props) override; + void applyBindings(QObject *obj, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings) override; }; diff --git a/src/quick/util/qquickstategroup.cpp b/src/quick/util/qquickstategroup.cpp index d8daec2f07..b53949d21c 100644 --- a/src/quick/util/qquickstategroup.cpp +++ b/src/quick/util/qquickstategroup.cpp @@ -130,6 +130,8 @@ QQuickStateGroup::~QQuickStateGroup() Q_D(const QQuickStateGroup); for (int i = 0; i < d->states.count(); ++i) d->states.at(i)->setStateGroup(nullptr); + if (d->nullState) + d->nullState->setStateGroup(nullptr); } QList<QQuickState *> QQuickStateGroup::states() const |