Commit 37cd29b2 authored by Michael Brasser's avatar Michael Brasser Committed by Qt by Nokia

Support (registered) non-local enums for signal/slot params in QML.

It's now possible to detect whether a registered type is an enum,
allowing registered non-local enums to be used as parameters in
signals and slots from QML/C++.

Author: Glenn Watson <glenn.watson@nokia.com>
Task-number: QTBUG-20639
Change-Id: I8c439f2dcc7bfd8ec31914b0c86cd3a1de3c038c
Reviewed-by: 's avatarChris Adams <christopher.adams@nokia.com>
Reviewed-by: 's avatarMartin Jones <martin.jones@nokia.com>
parent fd802851
......@@ -227,7 +227,10 @@ QQmlBoundSignalParameters::QQmlBoundSignalParameters(const QMetaMethod &method,
prop.setWritable(false);
} else {
QByteArray propType = type;
if (t >= QVariant::UserType || t == QVariant::Invalid) {
if ((QMetaType::typeFlags(t) & QMetaType::IsEnumeration) == QMetaType::IsEnumeration) {
t = QVariant::Int;
propType = "int";
} else if (t == QVariant::Invalid) {
QByteArray scope;
QByteArray name;
int scopeIdx = propType.lastIndexOf("::");
......
......@@ -734,7 +734,9 @@ int *QQmlPropertyCache::methodParameterTypes(QObject *object, int index,
for (int ii = 0; ii < argTypeNames.count(); ++ii) {
int type = QMetaType::type(argTypeNames.at(ii));
if (type == QVariant::Invalid)
if ((QMetaType::typeFlags(type) & QMetaType::IsEnumeration) == QMetaType::IsEnumeration)
type = QVariant::Int;
else if (type == QVariant::Invalid)
type = EnumType(object->metaObject(), argTypeNames.at(ii));
if (type == QVariant::Invalid) {
if (unknownTypeError) *unknownTypeError = argTypeNames.at(ii);
......@@ -757,7 +759,9 @@ int *QQmlPropertyCache::methodParameterTypes(QObject *object, int index,
for (int ii = 0; ii < argTypeNames.count(); ++ii) {
int type = QMetaType::type(argTypeNames.at(ii));
if (type == QVariant::Invalid)
if ((QMetaType::typeFlags(type) & QMetaType::IsEnumeration) == QMetaType::IsEnumeration)
type = QVariant::Int;
else if (type == QVariant::Invalid)
type = EnumType(object->metaObject(), argTypeNames.at(ii));
if (type == QVariant::Invalid) {
if (unknownTypeError) *unknownTypeError = argTypeNames.at(ii);
......
......@@ -196,7 +196,7 @@ void registerTypes()
qmlRegisterModuleApi("Qt.test.qobjectApi",2,0,qobject_api); // register (qobject) module API for a uri which doesn't contain elements, major version set
qmlRegisterModuleApi("Qt.test.qobjectApiParented",1,0,qobject_api_engine_parent); // register (parented qobject) module API for a uri which doesn't contain elements
qRegisterMetaType<MyQmlObject::MyType>("MyEnum2");
qRegisterMetaType<MyQmlObject::MyEnum2>("MyEnum2");
qRegisterMetaType<Qt::MouseButtons>("Qt::MouseButtons");
qmlRegisterType<CircularReferenceObject>("Qt.test", 1, 0, "CircularReferenceObject");
......
import QtQuick 2.0
import Test 1.0
Item {
MyEnum1Class {
id: enum1Class
objectName: "enum1Class"
}
MyEnumDerivedClass {
id: enumDerivedClass
objectName: "enumDerivedClass"
onValueAChanged: {
aValue = newValue;
}
onValueBChanged: {
bValue = newValue;
}
property int aValue: 0
property int bValue: 0
}
function setEnumValues() {
enum1Class.setValue(MyEnum1Class.A_13);
enumDerivedClass.setValueA(MyEnum1Class.A_11);
enumDerivedClass.setValueB(MyEnum2Class.B_37);
}
}
......@@ -77,6 +77,10 @@ void registerTypes()
qmlRegisterType<MyVersion2Class>("Test.VersionOrder", 2,0, "MyQmlObject");
qmlRegisterType<MyQmlObject>("Test.VersionOrder", 1,0, "MyQmlObject");
qmlRegisterType<MyEnum1Class>("Test",1,0,"MyEnum1Class");
qmlRegisterType<MyEnum2Class>("Test",1,0,"MyEnum2Class");
qmlRegisterType<MyEnumDerivedClass>("Test",1,0,"MyEnumDerivedClass");
}
QVariant myCustomVariantTypeConverter(const QString &data)
......@@ -85,4 +89,3 @@ QVariant myCustomVariantTypeConverter(const QString &data)
rv.a = data.toInt();
return QVariant::fromValue(rv);
}
......@@ -811,14 +811,76 @@ class MyVersion2Class : public QObject
Q_OBJECT
};
class MyEnum1Class : public QObject
{
Q_OBJECT
Q_ENUMS(EnumA)
public:
MyEnum1Class() : value(A_Invalid) {}
enum EnumA
{
A_Invalid = -1,
A_11 = 11,
A_13 = 13
};
Q_INVOKABLE void setValue(EnumA v) { value = v; }
EnumA getValue() { return value; }
private:
EnumA value;
};
class MyEnum2Class : public QObject
{
Q_OBJECT
Q_ENUMS(EnumB)
public:
MyEnum2Class() : valueA(MyEnum1Class::A_Invalid), valueB(B_Invalid) {}
enum EnumB
{
B_Invalid = -1,
B_29 = 29,
B_31 = 31,
B_37 = 37
};
MyEnum1Class::EnumA getValueA() { return valueA; }
EnumB getValueB() { return valueB; }
Q_INVOKABLE void setValueA(MyEnum1Class::EnumA v) { valueA = v; emit valueAChanged(v); }
Q_INVOKABLE void setValueB(EnumB v) { valueB = v; emit valueBChanged(v); }
signals:
void valueAChanged(MyEnum1Class::EnumA newValue);
void valueBChanged(MyEnum2Class::EnumB newValue);
private:
MyEnum1Class::EnumA valueA;
EnumB valueB;
};
class MyEnumDerivedClass : public MyEnum2Class
{
Q_OBJECT
};
Q_DECLARE_METATYPE(MyEnum2Class::EnumB)
Q_DECLARE_METATYPE(MyEnum1Class::EnumA)
QML_DECLARE_TYPE(MyRevisionedBaseClassRegistered)
QML_DECLARE_TYPE(MyRevisionedBaseClassUnregistered)
QML_DECLARE_TYPE(MyRevisionedClass)
QML_DECLARE_TYPE(MyRevisionedSubclass)
QML_DECLARE_TYPE(MySubclass)
void registerTypes();
#endif // TESTTYPES_H
......@@ -46,6 +46,7 @@
#include <QtCore/qdebug.h>
#include <QtCore/qfileinfo.h>
#include <QtCore/qdir.h>
#include <QSignalSpy>
#include <private/qqmlproperty_p.h>
#include <private/qqmlmetatype_p.h>
......@@ -176,6 +177,8 @@ private slots:
void crash1();
void crash2();
void globalEnums();
private:
QQmlEngine engine;
void testType(const QString& qml, const QString& type, const QString& error);
......@@ -2285,6 +2288,47 @@ void tst_qqmllanguage::remoteLoadCrash()
delete o;
}
// QTBUG-20639
void tst_qqmllanguage::globalEnums()
{
qRegisterMetaType<MyEnum1Class::EnumA>();
qRegisterMetaType<MyEnum2Class::EnumB>();
QQmlComponent component(&engine, TEST_FILE("globalEnums.qml"));
QObject *o = component.create();
QVERIFY(o != 0);
MyEnum1Class *enum1Class = o->findChild<MyEnum1Class *>(QString::fromLatin1("enum1Class"));
QVERIFY(enum1Class != 0);
QVERIFY(enum1Class->getValue() == -1);
MyEnumDerivedClass *enum2Class = o->findChild<MyEnumDerivedClass *>(QString::fromLatin1("enumDerivedClass"));
QVERIFY(enum2Class != 0);
QVERIFY(enum2Class->getValueA() == -1);
QVERIFY(enum2Class->getValueB() == -1);
QVERIFY(enum2Class->property("aValue") == 0);
QVERIFY(enum2Class->property("bValue") == 0);
QSignalSpy signalA(enum2Class, SIGNAL(valueAChanged(MyEnum1Class::EnumA)));
QSignalSpy signalB(enum2Class, SIGNAL(valueBChanged(MyEnum2Class::EnumB)));
QMetaObject::invokeMethod(o, "setEnumValues");
QVERIFY(enum1Class->getValue() == MyEnum1Class::A_13);
QVERIFY(enum2Class->getValueA() == MyEnum1Class::A_11);
QVERIFY(enum2Class->getValueB() == MyEnum2Class::B_37);
QVERIFY(signalA.count() == 1);
QVERIFY(signalB.count() == 1);
QVERIFY(enum2Class->property("aValue") == MyEnum1Class::A_11);
QVERIFY(enum2Class->property("bValue") == 37);
delete o;
}
QTEST_MAIN(tst_qqmllanguage)
#include "tst_qqmllanguage.moc"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment