diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2022-01-07 11:01:56 +0100 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2022-01-28 15:03:00 +0100 |
commit | b0fc028cb5a5dfa9e95640a32e9b38ca6df0734d (patch) | |
tree | 7a446acca0f5bcbe4e62a1ac22bdb0185913bc5a /src/qml/jsruntime/qv4sequenceobject.cpp | |
parent | 8c4c0605b077d63e3d73d34ad6dcc4a2cf607b4c (diff) | |
download | qtdeclarative-b0fc028cb5a5dfa9e95640a32e9b38ca6df0734d.tar.gz |
QML: Allow named lists of value types
We register QList<T> as sequential container type for any value type T
we get. This way we can always find a type to use for list<t> with t
being a value type. The metatypes are shuffled around so that we have an
easier time associating a type with its list and vice versa.
As QQmlPropertyData's isQList flag denotes both QQmlListProperty<T> and
QList<T> now, we need to use QMetaType::IsQmlList more often.
Conversely, any name given to extra sequential containers registered via
QML_SEQUENTIAL_CONTAINER is explicitly ignored now. As you can do
list<foo> for any type foo now, there is not much of a point in having
further named container registrations for the same type. It would just
make things more complicated. Mind that the name had already been
ignored before, just not explicitly.
[ChangeLog][QtQml] You can now use lists of value types in QML. For
example a property of type list<int> will hold a list of integers.
Task-number: QTBUG-82443
Change-Id: I7bee61cee3963dae5d231bf59f70b8012984371d
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/qml/jsruntime/qv4sequenceobject.cpp')
-rw-r--r-- | src/qml/jsruntime/qv4sequenceobject.cpp | 87 |
1 files changed, 52 insertions, 35 deletions
diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp index 7d4c91bb50..42ad6b8716 100644 --- a/src/qml/jsruntime/qv4sequenceobject.cpp +++ b/src/qml/jsruntime/qv4sequenceobject.cpp @@ -81,7 +81,7 @@ struct QV4Sequence : Object { void init(const QQmlType &qmlType, const void *container); void init(QObject *object, int propertyIndex, const QQmlType &qmlType, bool readOnly); void destroy() { - typePrivate->typeId.destroy(container); + typePrivate->listId.destroy(container); QQmlType::derefHandle(typePrivate); object.destroy(); Object::destroy(); @@ -110,31 +110,41 @@ struct QV4Sequence : public QV4::Object V4_NEEDS_DESTROY public: + static const QMetaSequence *metaSequence(const Heap::QV4Sequence *p) + { + return p->typePrivate->extraData.ld; + } + + static const QMetaType valueMetaType(const Heap::QV4Sequence *p) + { + return p->typePrivate->typeId; + } + qsizetype size() const { const auto *p = d(); - return meta(p)->size(p->container); + return metaSequence(p)->size(p->container); } QVariant at(int index) const { const auto *p = d(); - const auto *m = meta(p); - QVariant result(m->valueMetaType()); - m->valueAtIndex(p->container, index, result.data()); + QVariant result(valueMetaType(p)); + metaSequence(p)->valueAtIndex(p->container, index, result.data()); return result; } void append(const QVariant &item) { const auto *p = d(); - const auto *m = meta(p); - if (item.metaType() == m->valueMetaType()) { + const auto *m = metaSequence(p); + const QMetaType v = valueMetaType(p); + if (item.metaType() == v) { m->addValueAtEnd(p->container, item.constData()); } else { QVariant converted = item; - if (!converted.convert(m->valueMetaType())) - converted = QVariant(m->valueMetaType()); + if (!converted.convert(v)) + converted = QVariant(v); m->addValueAtEnd(p->container, converted.constData()); } } @@ -142,13 +152,14 @@ public: void replace(int index, const QVariant &item) { const auto *p = d(); - const auto *m = meta(p); - if (item.metaType() == m->valueMetaType()) { + const auto *m = metaSequence(p); + const QMetaType v = valueMetaType(p); + if (item.metaType() == v) { m->setValueAtIndex(p->container, index, item.constData()); } else { QVariant converted = item; - if (!converted.convert(m->valueMetaType())) - converted = QVariant(m->valueMetaType()); + if (!converted.convert(v)) + converted = QVariant(v); m->setValueAtIndex(p->container, index, converted.constData()); } } @@ -157,9 +168,9 @@ public: void sort(const Compare &compare) { const auto *p = d(); - const auto *m = meta(p); + const auto *m = metaSequence(p); - QSequentialIterable iterable(*m, p->typePrivate->typeId, p->container); + QSequentialIterable iterable(*m, p->typePrivate->listId, p->container); if (iterable.canRandomAccessIterate()) { std::sort(QSequentialIterable::RandomAccessIterator(iterable.mutableBegin()), QSequentialIterable::RandomAccessIterator(iterable.mutableEnd()), @@ -176,7 +187,7 @@ public: void removeLast(int num) { const auto *p = d(); - const auto *m = meta(p); + const auto *m = metaSequence(p); if (m->canEraseRangeAtIterator() && m->hasRandomAccessIterator() && num > 1) { void *i = m->end(p->container); @@ -194,7 +205,7 @@ public: QVariant toVariant() { const auto *p = d(); - return QVariant(p->typePrivate->typeId, p->container); + return QVariant(p->typePrivate->listId, p->container); } // ### Qt 7 use qsizetype instead. @@ -249,8 +260,8 @@ public: } quint32 count = quint32(size()); - const QMetaType valueMetaType = meta(d())->valueMetaType(); - const QVariant element = engine()->toVariant(value, valueMetaType, false); + const QMetaType valueType = valueMetaType(d()); + const QVariant element = engine()->toVariant(value, valueType, false); if (index == count) { append(element); @@ -260,7 +271,7 @@ public: /* according to ECMA262r3 we need to insert */ /* the value at the given index, increasing length to index+1. */ while (index > count++) - append(QVariant(valueMetaType)); + append(QVariant(valueType)); append(element); } @@ -471,7 +482,7 @@ void Heap::QV4Sequence::init(const QQmlType &qmlType, const void *container) typePrivate = qmlType.priv(); QQmlType::refHandle(typePrivate); - this->container = QMetaType(typePrivate->typeId).create(container); + this->container = typePrivate->listId.create(container); propertyIndex = -1; isReference = false; isReadOnly = false; @@ -490,7 +501,7 @@ void Heap::QV4Sequence::init(QObject *object, int propertyIndex, const QQmlType Q_ASSERT(qmlType.isSequentialContainer()); typePrivate = qmlType.priv(); QQmlType::refHandle(typePrivate); - container = QMetaType(typePrivate->typeId).create(); + container = QMetaType(typePrivate->listId).create(); this->propertyIndex = propertyIndex; isReference = true; this->isReadOnly = readOnly; @@ -571,7 +582,6 @@ static QV4::ReturnedValue method_set_length(const FunctionObject *f, const Value RETURN_UNDEFINED(); } - void SequencePrototype::init() { defineDefaultProperty(QStringLiteral("sort"), method_sort, 1); @@ -612,7 +622,7 @@ ReturnedValue SequencePrototype::newSequence( // (as well as object ptr + property index for updated-read and write-back) // and so access/mutate avoids variant conversion. - const QQmlType qmlType = QQmlMetaType::qmlType(sequenceType); + const QQmlType qmlType = QQmlMetaType::qmlListType(sequenceType); if (qmlType.isSequentialContainer()) { *succeeded = true; QV4::ScopedObject obj(scope, engine->memoryManager->allocate<QV4Sequence>( @@ -638,7 +648,7 @@ ReturnedValue SequencePrototype::fromData(ExecutionEngine *engine, QMetaType typ // Access and mutation is extremely fast since it will not need to modify any // QObject property. - const QQmlType qmlType = QQmlMetaType::qmlType(type); + const QQmlType qmlType = QQmlMetaType::qmlListType(type); if (qmlType.isSequentialContainer()) { *succeeded = true; QV4::ScopedObject obj(scope, engine->memoryManager->allocate<QV4Sequence>(qmlType, data)); @@ -666,18 +676,25 @@ QVariant SequencePrototype::toVariant(const QV4::Value &array, QMetaType typeHin QV4::Scope scope(array.as<Object>()->engine()); QV4::ScopedArrayObject a(scope, array); - const QQmlType type = QQmlMetaType::qmlType(typeHint); + const QQmlType type = QQmlMetaType::qmlListType(typeHint); if (type.isSequentialContainer()) { - const QMetaSequence *meta = type.priv()->extraData.ld; - const QMetaType containerMetaType(type.priv()->typeId); + const QQmlTypePrivate *priv = type.priv(); + const QMetaSequence *meta = priv->extraData.ld; + const QMetaType containerMetaType(priv->listId); QVariant result(containerMetaType); quint32 length = a->getLength(); QV4::ScopedValue v(scope); for (quint32 i = 0; i < length; ++i) { - const QMetaType valueMetaType = meta->valueMetaType(); + const QMetaType valueMetaType = priv->typeId; QVariant variant = scope.engine->toVariant(a->get(i), valueMetaType, false); - if (variant.metaType() != valueMetaType && !variant.convert(valueMetaType)) + const QMetaType originalType = variant.metaType(); + if (originalType != valueMetaType && !variant.convert(valueMetaType)) { + qWarning() << QLatin1String( + "Could not convert array value at position %1 from %2 to %3") + .arg(QString::number(i), QString::fromUtf8(originalType.name()), + QString::fromUtf8(valueMetaType.name())); variant = QVariant(valueMetaType); + } meta->addValueAtEnd(result.data(), variant.constData()); } return result; @@ -687,20 +704,20 @@ QVariant SequencePrototype::toVariant(const QV4::Value &array, QMetaType typeHin return QVariant(); } -void* SequencePrototype::getRawContainerPtr(const Object *object, int typeHint) +void *SequencePrototype::getRawContainerPtr(const Object *object, QMetaType typeHint) { if (auto *s = object->as<QV4Sequence>()) { - if (s->d()->typePrivate->typeId.id() == typeHint) + if (s->d()->typePrivate->listId == typeHint) return s->getRawContainerPtr(); } return nullptr; } -int SequencePrototype::metaTypeForSequence(const QV4::Object *object) +QMetaType SequencePrototype::metaTypeForSequence(const QV4::Object *object) { if (auto *s = object->as<QV4Sequence>()) - return s->d()->typePrivate->typeId.id(); - return -1; + return s->d()->typePrivate->listId; + return QMetaType(); } QT_END_NAMESPACE |