QML: Allow conversion from QV4::Sequence to different iterable
Pick-to: 6.5 Fixes: QTBUG-112291 Change-Id: Idd47ea8daf9c54759af6c1feba68bd52d1163615 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
parent
4307755655
commit
1b89c1edca
|
@ -2444,6 +2444,23 @@ void ExecutionEngine::setExtensionData(int index, Deletable *data)
|
||||||
m_extensionData[index] = data;
|
m_extensionData[index] = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename Source>
|
||||||
|
bool convertToIterable(QMetaType metaType, void *data, Source *sequence)
|
||||||
|
{
|
||||||
|
QSequentialIterable iterable;
|
||||||
|
if (!QMetaType::view(metaType, data, QMetaType::fromType<QSequentialIterable>(), &iterable))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const QMetaType elementMetaType = iterable.valueMetaType();
|
||||||
|
QVariant element(elementMetaType);
|
||||||
|
for (qsizetype i = 0, end = sequence->getLength(); i < end; ++i) {
|
||||||
|
if (!ExecutionEngine::metaTypeFromJS(sequence->get(i), elementMetaType, element.data()))
|
||||||
|
element = QVariant(elementMetaType);
|
||||||
|
iterable.addValue(element, QSequentialIterable::AtEnd);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Converts a JS value to a meta-type.
|
// Converts a JS value to a meta-type.
|
||||||
// data must point to a place that can store a value of the given type.
|
// data must point to a place that can store a value of the given type.
|
||||||
// Returns true if conversion succeeded, false otherwise.
|
// Returns true if conversion succeeded, false otherwise.
|
||||||
|
@ -2711,22 +2728,15 @@ bool ExecutionEngine::metaTypeFromJS(const Value &value, QMetaType metaType, voi
|
||||||
metaType.construct(data, result.constData());
|
metaType.construct(data, result.constData());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (convertToIterable(metaType, data, sequence))
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (const QV4::ArrayObject *array = value.as<ArrayObject>()) {
|
if (const QV4::ArrayObject *array = value.as<ArrayObject>()) {
|
||||||
QSequentialIterable iterable;
|
if (convertToIterable(metaType, data, array))
|
||||||
if (QMetaType::view(
|
|
||||||
metaType, data, QMetaType::fromType<QSequentialIterable>(), &iterable)) {
|
|
||||||
const QMetaType elementMetaType = iterable.valueMetaType();
|
|
||||||
QVariant element(elementMetaType);
|
|
||||||
for (qsizetype i = 0, end = array->getLength(); i < end; ++i) {
|
|
||||||
if (!metaTypeFromJS(array->get(i), elementMetaType, element.data()))
|
|
||||||
element = QVariant(elementMetaType);
|
|
||||||
iterable.addValue(element, QSequentialIterable::AtEnd);
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ set(cpp_sources
|
||||||
multiforeign.h
|
multiforeign.h
|
||||||
objectwithmethod.h
|
objectwithmethod.h
|
||||||
person.cpp person.h
|
person.cpp person.h
|
||||||
|
sequenceToIterable.h
|
||||||
sequencetypeexample.cpp sequencetypeexample.h
|
sequencetypeexample.cpp sequencetypeexample.h
|
||||||
state.h
|
state.h
|
||||||
theme.cpp theme.h
|
theme.cpp theme.h
|
||||||
|
@ -184,6 +185,7 @@ set(qml_files
|
||||||
scopeVsObject.qml
|
scopeVsObject.qml
|
||||||
script.js
|
script.js
|
||||||
script.mjs
|
script.mjs
|
||||||
|
sequenceToIterable.qml
|
||||||
shadowedMethod.qml
|
shadowedMethod.qml
|
||||||
shared/Slider.qml
|
shared/Slider.qml
|
||||||
shifts.qml
|
shifts.qml
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
#ifndef SEQUENCETOITERABLE_H
|
||||||
|
#define SEQUENCETOITERABLE_H
|
||||||
|
|
||||||
|
#include <QtCore/qobject.h>
|
||||||
|
#include <QtQml/qqml.h>
|
||||||
|
|
||||||
|
class Entry : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit Entry(const QString &name, QObject *parent = nullptr)
|
||||||
|
: QObject(parent), m_name(name)
|
||||||
|
{
|
||||||
|
setObjectName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString m_name;
|
||||||
|
};
|
||||||
|
|
||||||
|
class EntryWrapper {
|
||||||
|
Q_GADGET
|
||||||
|
QML_FOREIGN(Entry)
|
||||||
|
QML_NAMED_ELEMENT(Entry)
|
||||||
|
QML_UNCREATABLE("These are my Entry objects")
|
||||||
|
};
|
||||||
|
|
||||||
|
class EntryListRegistration
|
||||||
|
{
|
||||||
|
Q_GADGET
|
||||||
|
QML_FOREIGN(QList<Entry*>)
|
||||||
|
QML_ANONYMOUS
|
||||||
|
QML_SEQUENTIAL_CONTAINER(Entry*)
|
||||||
|
};
|
||||||
|
|
||||||
|
class EntrySource : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
QML_ELEMENT
|
||||||
|
QML_SINGLETON
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit EntrySource(QObject* parent = nullptr) : QObject(parent) {
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
m_entries.push_back(new Entry(QString("Item %1").arg(i), this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Q_INVOKABLE QList<Entry*> getEntries() const { return m_entries; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
QList<Entry*> m_entries;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SEQUENCETOITERABLE_H
|
|
@ -0,0 +1,19 @@
|
||||||
|
pragma Strict
|
||||||
|
import QtQuick
|
||||||
|
import TestTypes
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Component.onCompleted: () => {
|
||||||
|
repeater.model = EntrySource.getEntries()
|
||||||
|
}
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
id: repeater
|
||||||
|
Item {
|
||||||
|
required property int index
|
||||||
|
required property QtObject modelData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
property int c: children.length
|
||||||
|
}
|
|
@ -154,6 +154,7 @@ private slots:
|
||||||
void revisions();
|
void revisions();
|
||||||
void scopeObjectDestruction();
|
void scopeObjectDestruction();
|
||||||
void scopeVsObject();
|
void scopeVsObject();
|
||||||
|
void sequenceToIterable();
|
||||||
void shadowedMethod();
|
void shadowedMethod();
|
||||||
void shifts();
|
void shifts();
|
||||||
void signalHandler();
|
void signalHandler();
|
||||||
|
@ -3255,6 +3256,16 @@ void tst_QmlCppCodegen::scopeVsObject()
|
||||||
QCOMPARE(object->property("objectName").toString(), u"foobar"_s);
|
QCOMPARE(object->property("objectName").toString(), u"foobar"_s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QmlCppCodegen::sequenceToIterable()
|
||||||
|
{
|
||||||
|
QQmlEngine engine;
|
||||||
|
QQmlComponent component(&engine, QUrl(u"qrc:/qt/qml/TestTypes/sequenceToIterable.qml"_s));
|
||||||
|
QVERIFY2(!component.isError(), component.errorString().toUtf8());
|
||||||
|
QScopedPointer<QObject> object(component.create());
|
||||||
|
QVERIFY(!object.isNull());
|
||||||
|
QCOMPARE(object->property("c").toInt(), 11);
|
||||||
|
}
|
||||||
|
|
||||||
void tst_QmlCppCodegen::shadowedMethod()
|
void tst_QmlCppCodegen::shadowedMethod()
|
||||||
{
|
{
|
||||||
QQmlEngine e;
|
QQmlEngine e;
|
||||||
|
|
Loading…
Reference in New Issue