Allow more options for creating value types from JS objects
We allow value types to be created 1. by calling Q_INVOKABLE constructors 2. by setting their values from properties of a JS object Both have to be opted into by setting a class info. If opted into, these options override the existing methods. When a a type can be created by setting its properties, that implies you can also initialize it using an invokable constructor. However, when given a JS object, the properties method is used. We keep this internal and undocumented for now. As the last try (the create(QJSValue) methods and QJSValue ctors) was not that stellar, let's first wait a bit and see if we're getting it right this time around. Fixes: QTBUG-106480 Change-Id: I767230924afcba032d501846cc3263dad57b7bf0 Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
This commit is contained in:
parent
b101be9be6
commit
3195b44e1c
|
@ -1302,3 +1302,98 @@
|
||||||
|
|
||||||
\sa QML_ELEMENT, QML_NAMED_ELEMENT, QML_SINGLETON, qmlRegisterType(), qmlRegisterSingletonType()
|
\sa QML_ELEMENT, QML_NAMED_ELEMENT, QML_SINGLETON, qmlRegisterType(), qmlRegisterSingletonType()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\macro QML_VALUE_TYPE(name)
|
||||||
|
\relates QQmlEngine
|
||||||
|
|
||||||
|
Declares the enclosing type or namespace to be available in QML, using \a name
|
||||||
|
as the name. The type has to be a value type and the name has to be lower case.
|
||||||
|
|
||||||
|
\code
|
||||||
|
class MyValueType
|
||||||
|
{
|
||||||
|
Q_GADGET
|
||||||
|
QML_VALUE_TYPE(myValueType)
|
||||||
|
|
||||||
|
// ...
|
||||||
|
};
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
\sa {Choosing the Correct Integration Method Between C++ and QML}, QML_NAMED_ELEMENT
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\macro QML_CONSTRUCTIBLE_VALUE
|
||||||
|
\internal
|
||||||
|
\relates QQmlEngine
|
||||||
|
|
||||||
|
Marks the surrounding value type as constructible. That is, any \l Q_INVOKABLE
|
||||||
|
constructors of the type that take exactly one argument can be used when
|
||||||
|
assigning a JavaScript value to a property of this type.
|
||||||
|
|
||||||
|
You can declare a constructible value type as follows:
|
||||||
|
|
||||||
|
\code
|
||||||
|
class MyValueType
|
||||||
|
{
|
||||||
|
Q_GADGET
|
||||||
|
QML_VALUE_TYPE(myValueType)
|
||||||
|
QML_CONSTRUCTIBLE_VALUE
|
||||||
|
Q_INVOKABLE MyValueType(double d);
|
||||||
|
|
||||||
|
// ...
|
||||||
|
};
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
With the above type, the following QML code will produce a \c MyValueType
|
||||||
|
value using the given constructor and assign it to the property.
|
||||||
|
|
||||||
|
\qml
|
||||||
|
QtObject {
|
||||||
|
property myValueType v: 5.4
|
||||||
|
}
|
||||||
|
\endqml
|
||||||
|
|
||||||
|
\sa QML_VALUE_TYPE
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\macro QML_STRUCTURED_VALUE
|
||||||
|
\internal
|
||||||
|
\relates QQmlEngine
|
||||||
|
|
||||||
|
Marks the surrounding value type as structured. Structured value types can
|
||||||
|
and will preferably be constructed property-by-property from a JavaScript
|
||||||
|
object. A structured value type, however is always \l QML_CONSTRUCTIBLE_VALUE,
|
||||||
|
too. This means, you can still provide \l Q_INVOKABLE constructors in order to
|
||||||
|
handle construction from primitive types.
|
||||||
|
|
||||||
|
You can declare a structured value type as follows:
|
||||||
|
|
||||||
|
\code
|
||||||
|
class MyValueType
|
||||||
|
{
|
||||||
|
Q_GADGET
|
||||||
|
QML_VALUE_TYPE(myValueType)
|
||||||
|
QML_STRUCTURED_VALUE
|
||||||
|
Q_PROPERTY(double d READ d WRITE setD)
|
||||||
|
Q_PROPERTY(string e READ e WRITE setE)
|
||||||
|
|
||||||
|
// ...
|
||||||
|
};
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
Then you can populate a property of this type as follows:
|
||||||
|
|
||||||
|
\qml
|
||||||
|
QtObject {
|
||||||
|
property myValueType v: ({d: 4.4, e: "a string"})
|
||||||
|
}
|
||||||
|
\endqml
|
||||||
|
|
||||||
|
The extra parentheses are necessary to disambiguate the JavaScript object
|
||||||
|
from what might be interpreted as a JavaScript code block.
|
||||||
|
|
||||||
|
\sa QML_VALUE_TYPE QML_CONSTRUCTIBLE_VALUE
|
||||||
|
*/
|
||||||
|
|
|
@ -1580,7 +1580,13 @@ static QVariant toVariant(
|
||||||
QV4::ScopedValue arrayValue(scope);
|
QV4::ScopedValue arrayValue(scope);
|
||||||
for (qint64 i = 0; i < length; ++i) {
|
for (qint64 i = 0; i < length; ++i) {
|
||||||
arrayValue = a->get(i);
|
arrayValue = a->get(i);
|
||||||
QVariant asVariant;
|
QVariant asVariant(valueMetaType);
|
||||||
|
if (QQmlValueTypeProvider::createValueType(
|
||||||
|
arrayValue, valueMetaType, asVariant.data())) {
|
||||||
|
retnAsIterable.metaContainer().addValue(retn.data(), asVariant.constData());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (QMetaType::canConvert(QMetaType::fromType<QJSValue>(), valueMetaType)) {
|
if (QMetaType::canConvert(QMetaType::fromType<QJSValue>(), valueMetaType)) {
|
||||||
// before attempting a conversion from the concrete types,
|
// before attempting a conversion from the concrete types,
|
||||||
// check if there exists a conversion from QJSValue -> out type
|
// check if there exists a conversion from QJSValue -> out type
|
||||||
|
@ -1600,10 +1606,12 @@ static QVariant toVariant(
|
||||||
auto originalType = asVariant.metaType();
|
auto originalType = asVariant.metaType();
|
||||||
bool couldConvert = asVariant.convert(valueMetaType);
|
bool couldConvert = asVariant.convert(valueMetaType);
|
||||||
if (!couldConvert) {
|
if (!couldConvert) {
|
||||||
qWarning() << QLatin1String("Could not convert array value at position %1 from %2 to %3")
|
qWarning().noquote()
|
||||||
.arg(QString::number(i),
|
<< QLatin1String("Could not convert array value "
|
||||||
QString::fromUtf8(originalType.name()),
|
"at position %1 from %2 to %3")
|
||||||
QString::fromUtf8(valueMetaType.name()));
|
.arg(QString::number(i),
|
||||||
|
QString::fromUtf8(originalType.name()),
|
||||||
|
QString::fromUtf8(valueMetaType.name()));
|
||||||
// create default constructed value
|
// create default constructed value
|
||||||
asVariant = QVariant(valueMetaType, nullptr);
|
asVariant = QVariant(valueMetaType, nullptr);
|
||||||
}
|
}
|
||||||
|
@ -1662,6 +1670,12 @@ static QVariant toVariant(
|
||||||
return re->toQRegularExpression();
|
return re->toQRegularExpression();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (metaType.isValid() && !(metaType.flags() & QMetaType::PointerToQObject)) {
|
||||||
|
QVariant result(metaType);
|
||||||
|
if (QQmlValueTypeProvider::createValueType(value, metaType, result.data()))
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
if (createJSValueForObjects)
|
if (createJSValueForObjects)
|
||||||
return QVariant::fromValue(QJSValuePrivate::fromReturnedValue(o->asReturnedValue()));
|
return QVariant::fromValue(QJSValuePrivate::fromReturnedValue(o->asReturnedValue()));
|
||||||
|
|
||||||
|
@ -2504,8 +2518,17 @@ bool ExecutionEngine::metaTypeFromJS(const Value &value, QMetaType metaType, voi
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#if QT_CONFIG(qml_locale)
|
||||||
|
case QMetaType::QLocale: {
|
||||||
|
if (const QV4::QQmlLocaleData *l = value.as<QQmlLocaleData>()) {
|
||||||
|
*reinterpret_cast<QLocale *>(data) = *l->d()->locale;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (metaType.flags() & QMetaType::IsEnumeration) {
|
if (metaType.flags() & QMetaType::IsEnumeration) {
|
||||||
|
@ -2579,14 +2602,8 @@ bool ExecutionEngine::metaTypeFromJS(const Value &value, QMetaType metaType, voi
|
||||||
QJSValuePrivate::setValue(reinterpret_cast<QJSValue*>(data), value.asReturnedValue());
|
QJSValuePrivate::setValue(reinterpret_cast<QJSValue*>(data), value.asReturnedValue());
|
||||||
return true;
|
return true;
|
||||||
} else if (!isPointer) {
|
} else if (!isPointer) {
|
||||||
QVariant val;
|
if (QQmlValueTypeProvider::createValueType(value, metaType, data))
|
||||||
if (QQmlValueTypeProvider::createValueType(
|
|
||||||
metaType, QJSValuePrivate::fromReturnedValue(value.asReturnedValue()), val)) {
|
|
||||||
Q_ASSERT(val.metaType() == metaType);
|
|
||||||
metaType.destruct(data);
|
|
||||||
metaType.construct(data, val.constData());
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (const QV4::Sequence *sequence = value.as<Sequence>()) {
|
if (const QV4::Sequence *sequence = value.as<Sequence>()) {
|
||||||
|
|
|
@ -648,12 +648,20 @@ QVariant SequencePrototype::toVariant(const QV4::Value &array, QMetaType typeHin
|
||||||
meta->addValueAtEnd(result.data(), &variant);
|
meta->addValueAtEnd(result.data(), &variant);
|
||||||
} else {
|
} else {
|
||||||
const QMetaType originalType = variant.metaType();
|
const QMetaType originalType = variant.metaType();
|
||||||
if (originalType != valueMetaType && !variant.convert(valueMetaType)) {
|
if (originalType != valueMetaType) {
|
||||||
qWarning() << QLatin1String(
|
QVariant converted(valueMetaType);
|
||||||
"Could not convert array value at position %1 from %2 to %3")
|
if (QQmlValueTypeProvider::createValueType(
|
||||||
.arg(QString::number(i), QString::fromUtf8(originalType.name()),
|
variant, valueMetaType, converted.data())) {
|
||||||
QString::fromUtf8(valueMetaType.name()));
|
variant = converted;
|
||||||
variant = QVariant(valueMetaType);
|
} else if (!variant.convert(valueMetaType)) {
|
||||||
|
qWarning().noquote()
|
||||||
|
<< 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 = converted;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
meta->addValueAtEnd(result.data(), variant.constData());
|
meta->addValueAtEnd(result.data(), variant.constData());
|
||||||
}
|
}
|
||||||
|
|
|
@ -166,7 +166,8 @@ int qmlRegisterUncreatableMetaObject(const QMetaObject &staticMetaObject,
|
||||||
|
|
||||||
nullptr,
|
nullptr,
|
||||||
QTypeRevision::zero(),
|
QTypeRevision::zero(),
|
||||||
-1
|
-1,
|
||||||
|
QQmlPrivate::ValueTypeCreationMethod::None
|
||||||
};
|
};
|
||||||
|
|
||||||
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
|
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
|
||||||
|
@ -464,11 +465,19 @@ int QQmlPrivate::qmlregister(RegistrationType type, void *data)
|
||||||
&& boolClassInfo(type.classInfoMetaObject, "QML.Creatable", true);
|
&& boolClassInfo(type.classInfoMetaObject, "QML.Creatable", true);
|
||||||
|
|
||||||
QString noCreateReason;
|
QString noCreateReason;
|
||||||
|
ValueTypeCreationMethod creationMethod = ValueTypeCreationMethod::None;
|
||||||
|
|
||||||
if (!creatable) {
|
if (!creatable) {
|
||||||
noCreateReason = QString::fromUtf8(classInfo(type.classInfoMetaObject, "QML.UncreatableReason"));
|
noCreateReason = QString::fromUtf8(
|
||||||
|
classInfo(type.classInfoMetaObject, "QML.UncreatableReason"));
|
||||||
if (noCreateReason.isEmpty())
|
if (noCreateReason.isEmpty())
|
||||||
noCreateReason = QLatin1String("Type cannot be created in QML.");
|
noCreateReason = QLatin1String("Type cannot be created in QML.");
|
||||||
|
} else if (!(type.typeId.flags() & QMetaType::PointerToQObject)) {
|
||||||
|
const char *method = classInfo(type.classInfoMetaObject, "QML.CreationMethod");
|
||||||
|
if (qstrcmp(method, "structured") == 0)
|
||||||
|
creationMethod = ValueTypeCreationMethod::Structured;
|
||||||
|
else if (qstrcmp(method, "construct") == 0)
|
||||||
|
creationMethod = ValueTypeCreationMethod::Construct;
|
||||||
}
|
}
|
||||||
|
|
||||||
RegisterType typeRevision = {
|
RegisterType typeRevision = {
|
||||||
|
@ -493,7 +502,8 @@ int QQmlPrivate::qmlregister(RegistrationType type, void *data)
|
||||||
type.extensionMetaObject,
|
type.extensionMetaObject,
|
||||||
nullptr,
|
nullptr,
|
||||||
QTypeRevision(),
|
QTypeRevision(),
|
||||||
type.structVersion > 0 ? type.finalizerCast : -1
|
type.structVersion > 0 ? type.finalizerCast : -1,
|
||||||
|
creationMethod
|
||||||
};
|
};
|
||||||
|
|
||||||
QQmlPrivate::RegisterSequentialContainer sequenceRevision = {
|
QQmlPrivate::RegisterSequentialContainer sequenceRevision = {
|
||||||
|
|
|
@ -78,7 +78,8 @@ int qmlRegisterAnonymousType(const char *uri, int versionMajor)
|
||||||
|
|
||||||
nullptr,
|
nullptr,
|
||||||
QTypeRevision::zero(),
|
QTypeRevision::zero(),
|
||||||
QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast()
|
QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
|
||||||
|
QQmlPrivate::ValueTypeCreationMethod::None,
|
||||||
};
|
};
|
||||||
|
|
||||||
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
|
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
|
||||||
|
@ -115,7 +116,8 @@ int qmlRegisterAnonymousType(const char *uri, int versionMajor)
|
||||||
|
|
||||||
nullptr,
|
nullptr,
|
||||||
QTypeRevision::fromMinorVersion(metaObjectRevisionMinor),
|
QTypeRevision::fromMinorVersion(metaObjectRevisionMinor),
|
||||||
QQmlPrivate::StaticCastSelector<T, QQmlFinalizerHook>::cast()
|
QQmlPrivate::StaticCastSelector<T, QQmlFinalizerHook>::cast(),
|
||||||
|
QQmlPrivate::ValueTypeCreationMethod::None,
|
||||||
};
|
};
|
||||||
|
|
||||||
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
|
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
|
||||||
|
@ -160,7 +162,8 @@ int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMin
|
||||||
|
|
||||||
nullptr,
|
nullptr,
|
||||||
QTypeRevision::zero(),
|
QTypeRevision::zero(),
|
||||||
QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast()
|
QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
|
||||||
|
QQmlPrivate::ValueTypeCreationMethod::None,
|
||||||
};
|
};
|
||||||
|
|
||||||
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
|
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
|
||||||
|
@ -193,7 +196,8 @@ int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMin
|
||||||
|
|
||||||
nullptr,
|
nullptr,
|
||||||
QTypeRevision::fromMinorVersion(metaObjectRevision),
|
QTypeRevision::fromMinorVersion(metaObjectRevision),
|
||||||
QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast()
|
QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
|
||||||
|
QQmlPrivate::ValueTypeCreationMethod::None,
|
||||||
};
|
};
|
||||||
|
|
||||||
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
|
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
|
||||||
|
@ -233,7 +237,8 @@ int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int ve
|
||||||
|
|
||||||
nullptr,
|
nullptr,
|
||||||
QTypeRevision::zero(),
|
QTypeRevision::zero(),
|
||||||
QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast()
|
QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
|
||||||
|
QQmlPrivate::ValueTypeCreationMethod::None,
|
||||||
};
|
};
|
||||||
|
|
||||||
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
|
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
|
||||||
|
@ -273,7 +278,8 @@ int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int ve
|
||||||
|
|
||||||
nullptr,
|
nullptr,
|
||||||
QTypeRevision::fromMinorVersion(metaObjectRevision),
|
QTypeRevision::fromMinorVersion(metaObjectRevision),
|
||||||
QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast()
|
QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
|
||||||
|
QQmlPrivate::ValueTypeCreationMethod::None,
|
||||||
};
|
};
|
||||||
|
|
||||||
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
|
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
|
||||||
|
@ -306,7 +312,8 @@ int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const c
|
||||||
|
|
||||||
nullptr,
|
nullptr,
|
||||||
QTypeRevision::zero(),
|
QTypeRevision::zero(),
|
||||||
QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast()
|
QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
|
||||||
|
QQmlPrivate::ValueTypeCreationMethod::None,
|
||||||
};
|
};
|
||||||
|
|
||||||
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
|
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
|
||||||
|
@ -337,7 +344,8 @@ int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const c
|
||||||
|
|
||||||
nullptr,
|
nullptr,
|
||||||
QTypeRevision::fromMinorVersion(metaObjectRevision),
|
QTypeRevision::fromMinorVersion(metaObjectRevision),
|
||||||
QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast()
|
QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
|
||||||
|
QQmlPrivate::ValueTypeCreationMethod::None,
|
||||||
};
|
};
|
||||||
|
|
||||||
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
|
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
|
||||||
|
@ -368,7 +376,8 @@ int qmlRegisterRevision(const char *uri, int versionMajor, int versionMinor)
|
||||||
|
|
||||||
nullptr,
|
nullptr,
|
||||||
QTypeRevision::fromMinorVersion(metaObjectRevision),
|
QTypeRevision::fromMinorVersion(metaObjectRevision),
|
||||||
QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast()
|
QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
|
||||||
|
QQmlPrivate::ValueTypeCreationMethod::None,
|
||||||
};
|
};
|
||||||
|
|
||||||
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
|
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
|
||||||
|
@ -401,7 +410,8 @@ int qmlRegisterExtendedType(const char *uri, int versionMajor)
|
||||||
|
|
||||||
nullptr,
|
nullptr,
|
||||||
QTypeRevision::zero(),
|
QTypeRevision::zero(),
|
||||||
QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast()
|
QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
|
||||||
|
QQmlPrivate::ValueTypeCreationMethod::None,
|
||||||
};
|
};
|
||||||
|
|
||||||
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
|
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
|
||||||
|
@ -440,7 +450,8 @@ int qmlRegisterExtendedType(const char *uri, int versionMajor, int versionMinor,
|
||||||
|
|
||||||
nullptr,
|
nullptr,
|
||||||
QTypeRevision::zero(),
|
QTypeRevision::zero(),
|
||||||
QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast()
|
QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
|
||||||
|
QQmlPrivate::ValueTypeCreationMethod::None,
|
||||||
};
|
};
|
||||||
|
|
||||||
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
|
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
|
||||||
|
@ -490,7 +501,8 @@ int qmlRegisterCustomType(const char *uri, int versionMajor, int versionMinor,
|
||||||
|
|
||||||
parser,
|
parser,
|
||||||
QTypeRevision::zero(),
|
QTypeRevision::zero(),
|
||||||
QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast()
|
QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
|
||||||
|
QQmlPrivate::ValueTypeCreationMethod::None,
|
||||||
};
|
};
|
||||||
|
|
||||||
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
|
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
|
||||||
|
@ -522,7 +534,8 @@ int qmlRegisterCustomType(const char *uri, int versionMajor, int versionMinor,
|
||||||
|
|
||||||
parser,
|
parser,
|
||||||
QTypeRevision::fromMinorVersion(metaObjectRevision),
|
QTypeRevision::fromMinorVersion(metaObjectRevision),
|
||||||
QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast()
|
QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
|
||||||
|
QQmlPrivate::ValueTypeCreationMethod::None,
|
||||||
};
|
};
|
||||||
|
|
||||||
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
|
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
|
||||||
|
@ -561,7 +574,8 @@ int qmlRegisterCustomExtendedType(const char *uri, int versionMajor, int version
|
||||||
|
|
||||||
parser,
|
parser,
|
||||||
QTypeRevision::zero(),
|
QTypeRevision::zero(),
|
||||||
QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast()
|
QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
|
||||||
|
QQmlPrivate::ValueTypeCreationMethod::None,
|
||||||
};
|
};
|
||||||
|
|
||||||
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
|
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
|
||||||
|
|
|
@ -457,11 +457,9 @@ QVariant QtObject::font(const QJSValue &fontSpecifier) const
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
QVariant v;
|
QVariant v((QMetaType(QMetaType::QFont)));
|
||||||
if (QQmlValueTypeProvider::createValueType(
|
if (QQmlValueTypeProvider::constructFromJSValue(fontSpecifier, v.metaType(), v.data()))
|
||||||
QMetaType(QMetaType::QFont), fontSpecifier, v)) {
|
|
||||||
return v;
|
return v;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
v4Engine()->throwError(QStringLiteral("Qt.font(): Invalid argument: "
|
v4Engine()->throwError(QStringLiteral("Qt.font(): Invalid argument: "
|
||||||
|
@ -489,14 +487,14 @@ void addParameters(QJSEngine *e, QJSValue &result, int i, T parameter, Others...
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ...T>
|
template<typename ...T>
|
||||||
static QVariant createValueType(QJSEngine *e, QMetaType type, T... parameters)
|
static QVariant constructFromJSValue(QJSEngine *e, QMetaType type, T... parameters)
|
||||||
{
|
{
|
||||||
if (!e)
|
if (!e)
|
||||||
return QVariant();
|
return QVariant();
|
||||||
QJSValue params = e->newArray(sizeof...(parameters));
|
QJSValue params = e->newArray(sizeof...(parameters));
|
||||||
addParameters(e, params, 0, parameters...);
|
addParameters(e, params, 0, parameters...);
|
||||||
QVariant variant;
|
QVariant variant(type);
|
||||||
QQmlValueTypeProvider::createValueType(type, params, variant);
|
QQmlValueTypeProvider::constructFromJSValue(params, type, variant.data());
|
||||||
return variant;
|
return variant;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -507,7 +505,7 @@ static QVariant createValueType(QJSEngine *e, QMetaType type, T... parameters)
|
||||||
*/
|
*/
|
||||||
QVariant QtObject::vector2d(double x, double y) const
|
QVariant QtObject::vector2d(double x, double y) const
|
||||||
{
|
{
|
||||||
return createValueType(jsEngine(), QMetaType(QMetaType::QVector2D), x, y);
|
return constructFromJSValue(jsEngine(), QMetaType(QMetaType::QVector2D), x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -517,7 +515,7 @@ QVariant QtObject::vector2d(double x, double y) const
|
||||||
*/
|
*/
|
||||||
QVariant QtObject::vector3d(double x, double y, double z) const
|
QVariant QtObject::vector3d(double x, double y, double z) const
|
||||||
{
|
{
|
||||||
return createValueType(jsEngine(), QMetaType(QMetaType::QVector3D), x, y, z);
|
return constructFromJSValue(jsEngine(), QMetaType(QMetaType::QVector3D), x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -527,7 +525,7 @@ QVariant QtObject::vector3d(double x, double y, double z) const
|
||||||
*/
|
*/
|
||||||
QVariant QtObject::vector4d(double x, double y, double z, double w) const
|
QVariant QtObject::vector4d(double x, double y, double z, double w) const
|
||||||
{
|
{
|
||||||
return createValueType(jsEngine(), QMetaType(QMetaType::QVector4D), x, y, z, w);
|
return constructFromJSValue(jsEngine(), QMetaType(QMetaType::QVector4D), x, y, z, w);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -537,7 +535,7 @@ QVariant QtObject::vector4d(double x, double y, double z, double w) const
|
||||||
*/
|
*/
|
||||||
QVariant QtObject::quaternion(double scalar, double x, double y, double z) const
|
QVariant QtObject::quaternion(double scalar, double x, double y, double z) const
|
||||||
{
|
{
|
||||||
return createValueType(jsEngine(), QMetaType(QMetaType::QQuaternion), scalar, x, y, z);
|
return constructFromJSValue(jsEngine(), QMetaType(QMetaType::QQuaternion), scalar, x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -563,16 +561,17 @@ QVariant QtObject::quaternion(double scalar, double x, double y, double z) const
|
||||||
*/
|
*/
|
||||||
QVariant QtObject::matrix4x4() const
|
QVariant QtObject::matrix4x4() const
|
||||||
{
|
{
|
||||||
QVariant variant;
|
QVariant variant((QMetaType(QMetaType::QMatrix4x4)));
|
||||||
QQmlValueTypeProvider::createValueType(QMetaType(QMetaType::QMatrix4x4), QJSValue(), variant);
|
QQmlValueTypeProvider::constructFromJSValue(
|
||||||
|
QJSValue(), variant.metaType(), variant.data());
|
||||||
return variant;
|
return variant;
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant QtObject::matrix4x4(const QJSValue &value) const
|
QVariant QtObject::matrix4x4(const QJSValue &value) const
|
||||||
{
|
{
|
||||||
if (value.isObject()) {
|
if (value.isObject()) {
|
||||||
QVariant v;
|
QVariant v((QMetaType(QMetaType::QMatrix4x4)));
|
||||||
if (QQmlValueTypeProvider::createValueType(QMetaType(QMetaType::QMatrix4x4), value, v))
|
if (QQmlValueTypeProvider::constructFromJSValue(value, v.metaType(), v.data()))
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -586,7 +585,7 @@ QVariant QtObject::matrix4x4(double m11, double m12, double m13, double m14,
|
||||||
double m31, double m32, double m33, double m34,
|
double m31, double m32, double m33, double m34,
|
||||||
double m41, double m42, double m43, double m44) const
|
double m41, double m42, double m43, double m44) const
|
||||||
{
|
{
|
||||||
return createValueType(jsEngine(), QMetaType(QMetaType::QMatrix4x4),
|
return constructFromJSValue(jsEngine(), QMetaType(QMetaType::QMatrix4x4),
|
||||||
m11, m12, m13, m14, m21, m22, m23, m24,
|
m11, m12, m13, m14, m21, m22, m23, m24,
|
||||||
m31, m32, m33, m34, m41, m42, m43, m44);
|
m31, m32, m33, m34, m41, m42, m43, m44);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include <private/qqmlglobal_p.h>
|
#include <private/qqmlglobal_p.h>
|
||||||
#include <QtQml/private/qqmlmetatype_p.h>
|
#include <QtQml/private/qqmlmetatype_p.h>
|
||||||
|
#include <QtQml/private/qjsvalue_p.h>
|
||||||
|
|
||||||
#include <QtQml/qqmlengine.h>
|
#include <QtQml/qqmlengine.h>
|
||||||
#include <QtCore/qvariant.h>
|
#include <QtCore/qvariant.h>
|
||||||
|
@ -12,13 +13,237 @@
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
bool QQmlValueTypeProvider::createValueType(QMetaType metaType, const QJSValue &s, QVariant &data)
|
// Pre-filter the metatype before poking QQmlMetaType::qmlType() and locking its mutex.
|
||||||
|
static bool isConstructibleMetaType(const QMetaType metaType)
|
||||||
{
|
{
|
||||||
const QQmlType qmlType = QQmlMetaType::qmlType(metaType);
|
switch (metaType.id()) {
|
||||||
if (auto valueTypeFunction = qmlType.createValueTypeFunction()) {
|
// The builtins are not constructible this way.
|
||||||
|
case QMetaType::Void:
|
||||||
|
case QMetaType::Nullptr:
|
||||||
|
case QMetaType::QVariant:
|
||||||
|
case QMetaType::Int:
|
||||||
|
case QMetaType::UInt:
|
||||||
|
case QMetaType::LongLong:
|
||||||
|
case QMetaType::ULongLong:
|
||||||
|
case QMetaType::Float:
|
||||||
|
case QMetaType::Double:
|
||||||
|
case QMetaType::Long:
|
||||||
|
case QMetaType::ULong:
|
||||||
|
case QMetaType::Short:
|
||||||
|
case QMetaType::UShort:
|
||||||
|
case QMetaType::Char:
|
||||||
|
case QMetaType::SChar:
|
||||||
|
case QMetaType::UChar:
|
||||||
|
case QMetaType::QChar:
|
||||||
|
case QMetaType::QString:
|
||||||
|
case QMetaType::Bool:
|
||||||
|
case QMetaType::QDateTime:
|
||||||
|
case QMetaType::QDate:
|
||||||
|
case QMetaType::QTime:
|
||||||
|
case QMetaType::QUrl:
|
||||||
|
case QMetaType::QRegularExpression:
|
||||||
|
case QMetaType::QByteArray:
|
||||||
|
case QMetaType::QLocale:
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// QJSValue is also builtin
|
||||||
|
if (metaType == QMetaType::fromType<QJSValue>())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// We also don't want to construct pointers of any kind, or lists, or enums.
|
||||||
|
if (metaType.flags() &
|
||||||
|
(QMetaType::PointerToQObject
|
||||||
|
| QMetaType::IsEnumeration
|
||||||
|
| QMetaType::SharedPointerToQObject
|
||||||
|
| QMetaType::WeakPointerToQObject
|
||||||
|
| QMetaType::TrackingPointerToQObject
|
||||||
|
| QMetaType::IsUnsignedEnumeration
|
||||||
|
| QMetaType::PointerToGadget
|
||||||
|
| QMetaType::IsPointer
|
||||||
|
| QMetaType::IsQmlList)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void callConstructor(
|
||||||
|
const QMetaObject *mo, int i, void *parameter, QMetaType metaType, void *data)
|
||||||
|
{
|
||||||
|
// Unfortunately CreateInstance unconditionally creates the instance on the heap.
|
||||||
|
void *gadget = nullptr;
|
||||||
|
void *p[] = { &gadget, parameter };
|
||||||
|
mo->static_metacall(QMetaObject::CreateInstance, i, p);
|
||||||
|
Q_ASSERT(gadget);
|
||||||
|
metaType.destruct(data);
|
||||||
|
metaType.construct(data, gadget);
|
||||||
|
metaType.destroy(gadget);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool fromMatchingType(
|
||||||
|
const QMetaObject *mo, const QV4::Value &s, const QMetaType metaType, void *data)
|
||||||
|
{
|
||||||
|
for (int i = 0, end = mo->constructorCount(); i < end; ++i) {
|
||||||
|
const QMetaMethod ctor = mo->constructor(i);
|
||||||
|
if (ctor.parameterCount() != 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const QMetaType parameterType = ctor.parameterMetaType(0);
|
||||||
|
QVariant parameter = QV4::ExecutionEngine::toVariant(s, parameterType);
|
||||||
|
if (parameter.metaType() == parameterType) {
|
||||||
|
callConstructor(mo, i, parameter.data(), metaType, data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant converted(parameterType);
|
||||||
|
if (QQmlValueTypeProvider::createValueType(s, parameterType, converted.data())) {
|
||||||
|
callConstructor(mo, i, converted.data(), metaType, data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (QMetaType::convert(parameter.metaType(), parameter.constData(),
|
||||||
|
parameterType, converted.data())) {
|
||||||
|
callConstructor(mo, i, converted.data(), metaType, data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool fromMatchingType(
|
||||||
|
const QMetaObject *mo, QVariant s, const QMetaType metaType, void *data)
|
||||||
|
{
|
||||||
|
const QMetaType sourceMetaType = s.metaType();
|
||||||
|
if (sourceMetaType == QMetaType::fromType<QJSValue>()) {
|
||||||
|
QJSValue val = s.value<QJSValue>();
|
||||||
|
return fromMatchingType(
|
||||||
|
mo, QV4::Value(QJSValuePrivate::asReturnedValue(&val)), metaType, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0, end = mo->constructorCount(); i < end; ++i) {
|
||||||
|
const QMetaMethod ctor = mo->constructor(i);
|
||||||
|
if (ctor.parameterCount() != 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const QMetaType parameterType = ctor.parameterMetaType(0);
|
||||||
|
if (sourceMetaType == parameterType) {
|
||||||
|
callConstructor(mo, i, s.data(), metaType, data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant parameter(parameterType);
|
||||||
|
if (QQmlValueTypeProvider::createValueType(s, parameterType, parameter.data())) {
|
||||||
|
callConstructor(mo, i, parameter.data(), metaType, data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// At this point, s should be a builtin type. For builtin types
|
||||||
|
// the QMetaType converters are good enough.
|
||||||
|
if (QMetaType::convert(sourceMetaType, s.constData(), parameterType, parameter.data())) {
|
||||||
|
callConstructor(mo, i, s.data(), metaType, data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool fromString(
|
||||||
|
const QMetaObject *mo, QString s, const QMetaType metaType, void *data)
|
||||||
|
{
|
||||||
|
for (int i = 0, end = mo->constructorCount(); i < end; ++i) {
|
||||||
|
const QMetaMethod ctor = mo->constructor(i);
|
||||||
|
if (ctor.parameterCount() != 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (ctor.parameterMetaType(0) == QMetaType::fromType<QString>()) {
|
||||||
|
callConstructor(mo, i, &s, metaType, data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool byProperties(
|
||||||
|
const QMetaObject *mo, const QV4::Value &s, void *data)
|
||||||
|
{
|
||||||
|
if (!s.isObject())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!mo)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const QV4::Object *o = static_cast<const QV4::Object *>(&s);
|
||||||
|
QV4::Scope scope(o->engine());
|
||||||
|
QV4::ScopedObject object(scope, o);
|
||||||
|
|
||||||
|
for (int i = 0; i < mo->propertyCount(); ++i) {
|
||||||
|
const QMetaProperty metaProperty = mo->property(i);
|
||||||
|
const QString propertyName = QString::fromUtf8(metaProperty.name());
|
||||||
|
|
||||||
|
QV4::ScopedString v4PropName(scope, scope.engine->newString(propertyName));
|
||||||
|
QV4::ScopedValue v4PropValue(scope, object->get(v4PropName));
|
||||||
|
|
||||||
|
// We assume that data is freshly constructed.
|
||||||
|
// There is no point in reset()'ing properties of a freshly created object.
|
||||||
|
if (v4PropValue->isUndefined())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const QMetaType propertyType = metaProperty.metaType();
|
||||||
|
QVariant property = QV4::ExecutionEngine::toVariant(v4PropValue, propertyType);
|
||||||
|
if (property.metaType() == propertyType) {
|
||||||
|
metaProperty.writeOnGadget(data, property);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant converted(propertyType);
|
||||||
|
if (QQmlValueTypeProvider::createValueType(v4PropValue, propertyType, converted.data())) {
|
||||||
|
metaProperty.writeOnGadget(data, converted);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (QMetaType::convert(property.metaType(), property.constData(),
|
||||||
|
propertyType, converted.data())) {
|
||||||
|
metaProperty.writeOnGadget(data, converted);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
qWarning().noquote()
|
||||||
|
<< QLatin1String("Could not convert %1 to %2 for property %3")
|
||||||
|
.arg(v4PropValue->toQStringNoThrow(), QString::fromUtf8(propertyType.name()),
|
||||||
|
propertyName);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool byProperties(
|
||||||
|
const QMetaObject *mo, const QVariant &s, void *data)
|
||||||
|
{
|
||||||
|
if (!mo)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (s.metaType() == QMetaType::fromType<QJSValue>()) {
|
||||||
|
QJSValue val = s.value<QJSValue>();
|
||||||
|
return byProperties(mo, QV4::Value(QJSValuePrivate::asReturnedValue(&val)), data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool fromJSValue(
|
||||||
|
const QQmlType &type, const QJSValue &s, QMetaType metaType, void *data)
|
||||||
|
{
|
||||||
|
if (const auto valueTypeFunction = type.createValueTypeFunction()) {
|
||||||
QVariant result = valueTypeFunction(s);
|
QVariant result = valueTypeFunction(s);
|
||||||
if (result.metaType() == metaType) {
|
if (result.metaType() == metaType) {
|
||||||
data = std::move(result);
|
metaType.destruct(data);
|
||||||
|
metaType.construct(data, result.constData());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,6 +251,98 @@ bool QQmlValueTypeProvider::createValueType(QMetaType metaType, const QJSValue &
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool QQmlValueTypeProvider::constructFromJSValue(
|
||||||
|
const QJSValue &s, QMetaType metaType, void *data)
|
||||||
|
{
|
||||||
|
return isConstructibleMetaType(metaType)
|
||||||
|
&& fromJSValue(QQmlMetaType::qmlType(metaType), s, metaType, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QQmlValueTypeProvider::createValueType(
|
||||||
|
const QString &s, QMetaType metaType, void *data)
|
||||||
|
{
|
||||||
|
if (!isConstructibleMetaType(metaType))
|
||||||
|
return false;
|
||||||
|
const QQmlType type = QQmlMetaType::qmlType(metaType);
|
||||||
|
const QMetaObject *mo = QQmlMetaType::metaObjectForValueType(type);
|
||||||
|
if (mo && type.canConstructValueType()) {
|
||||||
|
if (fromString(mo, s, metaType, data))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fromJSValue(type, s, metaType, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QQmlValueTypeProvider::createValueType(
|
||||||
|
const QJSValue &s, QMetaType metaType, void *data)
|
||||||
|
{
|
||||||
|
if (!isConstructibleMetaType(metaType))
|
||||||
|
return false;
|
||||||
|
const QQmlType type = QQmlMetaType::qmlType(metaType);
|
||||||
|
if (const QMetaObject *mo = QQmlMetaType::metaObjectForValueType(type)) {
|
||||||
|
if (type.canPopulateValueType()
|
||||||
|
&& byProperties(mo, QV4::Value(QJSValuePrivate::asReturnedValue(&s)), data)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type.canConstructValueType()
|
||||||
|
&& fromMatchingType(mo, QV4::Value(QJSValuePrivate::asReturnedValue(&s)),
|
||||||
|
metaType, data)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return constructFromJSValue(s, metaType, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QQmlValueTypeProvider::createValueType(
|
||||||
|
const QV4::Value &s, QMetaType metaType, void *data)
|
||||||
|
{
|
||||||
|
if (!isConstructibleMetaType(metaType))
|
||||||
|
return false;
|
||||||
|
const QQmlType type = QQmlMetaType::qmlType(metaType);
|
||||||
|
if (const QMetaObject *mo = QQmlMetaType::metaObjectForValueType(type)) {
|
||||||
|
if (type.canPopulateValueType() && byProperties(mo, s, data))
|
||||||
|
return true;
|
||||||
|
if (type.canConstructValueType()) {
|
||||||
|
if (fromMatchingType(mo, s, metaType, data))
|
||||||
|
return true;
|
||||||
|
qWarning().noquote()
|
||||||
|
<< "Could not find any constructor for value type"
|
||||||
|
<< mo->className() << "to call with value" << s.toQStringNoThrow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return constructFromJSValue(
|
||||||
|
QJSValuePrivate::fromReturnedValue(s.asReturnedValue()), metaType, data);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \internal
|
||||||
|
* This should only be called with either builtin types or wrapped QJSValues as source.
|
||||||
|
*/
|
||||||
|
bool QQmlValueTypeProvider::createValueType(
|
||||||
|
const QVariant &s, QMetaType metaType, void *data)
|
||||||
|
{
|
||||||
|
if (!isConstructibleMetaType(metaType))
|
||||||
|
return false;
|
||||||
|
const QQmlType type = QQmlMetaType::qmlType(metaType);
|
||||||
|
if (const QMetaObject *mo = QQmlMetaType::metaObjectForValueType(type)) {
|
||||||
|
if (type.canPopulateValueType() && byProperties(mo, s, data))
|
||||||
|
return true;
|
||||||
|
if (type.canConstructValueType()) {
|
||||||
|
if (fromMatchingType(mo, s, metaType, data))
|
||||||
|
return true;
|
||||||
|
qWarning().noquote()
|
||||||
|
<< "Could not find any constructor for value type"
|
||||||
|
<< mo->className() << "to call with value" << s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
QQmlColorProvider::~QQmlColorProvider() {}
|
QQmlColorProvider::~QQmlColorProvider() {}
|
||||||
QVariant QQmlColorProvider::colorFromString(const QString &, bool *ok) { if (ok) *ok = false; return QVariant(); }
|
QVariant QQmlColorProvider::colorFromString(const QString &, bool *ok) { if (ok) *ok = false; return QVariant(); }
|
||||||
unsigned QQmlColorProvider::rgbaFromString(const QString &, bool *ok) { if (ok) *ok = false; return 0; }
|
unsigned QQmlColorProvider::rgbaFromString(const QString &, bool *ok) { if (ok) *ok = false; return 0; }
|
||||||
|
|
|
@ -185,7 +185,12 @@ inline void QQml_setParent_noEvent(QObject *object, QObject *parent)
|
||||||
class QQmlValueTypeProvider
|
class QQmlValueTypeProvider
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static bool createValueType(QMetaType, const QJSValue &, QVariant &);
|
static bool constructFromJSValue(const QJSValue &, QMetaType, void *);
|
||||||
|
|
||||||
|
static bool createValueType(const QString &, QMetaType, void *);
|
||||||
|
static bool createValueType(const QJSValue &, QMetaType, void *);
|
||||||
|
static bool createValueType(const QV4::Value &, QMetaType, void *);
|
||||||
|
static bool createValueType(const QVariant &, QMetaType, void *);
|
||||||
};
|
};
|
||||||
|
|
||||||
class Q_QML_PRIVATE_EXPORT QQmlColorProvider
|
class Q_QML_PRIVATE_EXPORT QQmlColorProvider
|
||||||
|
|
|
@ -152,6 +152,10 @@ static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &el
|
||||||
d->extraData.cd->customParser = reinterpret_cast<QQmlCustomParser *>(type.customParser);
|
d->extraData.cd->customParser = reinterpret_cast<QQmlCustomParser *>(type.customParser);
|
||||||
d->extraData.cd->registerEnumClassesUnscoped = true;
|
d->extraData.cd->registerEnumClassesUnscoped = true;
|
||||||
d->extraData.cd->registerEnumsFromRelatedTypes = true;
|
d->extraData.cd->registerEnumsFromRelatedTypes = true;
|
||||||
|
d->extraData.cd->constructValueType = type.has(QQmlPrivate::RegisterType::CreationMethod)
|
||||||
|
&& type.creationMethod != QQmlPrivate::ValueTypeCreationMethod::None;
|
||||||
|
d->extraData.cd->populateValueType = type.has(QQmlPrivate::RegisterType::CreationMethod)
|
||||||
|
&& type.creationMethod == QQmlPrivate::ValueTypeCreationMethod::Structured;
|
||||||
|
|
||||||
if (type.extensionMetaObject)
|
if (type.extensionMetaObject)
|
||||||
d->extraData.cd->extMetaObject = type.extensionMetaObject;
|
d->extraData.cd->extMetaObject = type.extensionMetaObject;
|
||||||
|
@ -1707,23 +1711,8 @@ const QMetaObject *QQmlMetaType::metaObjectForValueType(QMetaType metaType)
|
||||||
// call QObject pointers value types. Explicitly registered types also override
|
// call QObject pointers value types. Explicitly registered types also override
|
||||||
// the implicit use of gadgets.
|
// the implicit use of gadgets.
|
||||||
if (!(metaType.flags() & QMetaType::PointerToQObject)) {
|
if (!(metaType.flags() & QMetaType::PointerToQObject)) {
|
||||||
const QQmlType qmlType = QQmlMetaType::qmlType(metaType);
|
if (const QMetaObject *mo = metaObjectForValueType(QQmlMetaType::qmlType(metaType)))
|
||||||
|
return mo;
|
||||||
// Prefer the extension meta object, if any.
|
|
||||||
// Extensions allow registration of non-gadget value types.
|
|
||||||
if (const QMetaObject *extensionMetaObject = qmlType.extensionMetaObject()) {
|
|
||||||
// This may be a namespace even if the original metaType isn't.
|
|
||||||
// You can do such things with QML_FOREIGN declarations.
|
|
||||||
if (extensionMetaObject->metaType().flags() & QMetaType::IsGadget)
|
|
||||||
return extensionMetaObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (const QMetaObject *qmlTypeMetaObject = qmlType.metaObject()) {
|
|
||||||
// This may be a namespace even if the original metaType isn't.
|
|
||||||
// You can do such things with QML_FOREIGN declarations.
|
|
||||||
if (qmlTypeMetaObject->metaType().flags() & QMetaType::IsGadget)
|
|
||||||
return qmlTypeMetaObject;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If it _is_ a gadget, we can just use it.
|
// If it _is_ a gadget, we can just use it.
|
||||||
|
|
|
@ -240,6 +240,26 @@ public:
|
||||||
static bool isValueType(QMetaType type);
|
static bool isValueType(QMetaType type);
|
||||||
static QQmlValueType *valueType(QMetaType metaType);
|
static QQmlValueType *valueType(QMetaType metaType);
|
||||||
static const QMetaObject *metaObjectForValueType(QMetaType type);
|
static const QMetaObject *metaObjectForValueType(QMetaType type);
|
||||||
|
static const QMetaObject *metaObjectForValueType(const QQmlType &qmlType)
|
||||||
|
{
|
||||||
|
// Prefer the extension meta object, if any.
|
||||||
|
// Extensions allow registration of non-gadget value types.
|
||||||
|
if (const QMetaObject *extensionMetaObject = qmlType.extensionMetaObject()) {
|
||||||
|
// This may be a namespace even if the original metaType isn't.
|
||||||
|
// You can do such things with QML_FOREIGN declarations.
|
||||||
|
if (extensionMetaObject->metaType().flags() & QMetaType::IsGadget)
|
||||||
|
return extensionMetaObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (const QMetaObject *qmlTypeMetaObject = qmlType.metaObject()) {
|
||||||
|
// This may be a namespace even if the original metaType isn't.
|
||||||
|
// You can do such things with QML_FOREIGN declarations.
|
||||||
|
if (qmlTypeMetaObject->metaType().flags() & QMetaType::IsGadget)
|
||||||
|
return qmlTypeMetaObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
static QQmlPropertyCache::ConstPtr findPropertyCacheInCompositeTypes(QMetaType t);
|
static QQmlPropertyCache::ConstPtr findPropertyCacheInCompositeTypes(QMetaType t);
|
||||||
static void registerInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit);
|
static void registerInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit);
|
||||||
|
|
|
@ -425,9 +425,9 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case QMetaType::QColor: {
|
case QMetaType::QColor: {
|
||||||
QVariant data;
|
QVariant data(propertyType);
|
||||||
if (QQmlValueTypeProvider::createValueType(
|
if (QQmlValueTypeProvider::createValueType(
|
||||||
propertyType, compilationUnit->bindingValueAsString(binding), data)) {
|
compilationUnit->bindingValueAsString(binding), propertyType, data.data())) {
|
||||||
property->writeProperty(_qobject, data.data(), propertyWriteFlags);
|
property->writeProperty(_qobject, data.data(), propertyWriteFlags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -508,9 +508,10 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
|
||||||
case QMetaType::QVector3D:
|
case QMetaType::QVector3D:
|
||||||
case QMetaType::QVector4D:
|
case QMetaType::QVector4D:
|
||||||
case QMetaType::QQuaternion: {
|
case QMetaType::QQuaternion: {
|
||||||
QVariant result;
|
QVariant result(propertyType);
|
||||||
bool ok = QQmlValueTypeProvider::createValueType(
|
bool ok = QQmlValueTypeProvider::createValueType(
|
||||||
propertyType, compilationUnit->bindingValueAsString(binding), result);
|
compilationUnit->bindingValueAsString(binding),
|
||||||
|
result.metaType(), result.data());
|
||||||
assertOrNull(ok);
|
assertOrNull(ok);
|
||||||
Q_UNUSED(ok);
|
Q_UNUSED(ok);
|
||||||
property->writeProperty(_qobject, result.data(), propertyWriteFlags);
|
property->writeProperty(_qobject, result.data(), propertyWriteFlags);
|
||||||
|
@ -576,6 +577,35 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
|
||||||
}
|
}
|
||||||
property->writeProperty(_qobject, &value, propertyWriteFlags);
|
property->writeProperty(_qobject, &value, propertyWriteFlags);
|
||||||
break;
|
break;
|
||||||
|
} else {
|
||||||
|
QVariant source;
|
||||||
|
switch (binding->type()) {
|
||||||
|
case QV4::CompiledData::Binding::Type_Boolean:
|
||||||
|
source = binding->valueAsBoolean();
|
||||||
|
break;
|
||||||
|
case QV4::CompiledData::Binding::Type_Number: {
|
||||||
|
const double n = compilationUnit->bindingValueAsNumber(binding);
|
||||||
|
if (double(int(n)) == n)
|
||||||
|
source = int(n);
|
||||||
|
else
|
||||||
|
source = n;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QV4::CompiledData::Binding::Type_Null:
|
||||||
|
source = QVariant::fromValue<std::nullptr_t>(nullptr);
|
||||||
|
break;
|
||||||
|
case QV4::CompiledData::Binding::Type_Invalid:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
source = compilationUnit->bindingValueAsString(binding);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant target(propertyType);
|
||||||
|
if (QQmlValueTypeProvider::createValueType(source, propertyType, target.data())) {
|
||||||
|
property->writeProperty(_qobject, target.data(), propertyWriteFlags);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// string converters are not exposed, so ending up here indicates an error
|
// string converters are not exposed, so ending up here indicates an error
|
||||||
|
|
|
@ -427,11 +427,14 @@ namespace QQmlPrivate
|
||||||
enum AutoParentResult { Parented, IncompatibleObject, IncompatibleParent };
|
enum AutoParentResult { Parented, IncompatibleObject, IncompatibleParent };
|
||||||
typedef AutoParentResult (*AutoParentFunction)(QObject *object, QObject *parent);
|
typedef AutoParentResult (*AutoParentFunction)(QObject *object, QObject *parent);
|
||||||
|
|
||||||
|
enum class ValueTypeCreationMethod { None, Construct, Structured };
|
||||||
|
|
||||||
struct RegisterType {
|
struct RegisterType {
|
||||||
enum StructVersion: int {
|
enum StructVersion: int {
|
||||||
Base = 0,
|
Base = 0,
|
||||||
FinalizerCast = 1,
|
FinalizerCast = 1,
|
||||||
CurrentVersion = FinalizerCast,
|
CreationMethod = 2,
|
||||||
|
CurrentVersion = CreationMethod,
|
||||||
};
|
};
|
||||||
|
|
||||||
bool has(StructVersion v) const { return structVersion >= int(v); }
|
bool has(StructVersion v) const { return structVersion >= int(v); }
|
||||||
|
@ -446,6 +449,7 @@ namespace QQmlPrivate
|
||||||
void *userdata;
|
void *userdata;
|
||||||
QString noCreationReason;
|
QString noCreationReason;
|
||||||
|
|
||||||
|
// ### Qt7: Get rid of this. It can be covered by creationMethod below.
|
||||||
QVariant (*createValueType)(const QJSValue &);
|
QVariant (*createValueType)(const QJSValue &);
|
||||||
|
|
||||||
const char *uri;
|
const char *uri;
|
||||||
|
@ -467,6 +471,8 @@ namespace QQmlPrivate
|
||||||
|
|
||||||
QTypeRevision revision;
|
QTypeRevision revision;
|
||||||
int finalizerCast;
|
int finalizerCast;
|
||||||
|
|
||||||
|
ValueTypeCreationMethod creationMethod;
|
||||||
// If this is extended ensure "version" is bumped!!!
|
// If this is extended ensure "version" is bumped!!!
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1220,7 +1220,7 @@ bool QQmlPropertyPrivate::writeEnumProperty(const QMetaProperty &prop, int idx,
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
QVariant v = value;
|
QVariant v = value;
|
||||||
if (prop.isEnumType()) {
|
if (prop.isEnumType() && v.metaType() != prop.metaType()) {
|
||||||
QMetaEnum menum = prop.enumerator();
|
QMetaEnum menum = prop.enumerator();
|
||||||
if (v.userType() == QMetaType::QString) {
|
if (v.userType() == QMetaType::QString) {
|
||||||
bool ok;
|
bool ok;
|
||||||
|
@ -1360,6 +1360,80 @@ private:
|
||||||
QUntypedPropertyBinding untypedBinding;
|
QUntypedPropertyBinding untypedBinding;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ConvertAndAssignResult {
|
||||||
|
bool couldConvert = false;
|
||||||
|
bool couldWrite = false;
|
||||||
|
|
||||||
|
operator bool() const { return couldConvert; }
|
||||||
|
};
|
||||||
|
|
||||||
|
static ConvertAndAssignResult tryConvertAndAssign(
|
||||||
|
QObject *object, const QQmlPropertyData &property, const QVariant &value,
|
||||||
|
QQmlPropertyData::WriteFlags flags, QMetaType propertyMetaType, QMetaType variantMetaType,
|
||||||
|
bool isUrl) {
|
||||||
|
|
||||||
|
if (isUrl
|
||||||
|
|| variantMetaType == QMetaType::fromType<QString>()
|
||||||
|
|| propertyMetaType == QMetaType::fromType<QList<QUrl>>()
|
||||||
|
|| property.isQList()) {
|
||||||
|
return {false, false};
|
||||||
|
}
|
||||||
|
|
||||||
|
// common cases:
|
||||||
|
switch (propertyMetaType.id()) {
|
||||||
|
case QMetaType::Bool:
|
||||||
|
if (value.canConvert(propertyMetaType)) {
|
||||||
|
bool b = value.toBool();
|
||||||
|
return {true, property.writeProperty(object, &b, flags)};
|
||||||
|
}
|
||||||
|
return {false, false};
|
||||||
|
case QMetaType::Int: {
|
||||||
|
bool ok = false;
|
||||||
|
int i = value.toInt(&ok);
|
||||||
|
return {ok, ok && property.writeProperty(object, &i, flags)};
|
||||||
|
}
|
||||||
|
case QMetaType::UInt: {
|
||||||
|
bool ok = false;
|
||||||
|
uint u = value.toUInt(&ok);
|
||||||
|
return {ok, ok && property.writeProperty(object, &u, flags)};
|
||||||
|
}
|
||||||
|
case QMetaType::Double: {
|
||||||
|
bool ok = false;
|
||||||
|
double d = value.toDouble(&ok);
|
||||||
|
return {ok, ok && property.writeProperty(object, &d, flags)};
|
||||||
|
}
|
||||||
|
case QMetaType::Float: {
|
||||||
|
bool ok = false;
|
||||||
|
float f = value.toFloat(&ok);
|
||||||
|
return {ok, ok && property.writeProperty(object, &f, flags)};
|
||||||
|
}
|
||||||
|
case QMetaType::QString:
|
||||||
|
if (value.canConvert(propertyMetaType)) {
|
||||||
|
QString s = value.toString();
|
||||||
|
return {true, property.writeProperty(object, &s, flags)};
|
||||||
|
}
|
||||||
|
return {false, false};
|
||||||
|
case QMetaType::QVariantMap:
|
||||||
|
if (value.canConvert(propertyMetaType)) {
|
||||||
|
QVariantMap m = value.toMap();
|
||||||
|
return {true, property.writeProperty(object, &m, flags)};
|
||||||
|
}
|
||||||
|
return {false, false};
|
||||||
|
default: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant converted(propertyMetaType);
|
||||||
|
if (QQmlValueTypeProvider::createValueType(value, propertyMetaType, converted.data())
|
||||||
|
|| QMetaType::convert(value.metaType(), value.constData(),
|
||||||
|
propertyMetaType, converted.data())) {
|
||||||
|
return {true, property.writeProperty(object, converted.data(), flags)};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {false, false};
|
||||||
|
};
|
||||||
|
|
||||||
bool QQmlPropertyPrivate::write(
|
bool QQmlPropertyPrivate::write(
|
||||||
QObject *object, const QQmlPropertyData &property, const QVariant &value,
|
QObject *object, const QQmlPropertyData &property, const QVariant &value,
|
||||||
const QQmlRefPointer<QQmlContextData> &context, QQmlPropertyData::WriteFlags flags)
|
const QQmlRefPointer<QQmlContextData> &context, QQmlPropertyData::WriteFlags flags)
|
||||||
|
@ -1419,37 +1493,9 @@ bool QQmlPropertyPrivate::write(
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (value.canConvert(propertyMetaType)
|
} else if (ConvertAndAssignResult result = tryConvertAndAssign(
|
||||||
&& !isUrl && variantMetaType != QMetaType::fromType<QString>()
|
object, property, value, flags, propertyMetaType, variantMetaType, isUrl)) {
|
||||||
&& propertyMetaType != QMetaType::fromType<QList<QUrl>>() && !property.isQList()) {
|
return result.couldWrite;
|
||||||
// common cases:
|
|
||||||
switch (propertyMetaType.id()) {
|
|
||||||
case QMetaType::Bool: {
|
|
||||||
bool b = value.toBool();
|
|
||||||
return property.writeProperty(object, &b, flags);
|
|
||||||
}
|
|
||||||
case QMetaType::Int: {
|
|
||||||
int i = value.toInt();
|
|
||||||
return property.writeProperty(object, &i, flags);
|
|
||||||
}
|
|
||||||
case QMetaType::Double: {
|
|
||||||
double d = value.toDouble();
|
|
||||||
return property.writeProperty(object, &d, flags);
|
|
||||||
}
|
|
||||||
case QMetaType::Float: {
|
|
||||||
float f = value.toFloat();
|
|
||||||
return property.writeProperty(object, &f, flags);
|
|
||||||
}
|
|
||||||
case QMetaType::QString: {
|
|
||||||
QString s = value.toString();
|
|
||||||
return property.writeProperty(object, &s, flags);
|
|
||||||
}
|
|
||||||
default: { // "fallback":
|
|
||||||
QVariant v = value;
|
|
||||||
v.convert(propertyMetaType);
|
|
||||||
return property.writeProperty(object, const_cast<void *>(v.constData()), flags);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (propertyMetaType == QMetaType::fromType<QVariant>()) {
|
} else if (propertyMetaType == QMetaType::fromType<QVariant>()) {
|
||||||
return property.writeProperty(object, const_cast<QVariant *>(&value), flags);
|
return property.writeProperty(object, const_cast<QVariant *>(&value), flags);
|
||||||
} else if (isUrl) {
|
} else if (isUrl) {
|
||||||
|
|
|
@ -568,10 +568,10 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(
|
||||||
default: return QString();
|
default: return QString();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
QVariant result;
|
QVariant result(property->propType());
|
||||||
if (!QQmlValueTypeProvider::createValueType(
|
if (!QQmlValueTypeProvider::createValueType(
|
||||||
property->propType(),
|
compilationUnit->bindingValueAsString(binding),
|
||||||
compilationUnit->bindingValueAsString(binding), result)) {
|
result.metaType(), result.data())) {
|
||||||
return warnOrError(tr("Invalid property assignment: %1 expected")
|
return warnOrError(tr("Invalid property assignment: %1 expected")
|
||||||
.arg(typeName()));
|
.arg(typeName()));
|
||||||
}
|
}
|
||||||
|
@ -618,6 +618,8 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(
|
||||||
} else if (property->isQObject()
|
} else if (property->isQObject()
|
||||||
&& bindingType == QV4::CompiledData::Binding::Type_Null) {
|
&& bindingType == QV4::CompiledData::Binding::Type_Null) {
|
||||||
break;
|
break;
|
||||||
|
} else if (QQmlMetaType::qmlType(property->propType()).canConstructValueType()) {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return warnOrError(tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(property->propType().name())));
|
return warnOrError(tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(property->propType().name())));
|
||||||
|
|
|
@ -40,11 +40,15 @@ QVariant QQmlStringConverters::variantFromString(const QString &s, QMetaType pre
|
||||||
case QMetaType::QRect:
|
case QMetaType::QRect:
|
||||||
return QVariant::fromValue(rectFFromString(s, ok).toRect());
|
return QVariant::fromValue(rectFFromString(s, ok).toRect());
|
||||||
default: {
|
default: {
|
||||||
QVariant ret;
|
QVariant ret(preferredType);
|
||||||
bool success = QQmlValueTypeProvider::createValueType(preferredType, QJSValue(s), ret);
|
if (QQmlValueTypeProvider::createValueType(s, preferredType, ret.data())) {
|
||||||
|
if (ok)
|
||||||
|
*ok = true;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
if (ok)
|
if (ok)
|
||||||
*ok = success;
|
*ok = false;
|
||||||
return ret;
|
return QVariant();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -527,6 +527,20 @@ QQmlType::CreateValueTypeFunc QQmlType::createValueTypeFunction() const
|
||||||
return d->extraData.cd->createValueTypeFunc;
|
return d->extraData.cd->createValueTypeFunc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool QQmlType::canConstructValueType() const
|
||||||
|
{
|
||||||
|
if (!d || d->regType != CppType)
|
||||||
|
return false;
|
||||||
|
return d->extraData.cd->constructValueType;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QQmlType::canPopulateValueType() const
|
||||||
|
{
|
||||||
|
if (!d || d->regType != CppType)
|
||||||
|
return false;
|
||||||
|
return d->extraData.cd->populateValueType;
|
||||||
|
}
|
||||||
|
|
||||||
QQmlType::CreateFunc QQmlType::createFunction() const
|
QQmlType::CreateFunc QQmlType::createFunction() const
|
||||||
{
|
{
|
||||||
if (!d || d->regType != CppType)
|
if (!d || d->regType != CppType)
|
||||||
|
|
|
@ -71,6 +71,9 @@ public:
|
||||||
typedef QVariant (*CreateValueTypeFunc)(const QJSValue &);
|
typedef QVariant (*CreateValueTypeFunc)(const QJSValue &);
|
||||||
CreateValueTypeFunc createValueTypeFunction() const;
|
CreateValueTypeFunc createValueTypeFunction() const;
|
||||||
|
|
||||||
|
bool canConstructValueType() const;
|
||||||
|
bool canPopulateValueType() const;
|
||||||
|
|
||||||
QObject *create() const;
|
QObject *create() const;
|
||||||
QObject *create(void **, size_t) const;
|
QObject *create(void **, size_t) const;
|
||||||
QObject *createWithQQmlData() const;
|
QObject *createWithQQmlData() const;
|
||||||
|
|
|
@ -92,6 +92,8 @@ public:
|
||||||
int finalizerCast;
|
int finalizerCast;
|
||||||
bool registerEnumClassesUnscoped;
|
bool registerEnumClassesUnscoped;
|
||||||
bool registerEnumsFromRelatedTypes;
|
bool registerEnumsFromRelatedTypes;
|
||||||
|
bool constructValueType;
|
||||||
|
bool populateValueType;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct QQmlSingletonTypeData
|
struct QQmlSingletonTypeData
|
||||||
|
|
|
@ -100,6 +100,7 @@ struct Q_QML_PRIVATE_EXPORT QQmlPointFValueType
|
||||||
QML_FOREIGN(QPointF)
|
QML_FOREIGN(QPointF)
|
||||||
QML_ADDED_IN_VERSION(2, 0)
|
QML_ADDED_IN_VERSION(2, 0)
|
||||||
QML_EXTENDED(QQmlPointFValueType)
|
QML_EXTENDED(QQmlPointFValueType)
|
||||||
|
QML_STRUCTURED_VALUE
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Q_INVOKABLE QString toString() const;
|
Q_INVOKABLE QString toString() const;
|
||||||
|
@ -119,6 +120,7 @@ struct Q_QML_PRIVATE_EXPORT QQmlPointValueType
|
||||||
QML_FOREIGN(QPoint)
|
QML_FOREIGN(QPoint)
|
||||||
QML_ADDED_IN_VERSION(2, 0)
|
QML_ADDED_IN_VERSION(2, 0)
|
||||||
QML_EXTENDED(QQmlPointValueType)
|
QML_EXTENDED(QQmlPointValueType)
|
||||||
|
QML_STRUCTURED_VALUE
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Q_INVOKABLE QString toString() const;
|
Q_INVOKABLE QString toString() const;
|
||||||
|
@ -138,6 +140,7 @@ struct Q_QML_PRIVATE_EXPORT QQmlSizeFValueType
|
||||||
QML_FOREIGN(QSizeF)
|
QML_FOREIGN(QSizeF)
|
||||||
QML_ADDED_IN_VERSION(2, 0)
|
QML_ADDED_IN_VERSION(2, 0)
|
||||||
QML_EXTENDED(QQmlSizeFValueType)
|
QML_EXTENDED(QQmlSizeFValueType)
|
||||||
|
QML_STRUCTURED_VALUE
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Q_INVOKABLE QString toString() const;
|
Q_INVOKABLE QString toString() const;
|
||||||
|
@ -157,6 +160,7 @@ struct Q_QML_PRIVATE_EXPORT QQmlSizeValueType
|
||||||
QML_FOREIGN(QSize)
|
QML_FOREIGN(QSize)
|
||||||
QML_ADDED_IN_VERSION(2, 0)
|
QML_ADDED_IN_VERSION(2, 0)
|
||||||
QML_EXTENDED(QQmlSizeValueType)
|
QML_EXTENDED(QQmlSizeValueType)
|
||||||
|
QML_STRUCTURED_VALUE
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Q_INVOKABLE QString toString() const;
|
Q_INVOKABLE QString toString() const;
|
||||||
|
@ -182,6 +186,7 @@ struct Q_QML_PRIVATE_EXPORT QQmlRectFValueType
|
||||||
QML_FOREIGN(QRectF)
|
QML_FOREIGN(QRectF)
|
||||||
QML_ADDED_IN_VERSION(2, 0)
|
QML_ADDED_IN_VERSION(2, 0)
|
||||||
QML_EXTENDED(QQmlRectFValueType)
|
QML_EXTENDED(QQmlRectFValueType)
|
||||||
|
QML_STRUCTURED_VALUE
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Q_INVOKABLE QString toString() const;
|
Q_INVOKABLE QString toString() const;
|
||||||
|
@ -217,6 +222,7 @@ struct Q_QML_PRIVATE_EXPORT QQmlRectValueType
|
||||||
QML_FOREIGN(QRect)
|
QML_FOREIGN(QRect)
|
||||||
QML_ADDED_IN_VERSION(2, 0)
|
QML_ADDED_IN_VERSION(2, 0)
|
||||||
QML_EXTENDED(QQmlRectValueType)
|
QML_EXTENDED(QQmlRectValueType)
|
||||||
|
QML_STRUCTURED_VALUE
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Q_INVOKABLE QString toString() const;
|
Q_INVOKABLE QString toString() const;
|
||||||
|
@ -282,6 +288,7 @@ struct Q_QML_PRIVATE_EXPORT QQmlEasingValueType
|
||||||
QML_FOREIGN(QEasingCurve)
|
QML_FOREIGN(QEasingCurve)
|
||||||
QML_ADDED_IN_VERSION(2, 0)
|
QML_ADDED_IN_VERSION(2, 0)
|
||||||
QML_EXTENDED(QQmlEasingValueType)
|
QML_EXTENDED(QQmlEasingValueType)
|
||||||
|
QML_STRUCTURED_VALUE
|
||||||
|
|
||||||
Q_PROPERTY(QQmlEasingEnums::Type type READ type WRITE setType FINAL)
|
Q_PROPERTY(QQmlEasingEnums::Type type READ type WRITE setType FINAL)
|
||||||
Q_PROPERTY(qreal amplitude READ amplitude WRITE setAmplitude FINAL)
|
Q_PROPERTY(qreal amplitude READ amplitude WRITE setAmplitude FINAL)
|
||||||
|
|
|
@ -48,8 +48,15 @@ QT_END_NAMESPACE
|
||||||
Q_CLASSINFO("QML.UncreatableReason", REASON)
|
Q_CLASSINFO("QML.UncreatableReason", REASON)
|
||||||
|
|
||||||
#define QML_VALUE_TYPE(NAME) \
|
#define QML_VALUE_TYPE(NAME) \
|
||||||
Q_CLASSINFO("QML.Element", #NAME) \
|
Q_CLASSINFO("QML.Element", #NAME)
|
||||||
QML_UNCREATABLE("Value types cannot be created.")
|
|
||||||
|
#define QML_CONSTRUCTIBLE_VALUE \
|
||||||
|
Q_CLASSINFO("QML.Creatable", "true") \
|
||||||
|
Q_CLASSINFO("QML.CreationMethod", "construct")
|
||||||
|
|
||||||
|
#define QML_STRUCTURED_VALUE \
|
||||||
|
Q_CLASSINFO("QML.Creatable", "true") \
|
||||||
|
Q_CLASSINFO("QML.CreationMethod", "structured")
|
||||||
|
|
||||||
#define QML_SINGLETON \
|
#define QML_SINGLETON \
|
||||||
Q_CLASSINFO("QML.Singleton", "true") \
|
Q_CLASSINFO("QML.Singleton", "true") \
|
||||||
|
|
|
@ -52,6 +52,7 @@ struct QPointingDeviceUniqueIdForeign
|
||||||
QML_FOREIGN(QPointingDeviceUniqueId)
|
QML_FOREIGN(QPointingDeviceUniqueId)
|
||||||
QML_VALUE_TYPE(pointingDeviceUniqueId)
|
QML_VALUE_TYPE(pointingDeviceUniqueId)
|
||||||
QML_ADDED_IN_VERSION(2, 9)
|
QML_ADDED_IN_VERSION(2, 9)
|
||||||
|
QML_UNCREATABLE("pointingDeviceUniqueId cannot be created in QML.")
|
||||||
};
|
};
|
||||||
|
|
||||||
#if !QT_CONFIG(quick_animatedimage)
|
#if !QT_CONFIG(quick_animatedimage)
|
||||||
|
|
|
@ -10,6 +10,11 @@
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
QQuickColorValueType::QQuickColorValueType(const QString &string)
|
||||||
|
: v(QColor::fromString(string))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
QVariant QQuickColorValueType::create(const QJSValue ¶ms)
|
QVariant QQuickColorValueType::create(const QJSValue ¶ms)
|
||||||
{
|
{
|
||||||
return params.isString() ? QColor::fromString(params.toString()) : QVariant();
|
return params.isString() ? QColor::fromString(params.toString()) : QVariant();
|
||||||
|
|
|
@ -49,10 +49,12 @@ class Q_QUICK_PRIVATE_EXPORT QQuickColorValueType
|
||||||
QML_FOREIGN(QColor)
|
QML_FOREIGN(QColor)
|
||||||
QML_VALUE_TYPE(color)
|
QML_VALUE_TYPE(color)
|
||||||
QML_EXTENDED(QQuickColorValueType)
|
QML_EXTENDED(QQuickColorValueType)
|
||||||
|
QML_STRUCTURED_VALUE
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static QVariant create(const QJSValue ¶ms);
|
static QVariant create(const QJSValue ¶ms);
|
||||||
|
|
||||||
|
Q_INVOKABLE QQuickColorValueType(const QString &string);
|
||||||
Q_INVOKABLE QString toString() const;
|
Q_INVOKABLE QString toString() const;
|
||||||
|
|
||||||
Q_INVOKABLE QVariant alpha(qreal value) const;
|
Q_INVOKABLE QVariant alpha(qreal value) const;
|
||||||
|
@ -93,6 +95,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickVector2DValueType
|
||||||
QML_FOREIGN(QVector2D)
|
QML_FOREIGN(QVector2D)
|
||||||
QML_VALUE_TYPE(vector2d)
|
QML_VALUE_TYPE(vector2d)
|
||||||
QML_EXTENDED(QQuickVector2DValueType)
|
QML_EXTENDED(QQuickVector2DValueType)
|
||||||
|
QML_STRUCTURED_VALUE
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static QVariant create(const QJSValue ¶ms);
|
static QVariant create(const QJSValue ¶ms);
|
||||||
|
@ -128,6 +131,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickVector3DValueType
|
||||||
QML_FOREIGN(QVector3D)
|
QML_FOREIGN(QVector3D)
|
||||||
QML_VALUE_TYPE(vector3d)
|
QML_VALUE_TYPE(vector3d)
|
||||||
QML_EXTENDED(QQuickVector3DValueType)
|
QML_EXTENDED(QQuickVector3DValueType)
|
||||||
|
QML_STRUCTURED_VALUE
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static QVariant create(const QJSValue ¶ms);
|
static QVariant create(const QJSValue ¶ms);
|
||||||
|
@ -168,6 +172,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickVector4DValueType
|
||||||
QML_FOREIGN(QVector4D)
|
QML_FOREIGN(QVector4D)
|
||||||
QML_VALUE_TYPE(vector4d)
|
QML_VALUE_TYPE(vector4d)
|
||||||
QML_EXTENDED(QQuickVector4DValueType)
|
QML_EXTENDED(QQuickVector4DValueType)
|
||||||
|
QML_STRUCTURED_VALUE
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static QVariant create(const QJSValue ¶ms);
|
static QVariant create(const QJSValue ¶ms);
|
||||||
|
@ -209,6 +214,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickQuaternionValueType
|
||||||
QML_FOREIGN(QQuaternion)
|
QML_FOREIGN(QQuaternion)
|
||||||
QML_VALUE_TYPE(quaternion)
|
QML_VALUE_TYPE(quaternion)
|
||||||
QML_EXTENDED(QQuickQuaternionValueType)
|
QML_EXTENDED(QQuickQuaternionValueType)
|
||||||
|
QML_STRUCTURED_VALUE
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static QVariant create(const QJSValue ¶ms);
|
static QVariant create(const QJSValue ¶ms);
|
||||||
|
@ -267,6 +273,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickMatrix4x4ValueType
|
||||||
QML_FOREIGN(QMatrix4x4)
|
QML_FOREIGN(QMatrix4x4)
|
||||||
QML_VALUE_TYPE(matrix4x4)
|
QML_VALUE_TYPE(matrix4x4)
|
||||||
QML_EXTENDED(QQuickMatrix4x4ValueType)
|
QML_EXTENDED(QQuickMatrix4x4ValueType)
|
||||||
|
QML_STRUCTURED_VALUE
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static QVariant create(const QJSValue ¶ms);
|
static QVariant create(const QJSValue ¶ms);
|
||||||
|
@ -390,6 +397,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickFontValueType
|
||||||
QML_FOREIGN(QFont)
|
QML_FOREIGN(QFont)
|
||||||
QML_ADDED_IN_VERSION(2, 0)
|
QML_ADDED_IN_VERSION(2, 0)
|
||||||
QML_EXTENDED(QQuickFontValueType)
|
QML_EXTENDED(QQuickFontValueType)
|
||||||
|
QML_STRUCTURED_VALUE
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static QVariant create(const QJSValue &value);
|
static QVariant create(const QJSValue &value);
|
||||||
|
@ -494,6 +502,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickColorSpaceValueType
|
||||||
QML_FOREIGN(QColorSpace)
|
QML_FOREIGN(QColorSpace)
|
||||||
QML_ADDED_IN_VERSION(2, 15)
|
QML_ADDED_IN_VERSION(2, 15)
|
||||||
QML_EXTENDED(QQuickColorSpaceValueType)
|
QML_EXTENDED(QQuickColorSpaceValueType)
|
||||||
|
QML_STRUCTURED_VALUE
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static QVariant create(const QJSValue ¶ms);
|
static QVariant create(const QJSValue ¶ms);
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
import QtQml
|
||||||
|
import Test
|
||||||
|
|
||||||
|
MyTypeObject {
|
||||||
|
property point p: ({x: 7, y: 77, notthere: 2})
|
||||||
|
property size s: ({width: 7, height: "77"})
|
||||||
|
property rect r: ({x: 5, y: 55, width: 7, height: 77})
|
||||||
|
|
||||||
|
property point p2
|
||||||
|
property size s2
|
||||||
|
property rect r2
|
||||||
|
|
||||||
|
property constructible c1: 5
|
||||||
|
property constructible c2: ({foo: 7})
|
||||||
|
property constructible c3
|
||||||
|
property constructible c4
|
||||||
|
|
||||||
|
property list<point> ps: [{x: 1, y: 2}, {x: 3, y: 4}, {x: 55, y: Qt.locale()}]
|
||||||
|
property list<size> ss: [{width: 5, height: 6}, {width: 7, height: 8}, {height: 99}]
|
||||||
|
property list<constructible> cs: [1, 2, 3, 4, 5, {}]
|
||||||
|
|
||||||
|
property structured b1: ({i: 10, c: 14, p: {x: 1, y: 44} })
|
||||||
|
property structured b2
|
||||||
|
property list<structured> bb: [{i : 21}, {c: 22}, {p: {x: 199, y: 222}}]
|
||||||
|
|
||||||
|
constructible: 47
|
||||||
|
structured: ({i: 11, c: 12, p: {x: 7, y: 8}})
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
p2 = {x: 4, y: 5};
|
||||||
|
s2 = {width: 7, height: 8};
|
||||||
|
r2 = {x: 9, y: 10, width: 11, height: 12};
|
||||||
|
c3 = 99;
|
||||||
|
b2 = {i: 11, c: 15, p: {x: 4} }
|
||||||
|
|
||||||
|
c4 = {foo: 11};
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,4 +5,6 @@
|
||||||
void registerTypes()
|
void registerTypes()
|
||||||
{
|
{
|
||||||
qmlRegisterType<MyTypeObject>("Test", 1, 0, "MyTypeObject");
|
qmlRegisterType<MyTypeObject>("Test", 1, 0, "MyTypeObject");
|
||||||
|
qmlRegisterTypesAndRevisions<ConstructibleValueType>("Test", 1);
|
||||||
|
qmlRegisterTypesAndRevisions<StructuredValueType>("Test", 1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,61 @@
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
#include <qqml.h>
|
#include <qqml.h>
|
||||||
|
|
||||||
|
struct ConstructibleValueType
|
||||||
|
{
|
||||||
|
Q_GADGET
|
||||||
|
Q_PROPERTY(int foo MEMBER m_foo CONSTANT)
|
||||||
|
|
||||||
|
QML_VALUE_TYPE(constructible)
|
||||||
|
QML_CONSTRUCTIBLE_VALUE
|
||||||
|
|
||||||
|
public:
|
||||||
|
ConstructibleValueType() = default;
|
||||||
|
Q_INVOKABLE ConstructibleValueType(int foo) : m_foo(foo) {}
|
||||||
|
|
||||||
|
int foo() const { return m_foo; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend bool operator==(const ConstructibleValueType &a, const ConstructibleValueType &b)
|
||||||
|
{
|
||||||
|
return a.m_foo == b.m_foo;
|
||||||
|
}
|
||||||
|
|
||||||
|
int m_foo = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StructuredValueType
|
||||||
|
{
|
||||||
|
Q_GADGET
|
||||||
|
Q_PROPERTY(int i READ i WRITE setI)
|
||||||
|
Q_PROPERTY(ConstructibleValueType c READ c WRITE setC)
|
||||||
|
Q_PROPERTY(QPointF p READ p WRITE setP)
|
||||||
|
|
||||||
|
QML_VALUE_TYPE(structured)
|
||||||
|
QML_STRUCTURED_VALUE
|
||||||
|
|
||||||
|
public:
|
||||||
|
int i() const { return m_i; }
|
||||||
|
void setI(int newI) { m_i = newI; }
|
||||||
|
|
||||||
|
const ConstructibleValueType &c() const { return m_c; }
|
||||||
|
void setC(const ConstructibleValueType &newC) { m_c = newC; }
|
||||||
|
|
||||||
|
QPointF p() const { return m_p; }
|
||||||
|
void setP(QPointF newP) { m_p = newP; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
friend bool operator==(const StructuredValueType &a, const StructuredValueType &b)
|
||||||
|
{
|
||||||
|
return a.m_i == b.m_i && a.m_c == b.m_c && a.m_p == b.m_p;
|
||||||
|
}
|
||||||
|
|
||||||
|
int m_i = 0;
|
||||||
|
ConstructibleValueType m_c;
|
||||||
|
QPointF m_p;
|
||||||
|
};
|
||||||
|
|
||||||
class MyTypeObject : public QObject
|
class MyTypeObject : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -41,6 +96,8 @@ class MyTypeObject : public QObject
|
||||||
Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY changed)
|
Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY changed)
|
||||||
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY changed)
|
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY changed)
|
||||||
Q_PROPERTY(QVariant variant READ variant NOTIFY changed)
|
Q_PROPERTY(QVariant variant READ variant NOTIFY changed)
|
||||||
|
Q_PROPERTY(ConstructibleValueType constructible READ constructible WRITE setConstructible NOTIFY constructibleChanged)
|
||||||
|
Q_PROPERTY(StructuredValueType structured READ structured WRITE setStructured NOTIFY structuredChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MyTypeObject() :
|
MyTypeObject() :
|
||||||
|
@ -144,12 +201,36 @@ public:
|
||||||
|
|
||||||
void emitRunScript() { emit runScript(); }
|
void emitRunScript() { emit runScript(); }
|
||||||
|
|
||||||
|
const ConstructibleValueType &constructible() const { return m_constructible; }
|
||||||
|
void setConstructible(const ConstructibleValueType &newConstructible)
|
||||||
|
{
|
||||||
|
if (m_constructible == newConstructible)
|
||||||
|
return;
|
||||||
|
m_constructible = newConstructible;
|
||||||
|
emit constructibleChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
const StructuredValueType &structured() const { return m_structured; }
|
||||||
|
void setStructured(const StructuredValueType &newStructured)
|
||||||
|
{
|
||||||
|
if (m_structured == newStructured)
|
||||||
|
return;
|
||||||
|
m_structured = newStructured;
|
||||||
|
emit structuredChanged();
|
||||||
|
}
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void changed();
|
void changed();
|
||||||
void runScript();
|
void runScript();
|
||||||
|
|
||||||
|
void constructibleChanged();
|
||||||
|
void structuredChanged();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
QSize method() { return QSize(13, 14); }
|
QSize method() { return QSize(13, 14); }
|
||||||
|
private:
|
||||||
|
ConstructibleValueType m_constructible;
|
||||||
|
StructuredValueType m_structured;
|
||||||
};
|
};
|
||||||
|
|
||||||
void registerTypes();
|
void registerTypes();
|
||||||
|
|
|
@ -38,6 +38,7 @@ private slots:
|
||||||
void invokableFunctions();
|
void invokableFunctions();
|
||||||
void userType();
|
void userType();
|
||||||
void changedSignal();
|
void changedSignal();
|
||||||
|
void structured();
|
||||||
};
|
};
|
||||||
|
|
||||||
void tst_qqmlvaluetypeproviders::initTestCase()
|
void tst_qqmlvaluetypeproviders::initTestCase()
|
||||||
|
@ -245,6 +246,95 @@ void tst_qqmlvaluetypeproviders::changedSignal()
|
||||||
QVERIFY(object->property("success").toBool());
|
QVERIFY(object->property("success").toBool());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_qqmlvaluetypeproviders::structured()
|
||||||
|
{
|
||||||
|
QQmlEngine e;
|
||||||
|
const QUrl url = testFileUrl("structuredValueTypes.qml");
|
||||||
|
QQmlComponent component(&e, url);
|
||||||
|
QVERIFY2(!component.isError(), qPrintable(component.errorString()));
|
||||||
|
|
||||||
|
const char *warnings[] = {
|
||||||
|
"Could not find any constructor for value type ConstructibleValueType to call"
|
||||||
|
" with value [object Object]",
|
||||||
|
"Could not find any constructor for value type ConstructibleValueType to call"
|
||||||
|
" with value QVariant(QJSValue, )",
|
||||||
|
"Could not convert [object Object] to double for property y",
|
||||||
|
"Could not find any constructor for value type ConstructibleValueType to call"
|
||||||
|
" with value [object Object]",
|
||||||
|
"Could not find any constructor for value type ConstructibleValueType to call"
|
||||||
|
" with value QVariant(QVariantMap, QMap())",
|
||||||
|
"Could not convert array value at position 5 from QVariantMap to ConstructibleValueType",
|
||||||
|
"Could not find any constructor for value type ConstructibleValueType to call"
|
||||||
|
" with value [object Object]",
|
||||||
|
"Could not find any constructor for value type ConstructibleValueType to call"
|
||||||
|
" with value QVariant(QJSValue, )"
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const auto warning : warnings)
|
||||||
|
QTest::ignoreMessage(QtWarningMsg, warning);
|
||||||
|
|
||||||
|
QTest::ignoreMessage(QtWarningMsg, qPrintable(
|
||||||
|
url.toString() + QStringLiteral(":36: Error: Cannot assign QJSValue "
|
||||||
|
"to ConstructibleValueType")));
|
||||||
|
|
||||||
|
QTest::ignoreMessage(QtWarningMsg, qPrintable(
|
||||||
|
url.toString() + QStringLiteral(":14:5: Unable to assign QJSValue "
|
||||||
|
"to ConstructibleValueType")));
|
||||||
|
|
||||||
|
QScopedPointer<QObject> o(component.create());
|
||||||
|
QVERIFY2(!o.isNull(), qPrintable(component.errorString()));
|
||||||
|
|
||||||
|
QCOMPARE(o->property("p").value<QPointF>(), QPointF(7, 77));
|
||||||
|
QCOMPARE(o->property("s").value<QSizeF>(), QSizeF(7, 77));
|
||||||
|
QCOMPARE(o->property("r").value<QRectF>(), QRectF(5, 55, 7, 77));
|
||||||
|
|
||||||
|
QCOMPARE(o->property("p2").value<QPointF>(), QPointF(4, 5));
|
||||||
|
QCOMPARE(o->property("s2").value<QSizeF>(), QSizeF(7, 8));
|
||||||
|
QCOMPARE(o->property("r2").value<QRectF>(), QRectF(9, 10, 11, 12));
|
||||||
|
|
||||||
|
QCOMPARE(o->property("c1").value<ConstructibleValueType>(), ConstructibleValueType(5));
|
||||||
|
QCOMPARE(o->property("c2").value<ConstructibleValueType>(), ConstructibleValueType(0));
|
||||||
|
QCOMPARE(o->property("c3").value<ConstructibleValueType>(), ConstructibleValueType(99));
|
||||||
|
QCOMPARE(o->property("c4").value<ConstructibleValueType>(), ConstructibleValueType(0));
|
||||||
|
|
||||||
|
QCOMPARE(o->property("ps").value<QList<QPointF>>(),
|
||||||
|
QList<QPointF>({QPointF(1, 2), QPointF(3, 4), QPointF(55, 0)}));
|
||||||
|
QCOMPARE(o->property("ss").value<QList<QSizeF>>(),
|
||||||
|
QList<QSizeF>({QSizeF(5, 6), QSizeF(7, 8), QSizeF(-1, 99)}));
|
||||||
|
QCOMPARE(o->property("cs").value<QList<ConstructibleValueType>>(),
|
||||||
|
QList<ConstructibleValueType>({1, 2, 3, 4, 5, 0}));
|
||||||
|
|
||||||
|
StructuredValueType b1;
|
||||||
|
b1.setI(10);
|
||||||
|
b1.setC(14);
|
||||||
|
b1.setP(QPointF(1, 44));
|
||||||
|
QCOMPARE(o->property("b1").value<StructuredValueType>(), b1);
|
||||||
|
|
||||||
|
StructuredValueType b2;
|
||||||
|
b2.setI(11);
|
||||||
|
b2.setC(15);
|
||||||
|
b2.setP(QPointF(4, 0));
|
||||||
|
QCOMPARE(o->property("b2").value<StructuredValueType>(), b2);
|
||||||
|
|
||||||
|
|
||||||
|
QList<StructuredValueType> bb(3);
|
||||||
|
bb[0].setI(21);
|
||||||
|
bb[1].setC(22);
|
||||||
|
bb[2].setP(QPointF(199, 222));
|
||||||
|
QCOMPARE(o->property("bb").value<QList<StructuredValueType>>(), bb);
|
||||||
|
|
||||||
|
MyTypeObject *t = qobject_cast<MyTypeObject *>(o.data());
|
||||||
|
QVERIFY(t);
|
||||||
|
|
||||||
|
QCOMPARE(t->constructible(), ConstructibleValueType(47));
|
||||||
|
|
||||||
|
StructuredValueType structured;
|
||||||
|
structured.setI(11);
|
||||||
|
structured.setC(12);
|
||||||
|
structured.setP(QPointF(7, 8));
|
||||||
|
QCOMPARE(t->structured(), structured);
|
||||||
|
}
|
||||||
|
|
||||||
QTEST_MAIN(tst_qqmlvaluetypeproviders)
|
QTEST_MAIN(tst_qqmlvaluetypeproviders)
|
||||||
|
|
||||||
#include "tst_qqmlvaluetypeproviders.moc"
|
#include "tst_qqmlvaluetypeproviders.moc"
|
||||||
|
|
Loading…
Reference in New Issue