Reimplement QVariant to QDebug streaming.
authorJędrzej Nowacki <jedrzej.nowacki@nokia.com>
Mon, 5 Dec 2011 11:43:10 +0000 (12:43 +0100)
committerQt by Nokia <qt-info@nokia.com>
Tue, 10 Jan 2012 08:13:11 +0000 (09:13 +0100)
New implementation fixes some commented code marked as FIXME.

Change-Id: If8f5bebedd65bcf8f839d804c2022ca79ef82ddf
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
src/corelib/kernel/qvariant.cpp
src/corelib/kernel/qvariant.h
src/corelib/kernel/qvariant_p.h
src/gui/kernel/qguivariant.cpp
src/widgets/kernel/qwidgetsvariant.cpp
tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp

index 9cf1313..89d1290 100644 (file)
@@ -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<QObject *>(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<QUuid>().toString();
-        break;
-    case QVariant::BitArray:
-        //dbg.nospace() << v.toBitArray();
-        break;
-    default:
-        break;
-    }
+    QVariant::Private *d = const_cast<QVariant::Private *>(&v.data_ptr());
+    QVariantDebugStream<CoreTypesFilter> stream(dbg, d);
+    QMetaTypeSwitcher::switcher<void>(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");
index 12a512f..738e516 100644 (file)
@@ -397,6 +397,7 @@ private:
 public:
     typedef Private DataPtr;
     inline DataPtr &data_ptr() { return d; }
+    inline const DataPtr &data_ptr() const { return d; }
 };
 
 template <typename T>
index b79d462..015ca5b 100644 (file)
@@ -58,6 +58,9 @@
 
 #include <QtCore/qglobal.h>
 #include <QtCore/qvariant.h>
+#include <QtCore/private/qmetatype_p.h>
+#include <QtCore/qdebug.h>
+
 #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 Filter>
+class QVariantDebugStream
+{
+    template<typename T, bool IsAcceptedType = Filter::template Acceptor<T>::IsAccepted>
+    struct Filtered {
+        Filtered(QDebug dbg, QVariant::Private *d)
+        {
+            dbg.nospace() << *v_cast<T>(d);
+        }
+    };
+    template<typename T>
+    struct Filtered<T, /* IsAcceptedType = */ false> {
+        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<typename T>
+    void delegate(const T*)
+    {
+        Filtered<T> 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
index 8618c04..532a535 100644 (file)
@@ -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<QCursor>(v); //FIXME
-#endif
-        break;
-    case QVariant::Bitmap:
-//        dbg.nospace() << qvariant_cast<QBitmap>(v); //FIXME
-        break;
-    case QVariant::Polygon:
-        dbg.nospace() << qvariant_cast<QPolygon>(v);
-        break;
-    case QVariant::Region:
-        dbg.nospace() << qvariant_cast<QRegion>(v);
-        break;
-    case QVariant::Font:
-//        dbg.nospace() << qvariant_cast<QFont>(v);  //FIXME
-        break;
-    case QVariant::Matrix:
-        dbg.nospace() << qvariant_cast<QMatrix>(v);
-        break;
-    case QVariant::Transform:
-        dbg.nospace() << qvariant_cast<QTransform>(v);
-        break;
-    case QVariant::Pixmap:
-//        dbg.nospace() << qvariant_cast<QPixmap>(v); //FIXME
-        break;
-    case QVariant::Image:
-//        dbg.nospace() << qvariant_cast<QImage>(v); //FIXME
-        break;
-    case QVariant::Brush:
-        dbg.nospace() << qvariant_cast<QBrush>(v);
-        break;
-    case QVariant::Color:
-        dbg.nospace() << qvariant_cast<QColor>(v);
-        break;
-    case QVariant::Palette:
-//        dbg.nospace() << qvariant_cast<QPalette>(v); //FIXME
-        break;
-#ifndef QT_NO_ICON
-    case QVariant::Icon:
-//        dbg.nospace() << qvariant_cast<QIcon>(v); // FIXME
-        break;
-#endif
-    case QVariant::SizePolicy:
-//        dbg.nospace() << qvariant_cast<QSizePolicy>(v); //FIXME
-        break;
-#ifndef QT_NO_SHORTCUT
-    case QVariant::KeySequence:
-        dbg.nospace() << qvariant_cast<QKeySequence>(v);
-        break;
-#endif
-    case QVariant::Pen:
-        dbg.nospace() << qvariant_cast<QPen>(v);
-        break;
-#ifndef QT_NO_MATRIX4X4
-    case QVariant::Matrix4x4:
-        dbg.nospace() << qvariant_cast<QMatrix4x4>(v);
-        break;
-#endif
-#ifndef QT_NO_VECTOR2D
-    case QVariant::Vector2D:
-        dbg.nospace() << qvariant_cast<QVector2D>(v);
-        break;
-#endif
-#ifndef QT_NO_VECTOR3D
-    case QVariant::Vector3D:
-        dbg.nospace() << qvariant_cast<QVector3D>(v);
-        break;
-#endif
-#ifndef QT_NO_VECTOR4D
-    case QVariant::Vector4D:
-        dbg.nospace() << qvariant_cast<QVector4D>(v);
-        break;
-#endif
-#ifndef QT_NO_QUATERNION
-    case QVariant::Quaternion:
-        dbg.nospace() << qvariant_cast<QQuaternion>(v);
-        break;
-#endif
-    default:
-        qcoreVariantHandler()->debugStream(dbg, v);
-        break;
-    }
+    QVariant::Private *d = const_cast<QVariant::Private *>(&v.data_ptr());
+    QVariantDebugStream<GuiTypesFilter> stream(dbg, d);
+    QMetaTypeSwitcher::switcher<void>(stream, d->type, 0);
 }
 #endif
 
index e33d0da..e9fa99a 100644 (file)
@@ -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<QVariant::Private *>(&v.data_ptr());
+    switch (d->type) {
+#ifndef QT_NO_ICON
+    case QVariant::Icon:
+        dbg.nospace() << *v_cast<QIcon>(d);
+        break;
+#endif
+    case QVariant::SizePolicy:
+        dbg.nospace() << *v_cast<QSizePolicy>(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
index 8f75f13..c2d4f0a 100644 (file)
@@ -63,6 +63,7 @@
 #include <qvector3d.h>
 #include <qvector4d.h>
 #include <qquaternion.h>
+#include <qdebug.h>
 
 #include <limits.h>
 
@@ -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<QVariant>("variant");
+    QTest::addColumn<int>("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<QVariant::Type>(id)) << id;
+    }
+    QTest::newRow("QBitArray(111)") << QVariant(QBitArray(3, true)) << qMetaTypeId<QBitArray>();
+    QTest::newRow("CustomStreamableClass") << QVariant(qMetaTypeId<CustomStreamableClass>(), 0) << qMetaTypeId<CustomStreamableClass>();
+    QTest::newRow("MyClass") << QVariant(qMetaTypeId<MyClass>(), 0) << qMetaTypeId<MyClass>();
+}
+
+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"