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
13QT_BEGIN_NAMESPACE
14
15static QHash<QDynamicMetaObjectData *, bool> nodeInstanceMetaObjectList;
16static void (*notifyPropertyChangeCallBack)(QObject*, const QQuickDesignerSupport::PropertyName &propertyName) = nullptr;
17
18struct 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
45QQmlDesignerMetaObject* 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
64void 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
72QQmlPropertyCache::Ptr QQmlDesignerMetaObject::cache() const
73{
74 return type()->cache();
75}
76
77QQmlDesignerMetaObject::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
86QQmlDesignerMetaObject::~QQmlDesignerMetaObject()
87{
88 nodeInstanceMetaObjectList.remove(key: this);
89}
90
91void 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
104int 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
114void 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
122QVariant QQmlDesignerMetaObject::propertyWriteValue(int, const QVariant &value)
123{
124 return value;
125}
126
127QDynamicMetaObjectData *QQmlDesignerMetaObject::dynamicMetaObjectParent() const
128{
129 return parent();
130}
131
132int QQmlDesignerMetaObject::propertyOffset() const
133{
134 return cache()->propertyOffset();
135}
136
137int 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
165int 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
217void 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
230int QQmlDesignerMetaObject::count() const
231{
232 return type()->propertyCount();
233}
234
235QByteArray QQmlDesignerMetaObject::name(int idx) const
236{
237 return type()->propertyName(idx);
238}
239
240void QQmlDesignerMetaObject::registerNotifyPropertyChangeCallBack(void (*callback)(QObject *, const QQuickDesignerSupport::PropertyName &))
241{
242 notifyPropertyChangeCallBack = callback;
243}
244
245QT_END_NAMESPACE
246

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of qtdeclarative/src/quick/designer/qqmldesignermetaobject.cpp