aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml/qqmlopenmetaobject.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/qml/qqmlopenmetaobject.cpp')
-rw-r--r--src/qml/qml/qqmlopenmetaobject.cpp234
1 files changed, 126 insertions, 108 deletions
diff --git a/src/qml/qml/qqmlopenmetaobject.cpp b/src/qml/qml/qqmlopenmetaobject.cpp
index fe0946c6de..2d0a78c6cb 100644
--- a/src/qml/qml/qqmlopenmetaobject.cpp
+++ b/src/qml/qml/qqmlopenmetaobject.cpp
@@ -1,48 +1,15 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlopenmetaobject_p.h"
#include <private/qqmlpropertycache_p.h>
#include <private/qqmldata_p.h>
+#include <private/qqmlmetatype_p.h>
+
#include <private/qmetaobjectbuilder_p.h>
-#include <qqmlengine.h>
#include <qdebug.h>
+#include <QtCore/qpointer.h>
+#include <QtCore/qset.h>
QT_BEGIN_NAMESPACE
@@ -50,7 +17,7 @@ QT_BEGIN_NAMESPACE
class QQmlOpenMetaObjectTypePrivate
{
public:
- QQmlOpenMetaObjectTypePrivate() : mem(nullptr), cache(nullptr), engine(nullptr) {}
+ QQmlOpenMetaObjectTypePrivate() : mem(nullptr) {}
void init(const QMetaObject *metaObj);
@@ -59,15 +26,19 @@ public:
QHash<QByteArray, int> names;
QMetaObjectBuilder mob;
QMetaObject *mem;
- QQmlPropertyCache *cache;
- QQmlEngine *engine;
+
+ // TODO: We need to make sure that this does not escape into other threads.
+ // In particular, all its non-const uses are probably wrong. You should
+ // only set the open metaobject to "cached" once it's not going to be
+ // modified anymore.
+ QQmlPropertyCache::Ptr cache;
+
QSet<QQmlOpenMetaObject*> referers;
};
-QQmlOpenMetaObjectType::QQmlOpenMetaObjectType(const QMetaObject *base, QQmlEngine *engine)
- : QQmlCleanup(engine), d(new QQmlOpenMetaObjectTypePrivate)
+QQmlOpenMetaObjectType::QQmlOpenMetaObjectType(const QMetaObject *base)
+ : d(new QQmlOpenMetaObjectTypePrivate)
{
- d->engine = engine;
d->init(base);
}
@@ -75,16 +46,9 @@ QQmlOpenMetaObjectType::~QQmlOpenMetaObjectType()
{
if (d->mem)
free(d->mem);
- if (d->cache)
- d->cache->release();
delete d;
}
-void QQmlOpenMetaObjectType::clear()
-{
- d->engine = nullptr;
-}
-
int QQmlOpenMetaObjectType::propertyOffset() const
{
return d->propertyOffset;
@@ -97,24 +61,19 @@ int QQmlOpenMetaObjectType::signalOffset() const
int QQmlOpenMetaObjectType::propertyCount() const
{
- return d->names.count();
+ return d->names.size();
}
QByteArray QQmlOpenMetaObjectType::propertyName(int idx) const
{
- Q_ASSERT(idx >= 0 && idx < d->names.count());
+ Q_ASSERT(idx >= 0 && idx < d->names.size());
return d->mob.property(idx).name();
}
-QMetaObject *QQmlOpenMetaObjectType::metaObject() const
-{
- return d->mem;
-}
-
void QQmlOpenMetaObjectType::createProperties(const QVector<QByteArray> &names)
{
- for (int i = 0; i < names.count(); ++i) {
+ for (int i = 0; i < names.size(); ++i) {
const QByteArray &name = names.at(i);
const int id = d->mob.propertyCount();
d->mob.addSignal("__" + QByteArray::number(id) + "()");
@@ -136,13 +95,13 @@ void QQmlOpenMetaObjectType::createProperties(const QVector<QByteArray> &names)
int QQmlOpenMetaObjectType::createProperty(const QByteArray &name)
{
- int id = d->mob.propertyCount();
- d->mob.addSignal("__" + QByteArray::number(id) + "()");
- QMetaPropertyBuilder build = d->mob.addProperty(name, "QVariant", id);
- propertyCreated(id, build);
+ const int signalIdx = d->mob.addSignal(
+ "__" + QByteArray::number(d->mob.propertyCount()) + "()").index();
+ QMetaPropertyBuilder build = d->mob.addProperty(name, "QVariant", signalIdx);
+ propertyCreated(build.index(), build);
free(d->mem);
d->mem = d->mob.toMetaObject();
- d->names.insert(name, id);
+ d->names.insert(name, build.index());
QSet<QQmlOpenMetaObject*>::iterator it = d->referers.begin();
while (it != d->referers.end()) {
QQmlOpenMetaObject *omo = *it;
@@ -152,12 +111,12 @@ int QQmlOpenMetaObjectType::createProperty(const QByteArray &name)
++it;
}
- return d->propertyOffset + id;
+ return d->propertyOffset + build.index();
}
void QQmlOpenMetaObjectType::propertyCreated(int id, QMetaPropertyBuilder &builder)
{
- if (d->referers.count())
+ if (d->referers.size())
(*d->referers.begin())->propertyCreated(id, builder);
}
@@ -166,7 +125,7 @@ void QQmlOpenMetaObjectTypePrivate::init(const QMetaObject *metaObj)
if (!mem) {
mob.setSuperClass(metaObj);
mob.setClassName(metaObj->className());
- mob.setFlags(QMetaObjectBuilder::DynamicMetaObject);
+ mob.setFlags(MetaObjectFlag::DynamicMetaObject);
mem = mob.toMetaObject();
@@ -180,8 +139,8 @@ void QQmlOpenMetaObjectTypePrivate::init(const QMetaObject *metaObj)
class QQmlOpenMetaObjectPrivate
{
public:
- QQmlOpenMetaObjectPrivate(QQmlOpenMetaObject *_q, bool _autoCreate, QObject *obj)
- : q(_q), object(obj), autoCreate(_autoCreate) {}
+ QQmlOpenMetaObjectPrivate(QQmlOpenMetaObject *_q, QObject *obj)
+ : q(_q), object(obj) {}
struct Property {
private:
@@ -191,7 +150,7 @@ public:
bool valueSet = false;
QVariant value() const {
- if (QMetaType::typeFlags(m_value.userType()) & QMetaType::PointerToQObject
+ if (m_value.metaType().flags() & QMetaType::PointerToQObject
&& qobjectTracker.isNull())
return QVariant::fromValue<QObject*>(nullptr);
return m_value;
@@ -200,19 +159,19 @@ public:
void setValue(const QVariant &v) {
m_value = v;
valueSet = true;
- if (QMetaType::typeFlags(v.userType()) & QMetaType::PointerToQObject)
+ if (v.metaType().flags() & QMetaType::PointerToQObject)
qobjectTracker = m_value.value<QObject*>();
}
};
inline void setPropertyValue(int idx, const QVariant &value) {
- if (data.count() <= idx)
+ if (data.size() <= idx)
data.resize(idx + 1);
data[idx].setValue(value);
}
inline Property &propertyRef(int idx) {
- if (data.count() <= idx)
+ if (data.size() <= idx)
data.resize(idx + 1);
Property &prop = data[idx];
if (!prop.valueSet)
@@ -231,40 +190,47 @@ public:
}
inline bool hasProperty(int idx) const {
- if (idx >= data.count())
+ if (idx >= data.size())
return false;
return data[idx].valueSet;
}
+ void dropPropertyCache() {
+ if (QQmlData *ddata = QQmlData::get(object, /*create*/false))
+ ddata->propertyCache.reset();
+ }
+
QQmlOpenMetaObject *q;
- QAbstractDynamicMetaObject *parent = nullptr;
+ QDynamicMetaObjectData *parent = nullptr;
QVector<Property> data;
QObject *object;
QQmlRefPointer<QQmlOpenMetaObjectType> type;
- bool autoCreate;
+ QVector<QByteArray> *deferredPropertyNames = nullptr;
+ bool autoCreate = true;
bool cacheProperties = false;
};
-QQmlOpenMetaObject::QQmlOpenMetaObject(QObject *obj, const QMetaObject *base, bool automatic)
-: d(new QQmlOpenMetaObjectPrivate(this, automatic, obj))
+QQmlOpenMetaObject::QQmlOpenMetaObject(QObject *obj, const QMetaObject *base)
+: d(new QQmlOpenMetaObjectPrivate(this, obj))
{
- d->type.adopt(new QQmlOpenMetaObjectType(base ? base : obj->metaObject(), nullptr));
+ d->type.adopt(new QQmlOpenMetaObjectType(base ? base : obj->metaObject()));
d->type->d->referers.insert(this);
QObjectPrivate *op = QObjectPrivate::get(obj);
- d->parent = static_cast<QAbstractDynamicMetaObject *>(op->metaObject);
+ d->parent = op->metaObject;
*static_cast<QMetaObject *>(this) = *d->type->d->mem;
op->metaObject = this;
}
-QQmlOpenMetaObject::QQmlOpenMetaObject(QObject *obj, QQmlOpenMetaObjectType *type, bool automatic)
-: d(new QQmlOpenMetaObjectPrivate(this, automatic, obj))
+QQmlOpenMetaObject::QQmlOpenMetaObject(
+ QObject *obj, const QQmlRefPointer<QQmlOpenMetaObjectType> &type)
+: d(new QQmlOpenMetaObjectPrivate(this, obj))
{
d->type = type;
d->type->d->referers.insert(this);
QObjectPrivate *op = QObjectPrivate::get(obj);
- d->parent = static_cast<QAbstractDynamicMetaObject *>(op->metaObject);
+ d->parent = op->metaObject;
*static_cast<QMetaObject *>(this) = *d->type->d->mem;
op->metaObject = this;
}
@@ -290,6 +256,11 @@ void QQmlOpenMetaObject::emitPropertyNotification(const QByteArray &propertyName
activate(d->object, *iter + d->type->d->signalOffset, nullptr);
}
+void QQmlOpenMetaObject::unparent()
+{
+ d->parent = nullptr;
+}
+
int QQmlOpenMetaObject::metaCall(QObject *o, QMetaObject::Call c, int id, void **a)
{
Q_ASSERT(d->object == o);
@@ -301,7 +272,7 @@ int QQmlOpenMetaObject::metaCall(QObject *o, QMetaObject::Call c, int id, void *
propertyRead(propId);
*reinterpret_cast<QVariant *>(a[0]) = d->propertyValue(propId);
} else if (c == QMetaObject::WriteProperty) {
- if (propId >= d->data.count() || d->data.at(propId).value() != *reinterpret_cast<QVariant *>(a[0])) {
+ if (propId >= d->data.size() || d->data.at(propId).value() != *reinterpret_cast<QVariant *>(a[0])) {
propertyWrite(propId);
d->setPropertyValue(propId, propertyWriteValue(propId, *reinterpret_cast<QVariant *>(a[0])));
propertyWritten(propId);
@@ -317,11 +288,21 @@ int QQmlOpenMetaObject::metaCall(QObject *o, QMetaObject::Call c, int id, void *
}
}
-QAbstractDynamicMetaObject *QQmlOpenMetaObject::parent() const
+QDynamicMetaObjectData *QQmlOpenMetaObject::parent() const
{
return d->parent;
}
+bool QQmlOpenMetaObject::checkedSetValue(int index, const QVariant &value, bool force)
+{
+ if (!force && d->propertyValue(index) == value)
+ return false;
+
+ d->setPropertyValue(index, value);
+ activate(d->object, index + d->type->d->signalOffset, nullptr);
+ return true;
+}
+
QVariant QQmlOpenMetaObject::value(int id) const
{
return d->propertyValue(id);
@@ -361,16 +342,43 @@ bool QQmlOpenMetaObject::setValue(const QByteArray &name, const QVariant &val, b
id = *iter;
}
- if (id >= 0) {
- if (!force && d->propertyValue(id) == val)
- return false;
+ if (id >= 0)
+ return checkedSetValue(id, val, force);
- d->setPropertyValue(id, val);
- activate(d->object, id + d->type->d->signalOffset, nullptr);
- return true;
+ return false;
+}
+
+void QQmlOpenMetaObject::setValues(const QHash<QByteArray, QVariant> &values, bool force)
+{
+ QVector<QByteArray> missingProperties;
+ d->deferredPropertyNames = &missingProperties;
+ const auto &names = d->type->d->names;
+
+ for (auto valueIt = values.begin(), end = values.end(); valueIt != end; ++valueIt) {
+ const auto nameIt = names.constFind(valueIt.key());
+ if (nameIt == names.constEnd()) {
+ const int id = createProperty(valueIt.key(), "") - d->type->d->propertyOffset;
+
+ // If id >= 0 some override of createProperty() created it. Then set it.
+ // Else it either ends up in missingProperties and we create it later
+ // or it cannot be created.
+
+ if (id >= 0)
+ checkedSetValue(id, valueIt.value(), force);
+ } else {
+ checkedSetValue(*nameIt, valueIt.value(), force);
+ }
}
- return false;
+ d->deferredPropertyNames = nullptr;
+ if (missingProperties.isEmpty())
+ return;
+
+ d->type->createProperties(missingProperties);
+ d->dropPropertyCache();
+
+ for (const QByteArray &name : std::as_const(missingProperties))
+ checkedSetValue(names[name], values[name], force);
}
// returns true if this value has been initialized by a call to either value() or setValue()
@@ -381,37 +389,47 @@ bool QQmlOpenMetaObject::hasValue(int id) const
void QQmlOpenMetaObject::setCached(bool c)
{
- if (c == d->cacheProperties || !d->type->d->engine)
+ if (c == d->cacheProperties)
return;
d->cacheProperties = c;
QQmlData *qmldata = QQmlData::get(d->object, true);
if (d->cacheProperties) {
+ // As the propertyCache is not saved in QQmlMetaType (due to it being dynamic)
+ // we cannot leak it to other places before we're done with it. Yes, it's still
+ // terrible.
if (!d->type->d->cache)
- d->type->d->cache = new QQmlPropertyCache(this);
+ d->type->d->cache = QQmlPropertyCache::createStandalone(this);
qmldata->propertyCache = d->type->d->cache;
- d->type->d->cache->addref();
} else {
- if (d->type->d->cache)
- d->type->d->cache->release();
- qmldata->propertyCache = nullptr;
+ d->type->d->cache.reset();
+ qmldata->propertyCache.reset();
}
}
+bool QQmlOpenMetaObject::autoCreatesProperties() const
+{
+ return d->autoCreate;
+}
+
+void QQmlOpenMetaObject::setAutoCreatesProperties(bool autoCreate)
+{
+ d->autoCreate = autoCreate;
+}
+
int QQmlOpenMetaObject::createProperty(const char *name, const char *)
{
if (d->autoCreate) {
- int result = d->type->createProperty(name);
-
- if (QQmlData *ddata = QQmlData::get(d->object, /*create*/false)) {
- if (ddata->propertyCache) {
- ddata->propertyCache->release();
- ddata->propertyCache = nullptr;
- }
+ if (d->deferredPropertyNames) {
+ // Defer the creation of new properties. See setValues(QHash<QByteArray, QVariant>)
+ d->deferredPropertyNames->append(name);
+ return -1;
}
+ const int result = d->type->createProperty(name);
+ d->dropPropertyCache();
return result;
} else
return -1;
@@ -445,12 +463,12 @@ QVariant QQmlOpenMetaObject::initialValue(int)
int QQmlOpenMetaObject::count() const
{
- return d->type->d->names.count();
+ return d->type->d->names.size();
}
QByteArray QQmlOpenMetaObject::name(int idx) const
{
- Q_ASSERT(idx >= 0 && idx < d->type->d->names.count());
+ Q_ASSERT(idx >= 0 && idx < d->type->d->names.size());
return d->type->d->mob.property(idx).name();
}