From 14c7bb72b98ef39a9118ae0a8e48a3ccd58db07d Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Sun, 1 Apr 2012 20:31:55 +0200 Subject: [PATCH] Store the QMetaObject with the QMetaType. MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This will allow conversion between pointers to compatible QObject derived types. Change-Id: I19e08934571fb3f1b91e594892214041fe5f6a11 Reviewed-by: Jędrzej Nowacki --- src/corelib/kernel/qmetatype.cpp | 65 +++++++++++++++++- src/corelib/kernel/qmetatype.h | 27 ++++++-- src/corelib/kernel/qmetatype_p.h | 13 +++- src/widgets/kernel/qwidgetsvariant.cpp | 3 + .../corelib/kernel/qmetatype/tst_qmetatype.cpp | 14 ++++ tests/auto/widgets/kernel/kernel.pro | 1 + .../kernel/qwidgetmetatype/qwidgetmetatype.pro | 4 ++ .../kernel/qwidgetmetatype/tst_qwidgetmetatype.cpp | 78 ++++++++++++++++++++++ 8 files changed, 198 insertions(+), 7 deletions(-) create mode 100644 tests/auto/widgets/kernel/qwidgetmetatype/qwidgetmetatype.pro create mode 100644 tests/auto/widgets/kernel/qwidgetmetatype/tst_qwidgetmetatype.cpp diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp index e1cebc4..ea079fa 100644 --- a/src/corelib/kernel/qmetatype.cpp +++ b/src/corelib/kernel/qmetatype.cpp @@ -286,6 +286,7 @@ static const struct { const char * typeName; int typeNameLength; int type; } typ Q_CORE_EXPORT const QMetaTypeInterface *qMetaTypeGuiHelper = 0; Q_CORE_EXPORT const QMetaTypeInterface *qMetaTypeWidgetsHelper = 0; +Q_CORE_EXPORT const QMetaObject *qMetaObjectWidgetsHelper = 0; class QCustomTypeInfo : public QMetaTypeInterface { @@ -496,6 +497,7 @@ int QMetaType::registerNormalizedType(const NS(QByteArray) &normalizedTypeName, inf.destructor = destructor; inf.size = size; inf.flags = flags; + inf.metaObject = metaObject; idx = ct->size() + User; ct->append(inf); return idx; @@ -1521,6 +1523,51 @@ QMetaType::TypeFlags QMetaType::typeFlags(int type) return static_cast(QMetaTypeSwitcher::switcher(flags, type, 0)); } +#ifndef QT_BOOTSTRAPPED +namespace { +class MetaObject +{ +public: + MetaObject(const int type) + : m_type(type) + {} + template + const QMetaObject *delegate(const T*) { return QtPrivate::MetaObjectForType::value(); } + const QMetaObject *delegate(const void*) { return 0; } + const QMetaObject *delegate(const QMetaTypeSwitcher::UnknownType*) { return 0; } + const QMetaObject *delegate(const QMetaTypeSwitcher::NotBuiltinType*) { return customMetaObject(m_type); } +private: + const int m_type; + static const QMetaObject *customMetaObject(const int type) + { + const QVector * const ct = customTypes(); + if (Q_UNLIKELY(!ct || type < QMetaType::User)) + return 0; + QReadLocker locker(customTypesLock()); + if (Q_UNLIKELY(ct->count() <= type - QMetaType::User)) + return 0; + return ct->at(type - QMetaType::User).metaObject; + } +}; +} // namespace +#endif + +/*! + \since 5.0 + + Returns QMetaObject of a given \a type, if the \a type is a pointer to type derived from QObject. +*/ +const QMetaObject *QMetaType::metaObjectForType(int type) +{ +#ifndef QT_BOOTSTRAPPED + MetaObject mo(type); + return QMetaTypeSwitcher::switcher(mo, type, 0); +#else + Q_UNUSED(type); + return 0; +#endif +} + /*! \fn int qRegisterMetaType(const char *typeName) \relates QMetaType @@ -1710,7 +1757,7 @@ QMetaType QMetaType::typeInfo(const int type) , typeInfo.info.size , typeInfo.info.flags , type - , 0) + , typeInfo.info.metaObject) : QMetaType(UnknownType); } @@ -1809,4 +1856,20 @@ QMetaType::TypeFlags QMetaType::flagsExtended() const return 0; } +const QMetaObject *QMetaType::metaObjectExtended() const +{ + return 0; +} + + +namespace QtPrivate +{ +const QMetaObject *metaObjectForQWidget() +{ + if (!qMetaTypeWidgetsHelper) + return 0; + return qMetaObjectWidgetsHelper; +} +} + QT_END_NAMESPACE diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h index fa0726a..a42333f 100644 --- a/src/corelib/kernel/qmetatype.h +++ b/src/corelib/kernel/qmetatype.h @@ -196,7 +196,7 @@ class Q_CORE_EXPORT QMetaType { ConstructEx = 0x4, DestructEx = 0x8, NameEx = 0x10, SizeEx = 0x20, CtorEx = 0x40, DtorEx = 0x80, - FlagsEx = 0x100 + FlagsEx = 0x100, MetaObjectEx = 0x200 }; public: #ifndef Q_QDOC @@ -290,6 +290,7 @@ public: static const char *typeName(int type); static int sizeOf(int type); static TypeFlags typeFlags(int type); + static const QMetaObject *metaObjectForType(int type); static bool isRegistered(int type); static void *create(int type, const void *copy = 0); #if QT_DEPRECATED_SINCE(5, 0) @@ -312,6 +313,7 @@ public: inline bool isRegistered() const; inline int sizeOf() const; inline TypeFlags flags() const; + inline const QMetaObject *metaObject() const; inline void *create(const void *copy = 0) const; inline void destroy(void *data) const; @@ -339,6 +341,7 @@ private: void dtor(); uint sizeExtended() const; QMetaType::TypeFlags flagsExtended() const; + const QMetaObject *metaObjectExtended() const; void *createExtended(const void *copy = 0) const; void destroyExtended(void *data) const; void *constructExtended(void *where, const void *copy = 0) const; @@ -355,7 +358,7 @@ private: uint m_typeFlags; uint m_extensionFlags; int m_typeId; - const QMetaObject *m_metaObject; // Placeholder for Qt 5.1 feature. + const QMetaObject *m_metaObject; }; #undef QT_DEFINE_METATYPE_ID @@ -466,12 +469,21 @@ namespace QtPrivate { static inline const QMetaObject *value() { return 0; } }; + template struct MetaObjectForType { static inline const QMetaObject *value() { return &T::staticMetaObject; } }; + Q_CORE_EXPORT const QMetaObject *metaObjectForQWidget(); + + template<> + struct MetaObjectForType + { + static const QMetaObject *value() { return metaObjectForQWidget(); } + }; + template struct IsSharedPointerToTypeDerivedFromQObject { @@ -846,7 +858,7 @@ inline QMetaType::QMetaType(const ExtensionFlag extensionFlags, const QMetaTypeI uint size, uint theTypeFlags, int typeId, - const QMetaObject *metaObject) + const QMetaObject *_metaObject) : m_creator(creator) , m_deleter(deleter) , m_saveOp(saveOp) @@ -858,7 +870,7 @@ inline QMetaType::QMetaType(const ExtensionFlag extensionFlags, const QMetaTypeI , m_typeFlags(theTypeFlags) , m_extensionFlags(extensionFlags) , m_typeId(typeId) - , m_metaObject(metaObject) + , m_metaObject(_metaObject) { if (Q_UNLIKELY(isExtended(CtorEx) || typeId == QMetaType::Void)) ctor(info); @@ -924,6 +936,13 @@ inline QMetaType::TypeFlags QMetaType::flags() const return QMetaType::TypeFlags(m_typeFlags); } +inline const QMetaObject *QMetaType::metaObject() const +{ + if (Q_UNLIKELY(isExtended(MetaObjectEx))) + return metaObjectExtended(); + return m_metaObject; +} + QT_END_NAMESPACE diff --git a/src/corelib/kernel/qmetatype_p.h b/src/corelib/kernel/qmetatype_p.h index cffc45c..126acde 100644 --- a/src/corelib/kernel/qmetatype_p.h +++ b/src/corelib/kernel/qmetatype_p.h @@ -130,6 +130,7 @@ public: QMetaType::Destructor destructor; int size; quint32 flags; // same as QMetaType::TypeFlags + const QMetaObject *metaObject; }; #ifndef QT_NO_DATASTREAM @@ -147,6 +148,12 @@ public: QT_METATYPE_INTERFACE_INIT_EMPTY_DATASTREAM_IMPL(Type) #endif +#ifndef QT_BOOTSTRAPPED +#define METAOBJECT_DELEGATE(Type) (QtPrivate::MetaObjectForType::value()) +#else +#define METAOBJECT_DELEGATE(Type) 0 +#endif + #define QT_METATYPE_INTERFACE_INIT_IMPL(Type, DATASTREAM_DELEGATE) \ { \ /*creator*/(qMetaTypeCreateHelper), \ @@ -155,7 +162,8 @@ public: /*constructor*/(qMetaTypeConstructHelper), \ /*destructor*/(qMetaTypeDestructHelper), \ /*size*/(QTypeInfo::sizeOf), \ - /*flags*/QtPrivate::QMetaTypeTypeFlags::Flags \ + /*flags*/QtPrivate::QMetaTypeTypeFlags::Flags, \ + /*metaObject*/METAOBJECT_DELEGATE(Type) \ } @@ -179,7 +187,8 @@ public: /*constructor*/ 0, \ /*destructor*/ 0, \ /*size*/ 0, \ - /*flags*/ 0 \ + /*flags*/ 0, \ + /*metaObject*/ 0 \ } namespace QtMetaTypePrivate { diff --git a/src/widgets/kernel/qwidgetsvariant.cpp b/src/widgets/kernel/qwidgetsvariant.cpp index da75536..0e4d44b 100644 --- a/src/widgets/kernel/qwidgetsvariant.cpp +++ b/src/widgets/kernel/qwidgetsvariant.cpp @@ -42,6 +42,7 @@ #include "qvariant.h" #include "qsizepolicy.h" +#include "qwidget.h" #include "private/qvariant_p.h" #include @@ -151,10 +152,12 @@ static const QMetaTypeInterface qVariantWidgetsHelper[] = { } // namespace extern Q_CORE_EXPORT const QMetaTypeInterface *qMetaTypeWidgetsHelper; +extern Q_CORE_EXPORT const QMetaObject *qMetaObjectWidgetsHelper; void qRegisterWidgetsVariant() { qMetaTypeWidgetsHelper = qVariantWidgetsHelper; + qMetaObjectWidgetsHelper = &QWidget::staticMetaObject; QVariantPrivate::registerHandler(QModulesPrivate::Widgets, &widgets_handler); } Q_CONSTRUCTOR_FUNCTION(qRegisterWidgetsVariant) diff --git a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp index f1053ad..b616257 100644 --- a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp +++ b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp @@ -106,6 +106,7 @@ private slots: void saveAndLoadBuiltin_data(); void saveAndLoadBuiltin(); void saveAndLoadCustom(); + void metaObject(); }; struct Foo { int i; }; @@ -1618,6 +1619,19 @@ void tst_QMetaType::saveAndLoadCustom() QCOMPARE(stream.status(), QDataStream::ReadPastEnd); } +void tst_QMetaType::metaObject() +{ + QCOMPARE(QMetaType::metaObjectForType(QMetaType::QObjectStar), &QObject::staticMetaObject); + QCOMPARE(QMetaType::metaObjectForType(::qMetaTypeId()), &QFile::staticMetaObject); + QCOMPARE(QMetaType::metaObjectForType(::qMetaTypeId()), &MyObject::staticMetaObject); + QCOMPARE(QMetaType::metaObjectForType(QMetaType::Int), static_cast(0)); + + QCOMPARE(QMetaType(QMetaType::QObjectStar).metaObject(), &QObject::staticMetaObject); + QCOMPARE(QMetaType(::qMetaTypeId()).metaObject(), &QFile::staticMetaObject); + QCOMPARE(QMetaType(::qMetaTypeId()).metaObject(), &MyObject::staticMetaObject); + QCOMPARE(QMetaType(QMetaType::Int).metaObject(), static_cast(0)); +} + // Compile-time test, it should be possible to register function pointer types class Undefined; diff --git a/tests/auto/widgets/kernel/kernel.pro b/tests/auto/widgets/kernel/kernel.pro index 14ebda2..5947dcb 100644 --- a/tests/auto/widgets/kernel/kernel.pro +++ b/tests/auto/widgets/kernel/kernel.pro @@ -13,6 +13,7 @@ SUBDIRS=\ qwidget \ qwidget_window \ qwidgetaction \ + qwidgetmetatype \ qshortcut \ qsizepolicy diff --git a/tests/auto/widgets/kernel/qwidgetmetatype/qwidgetmetatype.pro b/tests/auto/widgets/kernel/qwidgetmetatype/qwidgetmetatype.pro new file mode 100644 index 0000000..55228e6 --- /dev/null +++ b/tests/auto/widgets/kernel/qwidgetmetatype/qwidgetmetatype.pro @@ -0,0 +1,4 @@ +CONFIG += testcase +TARGET = tst_qwidgetmetatype +QT += widgets testlib +SOURCES += tst_qwidgetmetatype.cpp diff --git a/tests/auto/widgets/kernel/qwidgetmetatype/tst_qwidgetmetatype.cpp b/tests/auto/widgets/kernel/qwidgetmetatype/tst_qwidgetmetatype.cpp new file mode 100644 index 0000000..9d2fd14 --- /dev/null +++ b/tests/auto/widgets/kernel/qwidgetmetatype/tst_qwidgetmetatype.cpp @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Stephen Kelly +** Contact: http://www.qt-project.org/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include +#include +#include + +class tst_QWidgetMetaType : public QObject +{ + Q_OBJECT + +public: + tst_QWidgetMetaType() {} + virtual ~tst_QWidgetMetaType() {} + +private slots: + void metaObject(); +}; + +class CustomWidget : public QWidget +{ + Q_OBJECT +public: + CustomWidget(QWidget *parent = 0) + : QWidget(parent) + { + + } +}; + +void tst_QWidgetMetaType::metaObject() +{ + QCOMPARE(QMetaType::metaObjectForType(QMetaType::QWidgetStar), &QWidget::staticMetaObject); + QCOMPARE(QMetaType::metaObjectForType(qMetaTypeId()), &QLabel::staticMetaObject); + QCOMPARE(QMetaType::metaObjectForType(qMetaTypeId()), &CustomWidget::staticMetaObject); +} + +QTEST_MAIN(tst_QWidgetMetaType) +#include "tst_qwidgetmetatype.moc" -- 2.7.4