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 "qqmldesignermetaobject_p.h" |
5 | |
6 | #include <QSharedPointer> |
7 | #include <QMetaProperty> |
8 | #include <QtCore/private/qnumeric_p.h> |
9 | #include <QDebug> |
10 | |
11 | #include <private/qqmlengine_p.h> |
12 | |
13 | QT_BEGIN_NAMESPACE |
14 | |
15 | static QHash<QDynamicMetaObjectData *, bool> nodeInstanceMetaObjectList; |
16 | static void (*notifyPropertyChangeCallBack)(QObject*, const QQuickDesignerSupport::PropertyName &propertyName) = nullptr; |
17 | |
18 | struct MetaPropertyData { |
19 | inline QPair<QVariant, bool> &getDataRef(int idx) { |
20 | while (m_data.size() <= idx) |
21 | m_data << QPair<QVariant, bool>(QVariant(), false); |
22 | return m_data[idx]; |
23 | } |
24 | |
25 | inline QVariant &getData(int idx) { |
26 | QPair<QVariant, bool> &prop = getDataRef(idx); |
27 | if (!prop.second) { |
28 | prop.first = QVariant(); |
29 | prop.second = true; |
30 | } |
31 | return prop.first; |
32 | } |
33 | |
34 | inline bool hasData(int idx) const { |
35 | if (idx >= m_data.size()) |
36 | return false; |
37 | return m_data[idx].second; |
38 | } |
39 | |
40 | inline int count() { return m_data.size(); } |
41 | |
42 | QVector<QPair<QVariant, bool> > m_data; |
43 | }; |
44 | |
45 | QQmlDesignerMetaObject* QQmlDesignerMetaObject::getNodeInstanceMetaObject(QObject *object, QQmlEngine *engine) |
46 | { |
47 | //Avoid setting up multiple MetaObjects on the same QObject |
48 | QObjectPrivate *op = QObjectPrivate::get(o: object); |
49 | QDynamicMetaObjectData *parent = op->metaObject; |
50 | if (nodeInstanceMetaObjectList.contains(key: parent)) |
51 | return static_cast<QQmlDesignerMetaObject *>(parent); |
52 | |
53 | // we just create one and the ownership goes automatically to the object in nodeinstance see init method |
54 | |
55 | QQmlData *ddata = QQmlData::get(object, create: false); |
56 | |
57 | QQmlDesignerMetaObject *mo = new QQmlDesignerMetaObject(object, engine); |
58 | ddata->hasVMEMetaObject = false; |
59 | ddata->hasInterceptorMetaObject = false; |
60 | |
61 | return mo; |
62 | } |
63 | |
64 | void QQmlDesignerMetaObject::init(QObject *object) |
65 | { |
66 | //Assign this to object |
67 | QObjectPrivate *op = QObjectPrivate::get(o: object); |
68 | op->metaObject = this; |
69 | nodeInstanceMetaObjectList.insert(key: this, value: true); |
70 | } |
71 | |
72 | QQmlPropertyCache::Ptr QQmlDesignerMetaObject::cache() const |
73 | { |
74 | return type()->cache(); |
75 | } |
76 | |
77 | QQmlDesignerMetaObject::QQmlDesignerMetaObject(QObject *object, QQmlEngine *engine) |
78 | : QQmlOpenMetaObject(object), |
79 | m_context(engine->contextForObject(object)), |
80 | m_data(new MetaPropertyData) |
81 | { |
82 | init(object); |
83 | setCached(true); |
84 | } |
85 | |
86 | QQmlDesignerMetaObject::~QQmlDesignerMetaObject() |
87 | { |
88 | nodeInstanceMetaObjectList.remove(key: this); |
89 | } |
90 | |
91 | void QQmlDesignerMetaObject::createNewDynamicProperty(const QString &name) |
92 | { |
93 | int id = type()->createProperty(name: name.toUtf8()); |
94 | setValue(id, value: QVariant()); |
95 | Q_ASSERT(id >= 0); |
96 | |
97 | //Updating cache |
98 | cache()->invalidate(this); |
99 | |
100 | QQmlProperty property(myObject(), name, m_context); |
101 | Q_ASSERT(property.isValid()); |
102 | } |
103 | |
104 | int QQmlDesignerMetaObject::createProperty(const char *name, const char *passAlong) |
105 | { |
106 | int ret = QQmlOpenMetaObject::createProperty(name, passAlong); |
107 | if (ret != -1) { |
108 | // compare createNewDynamicProperty |
109 | cache()->invalidate(this); |
110 | } |
111 | return ret; |
112 | } |
113 | |
114 | void QQmlDesignerMetaObject::setValue(int id, const QVariant &value) |
115 | { |
116 | QPair<QVariant, bool> &prop = m_data->getDataRef(idx: id); |
117 | prop.first = propertyWriteValue(id, value); |
118 | prop.second = true; |
119 | QMetaObject::activate(sender: myObject(), signal_index: id + type()->signalOffset(), argv: nullptr); |
120 | } |
121 | |
122 | QVariant QQmlDesignerMetaObject::propertyWriteValue(int, const QVariant &value) |
123 | { |
124 | return value; |
125 | } |
126 | |
127 | QDynamicMetaObjectData *QQmlDesignerMetaObject::dynamicMetaObjectParent() const |
128 | { |
129 | return parent(); |
130 | } |
131 | |
132 | int QQmlDesignerMetaObject::propertyOffset() const |
133 | { |
134 | return cache()->propertyOffset(); |
135 | } |
136 | |
137 | int QQmlDesignerMetaObject::openMetaCall(QObject *o, QMetaObject::Call call, int id, void **a) |
138 | { |
139 | if ((call == QMetaObject::ReadProperty || call == QMetaObject::WriteProperty) |
140 | && id >= type()->propertyOffset()) { |
141 | int propId = id - type()->propertyOffset(); |
142 | if (call == QMetaObject::ReadProperty) { |
143 | //propertyRead(propId); |
144 | *reinterpret_cast<QVariant *>(a[0]) = m_data->getData(idx: propId); |
145 | } else if (call == QMetaObject::WriteProperty) { |
146 | if (propId <= m_data->count() || m_data->m_data[propId].first != *reinterpret_cast<QVariant *>(a[0])) { |
147 | //propertyWrite(propId); |
148 | QPair<QVariant, bool> &prop = m_data->getDataRef(idx: propId); |
149 | prop.first = propertyWriteValue(propId, value: *reinterpret_cast<QVariant *>(a[0])); |
150 | prop.second = true; |
151 | //propertyWritten(propId); |
152 | activate(sender: myObject(), signal_index: type()->signalOffset() + propId, argv: nullptr); |
153 | } |
154 | } |
155 | return -1; |
156 | } else { |
157 | QDynamicMetaObjectData *dynamicParent = dynamicMetaObjectParent(); |
158 | if (dynamicParent) |
159 | return dynamicParent->metaCall(o, call, id: id, a); |
160 | else |
161 | return myObject()->qt_metacall(call, id, a); |
162 | } |
163 | } |
164 | |
165 | int QQmlDesignerMetaObject::metaCall(QObject *o, QMetaObject::Call call, int id, void **a) |
166 | { |
167 | Q_ASSERT(myObject() == o); |
168 | |
169 | int metaCallReturnValue = -1; |
170 | |
171 | const QMetaProperty propertyById = property(index: id); |
172 | |
173 | if (call == QMetaObject::WriteProperty |
174 | && propertyById.userType() == QMetaType::QVariant |
175 | && reinterpret_cast<QVariant *>(a[0])->userType() == QMetaType::Double |
176 | && qt_is_nan(d: reinterpret_cast<QVariant *>(a[0])->toDouble())) { |
177 | return -1; |
178 | } |
179 | |
180 | if (call == QMetaObject::WriteProperty |
181 | && propertyById.userType() == QMetaType::Double |
182 | && qt_is_nan(d: *reinterpret_cast<double*>(a[0]))) { |
183 | return -1; |
184 | } |
185 | |
186 | if (call == QMetaObject::WriteProperty |
187 | && propertyById.userType() == QMetaType::Float |
188 | && qt_is_nan(f: *reinterpret_cast<float*>(a[0]))) { |
189 | return -1; |
190 | } |
191 | |
192 | QVariant oldValue; |
193 | |
194 | if (call == QMetaObject::WriteProperty && !propertyById.hasNotifySignal()) |
195 | { |
196 | oldValue = propertyById.read(obj: myObject()); |
197 | } |
198 | |
199 | QDynamicMetaObjectData *dynamicParent = dynamicMetaObjectParent(); |
200 | const QMetaObject *staticParent = dynamicParent |
201 | ? dynamicParent->toDynamicMetaObject(object()) |
202 | : nullptr; |
203 | if (staticParent && id < staticParent->propertyOffset()) |
204 | metaCallReturnValue = dynamicParent->metaCall(o, call, id: id, a); |
205 | else |
206 | openMetaCall(o, call, id, a); |
207 | |
208 | |
209 | if (call == QMetaObject::WriteProperty |
210 | && !propertyById.hasNotifySignal() |
211 | && oldValue != propertyById.read(obj: myObject())) |
212 | notifyPropertyChange(id); |
213 | |
214 | return metaCallReturnValue; |
215 | } |
216 | |
217 | void QQmlDesignerMetaObject::notifyPropertyChange(int id) |
218 | { |
219 | const QMetaProperty propertyById = property(index: id); |
220 | |
221 | if (id < propertyOffset()) { |
222 | if (notifyPropertyChangeCallBack) |
223 | notifyPropertyChangeCallBack(myObject(), propertyById.name()); |
224 | } else { |
225 | if (notifyPropertyChangeCallBack) |
226 | notifyPropertyChangeCallBack(myObject(), name(id - propertyOffset())); |
227 | } |
228 | } |
229 | |
230 | int QQmlDesignerMetaObject::count() const |
231 | { |
232 | return type()->propertyCount(); |
233 | } |
234 | |
235 | QByteArray QQmlDesignerMetaObject::name(int idx) const |
236 | { |
237 | return type()->propertyName(idx); |
238 | } |
239 | |
240 | void QQmlDesignerMetaObject::registerNotifyPropertyChangeCallBack(void (*callback)(QObject *, const QQuickDesignerSupport::PropertyName &)) |
241 | { |
242 | notifyPropertyChangeCallBack = callback; |
243 | } |
244 | |
245 | QT_END_NAMESPACE |
246 |
Definitions
- nodeInstanceMetaObjectList
- notifyPropertyChangeCallBack
- MetaPropertyData
- getDataRef
- getData
- hasData
- count
- getNodeInstanceMetaObject
- init
- cache
- QQmlDesignerMetaObject
- ~QQmlDesignerMetaObject
- createNewDynamicProperty
- createProperty
- setValue
- propertyWriteValue
- dynamicMetaObjectParent
- propertyOffset
- openMetaCall
- metaCall
- notifyPropertyChange
- count
- name
Learn to use CMake with our Intro Training
Find out more