Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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
9#include <private/qmetaobjectbuilder_p.h>
10#include <qdebug.h>
11#include <QtCore/qpointer.h>
12#include <QtCore/qset.h>
13
15
16
18{
19public:
21
22 void init(const QMetaObject *metaObj);
23
26 QHash<QByteArray, int> names;
29
30 // TODO: We need to make sure that this does not escape into other threads.
31 // In particular, all its non-const uses are probably wrong. You should
32 // only set the open metaobject to "cached" once it's not going to be
33 // modified anymore.
35
36 QSet<QQmlOpenMetaObject*> referers;
37};
38
44
46{
47 if (d->mem)
48 free(d->mem);
49 delete d;
50}
51
56
58{
59 return d->signalOffset;
60}
61
63{
64 return d->names.size();
65}
66
68{
69 Q_ASSERT(idx >= 0 && idx < d->names.size());
70
71 return d->mob.property(idx).name();
72}
73
74void QQmlOpenMetaObjectType::createProperties(const QVector<QByteArray> &names)
75{
76 for (int i = 0; i < names.size(); ++i) {
77 const QByteArray &name = names.at(i);
78 const int id = d->mob.propertyCount();
79 d->mob.addSignal("__" + QByteArray::number(id) + "()");
80 QMetaPropertyBuilder build = d->mob.addProperty(name, "QVariant", id);
81 propertyCreated(id, build);
82 d->names.insert(name, id);
83 }
84 free(d->mem);
85 d->mem = d->mob.toMetaObject();
87 while (it != d->referers.end()) {
88 QQmlOpenMetaObject *omo = *it;
89 *static_cast<QMetaObject *>(omo) = *d->mem;
90 if (d->cache)
91 d->cache->update(omo);
92 ++it;
93 }
94}
95
97{
98 const int signalIdx = d->mob.addSignal(
99 "__" + QByteArray::number(d->mob.propertyCount()) + "()").index();
100 QMetaPropertyBuilder build = d->mob.addProperty(name, "QVariant", signalIdx);
101 propertyCreated(build.index(), build);
102 free(d->mem);
103 d->mem = d->mob.toMetaObject();
104 d->names.insert(name, build.index());
106 while (it != d->referers.end()) {
107 QQmlOpenMetaObject *omo = *it;
108 *static_cast<QMetaObject *>(omo) = *d->mem;
109 if (d->cache)
110 d->cache->update(omo);
111 ++it;
112 }
113
114 return d->propertyOffset + build.index();
115}
116
118{
119 if (d->referers.size())
120 (*d->referers.begin())->propertyCreated(id, builder);
121}
122
124{
125 if (!mem) {
126 mob.setSuperClass(metaObj);
127 mob.setClassName(metaObj->className());
129
130 mem = mob.toMetaObject();
131
134 }
135}
136
137//----------------------------------------------------------------------------
138
140{
141public:
144
145 struct Property {
146 private:
147 QVariant m_value;
148 QPointer<QObject> qobjectTracker;
149 public:
150 bool valueSet = false;
151
152 QVariant value() const {
154 && qobjectTracker.isNull())
155 return QVariant::fromValue<QObject*>(nullptr);
156 return m_value;
157 }
158 QVariant &valueRef() { return m_value; }
159 void setValue(const QVariant &v) {
160 m_value = v;
161 valueSet = true;
162 if (v.metaType().flags() & QMetaType::PointerToQObject)
163 qobjectTracker = m_value.value<QObject*>();
164 }
165 };
166
167 inline void setPropertyValue(int idx, const QVariant &value) {
168 if (data.size() <= idx)
169 data.resize(idx + 1);
170 data[idx].setValue(value);
171 }
172
173 inline Property &propertyRef(int idx) {
174 if (data.size() <= idx)
175 data.resize(idx + 1);
176 Property &prop = data[idx];
177 if (!prop.valueSet)
178 prop.setValue(q->initialValue(idx));
179 return prop;
180 }
181
182 inline QVariant propertyValue(int idx) {
183 auto &prop = propertyRef(idx);
184 return prop.value();
185 }
186
187 inline QVariant &propertyValueRef(int idx) {
188 auto &prop = propertyRef(idx);
189 return prop.valueRef();
190 }
191
192 inline bool hasProperty(int idx) const {
193 if (idx >= data.size())
194 return false;
195 return data[idx].valueSet;
196 }
197
199 if (QQmlData *ddata = QQmlData::get(object, /*create*/false))
200 ddata->propertyCache.reset();
201 }
202
205 QVector<Property> data;
207 QQmlRefPointer<QQmlOpenMetaObjectType> type;
208 QVector<QByteArray> *deferredPropertyNames = nullptr;
209 bool autoCreate = true;
210 bool cacheProperties = false;
211};
212
215{
216 d->type.adopt(new QQmlOpenMetaObjectType(base ? base : obj->metaObject()));
217 d->type->d->referers.insert(this);
218
220 d->parent = op->metaObject;
221 *static_cast<QMetaObject *>(this) = *d->type->d->mem;
222 op->metaObject = this;
223}
224
226 QObject *obj, const QQmlRefPointer<QQmlOpenMetaObjectType> &type)
228{
229 d->type = type;
230 d->type->d->referers.insert(this);
231
233 d->parent = op->metaObject;
234 *static_cast<QMetaObject *>(this) = *d->type->d->mem;
235 op->metaObject = this;
236}
237
239{
240 if (d->parent)
241 delete d->parent;
242 d->type->d->referers.remove(this);
243 delete d;
244}
245
247{
248 return d->type.data();
249}
250
252{
254 if (iter == d->type->d->names.constEnd())
255 return;
256 activate(d->object, *iter + d->type->d->signalOffset, nullptr);
257}
258
260{
261 d->parent = nullptr;
262}
263
265{
266 Q_ASSERT(d->object == o);
267
269 && id >= d->type->d->propertyOffset) {
270 int propId = id - d->type->d->propertyOffset;
272 propertyRead(propId);
273 *reinterpret_cast<QVariant *>(a[0]) = d->propertyValue(propId);
274 } else if (c == QMetaObject::WriteProperty) {
275 if (propId >= d->data.size() || d->data.at(propId).value() != *reinterpret_cast<QVariant *>(a[0])) {
276 propertyWrite(propId);
277 d->setPropertyValue(propId, propertyWriteValue(propId, *reinterpret_cast<QVariant *>(a[0])));
278 propertyWritten(propId);
279 activate(o, d->type->d->signalOffset + propId, nullptr);
280 }
281 }
282 return -1;
283 } else {
284 if (d->parent)
285 return d->parent->metaCall(o, c, id, a);
286 else
287 return o->qt_metacall(c, id, a);
288 }
289}
290
295
297{
298 if (!force && d->propertyValue(index) == value)
299 return false;
300
302 activate(d->object, index + d->type->d->signalOffset, nullptr);
303 return true;
304}
305
307{
308 return d->propertyValue(id);
309}
310
312{
314 activate(d->object, id + d->type->d->signalOffset, nullptr);
315}
316
318{
320 if (iter == d->type->d->names.cend())
321 return QVariant();
322
323 return d->propertyValue(*iter);
324}
325
333
335{
337
338 int id = -1;
339 if (iter == d->type->d->names.cend()) {
340 id = createProperty(name.constData(), "") - d->type->d->propertyOffset;
341 } else {
342 id = *iter;
343 }
344
345 if (id >= 0)
346 return checkedSetValue(id, val, force);
347
348 return false;
349}
350
351void QQmlOpenMetaObject::setValues(const QHash<QByteArray, QVariant> &values, bool force)
352{
353 QVector<QByteArray> missingProperties;
354 d->deferredPropertyNames = &missingProperties;
355 const auto &names = d->type->d->names;
356
357 for (auto valueIt = values.begin(), end = values.end(); valueIt != end; ++valueIt) {
358 const auto nameIt = names.constFind(valueIt.key());
359 if (nameIt == names.constEnd()) {
360 const int id = createProperty(valueIt.key(), "") - d->type->d->propertyOffset;
361
362 // If id >= 0 some override of createProperty() created it. Then set it.
363 // Else it either ends up in missingProperties and we create it later
364 // or it cannot be created.
365
366 if (id >= 0)
367 checkedSetValue(id, valueIt.value(), force);
368 } else {
369 checkedSetValue(*nameIt, valueIt.value(), force);
370 }
371 }
372
373 d->deferredPropertyNames = nullptr;
374 if (missingProperties.isEmpty())
375 return;
376
377 d->type->createProperties(missingProperties);
379
380 for (const QByteArray &name : std::as_const(missingProperties))
382}
383
384// returns true if this value has been initialized by a call to either value() or setValue()
386{
387 return d->hasProperty(id);
388}
389
391{
392 if (c == d->cacheProperties)
393 return;
394
395 d->cacheProperties = c;
396
397 QQmlData *qmldata = QQmlData::get(d->object, true);
398 if (d->cacheProperties) {
399 // As the propertyCache is not saved in QQmlMetaType (due to it being dynamic)
400 // we cannot leak it to other places before we're done with it. Yes, it's still
401 // terrible.
402 if (!d->type->d->cache)
404 qmldata->propertyCache = d->type->d->cache;
405 } else {
406 d->type->d->cache.reset();
407 qmldata->propertyCache.reset();
408 }
409}
410
412{
413 return d->autoCreate;
414}
415
417{
418 d->autoCreate = autoCreate;
419}
420
421
422int QQmlOpenMetaObject::createProperty(const char *name, const char *)
423{
424 if (d->autoCreate) {
425 if (d->deferredPropertyNames) {
426 // Defer the creation of new properties. See setValues(QHash<QByteArray, QVariant>)
427 d->deferredPropertyNames->append(name);
428 return -1;
429 }
430
431 const int result = d->type->createProperty(name);
433 return result;
434 } else
435 return -1;
436}
437
441
445
450
454
458
463
465{
466 return d->type->d->names.size();
467}
468
470{
471 Q_ASSERT(idx >= 0 && idx < d->type->d->names.size());
472
473 return d->type->d->mob.property(idx).name();
474}
475
477{
478 return d->object;
479}
480
\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:600
static QByteArray number(int, int base=10)
Returns a byte-array representing the whole number n as text.
\inmodule QtCore
Definition qhash.h:1145
qsizetype size() const noexcept
Returns the number of items in the hash.
Definition qhash.h:927
const_iterator constFind(const Key &key) const noexcept
Definition qhash.h:1299
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:1219
const_iterator cend() const noexcept
Definition qhash.h:1218
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition qhash.h:1303
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:2658
@ PointerToQObject
Definition qmetatype.h:406
QDynamicMetaObjectData * metaObject
Definition qobject.h:90
static QObjectPrivate * get(QObject *o)
Definition qobject_p.h:150
\inmodule QtCore
Definition qobject.h:103
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.
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:65
T value() const &
Definition qvariant.h:516
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]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum type
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
static const uint base
Definition qurlidna.cpp:20
QObject::connect nullptr
virtual int metaCall(QObject *, QMetaObject::Call, int _id, void **)=0
\inmodule QtCore
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:4193