aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml/qqmlproperty.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/qml/qqmlproperty.cpp')
-rw-r--r--src/qml/qml/qqmlproperty.cpp198
1 files changed, 103 insertions, 95 deletions
diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp
index ad08f06b05..7c78fbb984 100644
--- a/src/qml/qml/qqmlproperty.cpp
+++ b/src/qml/qml/qqmlproperty.cpp
@@ -2,40 +2,35 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlproperty.h"
-#include "qqmlproperty_p.h"
-
-#include "qqmlboundsignal_p.h"
-#include "qqmlcontext.h"
-#include "qqmlboundsignal_p.h"
-#include "qqmlengine.h"
-#include "qqmlengine_p.h"
-#include "qqmldata_p.h"
-#include "qqmlstringconverters_p.h"
-
-#include "qqmlvmemetaobject_p.h"
-#include "qqmlvaluetypeproxybinding_p.h"
+
#include <private/qjsvalue_p.h>
-#include <private/qv4functionobject_p.h>
-#include <private/qv4qobjectwrapper_p.h>
+#include <private/qmetaobject_p.h>
+#include <private/qproperty_p.h>
+#include <private/qqmlboundsignal_p.h>
#include <private/qqmlbuiltinfunctions_p.h>
+#include <private/qqmldata_p.h>
+#include <private/qqmlengine_p.h>
#include <private/qqmlirbuilder_p.h>
-#include <QtQml/private/qqmllist_p.h>
-
-#include <QStringList>
-#include <QVector>
-#include <private/qmetaobject_p.h>
+#include <private/qqmllist_p.h>
+#include <private/qqmlproperty_p.h>
+#include <private/qqmlsignalnames_p.h>
+#include <private/qqmlstringconverters_p.h>
+#include <private/qqmlvaluetypeproxybinding_p.h>
#include <private/qqmlvaluetypewrapper_p.h>
+#include <private/qqmlvmemetaobject_p.h>
+#include <private/qv4functionobject_p.h>
+#include <private/qv4qobjectwrapper_p.h>
+
+#include <QtQml/qqmlcontext.h>
+#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlpropertymap.h>
+
#include <QtCore/qdebug.h>
-#include <cmath>
-#include <QtQml/QQmlPropertyMap>
-#include <QtCore/private/qproperty_p.h>
#include <QtCore/qsequentialiterable.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qvector.h>
-Q_DECLARE_METATYPE(QList<int>)
-Q_DECLARE_METATYPE(QList<qreal>)
-Q_DECLARE_METATYPE(QList<bool>)
-Q_DECLARE_METATYPE(QList<QString>)
-Q_DECLARE_METATYPE(QList<QUrl>)
+#include <cmath>
QT_BEGIN_NAMESPACE
@@ -252,10 +247,11 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name,
// Types must begin with an uppercase letter (see checkRegistration()
// in qqmlmetatype.cpp for the enforcement of this).
if (typeNameCache && !pathName.isEmpty() && pathName.at(0).isUpper()) {
- QQmlTypeNameCache::Result r = typeNameCache->query(pathName);
+ QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine);
+ QQmlTypeLoader *typeLoader = QQmlTypeLoader::get(enginePrivate);
+ QQmlTypeNameCache::Result r = typeNameCache->query(pathName, typeLoader);
if (r.isValid()) {
if (r.type.isValid()) {
- QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine);
QQmlAttachedPropertiesFunc func = r.type.attachedPropertiesFunction(enginePrivate);
if (!func) return; // Not an attachable type
@@ -267,12 +263,11 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name,
// TODO: Do we really _not_ want to query the namespaced types here?
r = typeNameCache->query<QQmlTypeNameCache::QueryNamespaced::No>(
- path.at(ii), r.importNamespace);
+ path.at(ii), r.importNamespace, typeLoader);
if (!r.type.isValid())
return; // Invalid type in namespace
- QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine);
QQmlAttachedPropertiesFunc func = r.type.attachedPropertiesFunction(enginePrivate);
if (!func)
return; // Not an attachable type
@@ -370,10 +365,9 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name,
QQmlData *ddata = QQmlData::get(currentObject, false);
auto findChangeSignal = [&](QStringView signalName) {
- const QString changed = QStringLiteral("Changed");
- if (signalName.endsWith(changed)) {
- const QStringView propName = signalName.first(signalName.size() - changed.size());
- const QQmlPropertyData *d = ddata->propertyCache->property(propName, currentObject, context);
+ if (auto propName = QQmlSignalNames::changedSignalNameToPropertyName(signalName)) {
+ const QQmlPropertyData *d =
+ ddata->propertyCache->property(*propName, currentObject, context);
while (d && d->isFunction())
d = ddata->propertyCache->overrideData(d);
@@ -386,20 +380,11 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name,
return false;
};
- const QString terminalString = terminal.toString();
- if (QmlIR::IRBuilder::isSignalPropertyName(terminalString)) {
- QString signalName = terminalString.mid(2);
- int firstNon_;
- int length = signalName.size();
- for (firstNon_ = 0; firstNon_ < length; ++firstNon_)
- if (signalName.at(firstNon_) != u'_')
- break;
- signalName[firstNon_] = signalName.at(firstNon_).toLower();
-
+ const auto findSignal = [&](const QString &signalName) {
if (ddata && ddata->propertyCache) {
// Try method
- const QQmlPropertyData *d = ddata->propertyCache->property(
- signalName, currentObject, context);
+ const QQmlPropertyData *d
+ = ddata->propertyCache->property(signalName, currentObject, context);
// ### Qt7: This code treats methods as signals. It should use d->isSignal().
// That would be a change in behavior, though. Right now you can construct a
@@ -410,13 +395,30 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name,
if (d) {
object = currentObject;
core = *d;
- return;
+ return true;
}
- if (findChangeSignal(signalName))
- return;
- } else if (findSignalInMetaObject(signalName.toUtf8())) {
+ return findChangeSignal(signalName);
+ }
+
+ return findSignalInMetaObject(signalName.toUtf8());
+ };
+
+ auto signalName = QQmlSignalNames::handlerNameToSignalName(terminal);
+ if (signalName) {
+ if (findSignal(*signalName))
return;
+ } else {
+ signalName = QQmlSignalNames::badHandlerNameToSignalName(terminal);
+ if (signalName) {
+ if (findSignal(*signalName)) {
+ qWarning()
+ << terminal
+ << "is not a properly capitalized signal handler name."
+ << QQmlSignalNames::signalNameToHandlerName(*signalName)
+ << "would be correct.";
+ return;
+ }
}
}
@@ -429,7 +431,7 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name,
if (!property->isFunction()) {
object = currentObject;
core = *property;
- nameCache = terminalString;
+ nameCache = terminal.toString();
return;
}
property = ddata->propertyCache->overrideData(property);
@@ -750,15 +752,7 @@ QString QQmlProperty::name() const
d->nameCache = d->core.name(d->object) + QLatin1Char('.') + QString::fromUtf8(vtName);
} else if (type() & SignalProperty) {
// ### Qt7: Return the original signal name here. Do not prepend "on"
- QString name = QStringLiteral("on") + d->core.name(d->object);
- for (int i = 2, end = name.size(); i != end; ++i) {
- const QChar c = name.at(i);
- if (c != u'_') {
- name[i] = c.toUpper();
- break;
- }
- }
- d->nameCache = name;
+ d->nameCache = QQmlSignalNames::signalNameToHandlerName(d->core.name(d->object));
} else {
d->nameCache = d->core.name(d->object);
}
@@ -1231,14 +1225,9 @@ bool QQmlPropertyPrivate::writeEnumProperty(const QMetaProperty &prop, int idx,
v = QVariant(menum.keyToValue(value.toByteArray(), &ok));
if (!ok)
return false;
- } else if (v.userType() != QMetaType::Int && v.userType() != QMetaType::UInt) {
- int enumMetaTypeId = QMetaType::fromName(
- QByteArray(menum.scope() + QByteArray("::") + menum.name())).id();
- if ((enumMetaTypeId == QMetaType::UnknownType) || (v.userType() != enumMetaTypeId) || !v.constData())
- return false;
- v = QVariant(*reinterpret_cast<const int *>(v.constData()));
}
- v.convert(QMetaType(QMetaType::Int));
+ if (!v.convert(prop.metaType())) // ### TODO: underlyingType might be faster?
+ return false;
}
// the status variable is changed by qt_metacall to indicate what it did
@@ -1384,6 +1373,18 @@ static ConvertAndAssignResult tryConvertAndAssign(
return {false, false};
}
+ if (variantMetaType == QMetaType::fromType<QJSValue>()) {
+ // Handle Qt.binding bindings here to avoid mistaken conversion below
+ const QJSValue &jsValue = get<QJSValue>(value);
+ const QV4::FunctionObject *f
+ = QJSValuePrivate::asManagedType<QV4::FunctionObject>(&jsValue);
+ if (f && f->isBinding()) {
+ QV4::QObjectWrapper::setProperty(
+ f->engine(), object, &property, f->asReturnedValue());
+ return {true, true};
+ }
+ }
+
// common cases:
switch (propertyMetaType.id()) {
case QMetaType::Bool:
@@ -1429,14 +1430,15 @@ static ConvertAndAssignResult tryConvertAndAssign(
}
}
- QVariant converted(propertyMetaType);
- if (QQmlValueTypeProvider::createValueType(value, propertyMetaType, converted.data())
- || QMetaType::convert(value.metaType(), value.constData(),
- propertyMetaType, converted.data())) {
- return {true, property.writeProperty(object, converted.data(), flags)};
+ QVariant converted = QQmlValueTypeProvider::createValueType(value, propertyMetaType);
+ if (!converted.isValid()) {
+ converted = QVariant(propertyMetaType);
+ if (!QMetaType::convert(value.metaType(), value.constData(),
+ propertyMetaType, converted.data())) {
+ return {false, false};
+ }
}
-
- return {false, false};
+ return {true, property.writeProperty(object, converted.data(), flags)};
};
template<typename Op>
@@ -1559,18 +1561,26 @@ bool QQmlPropertyPrivate::write(
if (valueMetaObject.isNull())
return false;
- QQmlListProperty<void> prop;
+ QQmlListProperty<QObject> prop;
property.readProperty(object, &prop);
- if (!prop.clear)
+ if (!prop.clear || !prop.append)
return false;
- prop.clear(&prop);
+ const bool useNonsignalingListOps = prop.clear == &QQmlVMEMetaObject::list_clear
+ && prop.append == &QQmlVMEMetaObject::list_append;
+
+ auto propClear =
+ useNonsignalingListOps ? &QQmlVMEMetaObject::list_clear_nosignal : prop.clear;
+ auto propAppend =
+ useNonsignalingListOps ? &QQmlVMEMetaObject::list_append_nosignal : prop.append;
+
+ propClear(&prop);
const auto doAppend = [&](QObject *o) {
if (o && !QQmlMetaObject::canConvert(o, valueMetaObject))
o = nullptr;
- prop.append(&prop, o);
+ propAppend(&prop, o);
};
if (variantMetaType == QMetaType::fromType<QQmlListReference>()) {
@@ -1581,9 +1591,18 @@ bool QQmlPropertyPrivate::write(
const QList<QObject *> &list = qvariant_cast<QList<QObject *> >(value);
for (qsizetype ii = 0; ii < list.size(); ++ii)
doAppend(list.at(ii));
+ } else if (variantMetaType == QMetaType::fromType<QList<QVariant>>()) {
+ const QList<QVariant> &list
+ = *static_cast<const QList<QVariant> *>(value.constData());
+ for (const QVariant &entry : list)
+ doAppend(QQmlMetaType::toQObject(entry));
} else if (!iterateQObjectContainer(variantMetaType, value.data(), doAppend)) {
doAppend(QQmlMetaType::toQObject(value));
}
+ if (useNonsignalingListOps) {
+ Q_ASSERT(QQmlVMEMetaObject::get(object));
+ QQmlVMEResolvedList(&prop).activateSignal();
+ }
} else if (variantMetaType == propertyMetaType) {
QVariant v = value;
property.writeProperty(object, v.data(), flags);
@@ -1595,16 +1614,6 @@ bool QQmlPropertyPrivate::write(
sequence.addValue(list.data(), value.data());
property.writeProperty(object, list.data(), flags);
}
- } else if (variantMetaType == QMetaType::fromType<QJSValue>()) {
- QJSValue jsValue = qvariant_cast<QJSValue>(value);
- const QV4::FunctionObject *f
- = QJSValuePrivate::asManagedType<QV4::FunctionObject>(&jsValue);
- if (f && f->isBinding()) {
- QV4::QObjectWrapper::setProperty(
- f->engine(), object, &property, f->asReturnedValue());
- return true;
- }
- return false;
} else if (enginePriv && propertyMetaType == QMetaType::fromType<QJSValue>()) {
// We can convert everything into a QJSValue if we have an engine.
QJSValue jsValue = QJSValuePrivate::fromReturnedValue(
@@ -1696,13 +1705,13 @@ bool QQmlPropertyPrivate::write(
if (!ok && QQmlMetaType::isInterface(propertyMetaType)) {
auto valueAsQObject = qvariant_cast<QObject *>(value);
- if (void *interface = valueAsQObject
+ if (void *iface = valueAsQObject
? valueAsQObject->qt_metacast(QQmlMetaType::interfaceIId(propertyMetaType))
: nullptr;
- interface) {
+ iface) {
// this case can occur when object has an interface type
// and the variant contains a type implementing the interface
- return property.writeProperty(object, &interface, flags);
+ return property.writeProperty(object, &iface, flags);
}
}
@@ -1947,9 +1956,8 @@ QMetaMethod QQmlPropertyPrivate::findSignalByName(const QMetaObject *mo, const Q
// If no signal is found, but the signal is of the form "onBlahChanged",
// return the notify signal for the property "Blah"
- if (name.endsWith("Changed")) {
- QByteArray propName = name.mid(0, name.size() - 7);
- int propIdx = mo->indexOfProperty(propName.constData());
+ if (auto propName = QQmlSignalNames::changedSignalNameToPropertyName(name)) {
+ int propIdx = mo->indexOfProperty(propName->constData());
if (propIdx >= 0) {
QMetaProperty prop = mo->property(propIdx);
if (prop.hasNotifySignal())