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>
This commit is contained in:
parent
ba7edffda3
commit
b7738beda6
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
import Test 1.0
|
||||
|
||||
MyCompositeBaseType {
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
import Test 1.0
|
||||
|
||||
RegisteredCompositeTypeWithEnum {
|
||||
property int enumValue0: RegisteredCompositeTypeWithEnum.EnumValue0
|
||||
property int enumValue42: RegisteredCompositeTypeWithEnum.EnumValue42
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue