Allow anonymous value types to be constructed

Only anonymous object types are necessarily uncreatable. You don't need
a name in order to construct or populate a value type. Since we can now
construct QSize, QRect, and QPoint, the engine will try to construct
them from the 'F' variants where applicable. Allow this.

Pick-to: 6.5 6.6
Change-Id: I568b93c58d3184d9ac37bf0a542c0e50dd37d8de
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
Ulf Hermann 2023-05-30 10:25:31 +02:00
parent b4ce8051af
commit 6d1317e11a
6 changed files with 66 additions and 2 deletions

View File

@ -494,7 +494,8 @@ int QQmlPrivate::qmlregister(RegistrationType type, void *data)
const char *elementName = (type.structVersion > 1 && type.forceAnonymous) const char *elementName = (type.structVersion > 1 && type.forceAnonymous)
? nullptr ? nullptr
: classElementName(type.classInfoMetaObject); : classElementName(type.classInfoMetaObject);
const bool creatable = (elementName != nullptr) const bool isValueType = !(type.typeId.flags() & QMetaType::PointerToQObject);
const bool creatable = (elementName != nullptr || isValueType)
&& boolClassInfo(type.classInfoMetaObject, "QML.Creatable", true); && boolClassInfo(type.classInfoMetaObject, "QML.Creatable", true);
QString noCreateReason; QString noCreateReason;
@ -505,7 +506,7 @@ int QQmlPrivate::qmlregister(RegistrationType type, void *data)
classInfo(type.classInfoMetaObject, "QML.UncreatableReason")); classInfo(type.classInfoMetaObject, "QML.UncreatableReason"));
if (noCreateReason.isEmpty()) if (noCreateReason.isEmpty())
noCreateReason = QLatin1String("Type cannot be created in QML."); noCreateReason = QLatin1String("Type cannot be created in QML.");
} else if (!(type.typeId.flags() & QMetaType::PointerToQObject)) { } else if (isValueType) {
const char *method = classInfo(type.classInfoMetaObject, "QML.CreationMethod"); const char *method = classInfo(type.classInfoMetaObject, "QML.CreationMethod");
if (qstrcmp(method, "structured") == 0) if (qstrcmp(method, "structured") == 0)
creationMethod = ValueTypeCreationMethod::Structured; creationMethod = ValueTypeCreationMethod::Structured;

View File

@ -140,6 +140,8 @@ struct Q_QML_PRIVATE_EXPORT QQmlPointValueType
QML_STRUCTURED_VALUE QML_STRUCTURED_VALUE
public: public:
QQmlPointValueType() = default;
Q_INVOKABLE QQmlPointValueType(const QPointF &point) : v(point.toPoint()) {}
Q_INVOKABLE QString toString() const; Q_INVOKABLE QString toString() const;
int x() const; int x() const;
int y() const; int y() const;
@ -186,6 +188,8 @@ struct Q_QML_PRIVATE_EXPORT QQmlSizeValueType
QML_STRUCTURED_VALUE QML_STRUCTURED_VALUE
public: public:
QQmlSizeValueType() = default;
Q_INVOKABLE QQmlSizeValueType(const QSizeF &size) : v(size.toSize()) {}
Q_INVOKABLE QString toString() const; Q_INVOKABLE QString toString() const;
int width() const; int width() const;
int height() const; int height() const;
@ -254,6 +258,8 @@ struct Q_QML_PRIVATE_EXPORT QQmlRectValueType
QML_STRUCTURED_VALUE QML_STRUCTURED_VALUE
public: public:
QQmlRectValueType() = default;
Q_INVOKABLE QQmlRectValueType(const QRectF &rect) : v(rect.toRect()) {}
Q_INVOKABLE QString toString() const; Q_INVOKABLE QString toString() const;
int x() const; int x() const;
int y() const; int y() const;

View File

@ -43,4 +43,7 @@ MyTypeObject {
c4 = {foo: 11}; c4 = {foo: 11};
} }
barren: ({i: 17})
function changeBarren() { barren = "foos" }
} }

View File

@ -10,6 +10,7 @@ void registerTypes()
qmlRegisterTypesAndRevisions<ConstructibleValueType>("Test", 1); qmlRegisterTypesAndRevisions<ConstructibleValueType>("Test", 1);
qmlRegisterTypesAndRevisions<ConstructibleFromQReal>("Test", 1); qmlRegisterTypesAndRevisions<ConstructibleFromQReal>("Test", 1);
qmlRegisterTypesAndRevisions<StructuredValueType>("Test", 1); qmlRegisterTypesAndRevisions<StructuredValueType>("Test", 1);
qmlRegisterTypesAndRevisions<ForeignAnonymousStructuredValueType>("Test", 1);
qmlRegisterTypesAndRevisions<Padding>("Test", 1); qmlRegisterTypesAndRevisions<Padding>("Test", 1);
qmlRegisterTypesAndRevisions<MyItem>("Test", 1); qmlRegisterTypesAndRevisions<MyItem>("Test", 1);
} }

