Revision control

Copy as Markdown

// 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
// Qt-Security score:significant reason:default
#include "qqmldesignermetaobject_p.h"
#include <QSharedPointer>
#include <QMetaProperty>
#include <QtCore/private/qnumeric_p.h>
#include <QDebug>
#include <private/qqmlengine_p.h>
QT_BEGIN_NAMESPACE
static QHash<QDynamicMetaObjectData *, bool> nodeInstanceMetaObjectList;
static void (*notifyPropertyChangeCallBack)(QObject*, const QQuickDesignerSupport::PropertyName &propertyName) = nullptr;
struct MetaPropertyData {
inline std::pair<QVariant, bool> &getDataRef(int idx) {
while (m_data.size() <= idx)
m_data << std::pair<QVariant, bool>(QVariant(), false);
return m_data[idx];
}
inline QVariant &getData(int idx) {
std::pair<QVariant, bool> &prop = getDataRef(idx);
if (!prop.second) {
prop.first = QVariant();
prop.second = true;
}
return prop.first;
}
inline bool hasData(int idx) const {
if (idx >= m_data.size())
return false;
return m_data[idx].second;
}
inline int count() { return m_data.size(); }
QList<std::pair<QVariant, bool> > m_data;
};
QQmlDesignerMetaObject* QQmlDesignerMetaObject::getNodeInstanceMetaObject(QObject *object, QQmlEngine *engine)
{
//Avoid setting up multiple MetaObjects on the same QObject
QObjectPrivate *op = QObjectPrivate::get(object);
QDynamicMetaObjectData *parent = op->metaObject;
if (nodeInstanceMetaObjectList.contains(parent))
return static_cast<QQmlDesignerMetaObject *>(parent);
// we just create one and the ownership goes automatically to the object in nodeinstance see init method
QQmlData *ddata = QQmlData::get(object, false);
QQmlDesignerMetaObject *mo = new QQmlDesignerMetaObject(object, engine);
ddata->hasVMEMetaObject = false;
ddata->hasInterceptorMetaObject = false;
return mo;
}
void QQmlDesignerMetaObject::init(QObject *object)
{
//Assign this to object
QObjectPrivate *op = QObjectPrivate::get(object);
op->metaObject = this;
nodeInstanceMetaObjectList.insert(this, true);
}
QQmlPropertyCache::Ptr QQmlDesignerMetaObject::cache() const
{
return type()->cache();
}
QQmlDesignerMetaObject::QQmlDesignerMetaObject(QObject *object, QQmlEngine *engine)
: QQmlOpenMetaObject(object),
m_context(engine->contextForObject(object)),
m_data(new MetaPropertyData)
{
init(object);
setCached(true);
}
QQmlDesignerMetaObject::~QQmlDesignerMetaObject()
{
nodeInstanceMetaObjectList.remove(this);
}
void QQmlDesignerMetaObject::createNewDynamicProperty(const QString &name)
{
int id = type()->createProperty(name.toUtf8());
setValue(id, QVariant());
Q_ASSERT(id >= 0);
//Updating cache
cache()->invalidate(this);
QQmlProperty property(myObject(), name, m_context);
Q_ASSERT(property.isValid());
}
int QQmlDesignerMetaObject::createProperty(const char *name, const char *passAlong)
{
int ret = QQmlOpenMetaObject::createProperty(name, passAlong);
if (ret != -1) {
// compare createNewDynamicProperty
cache()->invalidate(this);
}
return ret;
}
void QQmlDesignerMetaObject::setValue(int id, const QVariant &value)
{
std::pair<QVariant, bool> &prop = m_data->getDataRef(id);
prop.first = propertyWriteValue(id, value);
prop.second = true;
QMetaObject::activate(myObject(), id + type()->signalOffset(), nullptr);
}
QVariant QQmlDesignerMetaObject::propertyWriteValue(int, const QVariant &value)
{
return value;
}
QDynamicMetaObjectData *QQmlDesignerMetaObject::dynamicMetaObjectParent() const
{
return parent();
}
int QQmlDesignerMetaObject::propertyOffset() const
{
return cache()->propertyOffset();
}
int QQmlDesignerMetaObject::openMetaCall(QObject *o, QMetaObject::Call call, int id, void **a)
{
if ((call == QMetaObject::ReadProperty || call == QMetaObject::WriteProperty)
&& id >= type()->propertyOffset()) {
int propId = id - type()->propertyOffset();
if (call == QMetaObject::ReadProperty) {
//propertyRead(propId);
*reinterpret_cast<QVariant *>(a[0]) = m_data->getData(propId);
} else if (call == QMetaObject::WriteProperty) {
if (propId <= m_data->count() || m_data->m_data[propId].first != *reinterpret_cast<QVariant *>(a[0])) {
//propertyWrite(propId);
std::pair<QVariant, bool> &prop = m_data->getDataRef(propId);
prop.first = propertyWriteValue(propId, *reinterpret_cast<QVariant *>(a[0]));
prop.second = true;
//propertyWritten(propId);
activate(myObject(), type()->signalOffset() + propId, nullptr);
}
}
return -1;
} else {
QDynamicMetaObjectData *dynamicParent = dynamicMetaObjectParent();
if (dynamicParent)
return dynamicParent->metaCall(o, call, id, a);
else
return myObject()->qt_metacall(call, id, a);
}
}
int QQmlDesignerMetaObject::metaCall(QObject *o, QMetaObject::Call call, int id, void **a)
{
Q_ASSERT(myObject() == o);
int metaCallReturnValue = -1;
const QMetaProperty propertyById = property(id);
if (call == QMetaObject::WriteProperty
&& propertyById.userType() == QMetaType::QVariant
&& reinterpret_cast<QVariant *>(a[0])->userType() == QMetaType::Double
&& qt_is_nan(reinterpret_cast<QVariant *>(a[0])->toDouble())) {
return -1;
}
if (call == QMetaObject::WriteProperty
&& propertyById.userType() == QMetaType::Double
&& qt_is_nan(*reinterpret_cast<double*>(a[0]))) {
return -1;
}
if (call == QMetaObject::WriteProperty
&& propertyById.userType() == QMetaType::Float
&& qt_is_nan(*reinterpret_cast<float*>(a[0]))) {
return -1;
}
QVariant oldValue;
if (call == QMetaObject::WriteProperty && !propertyById.hasNotifySignal())
{
oldValue = propertyById.read(myObject());
}
QDynamicMetaObjectData *dynamicParent = dynamicMetaObjectParent();
const QMetaObject *staticParent = dynamicParent
? dynamicParent->toDynamicMetaObject(object())
: nullptr;
if (staticParent && id < staticParent->propertyOffset())
metaCallReturnValue = dynamicParent->metaCall(o, call, id, a);
else
openMetaCall(o, call, id, a);
if (call == QMetaObject::WriteProperty
&& !propertyById.hasNotifySignal()
&& oldValue != propertyById.read(myObject()))
notifyPropertyChange(id);
return metaCallReturnValue;
}
void QQmlDesignerMetaObject::notifyPropertyChange(int id)
{
const QMetaProperty propertyById = property(id);
if (id < propertyOffset()) {
if (notifyPropertyChangeCallBack)
notifyPropertyChangeCallBack(myObject(), propertyById.name());
} else {
if (notifyPropertyChangeCallBack)
notifyPropertyChangeCallBack(myObject(), name(id - propertyOffset()));
}
}
int QQmlDesignerMetaObject::count() const
{
return type()->propertyCount();
}
QByteArray QQmlDesignerMetaObject::name(int idx) const
{
return type()->propertyName(idx);
}
void QQmlDesignerMetaObject::registerNotifyPropertyChangeCallBack(void (*callback)(QObject *, const QQuickDesignerSupport::PropertyName &))
{
notifyPropertyChangeCallBack = callback;
}
QT_END_NAMESPACE