1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qqmlproxymetaobject_p.h"
5#include "qqmlproperty_p.h"
6
7QT_BEGIN_NAMESPACE
8
9QQmlProxyMetaObject::QQmlProxyMetaObject(QObject *obj, QList<ProxyData> *mList)
10: metaObjects(mList), proxies(nullptr), parent(nullptr), object(obj)
11{
12 metaObject = metaObjects->constFirst().metaObject;
13
14 QObjectPrivate *op = QObjectPrivate::get(o: obj);
15 if (op->metaObject)
16 parent = op->metaObject;
17
18 op->metaObject = this;
19}
20
21QQmlProxyMetaObject::~QQmlProxyMetaObject()
22{
23 if (parent)
24 delete parent;
25 parent = nullptr;
26
27 if (proxies)
28 delete [] proxies;
29 proxies = nullptr;
30}
31
32QObject *QQmlProxyMetaObject::getProxy(int index)
33{
34 if (!proxies) {
35 proxies = new QObject *[metaObjects->size()];
36 ::memset(s: proxies, c: 0, n: sizeof(QObject *) * metaObjects->size());
37 }
38
39 if (!proxies[index]) {
40 const ProxyData &data = metaObjects->at(i: index);
41 if (!data.createFunc)
42 return nullptr;
43
44 QObject *proxy = data.createFunc(object);
45 const QMetaObject *metaObject = proxy->metaObject();
46 proxies[index] = proxy;
47
48 int localOffset = data.metaObject->methodOffset();
49 int methodOffset = metaObject->methodOffset();
50 int methods = metaObject->methodCount() - methodOffset;
51
52 // ### - Can this be done more optimally?
53 for (int jj = 0; jj < methods; ++jj) {
54 QMetaMethod method =
55 metaObject->method(index: jj + methodOffset);
56 if (method.methodType() == QMetaMethod::Signal)
57 QQmlPropertyPrivate::connect(sender: proxy, signal_index: methodOffset + jj, receiver: object, method_index: localOffset + jj);
58 }
59 }
60
61 return proxies[index];
62}
63
64int QQmlProxyMetaObject::metaCall(QObject *o, QMetaObject::Call c, int id, void **a)
65{
66 Q_ASSERT(object == o);
67
68 switch (c) {
69 case QMetaObject::ReadProperty:
70 case QMetaObject::WriteProperty: {
71 if (id < metaObjects->constLast().propertyOffset)
72 break;
73
74 for (int ii = 0; ii < metaObjects->size(); ++ii) {
75 const int globalPropertyOffset = metaObjects->at(i: ii).propertyOffset;
76 if (id < globalPropertyOffset)
77 continue;
78
79 QObject *proxy = getProxy(index: ii);
80 Q_ASSERT(proxy);
81 const int localProxyOffset = proxy->metaObject()->propertyOffset();
82 const int localProxyId = id - globalPropertyOffset + localProxyOffset;
83 return proxy->qt_metacall(c, localProxyId, a);
84 }
85 break;
86 }
87 case QMetaObject::InvokeMetaMethod: {
88 if (id < metaObjects->constLast().methodOffset)
89 break;
90
91 QMetaMethod m = object->metaObject()->method(index: id);
92 if (m.methodType() == QMetaMethod::Signal) {
93 QMetaObject::activate(sender: object, signal_index: id, argv: a);
94 return -1;
95 }
96
97 for (int ii = 0; ii < metaObjects->size(); ++ii) {
98 const int globalMethodOffset = metaObjects->at(i: ii).methodOffset;
99 if (id < globalMethodOffset)
100 continue;
101
102 QObject *proxy = getProxy(index: ii);
103 Q_ASSERT(proxy);
104 const int localMethodOffset = proxy->metaObject()->methodOffset();
105 const int localMethodId = id - globalMethodOffset + localMethodOffset;
106 return proxy->qt_metacall(c, localMethodId, a);
107 }
108
109 break;
110 }
111 case QMetaObject::CustomCall: {
112 if ((id & ~MaxExtensionCount) != ExtensionObjectId)
113 break;
114 int index = id & MaxExtensionCount;
115 if (qsizetype(index) >= metaObjects->size())
116 break;
117 a[0] = getProxy(index);
118 return id;
119 }
120 default:
121 break;
122 }
123
124 if (parent)
125 return parent->metaCall(o, c, id: id, a);
126 else
127 return object->qt_metacall(c, id, a);
128}
129
130QMetaObject *QQmlProxyMetaObject::toDynamicMetaObject(QObject *)
131{
132 return metaObject;
133}
134
135QT_END_NAMESPACE
136

source code of qtdeclarative/src/qml/qml/qqmlproxymetaobject.cpp