qmltyperegistrar: Fix handling of default properties
Default properties are always local. There is no way to declare a default property for a foreign type as the default property is queried directly from the classinfo at runtime. Change-Id: I30efb6fba190957ac2a4ad86da437f209cd1f3ad Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
parent
ecd54e68b9
commit
1b93a1d865
|
@ -113,7 +113,7 @@ void QmlTypesClassDescription::collectLocalAnonymous(
|
||||||
for (const QJsonValue &classInfo : classInfos) {
|
for (const QJsonValue &classInfo : classInfos) {
|
||||||
const QJsonObject obj = classInfo.toObject();
|
const QJsonObject obj = classInfo.toObject();
|
||||||
if (obj[QStringLiteral("name")].toString() == QStringLiteral("DefaultProperty"))
|
if (obj[QStringLiteral("name")].toString() == QStringLiteral("DefaultProperty"))
|
||||||
defaultProp = obj[obj[QStringLiteral("value")].toString()].toString();
|
defaultProp = obj[QStringLiteral("value")].toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
collectInterfaces(classDef);
|
collectInterfaces(classDef);
|
||||||
|
@ -129,6 +129,7 @@ void QmlTypesClassDescription::collect(
|
||||||
|
|
||||||
const auto classInfos = classDef->value(QLatin1String("classInfos")).toArray();
|
const auto classInfos = classDef->value(QLatin1String("classInfos")).toArray();
|
||||||
const QString classDefName = classDef->value(QLatin1String("className")).toString();
|
const QString classDefName = classDef->value(QLatin1String("className")).toString();
|
||||||
|
QString foreignTypeName;
|
||||||
for (const QJsonValue &classInfo : classInfos) {
|
for (const QJsonValue &classInfo : classInfos) {
|
||||||
const QJsonObject obj = classInfo.toObject();
|
const QJsonObject obj = classInfo.toObject();
|
||||||
const QString name = obj[QLatin1String("name")].toString();
|
const QString name = obj[QLatin1String("name")].toString();
|
||||||
|
@ -173,36 +174,44 @@ void QmlTypesClassDescription::collect(
|
||||||
if (value == QLatin1String("true"))
|
if (value == QLatin1String("true"))
|
||||||
isSingleton = true;
|
isSingleton = true;
|
||||||
} else if (name == QLatin1String("QML.Foreign")) {
|
} else if (name == QLatin1String("QML.Foreign")) {
|
||||||
if (const QJsonObject *other = findType(foreign, value)) {
|
foreignTypeName = value;
|
||||||
classDef = other;
|
|
||||||
// Foreign type can have a default property or an attached types
|
|
||||||
const auto classInfos = classDef->value(QLatin1String("classInfos")).toArray();
|
|
||||||
for (const QJsonValue &classInfo : classInfos) {
|
|
||||||
const QJsonObject obj = classInfo.toObject();
|
|
||||||
const QString foreignName = obj[QLatin1String("name")].toString();
|
|
||||||
const QString foreignValue = obj[QLatin1String("value")].toString();
|
|
||||||
if (defaultProp.isEmpty() && foreignName == QLatin1String("DefaultProperty")) {
|
|
||||||
defaultProp = foreignValue;
|
|
||||||
} else if (foreignName == QLatin1String("QML.Attached")) {
|
|
||||||
attachedType = foreignValue;
|
|
||||||
collectRelated(foreignValue, types, foreign, defaultRevision);
|
|
||||||
} else if (foreignName == QLatin1String("QML.Extended")) {
|
|
||||||
extensionType = foreignValue;
|
|
||||||
collectRelated(foreignValue, types, foreign, defaultRevision);
|
|
||||||
} else if (foreignName == QLatin1String("QML.Sequence")) {
|
|
||||||
sequenceValueType = foreignValue;
|
|
||||||
collectRelated(foreignValue, types, foreign, defaultRevision);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
className = value;
|
|
||||||
classDef = nullptr;
|
|
||||||
}
|
|
||||||
} else if (name == QLatin1String("QML.Root")) {
|
} else if (name == QLatin1String("QML.Root")) {
|
||||||
isRootClass = true;
|
isRootClass = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!foreignTypeName.isEmpty()) {
|
||||||
|
if (const QJsonObject *other = findType(foreign, foreignTypeName)) {
|
||||||
|
classDef = other;
|
||||||
|
|
||||||
|
// Default properties are always local.
|
||||||
|
defaultProp.clear();
|
||||||
|
|
||||||
|
// Foreign type can have a default property or an attached types
|
||||||
|
const auto classInfos = classDef->value(QLatin1String("classInfos")).toArray();
|
||||||
|
for (const QJsonValue &classInfo : classInfos) {
|
||||||
|
const QJsonObject obj = classInfo.toObject();
|
||||||
|
const QString foreignName = obj[QLatin1String("name")].toString();
|
||||||
|
const QString foreignValue = obj[QLatin1String("value")].toString();
|
||||||
|
if (defaultProp.isEmpty() && foreignName == QLatin1String("DefaultProperty")) {
|
||||||
|
defaultProp = foreignValue;
|
||||||
|
} else if (foreignName == QLatin1String("QML.Attached")) {
|
||||||
|
attachedType = foreignValue;
|
||||||
|
collectRelated(foreignValue, types, foreign, defaultRevision);
|
||||||
|
} else if (foreignName == QLatin1String("QML.Extended")) {
|
||||||
|
extensionType = foreignValue;
|
||||||
|
collectRelated(foreignValue, types, foreign, defaultRevision);
|
||||||
|
} else if (foreignName == QLatin1String("QML.Sequence")) {
|
||||||
|
sequenceValueType = foreignValue;
|
||||||
|
collectRelated(foreignValue, types, foreign, defaultRevision);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
className = foreignTypeName;
|
||||||
|
classDef = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (classDef) {
|
if (classDef) {
|
||||||
if (mode == RelatedType || !elementName.isEmpty()) {
|
if (mode == RelatedType || !elementName.isEmpty()) {
|
||||||
collectExtraVersions(classDef, QString::fromLatin1("properties"), revisions);
|
collectExtraVersions(classDef, QString::fromLatin1("properties"), revisions);
|
||||||
|
|
|
@ -171,4 +171,38 @@ void tst_qmltyperegistrar::multiExtensions()
|
||||||
QVERIFY(qmltypesData.contains("interfaces: [\"Interface3\"]"));
|
QVERIFY(qmltypesData.contains("interfaces: [\"Interface3\"]"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_qmltyperegistrar::localDefault()
|
||||||
|
{
|
||||||
|
QQmlEngine engine;
|
||||||
|
{
|
||||||
|
QQmlComponent c(&engine);
|
||||||
|
c.setData("import QmlTypeRegistrarTest\n"
|
||||||
|
"import QtQml\n"
|
||||||
|
"ForeignWithoutDefault { QtObject {} }", QUrl());
|
||||||
|
QVERIFY(c.isError());
|
||||||
|
QVERIFY(c.errorString().contains(
|
||||||
|
QStringLiteral("Cannot assign to non-existent default property")));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
QQmlComponent c(&engine);
|
||||||
|
c.setData("import QmlTypeRegistrarTest\n"
|
||||||
|
"import QtQml\n"
|
||||||
|
"Local { QtObject {} }", QUrl());
|
||||||
|
QVERIFY(c.isReady());
|
||||||
|
}
|
||||||
|
|
||||||
|
QCOMPARE(qmltypesData.count("name: \"LocalWithDefault\""), 1);
|
||||||
|
QCOMPARE(qmltypesData.count("name: \"ForeignWithoutDefault\""), 1);
|
||||||
|
QCOMPARE(qmltypesData.count("defaultProperty: \"d\""), 1);
|
||||||
|
|
||||||
|
const int local = qmltypesData.indexOf("name: \"LocalWithDefault\"");
|
||||||
|
const int foreign = qmltypesData.indexOf("name: \"ForeignWithoutDefault\"");
|
||||||
|
const int defaultProp = qmltypesData.indexOf("defaultProperty: \"d\"");
|
||||||
|
|
||||||
|
// We assume that name is emitted before defaultProperty.
|
||||||
|
// Then this proves that the default property does not belong to ForeignWithoutDefault.
|
||||||
|
QVERIFY(local < defaultProp);
|
||||||
|
QVERIFY(foreign > defaultProp || foreign < local);
|
||||||
|
}
|
||||||
|
|
||||||
QTEST_MAIN(tst_qmltyperegistrar)
|
QTEST_MAIN(tst_qmltyperegistrar)
|
||||||
|
|
|
@ -116,11 +116,61 @@ public:
|
||||||
void setWidth(int width) { v.setWidth(width); }
|
void setWidth(int width) { v.setWidth(width); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ForeignWithoutDefault : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(QObject *d READ d WRITE setD NOTIFY dChanged)
|
||||||
|
public:
|
||||||
|
QObject *d() const { return m_d; }
|
||||||
|
|
||||||
|
void setD(QObject *d)
|
||||||
|
{
|
||||||
|
if (m_d != d) {
|
||||||
|
m_d = d;
|
||||||
|
emit dChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void dChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QObject *m_d = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
class LocalWithDefault : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(QObject *d READ d WRITE setD NOTIFY dChanged)
|
||||||
|
QML_NAMED_ELEMENT(ForeignWithoutDefault)
|
||||||
|
QML_FOREIGN(ForeignWithoutDefault)
|
||||||
|
Q_CLASSINFO("DefaultProperty", "d")
|
||||||
|
|
||||||
|
public:
|
||||||
|
LocalWithDefault(QObject *parent = nullptr) : QObject(parent) {}
|
||||||
|
QObject *d() const { return m_d; }
|
||||||
|
|
||||||
|
void setD(QObject *d)
|
||||||
|
{
|
||||||
|
if (m_d != d) {
|
||||||
|
m_d = d;
|
||||||
|
emit dChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void dChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QObject *m_d = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
class Local : public Foreign
|
class Local : public Foreign
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
QML_ELEMENT
|
QML_ELEMENT
|
||||||
Q_PROPERTY(int someProperty MEMBER someProperty BINDABLE bindableSomeProperty)
|
Q_PROPERTY(int someProperty MEMBER someProperty BINDABLE bindableSomeProperty)
|
||||||
|
QML_EXTENDED(LocalWithDefault)
|
||||||
public:
|
public:
|
||||||
enum Flag {
|
enum Flag {
|
||||||
Flag1 = 0x1,
|
Flag1 = 0x1,
|
||||||
|
@ -216,6 +266,7 @@ private slots:
|
||||||
void derivedFromForeign();
|
void derivedFromForeign();
|
||||||
void metaTypesRegistered();
|
void metaTypesRegistered();
|
||||||
void multiExtensions();
|
void multiExtensions();
|
||||||
|
void localDefault();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QByteArray qmltypesData;
|
QByteArray qmltypesData;
|
||||||
|
|
Loading…
Reference in New Issue