From e1ca288daa9b7ff59ae8988671defcb25c848335 Mon Sep 17 00:00:00 2001 From: mhoff Date: Sun, 16 Jan 2022 22:23:44 -0800 Subject: [PATCH 1/2] Add qml_register_uncreatable_type. This allows for registering structs that don't implement Default, mirroring C++'s QQmlEngine::qmlRegisterUncreatableType. --- qmetaobject/src/qtdeclarative.rs | 97 ++++++++++++++++++++++++++++++-- qmetaobject/tests/tests.rs | 50 ++++++++++++++++ 2 files changed, 143 insertions(+), 4 deletions(-) diff --git a/qmetaobject/src/qtdeclarative.rs b/qmetaobject/src/qtdeclarative.rs index 55605b40..4fd5f4eb 100644 --- a/qmetaobject/src/qtdeclarative.rs +++ b/qmetaobject/src/qtdeclarative.rs @@ -502,16 +502,105 @@ pub fn qml_register_type( }) } -/// Wrapper around [`void qmlRegisterModule(const char *uri, int versionMajor, int versionMinor)`][qt] function. +/// Register the given type as an uncreatable QML type /// -/// [qt]: https://doc.qt.io/qt-5/qqmlengine.html#qmlRegisterModule -#[cfg(qt_5_9)] -pub fn qml_register_module( +/// Refer to the Qt documentation for QQmlEngine::qmlRegisterUncreatableType. +pub fn qml_register_uncreatable_type( uri: &CStr, version_major: u32, version_minor: u32, + qml_name: &CStr, + no_creation_reason: QString, ) { let uri_ptr = uri.as_ptr(); + let qml_name_ptr = qml_name.as_ptr(); + let meta_object = T::static_meta_object(); + + extern "C" fn extra_destruct(c: *mut c_void) { + cpp!(unsafe [c as "QObject *"] { + QQmlPrivate::qdeclarativeelement_destructor(c); + }) + } + + let size = T::cpp_size(); + + let type_id = as PropertyType>::register_type(Default::default()); + + cpp!(unsafe [ + qml_name_ptr as "char *", + uri_ptr as "char *", + version_major as "int", + version_minor as "int", + meta_object as "const QMetaObject *", + size as "size_t", + type_id as "int", + no_creation_reason as "QString" + ] { + // BEGIN: From QML_GETTYPENAMES + // FIXME: list type? + /*const int listLen = int(strlen("QQmlListProperty<")); + QVarLengthArray listName(listLen + nameLen + 2); + memcpy(listName.data(), "QQmlListProperty<", size_t(listLen)); + memcpy(listName.data()+listLen, className, size_t(nameLen)); + listName[listLen+nameLen] = '>'; + listName[listLen+nameLen+1] = '\0';*/ + // END + + int parserStatusCast = meta_object && qmeta_inherits(meta_object, &QQuickItem::staticMetaObject) + ? QQmlPrivate::StaticCastSelector::cast() + : -1; + + QQmlPrivate::RegisterType api = { + /*version*/ 0, + + #if QT_VERSION < QT_VERSION_CHECK(6,0,0) + /*typeId*/ type_id, + #else + /*typeId*/ QMetaType(type_id), + #endif + /*listId*/ {}, // FIXME: list type? + /*objectSize*/ int(size), + /*create*/ nullptr, + #if QT_VERSION >= QT_VERSION_CHECK(6,0,0) + /* userdata */ nullptr, + #endif + /*noCreationReason*/ no_creation_reason, + #if QT_VERSION >= QT_VERSION_CHECK(6,0,0) + /* createValueType */ nullptr, + #endif + + /*uri*/ uri_ptr, + #if QT_VERSION < QT_VERSION_CHECK(6,0,0) + /*versionMajor*/ version_major, + /*versionMinor*/ version_minor, + #else + /*version*/ QTypeRevision::fromVersion(version_major, version_minor), + #endif + /*elementName*/ qml_name_ptr, + /*metaObject*/ meta_object, + + /*attachedPropertiesFunction*/ nullptr, + /*attachedPropertiesMetaObject*/ nullptr, + + /*parserStatusCast*/ parserStatusCast, + /*valueSourceCast*/ -1, + /*valueInterceptorCast*/ -1, + + /*extensionObjectCreate*/ nullptr, + /*extensionMetaObject*/ nullptr, + /*customParser*/ nullptr, + /*revision*/ {} // FIXME: support revisions? + }; + QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &api); + }) +} + +/// Wrapper around [`void qmlRegisterModule(const char *uri, int versionMajor, int versionMinor)`][qt] function. +/// +/// [qt]: https://doc.qt.io/qt-5/qqmlengine.html#qmlRegisterModule +#[cfg(qt_5_9)] +pub fn qml_register_module(uri: &CStr, version_major: u32, version_minor: u32) { + let uri_ptr = uri.as_ptr(); cpp!(unsafe [ uri_ptr as "const char *", diff --git a/qmetaobject/tests/tests.rs b/qmetaobject/tests/tests.rs index 359170b9..f742677a 100644 --- a/qmetaobject/tests/tests.rs +++ b/qmetaobject/tests/tests.rs @@ -211,6 +211,56 @@ fn register_type() { )); } +#[derive(QObject)] +struct RegisteredObjWithNoDefault { + base: qt_base_class!(trait QObject), + value: qt_property!(u32), + square: qt_method!( + fn square(&self, v: u32) -> u32 { + self.value * self.internal_value * v + } + ), + internal_value: u32, +} + +impl RegisteredObjWithNoDefault { + fn new(internal_value: u32) -> RegisteredObjWithNoDefault { + RegisteredObjWithNoDefault { + internal_value: internal_value, + base: Default::default(), + value: Default::default(), + square: Default::default(), + } + } +} + +#[test] +fn register_uncreatable_type() { + qml_register_uncreatable_type::( + CStr::from_bytes_with_nul(b"TestRegisterUncreatable\0").unwrap(), + 1, + 0, + CStr::from_bytes_with_nul(b"RegisteredObjUncreatable\0").unwrap(), + QString::from("Type has no default"), + ); + + let mut obj = RegisteredObjWithNoDefault::new(44); + obj.value = 55; + + assert!(do_test( + obj, + r" + import TestRegister 1.0 + + Item { + function doTest() { + return _obj.square(66) === 44 * 55 * 66; + } + } + " + )); +} + #[test] #[cfg(qt_5_9)] fn register_module() { From a040ebcc45bfdae6c167e9a9ba207a460dca686f Mon Sep 17 00:00:00 2001 From: mhoff Date: Mon, 17 Jan 2022 14:34:46 -0800 Subject: [PATCH 2/2] Clean up some comments, inaccurate test names, and unused code. --- qmetaobject/src/qtdeclarative.rs | 20 +++++--------------- qmetaobject/tests/tests.rs | 16 ++++++++-------- 2 files changed, 13 insertions(+), 23 deletions(-) diff --git a/qmetaobject/src/qtdeclarative.rs b/qmetaobject/src/qtdeclarative.rs index 4fd5f4eb..02486d0d 100644 --- a/qmetaobject/src/qtdeclarative.rs +++ b/qmetaobject/src/qtdeclarative.rs @@ -397,9 +397,9 @@ impl QmlComponent { } } -/// Register the given type as a QML type +/// Wrapper around [`template int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName)`][qt] function. /// -/// Refer to the Qt documentation for qmlRegisterType. +/// [qt]: https://doc.qt.io/qt-5/qqmlengine.html#qmlRegisterType pub fn qml_register_type( uri: &CStr, version_major: u32, @@ -502,9 +502,9 @@ pub fn qml_register_type( }) } -/// Register the given type as an uncreatable QML type +/// Wrapper around [`template int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString &message)`][qt] function. /// -/// Refer to the Qt documentation for QQmlEngine::qmlRegisterUncreatableType. +/// [qt]: https://doc.qt.io/qt-5/qqmlengine.html#qmlRegisterUncreatableType pub fn qml_register_uncreatable_type( uri: &CStr, version_major: u32, @@ -516,12 +516,6 @@ pub fn qml_register_uncreatable_type( let qml_name_ptr = qml_name.as_ptr(); let meta_object = T::static_meta_object(); - extern "C" fn extra_destruct(c: *mut c_void) { - cpp!(unsafe [c as "QObject *"] { - QQmlPrivate::qdeclarativeelement_destructor(c); - }) - } - let size = T::cpp_size(); let type_id = as PropertyType>::register_type(Default::default()); @@ -546,10 +540,6 @@ pub fn qml_register_uncreatable_type( listName[listLen+nameLen+1] = '\0';*/ // END - int parserStatusCast = meta_object && qmeta_inherits(meta_object, &QQuickItem::staticMetaObject) - ? QQmlPrivate::StaticCastSelector::cast() - : -1; - QQmlPrivate::RegisterType api = { /*version*/ 0, @@ -582,7 +572,7 @@ pub fn qml_register_uncreatable_type( /*attachedPropertiesFunction*/ nullptr, /*attachedPropertiesMetaObject*/ nullptr, - /*parserStatusCast*/ parserStatusCast, + /*parserStatusCast*/ -1, /*valueSourceCast*/ -1, /*valueInterceptorCast*/ -1, diff --git a/qmetaobject/tests/tests.rs b/qmetaobject/tests/tests.rs index f742677a..80e48147 100644 --- a/qmetaobject/tests/tests.rs +++ b/qmetaobject/tests/tests.rs @@ -176,8 +176,8 @@ fn call_method() { struct RegisteredObj { base: qt_base_class!(trait QObject), value: qt_property!(u32), - square: qt_method!( - fn square(&self, v: u32) -> u32 { + multiply_values: qt_method!( + fn multiply_values(&self, v: u32) -> u32 { self.value * v } ), @@ -204,7 +204,7 @@ fn register_type() { value: 55 } function doTest() { - return test.square(66) === 55 * 66; + return test.multiply_values(66) === 55 * 66; } } " @@ -215,8 +215,8 @@ fn register_type() { struct RegisteredObjWithNoDefault { base: qt_base_class!(trait QObject), value: qt_property!(u32), - square: qt_method!( - fn square(&self, v: u32) -> u32 { + multiply_values: qt_method!( + fn multiply_values(&self, v: u32) -> u32 { self.value * self.internal_value * v } ), @@ -226,10 +226,10 @@ struct RegisteredObjWithNoDefault { impl RegisteredObjWithNoDefault { fn new(internal_value: u32) -> RegisteredObjWithNoDefault { RegisteredObjWithNoDefault { - internal_value: internal_value, + internal_value, base: Default::default(), value: Default::default(), - square: Default::default(), + multiply_values: Default::default(), } } } @@ -254,7 +254,7 @@ fn register_uncreatable_type() { Item { function doTest() { - return _obj.square(66) === 44 * 55 * 66; + return _obj.multiply_values(66) === 44 * 55 * 66; } } "