aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2022-11-15 11:57:47 +0100
committerUlf Hermann <ulf.hermann@qt.io>2022-11-22 16:17:15 +0100
commit0925c51c5988bee7ee96944de2d857b2132ebe65 (patch)
treeb0b2f411ffa9dacc81cd90f8f35621ff4fa063b0 /src/qml
parentc58d2e5229c39e8007ce5b93822c66af5e765a50 (diff)
QJSEngine: Optimize conversion from QObject* to QString
This is commonly done for logging. With this in place we can have the code generator use coerceType() for such constructs. [ChangeLog][QML][Important Behavior Changes] You can implement custom toString() methods for your QML objects in JavaScript or in C++. Those methods don't actually have to return a string. Previously, whatever return value the method generated was forwarded as-is. Now it is coerced to a string. Change-Id: I4a9721a6948be0c24a36b31d453a74bd747db729 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> Reviewed-by: Sami Shalayel <sami.shalayel@qt.io>
Diffstat (limited to 'src/qml')
-rw-r--r--src/qml/jsapi/qjsengine.cpp6
-rw-r--r--src/qml/jsapi/qjsengine.h13
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp65
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper_p.h3
4 files changed, 58 insertions, 29 deletions
diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp
index c15b5c1ccd..8b0b650c1f 100644
--- a/src/qml/jsapi/qjsengine.cpp
+++ b/src/qml/jsapi/qjsengine.cpp
@@ -920,6 +920,12 @@ bool QJSEngine::convertMetaType(QMetaType fromType, const void *from, QMetaType
return QV4::ExecutionEngine::metaTypeFromJS(handle()->fromData(fromType, from), toType, to);
}
+QString QJSEngine::convertQObjectToString(QObject *object)
+{
+ return QV4::QObjectWrapper::objectToString(
+ handle(), object ? object->metaObject() : nullptr, object);
+}
+
/*! \fn template <typename T> QJSValue QJSEngine::toScriptValue(const T &value)
Creates a QJSValue with the given \a value.
diff --git a/src/qml/jsapi/qjsengine.h b/src/qml/jsapi/qjsengine.h
index db78e1b9a9..9af6fd6e7c 100644
--- a/src/qml/jsapi/qjsengine.h
+++ b/src/qml/jsapi/qjsengine.h
@@ -101,6 +101,13 @@ public:
if constexpr (std::is_same_v<T, QJSManagedValue>)
return toManagedValue(value);
+ if constexpr (std::is_same_v<T, QString>) {
+ if (targetType.flags() & QMetaType::PointerToQObject) {
+ return convertQObjectToString(
+ *reinterpret_cast<QObject *const *>(value.constData()));
+ }
+ }
+
if (sourceType == QMetaType::fromType<QJSValue>())
return fromScriptValue<T>(*reinterpret_cast<const QJSValue *>(value.constData()));
@@ -148,6 +155,11 @@ public:
if constexpr (std::is_same_v<To, QVariant>)
return QVariant::fromValue(from);
+ if constexpr (std::is_same_v<To, QString>
+ && std::is_base_of_v<QObject, std::remove_const_t<std::remove_pointer_t<To>>>) {
+ return convertQObjectToString(from);
+ }
+
if constexpr (std::is_same_v<To, std::remove_const_t<std::remove_pointer_t<To>> const *>) {
using nonConstTo = std::remove_const_t<std::remove_pointer_t<To>> *;
if constexpr (std::is_same_v<From, nonConstTo>)
@@ -220,6 +232,7 @@ private:
bool convertVariant(const QVariant &value, QMetaType metaType, void *ptr);
bool convertMetaType(QMetaType fromType, const void *from, QMetaType toType, void *to);
+ QString convertQObjectToString(QObject *object);
template<typename T>
friend inline T qjsvalue_cast(const QJSValue &);
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index e83c111251..2d33b5f36e 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -1023,6 +1023,38 @@ int QObjectWrapper::virtualMetacall(Object *object, QMetaObject::Call call, int
return 0;
}
+QString QObjectWrapper::objectToString(
+ ExecutionEngine *engine, const QMetaObject *metaObject, QObject *object)
+{
+ if (!metaObject)
+ return QLatin1String("null");
+
+ if (!object)
+ return QString::fromUtf8(metaObject->className()) + QLatin1String("(0x0)");
+
+ const int id = metaObject->indexOfMethod("toString()");
+ if (id >= 0) {
+ const QMetaMethod method = metaObject->method(id);
+ const QMetaType returnType = method.returnMetaType();
+ QVariant result(returnType);
+ method.invoke(object, QGenericReturnArgument(returnType.name(), result.data()));
+ if (result.metaType() == QMetaType::fromType<QString>())
+ return result.toString();
+ QV4::Scope scope(engine);
+ QV4::ScopedValue value(scope, engine->fromVariant(result));
+ return value->toQString();
+ }
+
+ QString result;
+ result += QString::fromUtf8(metaObject->className()) +
+ QLatin1String("(0x") + QString::number(quintptr(object), 16);
+ QString objectName = object->objectName();
+ if (!objectName.isEmpty())
+ result += QLatin1String(", \"") + objectName + QLatin1Char('\"');
+ result += QLatin1Char(')');
+ return result;
+}
+
struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase
{
PersistentValue function;
@@ -2385,12 +2417,9 @@ static QObject *qObject(const Value *v)
return nullptr;
}
-ReturnedValue QObjectMethod::method_toString(ExecutionEngine *engine, const QV4::Value *thisObject) const
+ReturnedValue QObjectMethod::method_toString(
+ ExecutionEngine *engine, const QV4::Value *thisObject) const
{
- const auto encode = [engine](const QString &result) {
- return engine->newString(result)->asReturnedValue();
- };
-
QObject *o = qObject(thisObject);
d()->assertIntegrity(o);
@@ -2398,31 +2427,9 @@ ReturnedValue QObjectMethod::method_toString(ExecutionEngine *engine, const QV4:
const QMetaObject *metaObject = d()->metaObject();
if (!metaObject && o)
metaObject = o->metaObject();
- if (metaObject) {
- if (QObject *qobject = o ? o : d()->object()) {
- const int id = metaObject->indexOfMethod("toString()");
- if (id >= 0) {
- const QMetaMethod method = metaObject->method(id);
- const QMetaType returnType = method.returnMetaType();
- QVariant result(returnType);
- method.invoke(qobject, QGenericReturnArgument(returnType.name(), result.data()));
- return engine->fromVariant(result);
- }
-
- QString result;
- result += QString::fromUtf8(metaObject->className()) +
- QLatin1String("(0x") + QString::number(quintptr(qobject), 16);
- QString objectName = qobject->objectName();
- if (!objectName.isEmpty())
- result += QLatin1String(", \"") + objectName + QLatin1Char('\"');
- result += QLatin1Char(')');
- return encode(result);
- } else {
- return encode(QString::fromUtf8(metaObject->className()) + QLatin1String("(0x0)"));
- }
- }
- return encode(QLatin1String("null"));
+ return engine->newString(QObjectWrapper::objectToString(
+ engine, metaObject, o ? o : d()->object()))->asReturnedValue();
}
ReturnedValue QObjectMethod::method_destroy(ExecutionEngine *engine, const QV4::Value *thisObject, const Value *args, int argc) const
diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h
index 043afe79e7..d17b12ea4a 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper_p.h
+++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h
@@ -194,6 +194,9 @@ struct Q_QML_EXPORT QObjectWrapper : public Object
static int virtualMetacall(Object *object, QMetaObject::Call call, int index, void **a);
+ static QString objectToString(
+ ExecutionEngine *engine, const QMetaObject *metaObject, QObject *object);
+
protected:
static bool virtualIsEqualTo(Managed *that, Managed *o);
static ReturnedValue create(ExecutionEngine *engine, QObject *object);