Add public API for retrieving the extension object

Change-Id: I28bc1c177cb78d85d844c7a5cd5b6710db8fd65d
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
This commit is contained in:
Ulf Hermann 2022-03-14 15:56:28 +01:00
parent 00b59c391e
commit cc6bd22b61
6 changed files with 74 additions and 23 deletions

View File

@ -991,6 +991,16 @@
\sa QML_ATTACHED(), {Providing Attached Properties}
*/
/*!
\fn QObject *qmlExtendedObject(const QObject *base)
\relates QQmlEngine
This function returns the extension object that belongs to \a base, if there is any.
Otherwise it returns \c nullptr.
\sa QML_EXTENDED
*/
/*!
\fn int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName, QObject *(*callback)(QQmlEngine *, QJSEngine *))
\relates QQmlEngine

View File

@ -149,6 +149,25 @@ QObject *qmlAttachedPropertiesObject(QObject *object, QQmlAttachedPropertiesFunc
return resolveAttachedProperties(func, data, object, create);
}
QObject *qmlExtendedObject(QObject *object)
{
if (!object)
return nullptr;
void *result = nullptr;
QObjectPrivate *d = QObjectPrivate::get(object);
if (!d->metaObject)
return nullptr;
const int id = d->metaObject->metaCall(
object, QMetaObject::CustomCall,
QQmlProxyMetaObject::ExtensionObjectId, &result);
if (id != QQmlProxyMetaObject::ExtensionObjectId)
return nullptr;
return static_cast<QObject *>(result);
}
int qmlRegisterUncreatableMetaObject(const QMetaObject &staticMetaObject,
const char *uri, int versionMajor,
int versionMinor, const char *qmlName,

View File

@ -615,6 +615,7 @@ Q_QML_EXPORT QQmlAttachedPropertiesFunc qmlAttachedPropertiesFunction(QObject *,
const QMetaObject *);
Q_QML_EXPORT QObject *qmlAttachedPropertiesObject(QObject *, QQmlAttachedPropertiesFunc func,
bool create = true);
Q_QML_EXPORT QObject *qmlExtendedObject(QObject *);
//The C++ version of protected namespaces in qmldir
Q_QML_EXPORT bool qmlProtectModule(const char* uri, int majVersion);

View File

@ -104,39 +104,54 @@ int QQmlProxyMetaObject::metaCall(QObject *o, QMetaObject::Call c, int id, void
{
Q_ASSERT(object == o);
if ((c == QMetaObject::ReadProperty ||
c == QMetaObject::WriteProperty) &&
id >= metaObjects->constLast().propertyOffset) {
switch (c) {
case QMetaObject::ReadProperty:
case QMetaObject::WriteProperty: {
if (id < metaObjects->constLast().propertyOffset)
break;
for (int ii = 0; ii < metaObjects->count(); ++ii) {
const int globalPropertyOffset = metaObjects->at(ii).propertyOffset;
if (id >= globalPropertyOffset) {
QObject *proxy = getProxy(ii);
const int localProxyOffset = proxy->metaObject()->propertyOffset();
const int localProxyId = id - globalPropertyOffset + localProxyOffset;
if (id < globalPropertyOffset)
continue;
return proxy->qt_metacall(c, localProxyId, a);
}
QObject *proxy = getProxy(ii);
const int localProxyOffset = proxy->metaObject()->propertyOffset();
const int localProxyId = id - globalPropertyOffset + localProxyOffset;
return proxy->qt_metacall(c, localProxyId, a);
}
} else if (c == QMetaObject::InvokeMetaMethod &&
id >= metaObjects->constLast().methodOffset) {
break;
}
case QMetaObject::InvokeMetaMethod: {
if (id < metaObjects->constLast().methodOffset)
break;
QMetaMethod m = object->metaObject()->method(id);
if (m.methodType() == QMetaMethod::Signal) {
QMetaObject::activate(object, id, a);
return -1;
} else {
for (int ii = 0; ii < metaObjects->count(); ++ii) {
const int globalMethodOffset = metaObjects->at(ii).methodOffset;
if (id >= globalMethodOffset) {
QObject *proxy = getProxy(ii);
const int localMethodOffset = proxy->metaObject()->methodOffset();
const int localMethodId = id - globalMethodOffset + localMethodOffset;
return proxy->qt_metacall(c, localMethodId, a);
}
}
}
for (int ii = 0; ii < metaObjects->count(); ++ii) {
const int globalMethodOffset = metaObjects->at(ii).methodOffset;
if (id < globalMethodOffset)
continue;
QObject *proxy = getProxy(ii);
const int localMethodOffset = proxy->metaObject()->methodOffset();
const int localMethodId = id - globalMethodOffset + localMethodOffset;
return proxy->qt_metacall(c, localMethodId, a);
}
break;
}
case QMetaObject::CustomCall:
if (id != ExtensionObjectId)
break;
a[0] = getProxy(0);
return id;
default:
break;
}
if (parent)

View File

@ -65,6 +65,8 @@ QT_BEGIN_NAMESPACE
class QQmlProxyMetaObject : public QDynamicMetaObjectData
{
public:
enum { ExtensionObjectId = std::numeric_limits<int>::min() };
struct ProxyData {
typedef QObject *(*CreateFunc)(QObject *);
QMetaObject *metaObject;

View File

@ -5657,6 +5657,10 @@ void tst_qqmllanguage::extendedForeignTypes()
QCOMPARE(o->property("foreignExtendedObjectName").toString(), QLatin1String("foreignExtended"));
QCOMPARE(o->property("extendedInvokable").toInt(), 123);
QCOMPARE(o->property("extendedSlot").toInt(), 456);
QObject *extension = qmlExtendedObject(extended);
QVERIFY(extension != nullptr);
QVERIFY(qobject_cast<Extension *>(extension) != nullptr);
}
void tst_qqmllanguage::foreignTypeSingletons() {