diff options
author | Volker Hilsheimer <volker.hilsheimer@qt.io> | 2022-09-09 15:46:22 +0200 |
---|---|---|
committer | Volker Hilsheimer <volker.hilsheimer@qt.io> | 2022-09-14 13:19:44 +0200 |
commit | 734799d9f88c2383be87806d4931799b6f6a843a (patch) | |
tree | 96afab2367fd90eda01c885bf5a4f15dcf327cc6 /src/imports/location/location.cpp | |
parent | 22c3c1d155f817324ed535ba599633cad0e49b5e (diff) | |
download | qtlocation-734799d9f88c2383be87806d4931799b6f6a843a.tar.gz |
Implement generic conversion from QML types to gadgets
This is a temporary solution to facilitate the conversion of Places
QML types into value types, allowing us to get rid of the thin and
unnecessary QDeclarative* wrappers.
Support both conversion from QJSValue and from QVariantMap is needed to
allow value-initialization of nested types, such as QPlaceSupplier,
which has a QPlaceIcon property.
Once the QML engine implements property-by-property initialization, this
solution can be removed again. It is either way primarily relevant for
the unit tests, which need to be able to construct and initialize value
types from QML and JavaScript.
Change-Id: I253ce6415dd80ec6464c77bca197cff325149cf7
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/imports/location/location.cpp')
-rw-r--r-- | src/imports/location/location.cpp | 69 |
1 files changed, 69 insertions, 0 deletions
diff --git a/src/imports/location/location.cpp b/src/imports/location/location.cpp index a12c773b..39c8046f 100644 --- a/src/imports/location/location.cpp +++ b/src/imports/location/location.cpp @@ -79,6 +79,75 @@ QT_BEGIN_NAMESPACE +namespace { + +bool convertToGadget(const QMetaObject &metaObject, const QVariantMap &map, void *gadget) +{ + for (auto &&[key, value] : map.asKeyValueRange()) { + const int propIndex = metaObject.indexOfProperty(key.toUtf8()); + if (propIndex == -1) { + qCritical("No property %s in %s", qPrintable(key), metaObject.className()); + return false; + } + const QMetaProperty prop = metaObject.property(propIndex); + bool successfulWrite = false; + if (value.metaType() != prop.metaType()) { + QVariant coercedValue = value; + if (!coercedValue.convert(prop.metaType())) { + qCritical("Could not convert value from %s to %s for property %s::%s", + value.typeName(), prop.typeName(), metaObject.className(), qPrintable(key)); + return false; + } + successfulWrite = prop.writeOnGadget(gadget, coercedValue); + } else { + successfulWrite = prop.writeOnGadget(gadget, value); + } + if (!successfulWrite) { + qCritical("Could not set property %s on %s", qPrintable(key), metaObject.className()); + return false; + } + } + return true; +} + +template<typename SourceType, typename GadgetType> +bool converterToGadget(const void *src, void *gadget) +{ + const QMetaObject &metaObject = GadgetType::staticMetaObject; + QVariantMap variantMap; + if constexpr (std::is_same_v<SourceType, QJSValue>) { + const QJSValue &jsValue = *static_cast<const QJSValue *>(src); + const QVariant &variant = jsValue.toVariant(); + if (variant.metaType() != QMetaType::fromType<QVariantMap>()) + return false; + variantMap = variant.toMap(); + } else { + static_assert(std::is_same_v<SourceType, QVariantMap>); + variantMap = *static_cast<const QVariantMap *>(src); + } + return convertToGadget(metaObject, variantMap, gadget); +} + +template<typename GadgetType> +bool registerConverterToGadget() +{ + if (!QMetaType::registerConverterFunction(converterToGadget<QJSValue, GadgetType>, + QMetaType::fromType<QJSValue>(), QMetaType::fromType<GadgetType>())) { + qCritical("Failed to register conversion function from QJSValue to %s", + GadgetType::staticMetaObject.className()); + return false; + } + if (!QMetaType::registerConverterFunction(converterToGadget<QVariantMap, GadgetType>, + QMetaType::fromType<QVariantMap>(), QMetaType::fromType<GadgetType>())) { + qCritical("Failed to register conversion function from QVariantMap to %s", + GadgetType::staticMetaObject.className()); + return false; + } + + return true; +} + +} // anonymous namespace class QtLocationDeclarativeModule: public QQmlExtensionPlugin { |