diff options
author | Michael Brasser <mbrasser@ford.com> | 2017-04-13 17:10:45 -0500 |
---|---|---|
committer | Michael Brasser <michael.brasser@live.com> | 2017-05-03 11:38:21 +0000 |
commit | aae18aa05719c4b750905f467f42002f4cea1516 (patch) | |
tree | 167e75ae3aa157b47fccd75266ba40aa0325b63a /src/qml/qml | |
parent | f7656d06c0d2095a8d8dd3b930e48dc98996634f (diff) |
C++11 scoped enum support for QML
[ChangeLog][QtQml] Support C++11 scoped enums in QML. These can now be
accessed as <TypeName>.<EnumName>.<EnumValue>
Change-Id: I29bd3f16e980f3e6f1b2390b5a8e9e8e999952a3
Task-number: QTBUG-54961
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src/qml/qml')
-rw-r--r-- | src/qml/qml/qqmlcustomparser.cpp | 22 | ||||
-rw-r--r-- | src/qml/qml/qqmlmetatype.cpp | 191 | ||||
-rw-r--r-- | src/qml/qml/qqmlmetatype_p.h | 14 | ||||
-rw-r--r-- | src/qml/qml/qqmltypewrapper.cpp | 29 | ||||
-rw-r--r-- | src/qml/qml/qqmltypewrapper_p.h | 15 |
5 files changed, 265 insertions, 6 deletions
diff --git a/src/qml/qml/qqmlcustomparser.cpp b/src/qml/qml/qqmlcustomparser.cpp index 0b0bbef795..6ad641b8b1 100644 --- a/src/qml/qml/qqmlcustomparser.cpp +++ b/src/qml/qml/qqmlcustomparser.cpp @@ -121,13 +121,16 @@ int QQmlCustomParser::evaluateEnum(const QByteArray& script, bool *ok) const { Q_ASSERT_X(ok, "QQmlCustomParser::evaluateEnum", "ok must not be a null pointer"); *ok = false; + + // we support one or two '.' in the enum phrase: + // * <TypeName>.<EnumValue> + // * <TypeName>.<ScopedEnumName>.<EnumValue> + int dot = script.indexOf('.'); - if (dot == -1) + if (dot == -1 || dot == script.length()-1) return -1; - QString scope = QString::fromUtf8(script.left(dot)); - QByteArray enumValue = script.mid(dot+1); if (scope != QLatin1String("Qt")) { if (imports.isNull()) @@ -142,9 +145,20 @@ int QQmlCustomParser::evaluateEnum(const QByteArray& script, bool *ok) const type = result.type; } - return type ? type->enumValue(engine, QHashedCStringRef(enumValue.constData(), enumValue.length()), ok) : -1; + if (!type) + return -1; + + int dot2 = script.indexOf('.', dot+1); + const bool dot2Valid = dot2 != -1 && dot2 != script.length()-1; + QByteArray enumValue = script.mid(dot2Valid ? dot2 + 1 : dot + 1); + QByteArray scopedEnumName = (dot2Valid ? script.mid(dot + 1, dot2 - dot - 1) : QByteArray()); + if (!scopedEnumName.isEmpty()) + return type->scopedEnumValue(engine, scopedEnumName, enumValue, ok); + else + return type->enumValue(engine, QHashedCStringRef(enumValue.constData(), enumValue.length()), ok); } + QByteArray enumValue = script.mid(dot + 1); const QMetaObject *mo = StaticQtMetaObject::get(); int i = mo->enumeratorCount(); while (i--) { diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index bb9b69c479..0672618225 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -216,6 +216,8 @@ public: mutable bool haveSuperType:1; mutable QList<QQmlProxyMetaObject::ProxyData> metaObjects; mutable QStringHash<int> enums; + mutable QStringHash<int> scopedEnumIndex; // maps from enum name to index in scopedEnums + mutable QList<QStringHash<int>*> scopedEnums; static QHash<const QMetaObject *, int> attachedPropertyIds; }; @@ -313,6 +315,7 @@ QQmlTypePrivate::QQmlTypePrivate(QQmlType::RegistrationType type) QQmlTypePrivate::~QQmlTypePrivate() { + qDeleteAll(scopedEnums); switch (regType) { case QQmlType::CppType: delete extraData.cd->customParser; @@ -507,6 +510,67 @@ int QQmlType::resolveCompositeEnumValue(QQmlEnginePrivate *engine, const QString return type->enumValue(engine, name, ok); } +int QQmlType::resolveCompositeScopedEnumIndex(QQmlEnginePrivate *engine, const QV4::String *name, bool *ok) const +{ + Q_ASSERT(isComposite()); + *ok = false; + QQmlType *type = resolveCompositeBaseType(engine); + if (!type) + return -1; + return type->scopedEnumIndex(engine, name, ok); +} + +int QQmlType::resolveCompositeScopedEnumIndex(QQmlEnginePrivate *engine, const QString &name, bool *ok) const +{ + Q_ASSERT(isComposite()); + *ok = false; + QQmlType *type = resolveCompositeBaseType(engine); + if (!type) + return -1; + return type->scopedEnumIndex(engine, name, ok); +} + + +int QQmlType::resolveCompositeScopedEnumValue(QQmlEnginePrivate *engine, int index, const QV4::String *name, bool *ok) const +{ + Q_ASSERT(isComposite()); + *ok = false; + QQmlType *type = resolveCompositeBaseType(engine); + if (!type) + return -1; + return type->scopedEnumValue(engine, index, name, ok); +} + +int QQmlType::resolveCompositeScopedEnumValue(QQmlEnginePrivate *engine, int index, const QString &name, bool *ok) const +{ + Q_ASSERT(isComposite()); + *ok = false; + QQmlType *type = resolveCompositeBaseType(engine); + if (!type) + return -1; + return type->scopedEnumValue(engine, index, name, ok); +} + +int QQmlType::resolveCompositeScopedEnumValue(QQmlEnginePrivate *engine, const QByteArray &scopedName, const QByteArray &name, bool *ok) const +{ + Q_ASSERT(isComposite()); + *ok = false; + QQmlType *type = resolveCompositeBaseType(engine); + if (!type) + return -1; + return type->scopedEnumValue(engine, scopedName, name, ok); +} + +int QQmlType::resolveCompositeScopedEnumValue(QQmlEnginePrivate *engine, const QStringRef &scopedName, const QStringRef &name, bool *ok) const +{ + Q_ASSERT(isComposite()); + *ok = false; + QQmlType *type = resolveCompositeBaseType(engine); + if (!type) + return -1; + return type->scopedEnumValue(engine, scopedName, name, ok); +} + static void clone(QMetaObjectBuilder &builder, const QMetaObject *mo, const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd) { @@ -702,8 +766,21 @@ void QQmlTypePrivate::insertEnums(const QMetaObject *metaObject) const // Add any enum values defined by this class, overwriting any inherited values for (int ii = 0; ii < metaObject->enumeratorCount(); ++ii) { QMetaEnum e = metaObject->enumerator(ii); - for (int jj = 0; jj < e.keyCount(); ++jj) - enums.insert(QString::fromUtf8(e.key(jj)), e.value(jj)); + const bool isScoped = e.isScoped(); + QStringHash<int> *scoped = isScoped ? new QStringHash<int>() : 0; + + for (int jj = 0; jj < e.keyCount(); ++jj) { + const QString key = QString::fromUtf8(e.key(jj)); + const int value = e.value(jj); + enums.insert(key, value); + if (isScoped) + scoped->insert(key, value); + } + + if (isScoped) { + scopedEnums << scoped; + scopedEnumIndex.insert(QString::fromUtf8(e.name()), scopedEnums.count()-1); + } } } @@ -1004,6 +1081,116 @@ int QQmlType::enumValue(QQmlEnginePrivate *engine, const QV4::String *name, bool return -1; } +int QQmlType::scopedEnumIndex(QQmlEnginePrivate *engine, const QV4::String *name, bool *ok) const +{ + Q_ASSERT(ok); + if (isComposite()) + return resolveCompositeScopedEnumIndex(engine, name, ok); + *ok = true; + + d->initEnums(); + + int *rv = d->scopedEnumIndex.value(name); + if (rv) + return *rv; + + *ok = false; + return -1; +} + +int QQmlType::scopedEnumIndex(QQmlEnginePrivate *engine, const QString &name, bool *ok) const +{ + Q_ASSERT(ok); + if (isComposite()) + return resolveCompositeScopedEnumIndex(engine, name, ok); + *ok = true; + + d->initEnums(); + + int *rv = d->scopedEnumIndex.value(name); + if (rv) + return *rv; + + *ok = false; + return -1; +} + +int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, int index, const QV4::String *name, bool *ok) const +{ + Q_ASSERT(ok); + if (isComposite()) + return resolveCompositeScopedEnumValue(engine, index, name, ok); + *ok = true; + + Q_ASSERT(index > -1 && index < d->scopedEnums.count()); + int *rv = d->scopedEnums.at(index)->value(name); + if (rv) + return *rv; + + *ok = false; + return -1; +} + +int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, int index, const QString &name, bool *ok) const +{ + Q_ASSERT(ok); + if (isComposite()) + return resolveCompositeScopedEnumValue(engine, index, name, ok); + *ok = true; + + Q_ASSERT(index > -1 && index < d->scopedEnums.count()); + int *rv = d->scopedEnums.at(index)->value(name); + if (rv) + return *rv; + + *ok = false; + return -1; +} + +int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, const QByteArray &scopedEnumName, const QByteArray &name, bool *ok) const +{ + Q_ASSERT(ok); + if (isComposite()) + return resolveCompositeScopedEnumValue(engine, scopedEnumName, name, ok); + *ok = true; + + d->initEnums(); + + int *rv = d->scopedEnumIndex.value(QHashedCStringRef(scopedEnumName.constData(), scopedEnumName.length())); + if (rv) { + int index = *rv; + Q_ASSERT(index > -1 && index < d->scopedEnums.count()); + rv = d->scopedEnums.at(index)->value(QHashedCStringRef(name.constData(), name.length())); + if (rv) + return *rv; + } + + *ok = false; + return -1; +} + +int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, const QStringRef &scopedEnumName, const QStringRef &name, bool *ok) const +{ + Q_ASSERT(ok); + if (isComposite()) + return resolveCompositeScopedEnumValue(engine, scopedEnumName, name, ok); + *ok = true; + + d->initEnums(); + + int *rv = d->scopedEnumIndex.value(QHashedStringRef(scopedEnumName)); + if (rv) { + int index = *rv; + Q_ASSERT(index > -1 && index < d->scopedEnums.count()); + rv = d->scopedEnums.at(index)->value(QHashedStringRef(name)); + if (rv) + return *rv; + } + + *ok = false; + return -1; +} + QQmlTypeModule::QQmlTypeModule() : d(new QQmlTypeModulePrivate) { diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h index 2b615e645a..4dd28bbd36 100644 --- a/src/qml/qml/qqmlmetatype_p.h +++ b/src/qml/qml/qqmlmetatype_p.h @@ -216,10 +216,24 @@ public: 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; + + int scopedEnumIndex(QQmlEnginePrivate *engine, const QV4::String *, bool *ok) const; + int scopedEnumIndex(QQmlEnginePrivate *engine, const QString &, bool *ok) const; + int scopedEnumValue(QQmlEnginePrivate *engine, int index, const QV4::String *, bool *ok) const; + int scopedEnumValue(QQmlEnginePrivate *engine, int index, const QString &, bool *ok) const; + int scopedEnumValue(QQmlEnginePrivate *engine, const QByteArray &, const QByteArray &, bool *ok) const; + int scopedEnumValue(QQmlEnginePrivate *engine, const QStringRef &, const QStringRef &, bool *ok) const; + private: QQmlType *superType() const; QQmlType *resolveCompositeBaseType(QQmlEnginePrivate *engine) const; int resolveCompositeEnumValue(QQmlEnginePrivate *engine, const QString &name, bool *ok) const; + int resolveCompositeScopedEnumIndex(QQmlEnginePrivate *engine, const QV4::String *, bool *ok) const; + int resolveCompositeScopedEnumIndex(QQmlEnginePrivate *engine, const QString &name, bool *ok) const; + int resolveCompositeScopedEnumValue(QQmlEnginePrivate *engine, int index, const QV4::String *, bool *ok) const; + int resolveCompositeScopedEnumValue(QQmlEnginePrivate *engine, int index, const QString &name, bool *ok) const; + int resolveCompositeScopedEnumValue(QQmlEnginePrivate *engine, const QByteArray &scopedName, const QByteArray &name, bool *ok) const; + int resolveCompositeScopedEnumValue(QQmlEnginePrivate *engine, const QStringRef &scopedName, const QStringRef &name, bool *ok) const; friend class QQmlTypePrivate; friend struct QQmlMetaTypeData; diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp index 7b98096a7f..bf68b1ed4b 100644 --- a/src/qml/qml/qqmltypewrapper.cpp +++ b/src/qml/qml/qqmltypewrapper.cpp @@ -53,6 +53,7 @@ QT_BEGIN_NAMESPACE using namespace QV4; DEFINE_OBJECT_VTABLE(QmlTypeWrapper); +DEFINE_OBJECT_VTABLE(QQmlScopedEnumWrapper); void Heap::QmlTypeWrapper::init() { @@ -224,6 +225,14 @@ ReturnedValue QmlTypeWrapper::get(const Managed *m, String *name, bool *hasPrope if (ok) return QV4::Primitive::fromInt32(value).asReturnedValue(); + value = type->scopedEnumIndex(QQmlEnginePrivate::get(v4->qmlEngine()), name, &ok); + if (ok) { + Scoped<QQmlScopedEnumWrapper> enumWrapper(scope, v4->memoryManager->allocObject<QQmlScopedEnumWrapper>()); + enumWrapper->d()->type = type; + enumWrapper->d()->scopeEnumIndex = value; + return enumWrapper.asReturnedValue(); + } + // Fall through to base implementation } else if (w->d()->object) { @@ -382,4 +391,24 @@ ReturnedValue QmlTypeWrapper::instanceOf(const Object *typeObject, const Value & return QV4::Encode(QQmlMetaObject::canConvert(theirType, myQmlType)); } +ReturnedValue QQmlScopedEnumWrapper::get(const Managed *m, String *name, bool *hasProperty) +{ + Q_ASSERT(m->as<QQmlScopedEnumWrapper>()); + const QQmlScopedEnumWrapper *resource = static_cast<const QQmlScopedEnumWrapper *>(m); + QV4::ExecutionEngine *v4 = resource->engine(); + QV4::Scope scope(v4); + + QQmlType *type = resource->d()->type; + int index = resource->d()->scopeEnumIndex; + + bool ok = false; + int value = type->scopedEnumValue(QQmlEnginePrivate::get(v4->qmlEngine()), index, name, &ok); + if (hasProperty) + *hasProperty = ok; + if (ok) + return QV4::Primitive::fromInt32(value).asReturnedValue(); + + return Encode::undefined(); +} + QT_END_NAMESPACE diff --git a/src/qml/qml/qqmltypewrapper_p.h b/src/qml/qml/qqmltypewrapper_p.h index c584458ed4..86b2e47f29 100644 --- a/src/qml/qml/qqmltypewrapper_p.h +++ b/src/qml/qml/qqmltypewrapper_p.h @@ -81,6 +81,13 @@ struct QmlTypeWrapper : Object { const void *importNamespace; }; +struct QQmlScopedEnumWrapper : Object { + void init() { Object::init(); } + void destroy() { Object::destroy(); } + int scopeEnumIndex; + QQmlType *type; +}; + } struct Q_QML_EXPORT QmlTypeWrapper : Object @@ -106,6 +113,14 @@ struct Q_QML_EXPORT QmlTypeWrapper : Object static ReturnedValue instanceOf(const Object *typeObject, const Value &var); }; +struct Q_QML_EXPORT QQmlScopedEnumWrapper : Object +{ + V4_OBJECT2(QQmlScopedEnumWrapper, Object) + V4_NEEDS_DESTROY + + static ReturnedValue get(const Managed *m, String *name, bool *hasProperty); +}; + } QT_END_NAMESPACE |