Skip to content

Add qml_register_uncreatable_type #227

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 93 additions & 4 deletions qmetaobject/src/qtdeclarative.rs
Original file line number Diff line number Diff line change
Expand Up @@ -502,16 +502,105 @@ pub fn qml_register_type<T: QObject + Default + Sized>(
})
}

/// 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<T: QObject + Sized>(
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 = <RefCell<T> 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<char,64> 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)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ogoffart Why would we even need a parserStatus for uncreatable types?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was just following qml_register_type. I replace this with -1, which seems to be the default. Can you confirm that it's correct?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ping, can you confirm that the default value of -1 is correct here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know. The Qt code does put a value there but i don't know if it is usefull.
The type might not be created by QML but maybe it can still be cast? I have no idea

? QQmlPrivate::StaticCastSelector<QQuickItem, QQmlParserStatus>::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 *",
Expand Down
50 changes: 50 additions & 0 deletions qmetaobject/tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<RegisteredObjWithNoDefault>(
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() {
Expand Down