Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qqmlopenmetaobject.cpp
Go to the documentation of this file.
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
5#include <private/qqmlpropertycache_p.h>
6#include <private/qqmldata_p.h>
7#include <private/qqmlmetatype_p.h>
8#include <private/qmetaobjectbuilder_p.h>
9#include <qdebug.h>
10#include <QtCore/qset.h>
11
13
14
16{
17public:
19
20 void init(const QMetaObject *metaObj);
21
27
28 // TODO: We need to make sure that this does not escape into other threads.
29 // In particular, all its non-const uses are probably wrong. You should
30 // only set the open metaobject to "cached" once it's not going to be
31 // modified anymore.
33
35};
36
39{
40 d->init(base);
41}
42
44{
45 if (d->mem)
46 free(d->mem);
47 delete d;
48}
49
51{
52 return d->propertyOffset;
53}
54
56{
57 return d->signalOffset;
58}
59
61{
62 return d->names.size();
63}
64
66{
67 Q_ASSERT(idx >= 0 && idx < d->names.size());
68
69 return d->mob.property(idx).name();
70}
71
73{
74 for (int i = 0; i < names.size(); ++i) {
75 const QByteArray &name = names.at(i);
76 const int id = d->mob.propertyCount();
77 d->mob.addSignal("__" + QByteArray::number(id) + "()");
78 QMetaPropertyBuilder build = d->mob.addProperty(name, "QVariant", id);
79 propertyCreated(id, build);
80 d->names.insert(name, id);
81 }
82 free(d->mem);
83 d->mem = d->mob.toMetaObject();
85 while (it != d->referers.end()) {
86 QQmlOpenMetaObject *omo = *it;
87 *static_cast<QMetaObject *>(omo) = *d->mem;
88 if (d->cache)
89 d->cache->update(omo);
90 ++it;
91 }
92}
93
95{
96 const int signalIdx = d->mob.addSignal(
97 "__" + QByteArray::number(d->mob.propertyCount()) + "()").index();
98 QMetaPropertyBuilder build = d->mob.addProperty(name, "QVariant", signalIdx);
99 propertyCreated(build.index(), build);
100 free(d->mem);
101 d->mem = d->mob.toMetaObject();
102 d->names.insert(name, build.index());
104 while (it != d->referers.end()) {
105 QQmlOpenMetaObject *omo = *it;
106 *static_cast<QMetaObject *>(omo) = *d->mem;
107 if (d->cache)
108 d->cache->update(omo);
109 ++it;
110 }
111
112 return d->propertyOffset + build.index();
113}
114
116{
117 if (d->referers.size())
118 (*d->referers.begin())->propertyCreated(id, builder);
119}
120
122{
123 if (!mem) {
124 mob.setSuperClass(metaObj);
125 mob.setClassName(metaObj->className());
127
128 mem = mob.toMetaObject();
129
132 }
133}
134
135//----------------------------------------------------------------------------
136
138{
139public:
141 : q(_q), object(obj) {}
142
143 struct Property {
144 private:
145 QVariant m_value;
146 QPointer<QObject> qobjectTracker;
147 public:
148 bool valueSet = false;
149
150 QVariant value() const {
152 && qobjectTracker.isNull())
153 return QVariant::fromValue<QObject*>(nullptr);
154 return m_value;
155 }
156 QVariant &valueRef() { return m_value; }
157 void setValue(const QVariant &v) {
158 m_value = v;
159 valueSet = true;
160 if (v.metaType().flags() & QMetaType::PointerToQObject)
161 qobjectTracker = m_value.value<QObject*>();
162 }
163 };
164
165 inline void setPropertyValue(int idx, const QVariant &value) {
166 if (data.size() <= idx)
167 data.resize(idx + 1);
168 data[idx].setValue(value);
169 }
170
171 inline Property &propertyRef(int idx) {
172 if (data.size() <= idx)
173 data.resize(idx + 1);
174 Property &prop = data[idx];
175 if (!prop.valueSet)
176 prop.setValue(q->initialValue(idx));
177 return prop;
178 }
179
180 inline QVariant propertyValue(int idx) {
181 auto &prop = propertyRef(idx);
182 return prop.value();
183 }
184
185 inline QVariant &propertyValueRef(int idx) {
186 auto &prop = propertyRef(idx);
187 return prop.valueRef();
188 }
189
190 inline bool hasProperty(int idx) const {
191 if (idx >= data.size())
192 return false;
193 return data[idx].valueSet;
194 }
195
197 if (QQmlData *ddata = QQmlData::get(object, /*create*/false))
198 ddata->propertyCache.reset();
199 }
200
207 bool autoCreate = true;
208 bool cacheProperties = false;
209};
210
213{
214 d->type.adopt(new QQmlOpenMetaObjectType(base ? base : obj->metaObject()));
215 d->type->d->referers.insert(this);
216
218 d->parent = op->metaObject;
219 *static_cast<QMetaObject *>(this) = *d->type->d->mem;
220 op->metaObject = this;
221}
222
226{
227 d->type = type;
228 d->type->d->referers.insert(this);
229
231 d->parent = op->metaObject;
232 *static_cast<QMetaObject *>(this) = *d->type->d->mem;
233 op->metaObject = this;
234}
235
237{
238 if (d->parent)
239 delete d->parent;
240 d->type->d->referers.remove(this);
241 delete d;
242}
243
245{
246 return d->type.data();
247}
248
250{
252 if (iter == d->type->d->names.constEnd())
253 return;
254 activate(d->object, *iter + d->type->d->signalOffset, nullptr);
255}
256
258{
259 d->parent = nullptr;
260}
261
263{
264 Q_ASSERT(d->object == o);
265
267 && id >= d->type->d->propertyOffset) {
268 int propId = id - d->type->d->propertyOffset;
270 propertyRead(propId);
271 *reinterpret_cast<QVariant *>(a[0]) = d->propertyValue(propId);
272 } else if (c == QMetaObject::WriteProperty) {
273 if (propId >= d->data.size() || d->data.at(propId).value() != *reinterpret_cast<QVariant *>(a[0])) {
274 propertyWrite(propId);
275 d->setPropertyValue(propId, propertyWriteValue(propId, *reinterpret_cast<QVariant *>(a[0])));
276 propertyWritten(propId);
277 activate(o, d->type->d->signalOffset + propId, nullptr);
278 }
279 }
280 return -1;
281 } else {
282 if (d->parent)
283 return d->parent->metaCall(o, c, id, a);
284 else
285 return o->qt_metacall(c, id, a);
286 }
287}
288
290{
291 return d->parent;
292}
293
295{
296 if (!force && d->propertyValue(index) == value)
297 return false;
298
300 activate(d->object, index + d->type->d->signalOffset, nullptr);
301 return true;
302}
303
305{
306 return d->propertyValue(id);
307}
308
310{
312 activate(d->object, id + d->type->d->signalOffset, nullptr);
313}
314
316{
318 if (iter == d->type->d->names.cend())
319 return QVariant();
320
321 return d->propertyValue(*iter);
322}
323
325{
327 Q_ASSERT(iter != d->type->d->names.cend());
328
329 return d->propertyValueRef(*iter);
330}
331
333{
335
336 int id = -1;
337 if (iter == d->type->d->names.cend()) {
338 id = createProperty(name.constData(), "") - d->type->d->propertyOffset;
339 } else {
340 id = *iter;
341 }
342
343 if (id >= 0)
344 return checkedSetValue(id, val, force);
345
346 return false;
347}
348
350{
351 QVector<QByteArray> missingProperties;
352 d->deferredPropertyNames = &missingProperties;
353 const auto &names = d->type->d->names;
354
355 for (auto valueIt = values.begin(), end = values.end(); valueIt != end; ++valueIt) {
356 const auto nameIt = names.constFind(valueIt.key());
357 if (nameIt == names.constEnd()) {
358 const int id = createProperty(valueIt.key(), "") - d->type->d->propertyOffset;
359
360 // If id >= 0 some override of createProperty() created it. Then set it.
361 // Else it either ends up in missingProperties and we create it later
362 // or it cannot be created.
363
364 if (id >= 0)
365 checkedSetValue(id, valueIt.value(), force);
366 } else {
367 checkedSetValue(*nameIt, valueIt.value(), force);
368 }
369 }
370
371 d->deferredPropertyNames = nullptr;
372 if (missingProperties.isEmpty())
373 return;
374
375 d->type->createProperties(missingProperties);
377
378 for (const QByteArray &name : std::as_const(missingProperties))
380}
381
382// returns true if this value has been initialized by a call to either value() or setValue()
384{
385 return d->hasProperty(id);
386}
387
389{
390 if (c == d->cacheProperties)
391 return;
392
393 d->cacheProperties = c;
394
395 QQmlData *qmldata = QQmlData::get(d->object, true);
396 if (d->cacheProperties) {
397 // As the propertyCache is not saved in QQmlMetaType (due to it being dynamic)
398 // we cannot leak it to other places before we're done with it. Yes, it's still
399 // terrible.
400 if (!d->type->d->cache)
402 qmldata->propertyCache = d->type->d->cache;
403 } else {
404 d->type->d->cache.reset();
405 qmldata->propertyCache.reset();
406 }
407}
408
410{
411 return d->autoCreate;
412}
413
415{
416 d->autoCreate = autoCreate;
417}
418
419
420int QQmlOpenMetaObject::createProperty(const char *name, const char *)
421{
422 if (d->autoCreate) {
423 if (d->deferredPropertyNames) {
424 // Defer the creation of new properties. See setValues(QHash<QByteArray, QVariant>)
425 d->deferredPropertyNames->append(name);
426 return -1;
427 }
428
429 const int result = d->type->createProperty(name);
431 return result;
432 } else
433 return -1;
434}
435
437{
438}
439
441{
442}
443
445{
446 return value;
447}
448
450{
451}
452
454{
455}
456
458{
459 return QVariant();
460}
461
463{
464 return d->type->d->names.size();
465}
466
468{
469 Q_ASSERT(idx >= 0 && idx < d->type->d->names.size());
470
471 return d->type->d->mob.property(idx).name();
472}
473
475{
476 return d->object;
477}
478
\inmodule QtCore
Definition qbytearray.h:57
char at(qsizetype i) const
Returns the byte at index position i in the byte array.
Definition qbytearray.h:523
static QByteArray number(int, int base=10)
Returns a byte-array representing the whole number n as text.
\inmodule QtCore
Definition qhash.h:1135
\inmodule QtCore
Definition qhash.h:818
qsizetype size() const noexcept
Returns the number of items in the hash.
Definition qhash.h:925
const_iterator constFind(const Key &key) const noexcept
Definition qhash.h:1279
const_iterator constEnd() const noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the ...
Definition qhash.h:1209
const_iterator cend() const noexcept
Definition qhash.h:1208
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition qhash.h:1283
Definition qlist.h:74
bool isEmpty() const noexcept
Definition qlist.h:390
int index() const
Returns the index of this method within its QMetaObjectBuilder.
void setSuperClass(const QMetaObject *meta)
Sets the superclass meta object of the class being constructed by this meta object builder to meta.
QMetaObject * toMetaObject() const
Converts this meta object builder into a concrete QMetaObject.
QMetaMethodBuilder addSignal(const QByteArray &signature)
Adds a new signal to this class with the specified signature.
int propertyCount() const
Returns the number of properties in this class, excluding the number of properties in the base class.
void setFlags(MetaObjectFlags)
Sets the flags of the class being constructed by this meta object builder.
QMetaPropertyBuilder addProperty(const QByteArray &name, const QByteArray &type, int notifierId=-1)
Adds a new readable/writable property to this class with the specified name and type.
void setClassName(const QByteArray &name)
Sets the name of the class being constructed by this meta object builder.
QMetaPropertyBuilder property(int index) const
Returns the property at index in this class.
QByteArray name() const
Returns the name associated with this property.
constexpr TypeFlags flags() const
Definition qmetatype.h:2628
@ PointerToQObject
Definition qmetatype.h:385
QDynamicMetaObjectData * metaObject
Definition qobject.h:77
static QObjectPrivate * get(QObject *o)
Definition qobject_p.h:153
\inmodule QtCore
Definition qobject.h:90
\inmodule QtCore
Definition qpointer.h:18
bool isNull() const
Returns true if the referenced object has been destroyed or if there is no referenced object; otherwi...
Definition qpointer.h:67
QQmlPropertyCache::ConstPtr propertyCache
Definition qqmldata_p.h:195
static QQmlData * get(QObjectPrivate *priv, bool create)
Definition qqmldata_p.h:199
QDynamicMetaObjectData * parent
void setPropertyValue(int idx, const QVariant &value)
QVector< QByteArray > * deferredPropertyNames
QQmlOpenMetaObjectPrivate(QQmlOpenMetaObject *_q, QObject *obj)
QVariant & propertyValueRef(int idx)
QQmlRefPointer< QQmlOpenMetaObjectType > type
void init(const QMetaObject *metaObj)
QSet< QQmlOpenMetaObject * > referers
QHash< QByteArray, int > names
QByteArray propertyName(int) const
virtual void propertyCreated(int, QMetaPropertyBuilder &)
void createProperties(const QVector< QByteArray > &names)
int createProperty(const QByteArray &name)
QQmlOpenMetaObjectType(const QMetaObject *base)
bool autoCreatesProperties() const
QQmlOpenMetaObject(QObject *, const QMetaObject *=nullptr)
QDynamicMetaObjectData * parent() const
virtual void propertyRead(int)
void setValues(const QHash< QByteArray, QVariant > &, bool force=false)
virtual QVariant initialValue(int)
virtual void propertyCreated(int, QMetaPropertyBuilder &)
virtual void propertyWritten(int)
QByteArray name(int) const
bool checkedSetValue(int index, const QVariant &value, bool force)
virtual void propertyWrite(int)
QObject * object() const
QQmlOpenMetaObjectType * type() const
void emitPropertyNotification(const QByteArray &propertyName)
virtual QVariant propertyWriteValue(int, const QVariant &)
bool setValue(const QByteArray &, const QVariant &, bool force=false)
QVariant & valueRef(const QByteArray &)
int metaCall(QObject *o, QMetaObject::Call _c, int _id, void **_a) override
void setAutoCreatesProperties(bool autoCreate)
friend class QQmlOpenMetaObjectType
int createProperty(const char *, const char *) override
QVariant value(const QByteArray &) const
void update(const QMetaObject *)
static Ptr createStandalone(const QMetaObject *, QTypeRevision metaObjectRevision=QTypeRevision::zero())
Creates a standalone QQmlPropertyCache of metaObject.
T * data() const
void reset(T *t=nullptr)
QQmlRefPointer< T > & adopt(T *)
Takes ownership of other.
Definition qset.h:18
qsizetype size() const
Definition qset.h:50
bool remove(const T &value)
Definition qset.h:63
iterator begin()
Definition qset.h:136
iterator end()
Definition qset.h:140
iterator insert(const T &value)
Definition qset.h:155
\inmodule QtCore
Definition qvariant.h:64
T value() const &
Definition qvariant.h:511
QMetaType metaType() const
#define this
Definition dialogs.cpp:9
QSet< QString >::iterator it
Combined button and popup list for selecting options.
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter * iter
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
@ DynamicMetaObject
GLenum GLsizei GLsizei GLint * values
[15]
GLsizei const GLfloat * v
[13]
GLboolean GLboolean GLboolean GLboolean a
[7]
GLuint index
[2]
GLuint GLuint end
GLuint object
[3]
GLenum type
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLuint name
GLhandleARB obj
[2]
const GLubyte * c
GLuint GLfloat * val
GLuint GLuint * names
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLuint64EXT * result
[6]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QObject::connect nullptr
virtual int metaCall(QObject *, QMetaObject::Call, int _id, void **)=0
\inmodule QtCore
const char * className() const
Returns the class name.
int methodOffset() const
Returns the method offset for this class; i.e.
int propertyOffset() const
Returns the property offset for this class; i.e.
static void activate(QObject *sender, int signal_index, void **argv)
Definition qobject.cpp:4057