diff options
| author | Lars Knoll <lars.knoll@qt.io> | 2020-07-14 12:26:16 +0200 |
|---|---|---|
| committer | Lars Knoll <lars.knoll@qt.io> | 2020-08-24 00:18:24 +0200 |
| commit | 9d36032370f7b81279ff8774afd7dea4ea57ee6a (patch) | |
| tree | d750ccd6cd317f056d13495a03fde5881134ec89 /src/corelib/kernel/qvariant.cpp | |
| parent | 2d3b31171d8fce2ab364ca2ceea4e75020933334 (diff) | |
Implement QMetaType::canConvert() and use it in QVariant
Use the fact that we return the conversion function as a lambda
to find out reliably whether a conversion between two types
can be done.
This requires some minor adjustments to our tests:
* Nothing can convert to an unknown type and vice versa
* Adjust results to the fact that we don't convert from char
to QString anymore (where the old method was incorrect)
* QStringList->QString requires some adjustments, as we only
convert if the string list has exactly one element. For now
we return true in canConvert(), but the conversion behavior
in this case is something we should rethink, as it is very
surprising.
Change-Id: I3f5f87ee9cb99d690f5a7d13b13d6a6313d8038e
Reviewed-by: Maurice Kalinowski <maurice.kalinowski@qt.io>
Diffstat (limited to 'src/corelib/kernel/qvariant.cpp')
| -rw-r--r-- | src/corelib/kernel/qvariant.cpp | 396 |
1 files changed, 4 insertions, 392 deletions
diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp index 4f0664dc285..c16e4a0e062 100644 --- a/src/corelib/kernel/qvariant.cpp +++ b/src/corelib/kernel/qvariant.cpp @@ -1962,219 +1962,17 @@ QVariantList QVariant::toList() const return qVariantToHelper<QVariantList>(d); } - -static const quint32 qCanConvertMatrix[QMetaType::LastCoreType + 1] = -{ -/*Invalid*/ 0, - -/*Bool*/ 1 << QMetaType::Double | 1 << QMetaType::Int | 1 << QMetaType::UInt - | 1 << QMetaType::LongLong | 1 << QMetaType::ULongLong | 1 << QMetaType::QByteArray - | 1 << QMetaType::QString | 1 << QMetaType::QChar, - -/*Int*/ 1 << QMetaType::UInt | 1 << QMetaType::QString | 1 << QMetaType::Double - | 1 << QMetaType::Bool | 1 << QMetaType::LongLong | 1 << QMetaType::ULongLong - | 1 << QMetaType::QChar | 1 << QMetaType::QByteArray | 1 << QMetaType::Int, - -/*UInt*/ 1 << QMetaType::Int | 1 << QMetaType::QString | 1 << QMetaType::Double - | 1 << QMetaType::Bool | 1 << QMetaType::LongLong | 1 << QMetaType::ULongLong - | 1 << QMetaType::QChar | 1 << QMetaType::QByteArray, - -/*LLong*/ 1 << QMetaType::Int | 1 << QMetaType::QString | 1 << QMetaType::Double - | 1 << QMetaType::Bool | 1 << QMetaType::UInt | 1 << QMetaType::ULongLong - | 1 << QMetaType::QChar | 1 << QMetaType::QByteArray, - -/*ULlong*/ 1 << QMetaType::Int | 1 << QMetaType::QString | 1 << QMetaType::Double - | 1 << QMetaType::Bool | 1 << QMetaType::UInt | 1 << QMetaType::LongLong - | 1 << QMetaType::QChar | 1 << QMetaType::QByteArray, - -/*double*/ 1 << QMetaType::Int | 1 << QMetaType::QString | 1 << QMetaType::ULongLong - | 1 << QMetaType::Bool | 1 << QMetaType::UInt | 1 << QMetaType::LongLong - | 1 << QMetaType::QByteArray, - -/*QChar*/ 1 << QMetaType::Int | 1 << QMetaType::UInt | 1 << QMetaType::LongLong - | 1 << QMetaType::ULongLong, - -/*QMap*/ 0, - -/*QList*/ 1 << QMetaType::QStringList, - -/*QString*/ 1 << QMetaType::QStringList | 1 << QMetaType::QByteArray | 1 << QMetaType::Int - | 1 << QMetaType::UInt | 1 << QMetaType::Bool | 1 << QMetaType::Double - | 1 << QMetaType::QDate | 1 << QMetaType::QTime | 1 << QMetaType::QDateTime - | 1 << QMetaType::LongLong | 1 << QMetaType::ULongLong | 1 << QMetaType::QChar - | 1 << QMetaType::QUrl | 1 << QMetaType::QUuid, - -/*QStringList*/ 1 << QMetaType::QVariantList | 1 << QMetaType::QString, - -/*QByteArray*/ 1 << QMetaType::QString | 1 << QMetaType::Int | 1 << QMetaType::UInt | 1 << QMetaType::Bool - | 1 << QMetaType::Double | 1 << QMetaType::LongLong | 1 << QMetaType::ULongLong - | 1 << QMetaType::QUuid, - -/*QBitArray*/ 0, - -/*QDate*/ 1 << QMetaType::QString | 1 << QMetaType::QDateTime, - -/*QTime*/ 1 << QMetaType::QString | 1 << QMetaType::QDateTime, - -/*QDateTime*/ 1 << QMetaType::QString | 1 << QMetaType::QDate, - -/*QUrl*/ 1 << QMetaType::QString, - -/*QLocale*/ 0, - -/*QRect*/ 1 << QMetaType::QRectF, - -/*QRectF*/ 1 << QMetaType::QRect, - -/*QSize*/ 1 << QMetaType::QSizeF, - -/*QSizeF*/ 1 << QMetaType::QSize, - -/*QLine*/ 1 << QMetaType::QLineF, - -/*QLineF*/ 1 << QMetaType::QLine, - -/*QPoint*/ 1 << QMetaType::QPointF, - -/*QPointF*/ 1 << QMetaType::QPoint, - -/*unused, was: QRegExp*/ 0, - -/*QHash*/ 0, - -/*QEasingCurve*/ 0, - -/*QUuid*/ 1 << QMetaType::QString | 1 << QMetaType::QByteArray, -}; -static const size_t qCanConvertMatrixMaximumTargetType = 8 * sizeof(*qCanConvertMatrix); - -#ifndef QT_BOOTSTRAPPED -/* - Returns \c true if from inherits to. -*/ -static bool canConvertMetaObject(const QMetaObject *from, const QMetaObject *to) -{ - if (from && to == &QObject::staticMetaObject) - return true; - - while (from) { - if (from == to) - return true; - from = from->superClass(); - } - - return false; -} -#endif - -static bool canConvertMetaObject(int fromId, int toId, QObject *fromObject) -{ -#ifndef QT_BOOTSTRAPPED - QMetaType toType(toId); - if ((QMetaType::typeFlags(fromId) & QMetaType::PointerToQObject) && (toType.flags() & QMetaType::PointerToQObject)) { - if (!fromObject) - return true; - return canConvertMetaObject(fromObject->metaObject(), toType.metaObject()); - } -#else - Q_UNUSED(fromId); - Q_UNUSED(toId); - Q_UNUSED(fromObject); -#endif - return false; -} - - /*! Returns \c true if the variant's type can be cast to the requested type, \a targetTypeId. Such casting is done automatically when calling the toInt(), toBool(), ... methods. - The following casts are done automatically: - - \table - \header \li Type \li Automatically Cast To - \row \li \l QMetaType::Bool \li \l QMetaType::QChar, \l QMetaType::Double, - \l QMetaType::Int, \l QMetaType::LongLong, \l QMetaType::QString, - \l QMetaType::UInt, \l QMetaType::ULongLong - \row \li \l QMetaType::QByteArray \li \l QMetaType::Double, - \l QMetaType::Int, \l QMetaType::LongLong, \l QMetaType::QString, - \l QMetaType::UInt, \l QMetaType::ULongLong, \l QMetaType::QUuid - \row \li \l QMetaType::QChar \li \l QMetaType::Bool, \l QMetaType::Int, - \l QMetaType::UInt, \l QMetaType::LongLong, \l QMetaType::ULongLong - \row \li \l QMetaType::QColor \li \l QMetaType::QString - \row \li \l QMetaType::QDate \li \l QMetaType::QDateTime, - \l QMetaType::QString - \row \li \l QMetaType::QDateTime \li \l QMetaType::QDate, - \l QMetaType::QString, \l QMetaType::QTime - \row \li \l QMetaType::Double \li \l QMetaType::Bool, \l QMetaType::Int, - \l QMetaType::LongLong, \l QMetaType::QString, \l QMetaType::UInt, - \l QMetaType::ULongLong - \row \li \l QMetaType::QFont \li \l QMetaType::QString - \row \li \l QMetaType::Int \li \l QMetaType::Bool, \l QMetaType::QChar, - \l QMetaType::Double, \l QMetaType::LongLong, \l QMetaType::QString, - \l QMetaType::UInt, \l QMetaType::ULongLong - \row \li \l QMetaType::QKeySequence \li \l QMetaType::Int, - \l QMetaType::QString - \row \li \l QMetaType::QVariantList \li \l QMetaType::QStringList (if the - list's items can be converted to QStrings) - \row \li \l QMetaType::LongLong \li \l QMetaType::Bool, - \l QMetaType::QByteArray, \l QMetaType::QChar, \l QMetaType::Double, - \l QMetaType::Int, \l QMetaType::QString, \l QMetaType::UInt, - \l QMetaType::ULongLong - \row \li \l QMetaType::QPoint \li QMetaType::QPointF - \row \li \l QMetaType::QRect \li QMetaType::QRectF - \row \li \l QMetaType::QString \li \l QMetaType::Bool, - \l QMetaType::QByteArray, \l QMetaType::QChar, \l QMetaType::QColor, - \l QMetaType::QDate, \l QMetaType::QDateTime, \l QMetaType::Double, - \l QMetaType::QFont, \l QMetaType::Int, \l QMetaType::QKeySequence, - \l QMetaType::LongLong, \l QMetaType::QStringList, \l QMetaType::QTime, - \l QMetaType::UInt, \l QMetaType::ULongLong, \l QMetaType::QUuid - \row \li \l QMetaType::QStringList \li \l QMetaType::QVariantList, - \l QMetaType::QString (if the list contains exactly one item) - \row \li \l QMetaType::QTime \li \l QMetaType::QString - \row \li \l QMetaType::UInt \li \l QMetaType::Bool, \l QMetaType::QChar, - \l QMetaType::Double, \l QMetaType::Int, \l QMetaType::LongLong, - \l QMetaType::QString, \l QMetaType::ULongLong - \row \li \l QMetaType::ULongLong \li \l QMetaType::Bool, - \l QMetaType::QChar, \l QMetaType::Double, \l QMetaType::Int, - \l QMetaType::LongLong, \l QMetaType::QString, \l QMetaType::UInt - \row \li \l QMetaType::QUuid \li \l QMetaType::QByteArray, \l QMetaType::QString - \endtable - - A QVariant containing a pointer to a type derived from QObject will also return true for this - function if a qobject_cast to the type described by \a targetTypeId would succeed. Note that - this only works for QObject subclasses which use the Q_OBJECT macro. - - A QVariant containing a sequential container will also return true for this - function if the \a targetTypeId is QVariantList. It is possible to iterate over - the contents of the container without extracting it as a (copied) QVariantList: - - \snippet code/src_corelib_kernel_qvariant.cpp 9 - - This requires that the value_type of the container is itself a metatype. - - Similarly, a QVariant containing a sequential container will also return true for this - function the \a targetTypeId is QVariantHash or QVariantMap. It is possible to iterate over - the contents of the container without extracting it as a (copied) QVariantHash or QVariantMap: - - \snippet code/src_corelib_kernel_qvariant.cpp 10 - - \sa convert(), QSequentialIterable, Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(), QAssociativeIterable, - Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE() + \sa QMetaType::canConvert() */ bool QVariant::canConvert(int targetTypeId) const { - if (d.typeId() == targetTypeId) - return true; - -#if QT_CONFIG(itemmodel) - if ((targetTypeId == QMetaType::QModelIndex - && d.typeId() == QMetaType::QPersistentModelIndex) - || (targetTypeId == QMetaType::QPersistentModelIndex - && d.typeId() == QMetaType::QModelIndex)) + if (d.typeId() == targetTypeId && targetTypeId != QMetaType::UnknownType) return true; -#endif if (targetTypeId == QMetaType::QVariantList && (d.typeId() == QMetaType::QVariantList || d.typeId() == QMetaType::QStringList @@ -2197,193 +1995,7 @@ bool QVariant::canConvert(int targetTypeId) const return true; } - if ((d.typeId() >= QMetaType::LastCoreType|| targetTypeId >= QMetaType::LastCoreType) - && QMetaType::hasRegisteredConverterFunction(d.typeId(), targetTypeId)) { - return true; - } - - // TODO Reimplement this function, currently it works but it is a historical mess. - uint currentType = d.typeId(); - if (currentType == QMetaType::SChar || currentType == QMetaType::Char) - currentType = QMetaType::UInt; - if (targetTypeId == QMetaType::SChar || currentType == QMetaType::Char) - targetTypeId = QMetaType::UInt; - if (currentType == QMetaType::Short || currentType == QMetaType::UShort) - currentType = QMetaType::Int; - if (targetTypeId == QMetaType::Short || currentType == QMetaType::UShort) - targetTypeId = QMetaType::Int; - if (currentType == QMetaType::Float) - currentType = QMetaType::Double; - if (targetTypeId == QMetaType::Float) - targetTypeId = QMetaType::Double; - - if (currentType == uint(targetTypeId)) - return true; - - if (targetTypeId < 0) - return false; - if (targetTypeId >= QMetaType::User) { - if (QMetaType::typeFlags(targetTypeId) & QMetaType::IsEnumeration) { - targetTypeId = QMetaType::Int; - } else { - return canConvertMetaObject(currentType, targetTypeId, d.get<QObject *>()); - } - } - - if (currentType == QMetaType::QJsonValue || targetTypeId == QMetaType::QJsonValue) { - switch (currentType == QMetaType::QJsonValue ? targetTypeId : currentType) { - case QMetaType::Nullptr: - case QMetaType::QString: - case QMetaType::Bool: - case QMetaType::Int: - case QMetaType::UInt: - case QMetaType::Double: - case QMetaType::Float: - case QMetaType::ULong: - case QMetaType::Long: - case QMetaType::LongLong: - case QMetaType::ULongLong: - case QMetaType::UShort: - case QMetaType::UChar: - case QMetaType::Char: - case QMetaType::SChar: - case QMetaType::Short: - case QMetaType::QVariantList: - case QMetaType::QVariantMap: - case QMetaType::QVariantHash: - case QMetaType::QCborValue: - case QMetaType::QCborArray: - case QMetaType::QCborMap: - return true; - default: - return false; - } - } - if (currentType == QMetaType::QJsonArray) - return targetTypeId == QMetaType::QVariantList || targetTypeId == QMetaType::QCborValue - || targetTypeId == QMetaType::QCborArray; - if (currentType == QMetaType::QJsonObject) - return targetTypeId == QMetaType::QVariantMap || targetTypeId == QMetaType::QVariantHash - || targetTypeId == QMetaType::QCborValue || targetTypeId == QMetaType::QCborMap; - - if (currentType == QMetaType::QCborValue || targetTypeId == QMetaType::QCborValue) { - switch (currentType == QMetaType::QCborValue ? targetTypeId : currentType) { - case QMetaType::UnknownType: - case QMetaType::Nullptr: - case QMetaType::Bool: - case QMetaType::Int: - case QMetaType::UInt: - case QMetaType::Double: - case QMetaType::Float: - case QMetaType::ULong: - case QMetaType::Long: - case QMetaType::LongLong: - case QMetaType::ULongLong: - case QMetaType::UShort: - case QMetaType::UChar: - case QMetaType::Char: - case QMetaType::SChar: - case QMetaType::Short: - case QMetaType::QString: - case QMetaType::QByteArray: - case QMetaType::QDateTime: - case QMetaType::QUrl: -#if QT_CONFIG(regularexpression) - case QMetaType::QRegularExpression: -#endif - case QMetaType::QUuid: - case QMetaType::QVariantList: - case QMetaType::QVariantMap: - case QMetaType::QVariantHash: - case QMetaType::QJsonValue: - case QMetaType::QJsonArray: - case QMetaType::QJsonObject: - case QMetaType::QJsonDocument: - case QMetaType::QCborArray: - case QMetaType::QCborMap: - case QMetaType::QCborSimpleType: - return true; - default: - return false; - } - } - if (currentType == QMetaType::QCborArray) - return targetTypeId == QMetaType::QVariantList || targetTypeId == QMetaType::QCborValue - || targetTypeId == QMetaType::QJsonArray; - if (currentType == QMetaType::QCborMap) - return targetTypeId == QMetaType::QVariantMap || targetTypeId == QMetaType::QVariantHash - || targetTypeId == QMetaType::QCborValue || targetTypeId == QMetaType::QJsonObject; - - // FIXME It should be LastCoreType intead of Uuid - if (currentType > int(QMetaType::QUuid) || targetTypeId > int(QMetaType::QUuid)) { - switch (uint(targetTypeId)) { - case QVariant::Int: -#if QT_CONFIG(shortcut) - if (currentType == QVariant::KeySequence) - return true; - Q_FALLTHROUGH(); -#endif - case QVariant::UInt: - case QVariant::LongLong: - case QVariant::ULongLong: - return currentType == QMetaType::ULong - || currentType == QMetaType::Long - || currentType == QMetaType::UShort - || currentType == QMetaType::UChar - || currentType == QMetaType::Char - || currentType == QMetaType::SChar - || currentType == QMetaType::Short - || QMetaType::typeFlags(currentType) & QMetaType::IsEnumeration; - case QVariant::Image: - return currentType == QVariant::Pixmap || currentType == QVariant::Bitmap; - case QVariant::Pixmap: - return currentType == QVariant::Image || currentType == QVariant::Bitmap - || currentType == QVariant::Brush; - case QVariant::Bitmap: - return currentType == QVariant::Pixmap || currentType == QVariant::Image; - case QVariant::ByteArray: - return currentType == QVariant::Color || currentType == QMetaType::Nullptr - || ((QMetaType::typeFlags(currentType) & QMetaType::IsEnumeration) && QMetaType::metaObjectForType(currentType)); - case QVariant::String: - return currentType == QVariant::Font - || currentType == QVariant::Color || currentType == QMetaType::Nullptr -#if QT_CONFIG(shortcut) - || currentType == QVariant::KeySequence -#endif - || ((QMetaType::typeFlags(currentType) & QMetaType::IsEnumeration) && QMetaType::metaObjectForType(currentType)); -#if QT_CONFIG(shortcut) - case QVariant::KeySequence: - return currentType == QVariant::String || currentType == QVariant::Int; -#endif - case QVariant::Font: - return currentType == QVariant::String; - case QVariant::Color: - return currentType == QVariant::String || currentType == QVariant::ByteArray - || currentType == QVariant::Brush; - case QVariant::Brush: - return currentType == QVariant::Color || currentType == QVariant::Pixmap; - case QMetaType::Long: - case QMetaType::Char: - case QMetaType::SChar: - case QMetaType::UChar: - case QMetaType::ULong: - case QMetaType::Short: - case QMetaType::UShort: - return currentType == QVariant::Int - || (currentType < qCanConvertMatrixMaximumTargetType - && qCanConvertMatrix[QVariant::Int] & (1U << currentType)) - || QMetaType::typeFlags(currentType) & QMetaType::IsEnumeration; - case QMetaType::QObjectStar: - return canConvertMetaObject(currentType, targetTypeId, d.get<QObject *>()); - default: - return false; - } - } - - if (targetTypeId == String && currentType == StringList) - return d.get<QStringList>().count() == 1; - return currentType < qCanConvertMatrixMaximumTargetType - && qCanConvertMatrix[targetTypeId] & (1U << currentType); + return QMetaType::canConvert(d.type(), QMetaType(targetTypeId)); } /*! @@ -2409,7 +2021,7 @@ bool QVariant::canConvert(int targetTypeId) const bool QVariant::convert(int targetTypeId) { if (d.typeId() == targetTypeId) - return true; + return (targetTypeId != QMetaType::UnknownType); QVariant oldValue = *this; |
