diff options
-rw-r--r-- | src/corelib/kernel/qvariant.cpp | 74 | ||||
-rw-r--r-- | tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp | 79 |
2 files changed, 148 insertions, 5 deletions
diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp index 248ca4923b..34f4c6884f 100644 --- a/src/corelib/kernel/qvariant.cpp +++ b/src/corelib/kernel/qvariant.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. -** Copyright (C) 2013 Olivier Goffart <ogoffart@woboq.com> +** Copyright (C) 2015 Olivier Goffart <ogoffart@woboq.com> ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -57,6 +57,7 @@ #endif #include "private/qvariant_p.h" #include "qmetatype_p.h" +#include <qmetaobject.h> #ifndef QT_NO_GEOM_VARIANT #include "qsize.h" @@ -66,6 +67,7 @@ #endif #include <float.h> +#include <cstring> QT_BEGIN_NAMESPACE @@ -334,6 +336,27 @@ static const void *constData(const QVariant::Private &d) return d.is_shared ? d.data.shared->ptr : reinterpret_cast<const void *>(&d.data.c); } +#ifndef QT_NO_QOBJECT +/*! + \internal + returns a QMetaEnum for a given meta tape type id if possible +*/ +static QMetaEnum metaEnumFromType(int type) +{ + QMetaType t(type); + if (t.flags() & QMetaType::IsEnumeration) { + if (const QMetaObject *metaObject = t.metaObject()) { + const char *enumName = QMetaType::typeName(type); + const char *lastColon = std::strrchr(enumName, ':'); + if (lastColon) + enumName = lastColon + 1; + return metaObject->enumerator(metaObject->indexOfEnumerator(enumName)); + } + } + return QMetaEnum(); +} +#endif + /*! \internal @@ -433,6 +456,15 @@ static bool convert(const QVariant::Private *d, int t, void *result, bool *ok) *str = v_cast<QUuid>(d)->toString(); break; default: +#ifndef QT_NO_QOBJECT + { + QMetaEnum en = metaEnumFromType(d->type); + if (en.isValid()) { + *str = QString::fromUtf8(en.valueToKeys(qConvertToNumber(d, ok))); + return *ok; + } + } +#endif return false; } break; @@ -601,6 +633,15 @@ static bool convert(const QVariant::Private *d, int t, void *result, bool *ok) *ba = QByteArray(d->data.b ? "true" : "false"); break; default: +#ifndef QT_NO_QOBJECT + { + QMetaEnum en = metaEnumFromType(d->type); + if (en.isValid()) { + *ba = en.valueToKeys(qConvertToNumber(d, ok)); + return *ok; + } + } +#endif return false; } } @@ -861,6 +902,31 @@ static bool convert(const QVariant::Private *d, int t, void *result, bool *ok) } break; default: +#ifndef QT_NO_QOBJECT + if (d->type == QVariant::String || d->type == QVariant::ByteArray) { + QMetaEnum en = metaEnumFromType(t); + if (en.isValid()) { + QByteArray keys = (d->type == QVariant::String) ? v_cast<QString>(d)->toUtf8() : *v_cast<QByteArray>(d); + int value = en.keysToValue(keys.constData(), ok); + if (*ok) { + switch (QMetaType::sizeOf(t)) { + case 1: + *static_cast<signed char *>(result) = value; + return true; + case 2: + *static_cast<qint16 *>(result) = value; + return true; + case 4: + *static_cast<qint32 *>(result) = value; + return true; + case 8: + *static_cast<qint64 *>(result) = value; + return true; + } + } + } + } +#endif return false; } return true; @@ -3006,10 +3072,12 @@ bool QVariant::canConvert(int targetTypeId) const case QVariant::Bitmap: return currentType == QVariant::Pixmap || currentType == QVariant::Image; case QVariant::ByteArray: - return currentType == QVariant::Color; + return currentType == QVariant::Color + || ((QMetaType::typeFlags(currentType) & QMetaType::IsEnumeration) && QMetaType::metaObjectForType(currentType)); case QVariant::String: return currentType == QVariant::KeySequence || currentType == QVariant::Font - || currentType == QVariant::Color; + || currentType == QVariant::Color + || ((QMetaType::typeFlags(currentType) & QMetaType::IsEnumeration) && QMetaType::metaObjectForType(currentType)); case QVariant::KeySequence: return currentType == QVariant::String || currentType == QVariant::Int; case QVariant::Font: diff --git a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp index e95ec88774..52fc4e1806 100644 --- a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp +++ b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. +** Copyright (C) 2015 Olivier Goffart <ogoffart@woboq.com> ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. @@ -58,6 +59,12 @@ class CustomNonQObject; +#if defined(Q_COMPILER_CLASS_ENUM) +#define ENUM_SIZE(X) : X +#else +#define ENUM_SIZE(X) +#endif + class tst_QVariant : public QObject { Q_OBJECT @@ -69,6 +76,23 @@ public: } + + enum MetaEnumTest_Enum0 { MetaEnumTest_Enum0_value = 42, MetaEnsureSignedEnum0 = -1 }; + Q_ENUM(MetaEnumTest_Enum0) + enum MetaEnumTest_Enum1 { MetaEnumTest_Enum1_value = 42, MetaEnumTest_Enum1_bigValue = (Q_INT64_C(1) << 33) + 50 }; + Q_ENUM(MetaEnumTest_Enum1) + + enum MetaEnumTest_Enum3 ENUM_SIZE(qint64) { MetaEnumTest_Enum3_value = -47, MetaEnumTest_Enum3_bigValue = (Q_INT64_C(1) << 56) + 5 }; + Q_ENUM(MetaEnumTest_Enum3) + enum MetaEnumTest_Enum4 ENUM_SIZE(quint64) { MetaEnumTest_Enum4_value = 47, MetaEnumTest_Enum4_bigValue = (Q_INT64_C(1) << 52) + 45 }; + Q_ENUM(MetaEnumTest_Enum4) + enum MetaEnumTest_Enum5 ENUM_SIZE(uint) { MetaEnumTest_Enum5_value = 47 }; + Q_ENUM(MetaEnumTest_Enum5) + enum MetaEnumTest_Enum6 ENUM_SIZE(uchar) { MetaEnumTest_Enum6_value = 47 }; + Q_ENUM(MetaEnumTest_Enum6) + enum MetaEnumTest_Enum8 ENUM_SIZE(short) { MetaEnumTest_Enum8_value = 47 }; + Q_ENUM(MetaEnumTest_Enum8) + private slots: void cleanupTestCase(); @@ -249,7 +273,7 @@ private slots: void pairElements(); void enums(); - + void metaEnums(); void compareSanity_data(); void compareSanity(); @@ -4491,7 +4515,7 @@ void tst_QVariant::pairElements() TEST_PAIR_ELEMENT_ACCESS(std::pair, int, QVariant, 44, 15) } -enum EnumTest_Enum0 { EnumTest_Enum0_value = 42, ensureSignedEnum0 = -1 }; +enum EnumTest_Enum0 { EnumTest_Enum0_value = 42, EnumTest_Enum0_negValue = -8 }; Q_DECLARE_METATYPE(EnumTest_Enum0) enum EnumTest_Enum1 { EnumTest_Enum1_value = 42, EnumTest_Enum1_bigValue = (Q_INT64_C(1) << 33) + 50 }; Q_DECLARE_METATYPE(EnumTest_Enum1) @@ -4533,6 +4557,11 @@ template<typename Enum> void testVariant(Enum value, bool *ok) QCOMPARE(var.value<short>(), static_cast<short>(value)); QCOMPARE(var.value<unsigned short>(), static_cast<unsigned short>(value)); QCOMPARE(var.value<qint64>(), static_cast<qint64>(value)); + if (sizeof(value) < 8 && static_cast<qint64>(value) < 0) { + QEXPECT_FAIL("", "The metatype system don't store the sign of enums", Continue); + // The value is stored internaly with 32 bit. When asked to convert it to 64 bit unsigned, + // we consider that the value was unsigned, so we don't extent the bit signs + } QCOMPARE(var.value<quint64>(), static_cast<quint64>(value)); QVariant var2 = var; @@ -4547,6 +4576,8 @@ void tst_QVariant::enums() bool ok = false; testVariant(EnumTest_Enum0_value, &ok); QVERIFY(ok); + testVariant(EnumTest_Enum0_negValue, &ok); + QVERIFY(ok); testVariant(EnumTest_Enum1_value, &ok); QVERIFY(ok); testVariant(EnumTest_Enum1_bigValue, &ok); @@ -4573,6 +4604,50 @@ void tst_QVariant::enums() #endif } +template<typename Enum> void testVariantMeta(Enum value, bool *ok, const char *string) +{ + testVariant<Enum>(value, ok); + QVERIFY(ok); + *ok = false; + + QVariant var = QVariant::fromValue(value); + QVERIFY(var.canConvert<QString>()); + QVERIFY(var.canConvert<QByteArray>()); + + QCOMPARE(var.value<QString>(), QString::fromLatin1(string)); + QCOMPARE(var.value<QByteArray>(), QByteArray(string)); + + QVariant strVar = QString::fromLatin1(string); + QVERIFY(strVar.canConvert<Enum>()); + if (value > INT_MAX) { + QEXPECT_FAIL("", "QMetaEnum api uses 'int' as return type QTBUG-27451", Abort); + *ok = true; + } + QCOMPARE(strVar.value<Enum>(), value); + strVar = QByteArray(string); + QVERIFY(strVar.canConvert<Enum>()); + QCOMPARE(strVar.value<Enum>(), value); + *ok = true; +} + +void tst_QVariant::metaEnums() +{ + bool ok = false; +#define METAENUMS_TEST(Value) \ + testVariantMeta(Value, &ok, #Value); QVERIFY(ok) + + METAENUMS_TEST(MetaEnumTest_Enum0_value); + METAENUMS_TEST(MetaEnumTest_Enum1_value); + METAENUMS_TEST(MetaEnumTest_Enum1_bigValue); + METAENUMS_TEST(MetaEnumTest_Enum3_value); + METAENUMS_TEST(MetaEnumTest_Enum3_bigValue); + METAENUMS_TEST(MetaEnumTest_Enum4_value); + METAENUMS_TEST(MetaEnumTest_Enum4_bigValue); + METAENUMS_TEST(MetaEnumTest_Enum5_value); + METAENUMS_TEST(MetaEnumTest_Enum6_value); + METAENUMS_TEST(MetaEnumTest_Enum8_value); +} + void tst_QVariant::compareSanity_data() { QTest::addColumn<QVariant>("value1"); |