View File

@ -109,6 +109,35 @@ private:
QList<QSizeF> m_sizes = { QSizeF(1, 1), QSizeF(2, 2) }; QList<QSizeF> m_sizes = { QSizeF(1, 1), QSizeF(2, 2) };
}; };
struct BarrenValueType
{
Q_GADGET
Q_PROPERTY(int i READ i WRITE setI)
public:
BarrenValueType() = default;
Q_INVOKABLE BarrenValueType(const QString &) : m_i(25) {}
int i() const { return m_i; }
void setI(int newI) { m_i = newI; }
private:
friend bool operator==(const BarrenValueType &a, const BarrenValueType &b)
{
return a.m_i == b.m_i;
}
int m_i = 0;
};
struct ForeignAnonymousStructuredValueType
{
Q_GADGET
QML_ANONYMOUS
QML_FOREIGN(BarrenValueType)
QML_STRUCTURED_VALUE
};
class MyTypeObject : public QObject class MyTypeObject : public QObject
{ {
Q_OBJECT Q_OBJECT
@ -133,6 +162,7 @@ class MyTypeObject : public QObject
Q_PROPERTY(QVariant variant READ variant NOTIFY changed) Q_PROPERTY(QVariant variant READ variant NOTIFY changed)
Q_PROPERTY(ConstructibleValueType constructible READ constructible WRITE setConstructible NOTIFY constructibleChanged) Q_PROPERTY(ConstructibleValueType constructible READ constructible WRITE setConstructible NOTIFY constructibleChanged)
Q_PROPERTY(StructuredValueType structured READ structured WRITE setStructured NOTIFY structuredChanged) Q_PROPERTY(StructuredValueType structured READ structured WRITE setStructured NOTIFY structuredChanged)
Q_PROPERTY(BarrenValueType barren READ barren WRITE setBarren NOTIFY barrenChanged)
Q_PROPERTY(QDateTime aDateTime READ aDateTime WRITE setADateTime NOTIFY aDateTimeChanged) Q_PROPERTY(QDateTime aDateTime READ aDateTime WRITE setADateTime NOTIFY aDateTimeChanged)
Q_PROPERTY(QDate aDate READ aDate WRITE setADate NOTIFY aDateChanged) Q_PROPERTY(QDate aDate READ aDate WRITE setADate NOTIFY aDateChanged)
@ -307,6 +337,19 @@ public:
emit aVariantChanged(); emit aVariantChanged();
} }
BarrenValueType barren() const
{
return m_barren;
}
void setBarren(const BarrenValueType &newBarren)
{
if (m_barren == newBarren)
return;
m_barren = newBarren;
emit barrenChanged();
}
signals: signals:
void changed(); void changed();
void runScript(); void runScript();
@ -319,6 +362,8 @@ signals:
void aTimeChanged(); void aTimeChanged();
void aVariantChanged(); void aVariantChanged();
void barrenChanged();
public slots: public slots:
QSize method() { return QSize(13, 14); } QSize method() { return QSize(13, 14); }
private: private:
@ -329,6 +374,7 @@ private:
QDate m_aDate; QDate m_aDate;
QTime m_aTime; QTime m_aTime;
QVariant m_aVariant; QVariant m_aVariant;
BarrenValueType m_barren;
}; };
class Padding class Padding

View File

@ -351,6 +351,13 @@ void tst_qqmlvaluetypeproviders::structured()
ConstructibleFromQReal(-112.5)); ConstructibleFromQReal(-112.5));
QCOMPARE(o->property("cr7").value<ConstructibleFromQReal>(), QCOMPARE(o->property("cr7").value<ConstructibleFromQReal>(),
ConstructibleFromQReal(50)); ConstructibleFromQReal(50));
BarrenValueType barren;
barren.setI(17);
QCOMPARE(o->property("barren").value<BarrenValueType>(), barren);
QMetaObject::invokeMethod(o.data(), "changeBarren");
QCOMPARE(o->property("barren").value<BarrenValueType>(), BarrenValueType(QString()));
} }
void tst_qqmlvaluetypeproviders::recursive() void tst_qqmlvaluetypeproviders::recursive()