aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/particles/qquickcumulativedirection.cpp2
-rw-r--r--src/qml/qml/qqmllist.cpp132
-rw-r--r--src/qml/qml/qqmllist.h129
-rw-r--r--src/qml/qml/qqmllistwrapper.cpp82
-rw-r--r--src/quick/items/qquickitem_p.h2
-rw-r--r--src/quick/items/qquickitemanimation.cpp2
-rw-r--r--src/quick/items/qquickitemviewtransition.cpp2
-rw-r--r--src/quick/items/qquickmultipointtoucharea_p.h2
-rw-r--r--src/quick/items/qquickrectangle.cpp2
-rw-r--r--src/quick/items/qquickspriteengine_p.h4
-rw-r--r--src/quick/util/qquickanimation.cpp61
-rw-r--r--src/quick/util/qquickanimation_p.h2
-rw-r--r--src/quick/util/qquickanimation_p_p.h5
-rw-r--r--tests/auto/qml/qqmllistreference/tst_qqmllistreference.cpp211
-rw-r--r--tools/qml/conf.h2
15 files changed, 572 insertions, 68 deletions
diff --git a/src/particles/qquickcumulativedirection.cpp b/src/particles/qquickcumulativedirection.cpp
index 905d44cae9..e37435e960 100644
--- a/src/particles/qquickcumulativedirection.cpp
+++ b/src/particles/qquickcumulativedirection.cpp
@@ -56,7 +56,7 @@ QQuickCumulativeDirection::QQuickCumulativeDirection(QObject *parent):QQuickDire
QQmlListProperty<QQuickDirection> QQuickCumulativeDirection::directions()
{
- return QQmlListProperty<QQuickDirection>(this, m_directions);//TODO: Proper list property
+ return QQmlListProperty<QQuickDirection>(this, &m_directions);//TODO: Proper list property
}
QPointF QQuickCumulativeDirection::sample(const QPointF &from)
diff --git a/src/qml/qml/qqmllist.cpp b/src/qml/qml/qqmllist.cpp
index 5425bf498c..b504fdf22d 100644
--- a/src/qml/qml/qqmllist.cpp
+++ b/src/qml/qml/qqmllist.cpp
@@ -250,10 +250,37 @@ bool QQmlListReference::canCount() const
}
/*!
- Return true if at(), count(), append() and clear() are implemented, so you can manipulate
- the list.
+Returns true if items in the list property can be replaced, otherwise false.
+Returns false if the reference is invalid.
+
+\sa replace()
+*/
+bool QQmlListReference::canReplace() const
+{
+ return (isValid() && d->property.replace);
+}
+
+/*!
+Returns true if the last item can be removed from the list property, otherwise false.
+Returns false if the reference is invalid.
+
+\sa removeLast()
+*/
+bool QQmlListReference::canRemoveLast() const
+{
+ return (isValid() && d->property.removeLast);
+}
+
+/*!
+ Return true if at(), count(), append(), and either clear() or removeLast()
+ are implemented, so you can manipulate the list.
+
+ Mind that replace() and removeLast() can be emulated by stashing all
+ items and rebuilding the list using clear() and append(). Therefore,
+ they are not required for the list to be manipulable. Furthermore,
+ clear() can be emulated using removeLast().
-\sa isReadable(), at(), count(), append(), clear()
+\sa isReadable(), at(), count(), append(), clear(), replace(), removeLast()
*/
bool QQmlListReference::isManipulable() const
{
@@ -329,6 +356,39 @@ int QQmlListReference::count() const
}
/*!
+Replaces the item at \a index in the list with \a object.
+Returns true if the operation succeeded, otherwise false.
+
+\sa canReplace()
+*/
+bool QQmlListReference::replace(int index, QObject *object) const
+{
+ if (!canReplace())
+ return false;
+
+ if (object && !QQmlMetaObject::canConvert(object, d->elementType))
+ return false;
+
+ d->property.replace(&d->property, index, object);
+ return true;
+}
+
+/*!
+Removes the last item in the list.
+Returns true if the operation succeeded, otherwise false.
+
+\sa canRemoveLast()
+*/
+bool QQmlListReference::removeLast() const
+{
+ if (!canRemoveLast())
+ return false;
+
+ d->property.removeLast(&d->property);
+ return true;
+}
+
+/*!
\class QQmlListProperty
\since 5.0
\inmodule QtQml
@@ -375,14 +435,25 @@ QML list properties are type-safe - in this case \c {Fruit} is a QObject type th
/*!
\fn template<typename T> QQmlListProperty<T>::QQmlListProperty(QObject *object, QList<T *> &list)
+\deprecated
Convenience constructor for making a QQmlListProperty value from an existing
QList \a list. The \a list reference must remain valid for as long as \a object
exists. \a object must be provided.
-Generally this constructor should not be used in production code, as a
-writable QList violates QML's memory management rules. However, this constructor
-can be very useful while prototyping.
+This constructor synthesizes the removeLast() and replace() methods
+introduced in Qt 5.15, using count(), at(), clear(), and append(). This is slow.
+If you intend to manipulate the list beyond clearing it, you should explicitly
+provide these methods.
+*/
+
+/*!
+\fn template<typename T> QQmlListProperty<T>::QQmlListProperty(QObject *object, QList<T *> *list)
+\since 5.15
+
+Convenience constructor for making a QQmlListProperty value from an existing
+QList \a list. The \a list reference must remain valid for as long as \a object
+exists. \a object must be provided.
*/
/*!
@@ -408,6 +479,39 @@ remains valid while \a object exists.
Null pointers can be passed for any function. If any null pointers are passed in, the list
will be neither designable nor alterable by the debugger. It is recommended to provide valid
pointers for all functions.
+
+\note The resulting QQmlListProperty will synthesize the removeLast() and
+replace() methods using \a count, \a at, \a clear, and \a append if all of those
+are given. This is slow. If you intend to manipulate the list beyond clearing it,
+you should explicitly provide these methods.
+*/
+
+/*!
+\fn template<typename T> QQmlListProperty<T>::QQmlListProperty(
+ QObject *object, void *data, AppendFunction append, CountFunction count,
+ AtFunction at, ClearFunction clear, ReplaceFunction replace,
+ RemoveLastFunction removeLast)
+
+Construct a QQmlListProperty from a set of operation functions \a append,
+\a count, \a at, \a clear, \a replace, and \removeLast. An opaque \a data handle
+may be passed which can be accessed from within the operation functions. The
+list property remains valid while \a object exists.
+
+Null pointers can be passed for any function, causing the respective function to
+be synthesized using the others, if possible. QQmlListProperty can synthesize
+\list
+ \li \a clear using \a count and \a removeLast
+ \li \a replace using \a count, \a at, \a clear, and \a append
+ \li \a replace using \a count, \a at, \a removeLast, and \a append
+ \li \a removeLast using \a count, \a at, \a clear, and \a append
+\endlist
+if those are given. This is slow, but if your list does not natively provide
+faster options for these primitives, you may want to use the synthesized ones.
+
+Furthermore, if either of \a count, \a at, \a append, and \a clear are neither
+given explicitly nor synthesized, the list will be neither designable nor
+alterable by the debugger. It is recommended to provide enough valid pointers
+to avoid this situation.
*/
/*!
@@ -448,4 +552,20 @@ Synonym for \c {void (*)(QQmlListProperty<T> *property)}.
Clear the list \a property.
*/
+/*!
+\typedef QQmlListProperty::ReplaceFunction
+
+Synonym for \c {void (*)(QQmlListProperty<T> *property, int index, T *value)}.
+
+Replace the element at position \a index in the list \a property with \a value.
+*/
+
+/*!
+\typedef QQmlListProperty::RemoveLastFunction
+
+Synonym for \c {void (*)(QQmlListProperty<T> *property)}.
+
+Remove the last element from the list \a property.
+*/
+
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmllist.h b/src/qml/qml/qqmllist.h
index 90ec57c911..17333ca9e4 100644
--- a/src/qml/qml/qqmllist.h
+++ b/src/qml/qml/qqmllist.h
@@ -55,22 +55,28 @@ struct QMetaObject;
template<typename T>
class QQmlListProperty {
public:
- typedef void (*AppendFunction)(QQmlListProperty<T> *, T*);
- typedef int (*CountFunction)(QQmlListProperty<T> *);
- typedef T *(*AtFunction)(QQmlListProperty<T> *, int);
- typedef void (*ClearFunction)(QQmlListProperty<T> *);
-
- QQmlListProperty()
- : append(nullptr),
- count(nullptr),
- at(nullptr),
- clear(nullptr)
- {}
+ using AppendFunction = void (*)(QQmlListProperty<T> *, T *);
+ using CountFunction = int (*)(QQmlListProperty<T> *);
+ using AtFunction = T *(*)(QQmlListProperty<T> *, int);
+ using ClearFunction = void (*)(QQmlListProperty<T> *);
+ using ReplaceFunction = void (*)(QQmlListProperty<T> *, int, T *);
+ using RemoveLastFunction = void (*)(QQmlListProperty<T> *);
+
+ QQmlListProperty() = default;
+
+#if QT_DEPRECATED_SINCE(5,15)
+ QT_DEPRECATED_X("Use constructor taking QList pointer, and gain improved performance")
QQmlListProperty(QObject *o, QList<T *> &list)
: object(o), data(&list), append(qlist_append), count(qlist_count), at(qlist_at),
- clear(qlist_clear)
+ clear(qlist_clear), replace(qslow_replace), removeLast(qslow_removeLast)
+ {}
+#endif
+ QQmlListProperty(QObject *o, QList<T *> *list)
+ : object(o), data(list), append(qlist_append), count(qlist_count), at(qlist_at),
+ clear(qlist_clear), replace(qlist_replace), removeLast(qlist_removeLast)
{}
+
QQmlListProperty(QObject *o, void *d, AppendFunction a, CountFunction c, AtFunction t,
ClearFunction r )
: object(o),
@@ -78,37 +84,47 @@ public:
append(a),
count(c),
at(t),
- clear(r)
-
+ clear(r),
+ replace((a && c && t && r) ? qslow_replace : nullptr),
+ removeLast((a && c && t && r) ? qslow_removeLast : nullptr)
{}
- QQmlListProperty(QObject *o, void *d, CountFunction c, AtFunction t)
+
+ QQmlListProperty(QObject *o, void *d, AppendFunction a, CountFunction c, AtFunction t,
+ ClearFunction r, ReplaceFunction s, RemoveLastFunction p)
: object(o),
data(d),
- append(nullptr),
- count(c), at(t),
- clear(nullptr)
+ append(a),
+ count(c),
+ at(t),
+ clear((!r && p && c) ? qslow_clear : r),
+ replace((!s && a && c && t && (r || p)) ? qslow_replace : s),
+ removeLast((!p && a && c && t && r) ? qslow_removeLast : p)
+ {}
+
+ QQmlListProperty(QObject *o, void *d, CountFunction c, AtFunction a)
+ : object(o), data(d), count(c), at(a)
{}
+
bool operator==(const QQmlListProperty &o) const {
return object == o.object &&
data == o.data &&
append == o.append &&
count == o.count &&
at == o.at &&
- clear == o.clear;
+ clear == o.clear &&
+ replace == o.replace &&
+ removeLast == o.removeLast;
}
QObject *object = nullptr;
void *data = nullptr;
- AppendFunction append;
-
- CountFunction count;
- AtFunction at;
-
- ClearFunction clear;
-
- void *dummy1 = nullptr;
- void *dummy2 = nullptr;
+ AppendFunction append = nullptr;
+ CountFunction count = nullptr;
+ AtFunction at = nullptr;
+ ClearFunction clear = nullptr;
+ ReplaceFunction replace = nullptr;
+ RemoveLastFunction removeLast = nullptr;
private:
static void qlist_append(QQmlListProperty *p, T *v) {
@@ -123,6 +139,59 @@ private:
static void qlist_clear(QQmlListProperty *p) {
return reinterpret_cast<QList<T *> *>(p->data)->clear();
}
+ static void qlist_replace(QQmlListProperty *p, int idx, T *v) {
+ return reinterpret_cast<QList<T *> *>(p->data)->replace(idx, v);
+ }
+ static void qlist_removeLast(QQmlListProperty *p) {
+ return reinterpret_cast<QList<T *> *>(p->data)->removeLast();
+ }
+
+ static void qslow_replace(QQmlListProperty<T> *list, int idx, T *v)
+ {
+ const int length = list->count(list);
+ if (idx < 0 || idx >= length)
+ return;
+
+ QVector<T *> stash;
+ if (list->clear != qslow_clear) {
+ stash.reserve(length);
+ for (int i = 0; i < length; ++i)
+ stash.append(i == idx ? v : list->at(list, i));
+ list->clear(list);
+ for (T *item : qAsConst(stash))
+ list->append(list, item);
+ } else {
+ stash.reserve(length - idx - 1);
+ for (int i = length - 1; i > idx; --i) {
+ stash.append(list->at(list, i));
+ list->removeLast(list);
+ }
+ list->removeLast(list);
+ list->append(list, v);
+ while (!stash.isEmpty())
+ list->append(list, stash.takeLast());
+ }
+ }
+
+ static void qslow_clear(QQmlListProperty<T> *list)
+ {
+ for (int i = 0, end = list->count(list); i < end; ++i)
+ list->removeLast(list);
+ }
+
+ static void qslow_removeLast(QQmlListProperty<T> *list)
+ {
+ const int length = list->count(list) - 1;
+ if (length < 0)
+ return;
+ QVector<T *> stash;
+ stash.reserve(length);
+ for (int i = 0; i < length; ++i)
+ stash.append(list->at(list, i));
+ list->clear(list);
+ for (T *item : qAsConst(stash))
+ list->append(list, item);
+ }
};
#endif
@@ -146,6 +215,8 @@ public:
bool canAt() const;
bool canClear() const;
bool canCount() const;
+ bool canReplace() const;
+ bool canRemoveLast() const;
bool isManipulable() const;
bool isReadable() const;
@@ -154,6 +225,8 @@ public:
QObject *at(int) const;
bool clear() const;
int count() const;
+ bool replace(int, QObject *) const;
+ bool removeLast() const;
private:
friend class QQmlListReferencePrivate;
diff --git a/src/qml/qml/qqmllistwrapper.cpp b/src/qml/qml/qqmllistwrapper.cpp
index 5349572921..e5c1cb04a9 100644
--- a/src/qml/qml/qqmllistwrapper.cpp
+++ b/src/qml/qml/qqmllistwrapper.cpp
@@ -119,11 +119,13 @@ ReturnedValue QmlListWrapper::virtualGet(const Managed *m, PropertyKey id, const
if (hasProperty)
*hasProperty = false;
return Value::undefinedValue().asReturnedValue();
- } else if (id.isString()) {
- if (id == v4->id_length()->propertyKey() && !w->d()->object.isNull()) {
- quint32 count = w->d()->property().count ? w->d()->property().count(&w->d()->property()) : 0;
- return Value::fromUInt32(count).asReturnedValue();
- }
+ }
+
+ if (id.isString() && id == v4->id_length()->propertyKey()) {
+ if (hasProperty)
+ *hasProperty = true;
+ quint32 count = w->d()->property().count ? w->d()->property().count(&w->d()->property()) : 0;
+ return Value::fromUInt32(count).asReturnedValue();
}
return Object::virtualGet(m, id, receiver, hasProperty);
@@ -131,12 +133,70 @@ ReturnedValue QmlListWrapper::virtualGet(const Managed *m, PropertyKey id, const
bool QmlListWrapper::virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver)
{
- // doesn't do anything. Should we throw?
- Q_UNUSED(m);
- Q_UNUSED(id);
- Q_UNUSED(value);
- Q_UNUSED(receiver);
- return false;
+ Q_ASSERT(m->as<QmlListWrapper>());
+
+ const auto *w = static_cast<const QmlListWrapper *>(m);
+ QV4::ExecutionEngine *v4 = w->engine();
+
+ QQmlListProperty<QObject> *prop = &(w->d()->property());
+
+ if (id.isArrayIndex()) {
+ if (!prop->count || !prop->replace)
+ return false;
+
+ const uint index = id.asArrayIndex();
+ const int count = prop->count(prop);
+ if (count < 0 || index >= uint(count))
+ return false;
+
+ QV4::Scope scope(v4);
+ QV4::ScopedObject so(scope, value.toObject(scope.engine));
+ if (auto *wrapper = so->as<QV4::QObjectWrapper>()) {
+ prop->replace(prop, index, wrapper->object());
+ return true;
+ }
+
+ return false;
+ }
+
+ if (id.isString() && id == v4->id_length()->propertyKey()) {
+ if (!prop->count)
+ return false;
+
+ const quint32 count = prop->count(prop);
+
+ bool ok = false;
+ const uint newLength = value.asArrayLength(&ok);
+ if (!ok)
+ return false;
+
+ if (newLength == 0) {
+ if (!prop->clear)
+ return false;
+ prop->clear(prop);
+ return true;
+ }
+
+ if (newLength < count) {
+ if (!prop->removeLast)
+ return false;
+
+ for (uint i = newLength; i < count; ++i)
+ prop->removeLast(prop);
+
+ return true;
+ }
+
+ if (!prop->append)
+ return false;
+
+ for (uint i = count; i < newLength; ++i)
+ prop->append(prop, nullptr);
+
+ return true;
+ }
+
+ return Object::virtualPut(m, id, value, receiver);
}
struct QmlListWrapperOwnPropertyKeyIterator : ObjectOwnPropertyKeyIterator
diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h
index baef37a0ff..3c0517cb3b 100644
--- a/src/quick/items/qquickitem_p.h
+++ b/src/quick/items/qquickitem_p.h
@@ -867,7 +867,7 @@ public:
QQmlListProperty<QQuickItem> forwardTo() {
Q_D(QQuickKeysAttached);
- return QQmlListProperty<QQuickItem>(this, d->targets);
+ return QQmlListProperty<QQuickItem>(this, &(d->targets));
}
void componentComplete() override;
diff --git a/src/quick/items/qquickitemanimation.cpp b/src/quick/items/qquickitemanimation.cpp
index 8251282736..23694e2de3 100644
--- a/src/quick/items/qquickitemanimation.cpp
+++ b/src/quick/items/qquickitemanimation.cpp
@@ -456,7 +456,7 @@ QQuickAnchorAnimation::~QQuickAnchorAnimation()
QQmlListProperty<QQuickItem> QQuickAnchorAnimation::targets()
{
Q_D(QQuickAnchorAnimation);
- return QQmlListProperty<QQuickItem>(this, d->targets);
+ return QQmlListProperty<QQuickItem>(this, &(d->targets));
}
/*!
diff --git a/src/quick/items/qquickitemviewtransition.cpp b/src/quick/items/qquickitemviewtransition.cpp
index 109851608b..b7649c9952 100644
--- a/src/quick/items/qquickitemviewtransition.cpp
+++ b/src/quick/items/qquickitemviewtransition.cpp
@@ -925,7 +925,7 @@ QQuickViewTransitionAttached::QQuickViewTransitionAttached(QObject *parent)
*/
QQmlListProperty<QObject> QQuickViewTransitionAttached::targetItems()
{
- return QQmlListProperty<QObject>(this, m_targetItems);
+ return QQmlListProperty<QObject>(this, &m_targetItems);
}
QQuickViewTransitionAttached *QQuickViewTransitionAttached::qmlAttachedProperties(QObject *obj)
diff --git a/src/quick/items/qquickmultipointtoucharea_p.h b/src/quick/items/qquickmultipointtoucharea_p.h
index 42b42a45c5..363e62593b 100644
--- a/src/quick/items/qquickmultipointtoucharea_p.h
+++ b/src/quick/items/qquickmultipointtoucharea_p.h
@@ -198,7 +198,7 @@ public:
bool wantsGrab() const { return _grab; }
QQmlListProperty<QObject> touchPoints() {
- return QQmlListProperty<QObject>(this, _touchPoints);
+ return QQmlListProperty<QObject>(this, &_touchPoints);
}
qreal dragThreshold() const { return _dragThreshold; }
diff --git a/src/quick/items/qquickrectangle.cpp b/src/quick/items/qquickrectangle.cpp
index f3cefc7463..c1f2b77f5b 100644
--- a/src/quick/items/qquickrectangle.cpp
+++ b/src/quick/items/qquickrectangle.cpp
@@ -257,7 +257,7 @@ QQuickGradient::~QQuickGradient()
QQmlListProperty<QQuickGradientStop> QQuickGradient::stops()
{
- return QQmlListProperty<QQuickGradientStop>(this, m_stops);
+ return QQmlListProperty<QQuickGradientStop>(this, &m_stops);
}
/*!
diff --git a/src/quick/items/qquickspriteengine_p.h b/src/quick/items/qquickspriteengine_p.h
index da505be911..d76055c831 100644
--- a/src/quick/items/qquickspriteengine_p.h
+++ b/src/quick/items/qquickspriteengine_p.h
@@ -196,7 +196,7 @@ public:
QQmlListProperty<QQuickStochasticState> states()
{
- return QQmlListProperty<QQuickStochasticState>(this, m_states);
+ return QQmlListProperty<QQuickStochasticState>(this, &m_states);
}
QString globalGoal() const
@@ -272,7 +272,7 @@ public:
~QQuickSpriteEngine() override;
QQmlListProperty<QQuickSprite> sprites()
{
- return QQmlListProperty<QQuickSprite>(this, m_sprites);
+ return QQmlListProperty<QQuickSprite>(this, &m_sprites);
}
QQuickSprite* sprite(int sprite = 0) const;
diff --git a/src/quick/util/qquickanimation.cpp b/src/quick/util/qquickanimation.cpp
index 5e9722e6b4..d6d6f1d8d4 100644
--- a/src/quick/util/qquickanimation.cpp
+++ b/src/quick/util/qquickanimation.cpp
@@ -490,7 +490,7 @@ QQuickAnimationGroup *QQuickAbstractAnimation::group() const
return d->group;
}
-void QQuickAbstractAnimation::setGroup(QQuickAnimationGroup *g)
+void QQuickAbstractAnimation::setGroup(QQuickAnimationGroup *g, int index)
{
Q_D(QQuickAbstractAnimation);
if (d->group == g)
@@ -500,8 +500,12 @@ void QQuickAbstractAnimation::setGroup(QQuickAnimationGroup *g)
d->group = g;
- if (d->group && !d->group->d_func()->animations.contains(this))
- d->group->d_func()->animations.append(this);
+ if (d->group && !d->group->d_func()->animations.contains(this)) {
+ if (index >= 0)
+ d->group->d_func()->animations.insert(index, this);
+ else
+ d->group->d_func()->animations.append(this);
+ }
}
/*!
@@ -1170,7 +1174,7 @@ void QQuickPropertyAction::setProperties(const QString &p)
QQmlListProperty<QObject> QQuickPropertyAction::targets()
{
Q_D(QQuickPropertyAction);
- return QQmlListProperty<QObject>(this, d->targets);
+ return QQmlListProperty<QObject>(this, &(d->targets));
}
/*!
@@ -1182,7 +1186,7 @@ QQmlListProperty<QObject> QQuickPropertyAction::targets()
QQmlListProperty<QObject> QQuickPropertyAction::exclude()
{
Q_D(QQuickPropertyAction);
- return QQmlListProperty<QObject>(this, d->exclude);
+ return QQmlListProperty<QObject>(this, &(d->exclude));
}
/*!
@@ -1722,6 +1726,20 @@ void QQuickAnimationGroupPrivate::append_animation(QQmlListProperty<QQuickAbstra
a->setGroup(q);
}
+QQuickAbstractAnimation *QQuickAnimationGroupPrivate::at_animation(QQmlListProperty<QQuickAbstractAnimation> *list, int index)
+{
+ if (auto q = qmlobject_cast<QQuickAnimationGroup *>(list->object))
+ return q->d_func()->animations.at(index);
+ return nullptr;
+}
+
+int QQuickAnimationGroupPrivate::count_animation(QQmlListProperty<QQuickAbstractAnimation> *list)
+{
+ if (auto q = qmlobject_cast<QQuickAnimationGroup *>(list->object))
+ return q->d_func()->animations.count();
+ return 0;
+}
+
void QQuickAnimationGroupPrivate::clear_animation(QQmlListProperty<QQuickAbstractAnimation> *list)
{
QQuickAnimationGroup *q = qobject_cast<QQuickAnimationGroup *>(list->object);
@@ -1733,6 +1751,23 @@ void QQuickAnimationGroupPrivate::clear_animation(QQmlListProperty<QQuickAbstrac
}
}
+void QQuickAnimationGroupPrivate::replace_animation(QQmlListProperty<QQuickAbstractAnimation> *list,
+ int i, QQuickAbstractAnimation *a)
+{
+ if (auto *q = qmlobject_cast<QQuickAnimationGroup *>(list->object)) {
+ if (QQuickAbstractAnimation *anim = q->d_func()->animations.at(i))
+ anim->setGroup(nullptr);
+ if (a)
+ a->setGroup(q, i);
+ }
+}
+
+void QQuickAnimationGroupPrivate::removeLast_animation(QQmlListProperty<QQuickAbstractAnimation> *list)
+{
+ if (auto *q = qobject_cast<QQuickAnimationGroup *>(list->object))
+ q->d_func()->animations.last()->setGroup(nullptr);
+}
+
QQuickAnimationGroup::~QQuickAnimationGroup()
{
Q_D(QQuickAnimationGroup);
@@ -1744,10 +1779,14 @@ QQuickAnimationGroup::~QQuickAnimationGroup()
QQmlListProperty<QQuickAbstractAnimation> QQuickAnimationGroup::animations()
{
Q_D(QQuickAnimationGroup);
- QQmlListProperty<QQuickAbstractAnimation> list(this, d->animations);
- list.append = &QQuickAnimationGroupPrivate::append_animation;
- list.clear = &QQuickAnimationGroupPrivate::clear_animation;
- return list;
+ return QQmlListProperty<QQuickAbstractAnimation>(
+ this, &(d->animations),
+ &QQuickAnimationGroupPrivate::append_animation,
+ &QQuickAnimationGroupPrivate::count_animation,
+ &QQuickAnimationGroupPrivate::at_animation,
+ &QQuickAnimationGroupPrivate::clear_animation,
+ &QQuickAnimationGroupPrivate::replace_animation,
+ &QQuickAnimationGroupPrivate::removeLast_animation);
}
/*!
@@ -2533,7 +2572,7 @@ void QQuickPropertyAnimation::setProperties(const QString &prop)
QQmlListProperty<QObject> QQuickPropertyAnimation::targets()
{
Q_D(QQuickPropertyAnimation);
- return QQmlListProperty<QObject>(this, d->targets);
+ return QQmlListProperty<QObject>(this, &(d->targets));
}
/*!
@@ -2544,7 +2583,7 @@ QQmlListProperty<QObject> QQuickPropertyAnimation::targets()
QQmlListProperty<QObject> QQuickPropertyAnimation::exclude()
{
Q_D(QQuickPropertyAnimation);
- return QQmlListProperty<QObject>(this, d->exclude);
+ return QQmlListProperty<QObject>(this, &(d->exclude));
}
void QQuickAnimationPropertyUpdater::setValue(qreal v)
diff --git a/src/quick/util/qquickanimation_p.h b/src/quick/util/qquickanimation_p.h
index 45f1635c91..7bad9d50c4 100644
--- a/src/quick/util/qquickanimation_p.h
+++ b/src/quick/util/qquickanimation_p.h
@@ -111,7 +111,7 @@ public:
void setCurrentTime(int);
QQuickAnimationGroup *group() const;
- void setGroup(QQuickAnimationGroup *);
+ void setGroup(QQuickAnimationGroup *, int index = -1);
void setDefaultTarget(const QQmlProperty &);
void setDisableUserControl();
diff --git a/src/quick/util/qquickanimation_p_p.h b/src/quick/util/qquickanimation_p_p.h
index c20ec65c24..8d23242b68 100644
--- a/src/quick/util/qquickanimation_p_p.h
+++ b/src/quick/util/qquickanimation_p_p.h
@@ -256,7 +256,12 @@ public:
: QQuickAbstractAnimationPrivate() {}
static void append_animation(QQmlListProperty<QQuickAbstractAnimation> *list, QQuickAbstractAnimation *role);
+ static QQuickAbstractAnimation *at_animation(QQmlListProperty<QQuickAbstractAnimation> *list, int index);
+ static int count_animation(QQmlListProperty<QQuickAbstractAnimation> *list);
static void clear_animation(QQmlListProperty<QQuickAbstractAnimation> *list);
+ static void replace_animation(QQmlListProperty<QQuickAbstractAnimation> *list, int index,
+ QQuickAbstractAnimation *role);
+ static void removeLast_animation(QQmlListProperty<QQuickAbstractAnimation> *list);
QList<QQuickAbstractAnimation *> animations;
};
diff --git a/tests/auto/qml/qqmllistreference/tst_qqmllistreference.cpp b/tests/auto/qml/qqmllistreference/tst_qqmllistreference.cpp
index 8efaedf5b5..e25d555d61 100644
--- a/tests/auto/qml/qqmllistreference/tst_qqmllistreference.cpp
+++ b/tests/auto/qml/qqmllistreference/tst_qqmllistreference.cpp
@@ -45,6 +45,9 @@ class tst_qqmllistreference : public QQmlDataTest
public:
tst_qqmllistreference() {}
+private:
+ void modeData();
+
private slots:
void initTestCase();
void qmllistreference();
@@ -56,12 +59,19 @@ private slots:
void canAt();
void canClear();
void canCount();
+ void canReplace();
+ void canRemoveLast();
void isReadable();
void isManipulable();
void append();
void at();
+ void clear_data() { modeData(); }
void clear();
void count();
+ void replace_data() { modeData(); }
+ void replace();
+ void removeLast_data() { modeData(); }
+ void removeLast();
void copy();
void qmlmetaproperty();
void engineTypes();
@@ -76,7 +86,67 @@ class TestType : public QObject
Q_PROPERTY(int intProperty READ intProperty)
public:
- TestType() : property(this, data) {}
+ enum Mode {
+ SyntheticClear,
+ SyntheticReplace,
+ SyntheticClearAndReplace,
+ SyntheticRemoveLast,
+ SyntheticRemoveLastAndReplace,
+ AutomaticReference,
+ AutomaticPointer
+ };
+
+ static void append(QQmlListProperty<TestType> *p, TestType *v) {
+ reinterpret_cast<QList<TestType *> *>(p->data)->append(v);
+ }
+ static int count(QQmlListProperty<TestType> *p) {
+ return reinterpret_cast<QList<TestType *> *>(p->data)->count();
+ }
+ static TestType *at(QQmlListProperty<TestType> *p, int idx) {
+ return reinterpret_cast<QList<TestType *> *>(p->data)->at(idx);
+ }
+ static void clear(QQmlListProperty<TestType> *p) {
+ return reinterpret_cast<QList<TestType *> *>(p->data)->clear();
+ }
+ static void replace(QQmlListProperty<TestType> *p, int idx, TestType *v) {
+ return reinterpret_cast<QList<TestType *> *>(p->data)->replace(idx, v);
+ }
+ static void removeLast(QQmlListProperty<TestType> *p) {
+ return reinterpret_cast<QList<TestType *> *>(p->data)->removeLast();
+ }
+
+ TestType(Mode mode = AutomaticReference)
+ {
+ switch (mode) {
+ case SyntheticClear:
+ property = QQmlListProperty<TestType>(this, &data, append, count, at, nullptr,
+ replace, removeLast);
+ break;
+ case SyntheticReplace:
+ property = QQmlListProperty<TestType>(this, &data, append, count, at, clear,
+ nullptr, removeLast);
+ break;
+ case SyntheticClearAndReplace:
+ property = QQmlListProperty<TestType>(this, &data, append, count, at, nullptr,
+ nullptr, removeLast);
+ break;
+ case SyntheticRemoveLast:
+ property = QQmlListProperty<TestType>(this, &data, append, count, at, clear,
+ replace, nullptr);
+ break;
+ case SyntheticRemoveLastAndReplace:
+ property = QQmlListProperty<TestType>(this, &data, append, count, at, clear,
+ nullptr, nullptr);
+ break;
+ case AutomaticReference:
+ property = QQmlListProperty<TestType>(this, data);
+ break;
+ case AutomaticPointer:
+ property = QQmlListProperty<TestType>(this, &data);
+ break;
+ }
+ }
+
QQmlListProperty<TestType> dataProperty() { return property; }
int intProperty() const { return 10; }
@@ -84,6 +154,20 @@ public:
QQmlListProperty<TestType> property;
};
+Q_DECLARE_METATYPE(TestType::Mode)
+
+void tst_qqmllistreference::modeData()
+{
+ QTest::addColumn<TestType::Mode>("mode");
+ QTest::addRow("AutomaticReference") << TestType::AutomaticReference;
+ QTest::addRow("AutomaticPointer") << TestType::AutomaticPointer;
+ QTest::addRow("SyntheticClear") << TestType::SyntheticClear;
+ QTest::addRow("SyntheticReplace") << TestType::SyntheticReplace;
+ QTest::addRow("SyntheticClearAndReplace") << TestType::SyntheticClearAndReplace;
+ QTest::addRow("SyntheticRemoveLast") << TestType::SyntheticRemoveLast;
+ QTest::addRow("SyntheticRemoveLastAndReplace") << TestType::SyntheticRemoveLastAndReplace;
+}
+
void tst_qqmllistreference::initTestCase()
{
QQmlDataTest::initTestCase();
@@ -340,6 +424,64 @@ void tst_qqmllistreference::canCount()
}
}
+void tst_qqmllistreference::canReplace()
+{
+ QScopedPointer<TestType> tt(new TestType);
+
+ {
+ QQmlListReference ref;
+ QVERIFY(!ref.canReplace());
+ }
+
+ {
+ QQmlListReference ref(tt.data(), "blah");
+ QVERIFY(!ref.canReplace());
+ }
+
+ {
+ QQmlListReference ref(tt.data(), "data");
+ QVERIFY(ref.canReplace());
+ tt.reset();
+ QVERIFY(!ref.canReplace());
+ }
+
+ {
+ TestType tt;
+ tt.property.replace = nullptr;
+ QQmlListReference ref(&tt, "data");
+ QVERIFY(!ref.canReplace());
+ }
+}
+
+void tst_qqmllistreference::canRemoveLast()
+{
+ QScopedPointer<TestType> tt(new TestType);
+
+ {
+ QQmlListReference ref;
+ QVERIFY(!ref.canRemoveLast());
+ }
+
+ {
+ QQmlListReference ref(tt.data(), "blah");
+ QVERIFY(!ref.canRemoveLast());
+ }
+
+ {
+ QQmlListReference ref(tt.data(), "data");
+ QVERIFY(ref.canRemoveLast());
+ tt.reset();
+ QVERIFY(!ref.canRemoveLast());
+ }
+
+ {
+ TestType tt;
+ tt.property.removeLast = nullptr;
+ QQmlListReference ref(&tt, "data");
+ QVERIFY(!ref.canRemoveLast());
+ }
+}
+
void tst_qqmllistreference::isReadable()
{
TestType *tt = new TestType;
@@ -474,7 +616,8 @@ void tst_qqmllistreference::at()
void tst_qqmllistreference::clear()
{
- TestType *tt = new TestType;
+ QFETCH(TestType::Mode, mode);
+ TestType *tt = new TestType(mode);
tt->data.append(tt);
tt->data.append(0);
tt->data.append(tt);
@@ -540,6 +683,70 @@ void tst_qqmllistreference::count()
}
}
+void tst_qqmllistreference::replace()
+{
+ QFETCH(TestType::Mode, mode);
+ QScopedPointer<TestType> tt(new TestType(mode));
+ tt->data.append(tt.get());
+ tt->data.append(nullptr);
+ tt->data.append(tt.get());
+
+ {
+ QQmlListReference ref(tt.get(), "data");
+ QVERIFY(ref.replace(1, tt.get()));
+ QCOMPARE(ref.at(1), tt.get());
+ QVERIFY(ref.replace(2, nullptr));
+ QCOMPARE(ref.at(2), nullptr);
+ QCOMPARE(ref.count(), 3);
+ tt.reset();
+ QVERIFY(!ref.replace(0, tt.get()));
+ }
+
+ {
+ TestType tt;
+ tt.data.append(&tt);
+ tt.property.replace = nullptr;
+ QQmlListReference ref(&tt, "data");
+ QVERIFY(!ref.replace(0, nullptr));
+ }
+}
+
+void tst_qqmllistreference::removeLast()
+{
+ QFETCH(TestType::Mode, mode);
+ QScopedPointer<TestType> tt(new TestType(mode));
+ tt->data.append(tt.get());
+ tt->data.append(nullptr);
+ tt->data.append(tt.get());
+
+ {
+ QQmlListReference ref;
+ QVERIFY(!ref.removeLast());
+ }
+
+ {
+ QQmlListReference ref(tt.get(), "blah");
+ QVERIFY(!ref.removeLast());
+ }
+
+ {
+ QQmlListReference ref(tt.get(), "data");
+ QCOMPARE(tt->data.count(), 3);
+ QVERIFY(ref.removeLast());
+ QCOMPARE(tt->data.count(), 2);
+ tt.reset();
+ QVERIFY(!ref.removeLast());
+ }
+
+ {
+ TestType tt;
+ tt.property.removeLast = nullptr;
+ QQmlListReference ref(&tt, "data");
+ ref.append(&tt);
+ QVERIFY(!ref.removeLast());
+ }
+}
+
void tst_qqmllistreference::copy()
{
TestType tt;
diff --git a/tools/qml/conf.h b/tools/qml/conf.h
index e83d63cba5..4ad45428ed 100644
--- a/tools/qml/conf.h
+++ b/tools/qml/conf.h
@@ -81,7 +81,7 @@ public:
QQmlListProperty<PartialScene> sceneCompleters()
{
- return QQmlListProperty<PartialScene>(this, completers);
+ return QQmlListProperty<PartialScene>(this, &completers);
}
QList<PartialScene*> completers;