aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJ-P Nurmi <jpnurmi@theqtcompany.com>2015-09-14 21:23:32 +0200
committerJ-P Nurmi <jpnurmi@theqtcompany.com>2015-09-21 19:59:27 +0000
commitb7738beda651c2927e1a9d58c592148b1dc99576 (patch)
tree55d62516410088f22885ff551d57fff5ae50a5bc
parentba7edffda3f360955825c3ef886ec232c0b2022b (diff)
Make QML composite types inherit enums
Problem: in Qt Quick Controls 2, enums declared in the abstract C++ base types were not accessible with the concrete QML type name, but had to be referenced using the base type name: Slider { snapMode: AbstractSlider.SnapOnRelease } Solution: this change resolves the C++ base type and creates the missing link between the composite type and its base type's meta- object. This allows referencing enums using the concrete/composite QML type name: Slider { snapMode: Slider.SnapOnRelease } Change-Id: Icefdec91b012b12728367fd54b4d16796233ee12 Task-number: QTBUG-43582 Reviewed-by: Simon Hausmann <simon.hausmann@theqtcompany.com>
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp2
-rw-r--r--src/qml/compiler/qqmltypecompiler.cpp10
-rw-r--r--src/qml/compiler/qqmltypecompiler_p.h1
-rw-r--r--src/qml/qml/qqmlcustomparser.cpp2
-rw-r--r--src/qml/qml/qqmlcustomparser_p.h6
-rw-r--r--src/qml/qml/qqmlmetatype.cpp30
-rw-r--r--src/qml/qml/qqmlmetatype_p.h8
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp2
-rw-r--r--src/qml/qml/qqmltypewrapper.cpp2
-rw-r--r--tests/auto/qml/qqmllanguage/data/CompositeTypeWithEnum.qml4
-rw-r--r--tests/auto/qml/qqmllanguage/data/registeredCompositeTypeWithEnum.qml6
-rw-r--r--tests/auto/qml/qqmllanguage/testtypes.cpp2
-rw-r--r--tests/auto/qml/qqmllanguage/testtypes.h11
-rw-r--r--tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp17
14 files changed, 88 insertions, 15 deletions
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp
index 4b1e3601dc..7b0d4240c4 100644
--- a/src/qml/compiler/qqmlirbuilder.cpp
+++ b/src/qml/compiler/qqmlirbuilder.cpp
@@ -1590,7 +1590,7 @@ static QV4::IR::Type resolveQmlType(QQmlEnginePrivate *qmlEngine, QV4::IR::Membe
if (member->name->constData()->isUpper()) {
bool ok = false;
- int value = type->enumValue(*member->name, &ok);
+ int value = type->enumValue(qmlEngine, *member->name, &ok);
if (ok) {
member->setEnumValue(value);
resolver->clear();
diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp
index 7f62446c22..e36ba76326 100644
--- a/src/qml/compiler/qqmltypecompiler.cpp
+++ b/src/qml/compiler/qqmltypecompiler.cpp
@@ -1163,8 +1163,6 @@ bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj,
if (!type && typeName != QLatin1String("Qt"))
return true;
- if (type && type->isComposite()) //No enums on composite (or composite singleton) types
- return true;
int value = 0;
bool ok = false;
@@ -1182,7 +1180,7 @@ bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj,
} else {
// Otherwise we have to search the whole type
if (type) {
- value = type->enumValue(QHashedStringRef(enumValue), &ok);
+ value = type->enumValue(compiler->enginePrivate(), QHashedStringRef(enumValue), &ok);
} else {
QByteArray enumName = enumValue.toUtf8();
const QMetaObject *metaObject = StaticQtMetaObject::get();
@@ -1210,7 +1208,9 @@ int QQmlEnumTypeResolver::evaluateEnum(const QString &scope, const QByteArray &e
if (scope != QLatin1String("Qt")) {
QQmlType *type = 0;
imports->resolveType(scope, &type, 0, 0, 0);
- return type ? type->enumValue(QHashedCStringRef(enumValue.constData(), enumValue.length()), ok) : -1;
+ if (!type)
+ return -1;
+ return type ? type->enumValue(compiler->enginePrivate(), QHashedCStringRef(enumValue.constData(), enumValue.length()), ok) : -1;
}
const QMetaObject *mo = StaticQtMetaObject::get();
@@ -1988,9 +1988,11 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD
if (customParser && !customBindings.isEmpty()) {
customParser->clearErrors();
customParser->validator = this;
+ customParser->engine = enginePrivate;
customParser->imports = compiler->imports();
customParser->verifyBindings(qmlUnit, customBindings);
customParser->validator = 0;
+ customParser->engine = 0;
customParser->imports = (QQmlImports*)0;
customParserBindingsPerObject->insert(objectIndex, customParserBindings);
const QList<QQmlError> parserErrors = customParser->errors();
diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h
index cbc68280b7..09ef7aad67 100644
--- a/src/qml/compiler/qqmltypecompiler_p.h
+++ b/src/qml/compiler/qqmltypecompiler_p.h
@@ -273,6 +273,7 @@ public:
bool validate();
const QQmlImports &imports() const;
+ QQmlEnginePrivate *engine() const { return enginePrivate; }
private:
bool validateObject(int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding, bool populatingValueTypeGroupProperty = false) const;
diff --git a/src/qml/qml/qqmlcustomparser.cpp b/src/qml/qml/qqmlcustomparser.cpp
index ec88ee015a..517f8d42ed 100644
--- a/src/qml/qml/qqmlcustomparser.cpp
+++ b/src/qml/qml/qqmlcustomparser.cpp
@@ -141,7 +141,7 @@ int QQmlCustomParser::evaluateEnum(const QByteArray& script, bool *ok) const
type = result.type;
}
- return type ? type->enumValue(QHashedCStringRef(enumValue.constData(), enumValue.length()), ok) : -1;
+ return type ? type->enumValue(engine, QHashedCStringRef(enumValue.constData(), enumValue.length()), ok) : -1;
}
const QMetaObject *mo = StaticQtMetaObject::get();
diff --git a/src/qml/qml/qqmlcustomparser_p.h b/src/qml/qml/qqmlcustomparser_p.h
index dd461ba299..8bdc73fab1 100644
--- a/src/qml/qml/qqmlcustomparser_p.h
+++ b/src/qml/qml/qqmlcustomparser_p.h
@@ -56,6 +56,7 @@ QT_BEGIN_NAMESPACE
class QQmlCompiledData;
class QQmlPropertyValidator;
+class QQmlEnginePrivate;
class Q_QML_PRIVATE_EXPORT QQmlCustomParser
{
@@ -67,8 +68,8 @@ public:
};
Q_DECLARE_FLAGS(Flags, Flag)
- QQmlCustomParser() : validator(0), m_flags(NoFlag) {}
- QQmlCustomParser(Flags f) : validator(0), m_flags(f) {}
+ QQmlCustomParser() : engine(0), validator(0), m_flags(NoFlag) {}
+ QQmlCustomParser(Flags f) : engine(0), validator(0), m_flags(f) {}
virtual ~QQmlCustomParser() {}
void clearErrors();
@@ -92,6 +93,7 @@ protected:
private:
QList<QQmlError> exceptions;
+ QQmlEnginePrivate *engine;
const QQmlPropertyValidator *validator;
Flags m_flags;
QBiPointer<const QQmlImports, QQmlTypeNameCache> imports;
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index f0debb8e59..b173bc8bec 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -38,6 +38,7 @@
#include <private/qqmlcustomparser_p.h>
#include <private/qhashedstring_p.h>
#include <private/qqmlimport_p.h>
+#include <private/qqmlcompiler_p.h>
#include <QtCore/qdebug.h>
#include <QtCore/qstringlist.h>
@@ -473,6 +474,23 @@ QQmlType *QQmlType::superType() const
return d->superType;
}
+int QQmlType::resolveCompositeEnumValue(QQmlEnginePrivate *engine, const QString &name, bool *ok) const
+{
+ Q_ASSERT(isComposite());
+ *ok = false;
+ if (!engine)
+ return -1;
+ QQmlTypeData *td = engine->typeLoader.getType(sourceUrl());
+ if (!td || !td->isComplete())
+ return -1;
+ QQmlCompiledData *cd = td->compiledData();
+ const QMetaObject *mo = cd->rootPropertyCache->firstCppMetaObject();
+ QQmlType *type = QQmlMetaType::qmlType(mo);
+ if (!type)
+ return -1;
+ return type->enumValue(engine, name, ok);
+}
+
static void clone(QMetaObjectBuilder &builder, const QMetaObject *mo,
const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd)
{
@@ -907,9 +925,11 @@ QUrl QQmlType::sourceUrl() const
return QUrl();
}
-int QQmlType::enumValue(const QHashedStringRef &name, bool *ok) const
+int QQmlType::enumValue(QQmlEnginePrivate *engine, const QHashedStringRef &name, bool *ok) const
{
Q_ASSERT(ok);
+ if (isComposite())
+ return resolveCompositeEnumValue(engine, name.toString(), ok);
*ok = true;
d->initEnums();
@@ -922,9 +942,11 @@ int QQmlType::enumValue(const QHashedStringRef &name, bool *ok) const
return -1;
}
-int QQmlType::enumValue(const QHashedCStringRef &name, bool *ok) const
+int QQmlType::enumValue(QQmlEnginePrivate *engine, const QHashedCStringRef &name, bool *ok) const
{
Q_ASSERT(ok);
+ if (isComposite())
+ return resolveCompositeEnumValue(engine, name.toUtf16(), ok);
*ok = true;
d->initEnums();
@@ -937,9 +959,11 @@ int QQmlType::enumValue(const QHashedCStringRef &name, bool *ok) const
return -1;
}
-int QQmlType::enumValue(const QV4::String *name, bool *ok) const
+int QQmlType::enumValue(QQmlEnginePrivate *engine, const QV4::String *name, bool *ok) const
{
Q_ASSERT(ok);
+ if (isComposite())
+ return resolveCompositeEnumValue(engine, name->toQString(), ok);
*ok = true;
d->initEnums();
diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h
index 61a6567f1d..08f19bcf09 100644
--- a/src/qml/qml/qqmlmetatype_p.h
+++ b/src/qml/qml/qqmlmetatype_p.h
@@ -57,6 +57,7 @@ QT_BEGIN_NAMESPACE
class QQmlType;
class QQmlEngine;
+class QQmlEnginePrivate;
class QQmlCustomParser;
class QQmlTypePrivate;
class QQmlTypeModule;
@@ -204,11 +205,12 @@ public:
QUrl sourceUrl() const;
- int enumValue(const QHashedStringRef &, bool *ok) const;
- int enumValue(const QHashedCStringRef &, bool *ok) const;
- int enumValue(const QV4::String *, bool *ok) const;
+ int enumValue(QQmlEnginePrivate *engine, const QHashedStringRef &, bool *ok) const;
+ int enumValue(QQmlEnginePrivate *engine, const QHashedCStringRef &, bool *ok) const;
+ int enumValue(QQmlEnginePrivate *engine, const QV4::String *, bool *ok) const;
private:
QQmlType *superType() const;
+ int resolveCompositeEnumValue(QQmlEnginePrivate *engine, const QString &name, bool *ok) const;
friend class QQmlTypePrivate;
friend struct QQmlMetaTypeData;
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index f371a369a1..171fa048ce 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -1101,6 +1101,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
if (customParser) {
QHash<int, QBitArray>::ConstIterator customParserBindings = compiledData->customParserBindings.constFind(index);
if (customParserBindings != compiledData->customParserBindings.constEnd()) {
+ customParser->engine = QQmlEnginePrivate::get(engine);
customParser->imports = compiledData->importCache;
QList<const QV4::CompiledData::Binding *> bindings;
@@ -1110,6 +1111,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
bindings << obj->bindingTable() + i;
customParser->applyBindings(instance, compiledData, bindings);
+ customParser->engine = 0;
customParser->imports = (QQmlTypeNameCache*)0;
bindingsToSkip = *customParserBindings;
}
diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp
index 1d72b2da0d..1145f1b64f 100644
--- a/src/qml/qml/qqmltypewrapper.cpp
+++ b/src/qml/qml/qqmltypewrapper.cpp
@@ -182,7 +182,7 @@ ReturnedValue QmlTypeWrapper::get(const Managed *m, String *name, bool *hasPrope
if (name->startsWithUpper()) {
bool ok = false;
- int value = type->enumValue(name, &ok);
+ int value = type->enumValue(QQmlEnginePrivate::get(v4->qmlEngine()), name, &ok);
if (ok)
return QV4::Primitive::fromInt32(value).asReturnedValue();
diff --git a/tests/auto/qml/qqmllanguage/data/CompositeTypeWithEnum.qml b/tests/auto/qml/qqmllanguage/data/CompositeTypeWithEnum.qml
new file mode 100644
index 0000000000..6a14e72a31
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/CompositeTypeWithEnum.qml
@@ -0,0 +1,4 @@
+import Test 1.0
+
+MyCompositeBaseType {
+}
diff --git a/tests/auto/qml/qqmllanguage/data/registeredCompositeTypeWithEnum.qml b/tests/auto/qml/qqmllanguage/data/registeredCompositeTypeWithEnum.qml
new file mode 100644
index 0000000000..5f8c11e5f6
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/registeredCompositeTypeWithEnum.qml
@@ -0,0 +1,6 @@
+import Test 1.0
+
+RegisteredCompositeTypeWithEnum {
+ property int enumValue0: RegisteredCompositeTypeWithEnum.EnumValue0
+ property int enumValue42: RegisteredCompositeTypeWithEnum.EnumValue42
+}
diff --git a/tests/auto/qml/qqmllanguage/testtypes.cpp b/tests/auto/qml/qqmllanguage/testtypes.cpp
index 0b44daca30..95a98788c3 100644
--- a/tests/auto/qml/qqmllanguage/testtypes.cpp
+++ b/tests/auto/qml/qqmllanguage/testtypes.cpp
@@ -91,6 +91,8 @@ void registerTypes()
qmlRegisterCustomExtendedType<SimpleObjectWithCustomParser, SimpleObjectExtension>("Test", 1, 0, "SimpleExtendedObjectWithCustomParser", new SimpleObjectCustomParser);
qmlRegisterType<RootObjectInCreationTester>("Test", 1, 0, "RootObjectInCreationTester");
+
+ qmlRegisterType<MyCompositeBaseType>("Test", 1, 0, "MyCompositeBaseType");
}
QVariant myCustomVariantTypeConverter(const QString &data)
diff --git a/tests/auto/qml/qqmllanguage/testtypes.h b/tests/auto/qml/qqmllanguage/testtypes.h
index b8792a892f..985acc2539 100644
--- a/tests/auto/qml/qqmllanguage/testtypes.h
+++ b/tests/auto/qml/qqmllanguage/testtypes.h
@@ -1079,9 +1079,19 @@ class MyEnumDerivedClass : public MyEnum2Class
Q_OBJECT
};
+class MyCompositeBaseType : public QObject
+{
+ Q_OBJECT
+ Q_ENUMS(CompositeEnum)
+
+public:
+ enum CompositeEnum { EnumValue0, EnumValue42 = 42 };
+};
+
Q_DECLARE_METATYPE(MyEnum2Class::EnumB)
Q_DECLARE_METATYPE(MyEnum1Class::EnumA)
Q_DECLARE_METATYPE(Qt::TextFormat)
+Q_DECLARE_METATYPE(MyCompositeBaseType::CompositeEnum)
QML_DECLARE_TYPE(MyRevisionedBaseClassRegistered)
QML_DECLARE_TYPE(MyRevisionedBaseClassUnregistered)
@@ -1089,6 +1099,7 @@ QML_DECLARE_TYPE(MyRevisionedClass)
QML_DECLARE_TYPE(MyRevisionedSubclass)
QML_DECLARE_TYPE(MySubclass)
QML_DECLARE_TYPE(MyReceiversTestObject)
+QML_DECLARE_TYPE(MyCompositeBaseType)
class CustomBinding : public QObject, public QQmlParserStatus
{
diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
index 97501118dd..b48f3640f4 100644
--- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
+++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
@@ -159,6 +159,7 @@ private slots:
void readonlyObjectProperties();
void receivers();
void registeredCompositeType();
+ void registeredCompositeTypeWithEnum();
void implicitImportsLast();
void basicRemote_data();
@@ -3174,6 +3175,7 @@ void tst_qqmllanguage::initTestCase()
qmlRegisterType(testFileUrl("CompositeType.qml"), "Test", 1, 0, "RegisteredCompositeType");
qmlRegisterType(testFileUrl("CompositeType.DoesNotExist.qml"), "Test", 1, 0, "RegisteredCompositeType2");
qmlRegisterType(testFileUrl("invalidRoot.1.qml"), "Test", 1, 0, "RegisteredCompositeType3");
+ qmlRegisterType(testFileUrl("CompositeTypeWithEnum.qml"), "Test", 1, 0, "RegisteredCompositeTypeWithEnum");
// Registering the TestType class in other modules should have no adverse effects
qmlRegisterType<TestType>("org.qtproject.TestPre", 1, 0, "Test");
@@ -3350,6 +3352,21 @@ void tst_qqmllanguage::registeredCompositeType()
delete o;
}
+// QTBUG-43582
+void tst_qqmllanguage::registeredCompositeTypeWithEnum()
+{
+ QQmlComponent component(&engine, testFileUrl("registeredCompositeTypeWithEnum.qml"));
+
+ VERIFY_ERRORS(0);
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+
+ QCOMPARE(o->property("enumValue0").toInt(), static_cast<int>(MyCompositeBaseType::EnumValue0));
+ QCOMPARE(o->property("enumValue42").toInt(), static_cast<int>(MyCompositeBaseType::EnumValue42));
+
+ delete o;
+}
+
// QTBUG-18268
void tst_qqmllanguage::remoteLoadCrash()
{