From f85b9f824269073664770c11f58e674993d33e47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Nowacki?= Date: Mon, 5 Dec 2011 12:43:10 +0100 Subject: Reimplement QVariant to QDebug streaming. New implementation fixes some commented code marked as FIXME. Change-Id: If8f5bebedd65bcf8f839d804c2022ca79ef82ddf Reviewed-by: Thiago Macieira --- src/corelib/kernel/qvariant.cpp | 105 +-------------------- src/corelib/kernel/qvariant.h | 1 + src/corelib/kernel/qvariant_p.h | 51 ++++++++++ src/gui/kernel/qguivariant.cpp | 87 +---------------- src/widgets/kernel/qwidgetsvariant.cpp | 19 +++- .../auto/corelib/kernel/qvariant/tst_qvariant.cpp | 62 ++++++++++++ 6 files changed, 140 insertions(+), 185 deletions(-) diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp index 9cf131312b..89d1290022 100644 --- a/src/corelib/kernel/qvariant.cpp +++ b/src/corelib/kernel/qvariant.cpp @@ -731,104 +731,9 @@ static bool convert(const QVariant::Private *d, QVariant::Type t, void *result, #if !defined(QT_NO_DEBUG_STREAM) && !defined(Q_BROKEN_DEBUG_STREAM) static void streamDebug(QDebug dbg, const QVariant &v) { - switch (v.userType()) { - case QVariant::Int: - dbg.nospace() << v.toInt(); - break; - case QVariant::UInt: - dbg.nospace() << v.toUInt(); - break; - case QVariant::LongLong: - dbg.nospace() << v.toLongLong(); - break; - case QVariant::ULongLong: - dbg.nospace() << v.toULongLong(); - break; - case QMetaType::Float: - dbg.nospace() << v.toFloat(); - break; - case QMetaType::QObjectStar: - dbg.nospace() << qvariant_cast(v); - break; - case QVariant::Double: - dbg.nospace() << v.toDouble(); - break; - case QVariant::Bool: - dbg.nospace() << v.toBool(); - break; - case QVariant::String: - dbg.nospace() << v.toString(); - break; - case QVariant::Char: - dbg.nospace() << v.toChar(); - break; - case QVariant::StringList: - dbg.nospace() << v.toStringList(); - break; - case QVariant::Map: - dbg.nospace() << v.toMap(); - break; - case QVariant::Hash: - dbg.nospace() << v.toHash(); - break; - case QVariant::List: - dbg.nospace() << v.toList(); - break; - case QVariant::Date: - dbg.nospace() << v.toDate(); - break; - case QVariant::Time: - dbg.nospace() << v.toTime(); - break; - case QVariant::DateTime: - dbg.nospace() << v.toDateTime(); - break; -#ifndef QT_BOOTSTRAPPED - case QVariant::EasingCurve: - dbg.nospace() << v.toEasingCurve(); - break; -#endif - case QVariant::ByteArray: - dbg.nospace() << v.toByteArray(); - break; - case QVariant::Url: - dbg.nospace() << v.toUrl(); - break; -#ifndef QT_NO_GEOM_VARIANT - case QVariant::Point: - dbg.nospace() << v.toPoint(); - break; - case QVariant::PointF: - dbg.nospace() << v.toPointF(); - break; - case QVariant::Rect: - dbg.nospace() << v.toRect(); - break; - case QVariant::Size: - dbg.nospace() << v.toSize(); - break; - case QVariant::SizeF: - dbg.nospace() << v.toSizeF(); - break; - case QVariant::Line: - dbg.nospace() << v.toLine(); - break; - case QVariant::LineF: - dbg.nospace() << v.toLineF(); - break; - case QVariant::RectF: - dbg.nospace() << v.toRectF(); - break; -#endif - case QVariant::Uuid: - dbg.nospace() << v.value().toString(); - break; - case QVariant::BitArray: - //dbg.nospace() << v.toBitArray(); - break; - default: - break; - } + QVariant::Private *d = const_cast(&v.data_ptr()); + QVariantDebugStream stream(dbg, d); + QMetaTypeSwitcher::switcher(stream, d->type, 0); } #endif @@ -2707,7 +2612,7 @@ bool QVariant::isNull() const QDebug operator<<(QDebug dbg, const QVariant &v) { #ifndef Q_BROKEN_DEBUG_STREAM - dbg.nospace() << "QVariant(" << v.typeName() << ", "; + dbg.nospace() << "QVariant(" << QMetaType::typeName(v.userType()) << ", "; handlerManager[v.d.type]->debugStream(dbg, v); dbg.nospace() << ')'; return dbg.space(); @@ -2721,7 +2626,7 @@ QDebug operator<<(QDebug dbg, const QVariant &v) QDebug operator<<(QDebug dbg, const QVariant::Type p) { #ifndef Q_BROKEN_DEBUG_STREAM - dbg.nospace() << "QVariant::" << QVariant::typeToName(p); + dbg.nospace() << "QVariant::" << QMetaType::typeName(p); return dbg.space(); #else qWarning("This compiler doesn't support streaming QVariant::Type to QDebug"); diff --git a/src/corelib/kernel/qvariant.h b/src/corelib/kernel/qvariant.h index 12a512f0dd..738e516b82 100644 --- a/src/corelib/kernel/qvariant.h +++ b/src/corelib/kernel/qvariant.h @@ -397,6 +397,7 @@ private: public: typedef Private DataPtr; inline DataPtr &data_ptr() { return d; } + inline const DataPtr &data_ptr() const { return d; } }; template diff --git a/src/corelib/kernel/qvariant_p.h b/src/corelib/kernel/qvariant_p.h index b79d4623c1..015ca5b464 100644 --- a/src/corelib/kernel/qvariant_p.h +++ b/src/corelib/kernel/qvariant_p.h @@ -58,6 +58,9 @@ #include #include +#include +#include + #include "qmetatypeswitcher_p.h" QT_BEGIN_NAMESPACE @@ -418,6 +421,54 @@ Q_CORE_EXPORT void registerHandler(const int /* Modules::Names */ name, const QV Q_CORE_EXPORT void unregisterHandler(const int /* Modules::Names */ name); } +#if !defined(QT_NO_DEBUG_STREAM) && !defined(Q_BROKEN_DEBUG_STREAM) +template +class QVariantDebugStream +{ + template::IsAccepted> + struct Filtered { + Filtered(QDebug dbg, QVariant::Private *d) + { + dbg.nospace() << *v_cast(d); + } + }; + template + struct Filtered { + Filtered(QDebug dbg, QVariant::Private *d) + { + dbg.nospace() << "QVariant::Type(" << d->type << ")"; + } + }; + +public: + QVariantDebugStream(QDebug dbg, QVariant::Private *d) + : m_debugStream(dbg) + , m_d(d) + {} + + template + void delegate(const T*) + { + Filtered streamIt(m_debugStream, m_d); + } + + void delegate(const QMetaTypeSwitcher::UnknownType*) + { + if (m_d->type == QVariant::UserType) + m_debugStream.nospace() << "QVariant::UserType"; + else + qWarning("Trying to stream an instance of an invalid type, type id: %i", m_d->type); + } + void delegate(const void*) + { + m_debugStream.nospace() << "QVariant::Invalid"; + } +private: + QDebug m_debugStream; + QVariant::Private *m_d; +}; +#endif + QT_END_NAMESPACE #endif // QVARIANT_P_H diff --git a/src/gui/kernel/qguivariant.cpp b/src/gui/kernel/qguivariant.cpp index 8618c04a32..532a5353e2 100644 --- a/src/gui/kernel/qguivariant.cpp +++ b/src/gui/kernel/qguivariant.cpp @@ -345,90 +345,9 @@ static bool convert(const QVariant::Private *d, QVariant::Type t, #if !defined(QT_NO_DEBUG_STREAM) && !defined(Q_BROKEN_DEBUG_STREAM) static void streamDebug(QDebug dbg, const QVariant &v) { - switch(v.type()) { - case QVariant::Cursor: -#ifndef QT_NO_CURSOR -// dbg.nospace() << qvariant_cast(v); //FIXME -#endif - break; - case QVariant::Bitmap: -// dbg.nospace() << qvariant_cast(v); //FIXME - break; - case QVariant::Polygon: - dbg.nospace() << qvariant_cast(v); - break; - case QVariant::Region: - dbg.nospace() << qvariant_cast(v); - break; - case QVariant::Font: -// dbg.nospace() << qvariant_cast(v); //FIXME - break; - case QVariant::Matrix: - dbg.nospace() << qvariant_cast(v); - break; - case QVariant::Transform: - dbg.nospace() << qvariant_cast(v); - break; - case QVariant::Pixmap: -// dbg.nospace() << qvariant_cast(v); //FIXME - break; - case QVariant::Image: -// dbg.nospace() << qvariant_cast(v); //FIXME - break; - case QVariant::Brush: - dbg.nospace() << qvariant_cast(v); - break; - case QVariant::Color: - dbg.nospace() << qvariant_cast(v); - break; - case QVariant::Palette: -// dbg.nospace() << qvariant_cast(v); //FIXME - break; -#ifndef QT_NO_ICON - case QVariant::Icon: -// dbg.nospace() << qvariant_cast(v); // FIXME - break; -#endif - case QVariant::SizePolicy: -// dbg.nospace() << qvariant_cast(v); //FIXME - break; -#ifndef QT_NO_SHORTCUT - case QVariant::KeySequence: - dbg.nospace() << qvariant_cast(v); - break; -#endif - case QVariant::Pen: - dbg.nospace() << qvariant_cast(v); - break; -#ifndef QT_NO_MATRIX4X4 - case QVariant::Matrix4x4: - dbg.nospace() << qvariant_cast(v); - break; -#endif -#ifndef QT_NO_VECTOR2D - case QVariant::Vector2D: - dbg.nospace() << qvariant_cast(v); - break; -#endif -#ifndef QT_NO_VECTOR3D - case QVariant::Vector3D: - dbg.nospace() << qvariant_cast(v); - break; -#endif -#ifndef QT_NO_VECTOR4D - case QVariant::Vector4D: - dbg.nospace() << qvariant_cast(v); - break; -#endif -#ifndef QT_NO_QUATERNION - case QVariant::Quaternion: - dbg.nospace() << qvariant_cast(v); - break; -#endif - default: - qcoreVariantHandler()->debugStream(dbg, v); - break; - } + QVariant::Private *d = const_cast(&v.data_ptr()); + QVariantDebugStream stream(dbg, d); + QMetaTypeSwitcher::switcher(stream, d->type, 0); } #endif diff --git a/src/widgets/kernel/qwidgetsvariant.cpp b/src/widgets/kernel/qwidgetsvariant.cpp index e33d0da0a1..e9fa99a80e 100644 --- a/src/widgets/kernel/qwidgetsvariant.cpp +++ b/src/widgets/kernel/qwidgetsvariant.cpp @@ -127,6 +127,23 @@ static bool convert(const QVariant::Private *d, QVariant::Type type, void *resul return false; } +static void streamDebug(QDebug dbg, const QVariant &v) +{ + QVariant::Private *d = const_cast(&v.data_ptr()); + switch (d->type) { +#ifndef QT_NO_ICON + case QVariant::Icon: + dbg.nospace() << *v_cast(d); + break; +#endif + case QVariant::SizePolicy: + dbg.nospace() << *v_cast(d); + break; + default: + dbg.nospace() << "QVariant::Type(" << d->type << ")"; + } +} + static const QVariant::Handler widgets_handler = { construct, clear, @@ -139,7 +156,7 @@ static const QVariant::Handler widgets_handler = { convert, 0, #if !defined(QT_NO_DEBUG_STREAM) && !defined(Q_BROKEN_DEBUG_STREAM) - 0 + streamDebug #else 0 #endif diff --git a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp index 8f75f13958..c2d4f0a240 100644 --- a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp +++ b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp @@ -63,6 +63,7 @@ #include #include #include +#include #include @@ -259,6 +260,8 @@ private slots: void colorInteger(); void forwardDeclare(); + void debugStream_data(); + void debugStream(); }; Q_DECLARE_METATYPE(QDate) @@ -3331,5 +3334,64 @@ void tst_QVariant::forwardDeclare() } +class MessageHandler { +public: + MessageHandler(const int typeId) + : oldMsgHandler(qInstallMsgHandler(handler)) + { + currentId = typeId; + } + + ~MessageHandler() + { + qInstallMsgHandler(oldMsgHandler); + } + + bool testPassed() const + { + return ok; + } +private: + static void handler(QtMsgType, const char *txt) + { + QString msg = QString::fromLatin1(txt); + // Format itself is not important, but basic data as a type name should be included in the output + ok = msg.startsWith("QVariant(") + QMetaType::typeName(currentId); + QVERIFY2(ok, (QString::fromLatin1("Message is not valid: '") + msg + '\'').toLatin1().constData()); + } + + QtMsgHandler oldMsgHandler; + static int currentId; + static bool ok; +}; +bool MessageHandler::ok; +int MessageHandler::currentId; + +void tst_QVariant::debugStream_data() +{ + QTest::addColumn("variant"); + QTest::addColumn("typeId"); + for (int id = QMetaType::Void; id < QMetaType::User; ++id) { + const char *tagName = QMetaType::typeName(id); + if (!tagName) + continue; + QTest::newRow(tagName) << QVariant(static_cast(id)) << id; + } + QTest::newRow("QBitArray(111)") << QVariant(QBitArray(3, true)) << qMetaTypeId(); + QTest::newRow("CustomStreamableClass") << QVariant(qMetaTypeId(), 0) << qMetaTypeId(); + QTest::newRow("MyClass") << QVariant(qMetaTypeId(), 0) << qMetaTypeId(); +} + +void tst_QVariant::debugStream() +{ + QFETCH(QVariant, variant); + QFETCH(int, typeId); + + MessageHandler msgHandler(typeId); + qDebug() << variant; + QVERIFY(msgHandler.testPassed()); +} + + QTEST_MAIN(tst_QVariant) #include "tst_qvariant.moc" -- cgit v1.2.3