MetaObject: store the QMetaType of the properties
Change-Id: I563e7232b70e94de4184f2c23a581319313dcf5c Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
a68e4f3b96
commit
46f407126e
@ -2833,10 +2833,6 @@ QByteArray QMetaEnum::valueToKeys(int value) const
|
||||
The enum needs to be declared with Q_ENUM.
|
||||
*/
|
||||
|
||||
static QByteArray qualifiedName(const QMetaEnum &e)
|
||||
{
|
||||
return QByteArray(e.scope()) + "::" + e.name();
|
||||
}
|
||||
|
||||
/*!
|
||||
\class QMetaProperty
|
||||
@ -2927,65 +2923,45 @@ const char *QMetaProperty::typeName() const
|
||||
Returns this property's type. The return value is one
|
||||
of the values of the QVariant::Type enumeration.
|
||||
|
||||
\sa userType(), typeName(), name()
|
||||
\sa userType(), typeName(), name(), metaType()
|
||||
*/
|
||||
QVariant::Type QMetaProperty::type() const
|
||||
{
|
||||
if (!mobj)
|
||||
return QVariant::Invalid;
|
||||
int handle = priv(mobj->d.data)->propertyData + 3*idx;
|
||||
|
||||
Q_ASSERT(priv(mobj->d.data)->revision >= 7);
|
||||
uint type = typeFromTypeInfo(mobj, mobj->d.data[handle + 1]);
|
||||
uint type = userType();
|
||||
if (type >= QMetaType::User)
|
||||
return QVariant::UserType;
|
||||
if (type != QMetaType::UnknownType)
|
||||
return QVariant::Type(type);
|
||||
if (isEnumType()) {
|
||||
int enumMetaTypeId = QMetaType::type(qualifiedName(menum));
|
||||
if (enumMetaTypeId == QMetaType::UnknownType)
|
||||
return QVariant::Int;
|
||||
}
|
||||
#ifdef QT_COORD_TYPE
|
||||
// qreal metatype must be resolved at runtime.
|
||||
if (strcmp(typeName(), "qreal") == 0)
|
||||
return QVariant::Type(qMetaTypeId<qreal>());
|
||||
#endif
|
||||
|
||||
return QVariant::UserType;
|
||||
return QVariant::Type(type);
|
||||
}
|
||||
|
||||
/*!
|
||||
\since 4.2
|
||||
|
||||
Returns this property's user type. The return value is one
|
||||
of the values that are registered with QMetaType, or QMetaType::UnknownType if
|
||||
the type is not registered.
|
||||
of the values that are registered with QMetaType.
|
||||
|
||||
\sa type(), QMetaType, typeName()
|
||||
This is equivalent to metaType().id()
|
||||
|
||||
\sa type(), QMetaType, typeName(), metaType()
|
||||
*/
|
||||
int QMetaProperty::userType() const
|
||||
{
|
||||
if (!mobj)
|
||||
return QMetaType::UnknownType;
|
||||
Q_ASSERT(priv(mobj->d.data)->revision >= 7);
|
||||
int handle = priv(mobj->d.data)->propertyData + 3*idx;
|
||||
int type = typeFromTypeInfo(mobj, mobj->d.data[handle + 1]);
|
||||
if (type != QMetaType::UnknownType)
|
||||
return type;
|
||||
if (isEnumType()) {
|
||||
type = QMetaType::type(qualifiedName(menum));
|
||||
if (type == QMetaType::UnknownType) {
|
||||
type = registerPropertyType();
|
||||
if (type == QMetaType::UnknownType)
|
||||
return QMetaType::Int; // Match behavior of QMetaType::type()
|
||||
}
|
||||
return type;
|
||||
}
|
||||
type = QMetaType::type(typeName());
|
||||
if (type != QMetaType::UnknownType)
|
||||
return type;
|
||||
return registerPropertyType();
|
||||
return QMetaType(mobj->d.metaTypes[idx]).id();
|
||||
}
|
||||
|
||||
/*!
|
||||
\since 6.0
|
||||
|
||||
Returns this property's QMetaType.
|
||||
|
||||
\sa QMetaType
|
||||
*/
|
||||
QMetaType QMetaProperty::metaType() const
|
||||
{
|
||||
if (!mobj)
|
||||
return {};
|
||||
return QMetaType(mobj->d.metaTypes[idx]);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -3096,37 +3072,6 @@ QVariant QMetaProperty::read(const QObject *object) const
|
||||
if (!object || !mobj)
|
||||
return QVariant();
|
||||
|
||||
uint t = QMetaType::Int;
|
||||
if (isEnumType()) {
|
||||
/*
|
||||
try to create a QVariant that can be converted to this enum
|
||||
type (only works if the enum has already been registered
|
||||
with QMetaType)
|
||||
*/
|
||||
int enumMetaTypeId = QMetaType::type(qualifiedName(menum));
|
||||
if (enumMetaTypeId != QMetaType::UnknownType)
|
||||
t = enumMetaTypeId;
|
||||
} else {
|
||||
int handle = priv(mobj->d.data)->propertyData + 3*idx;
|
||||
const char *typeName = nullptr;
|
||||
Q_ASSERT(priv(mobj->d.data)->revision >= 7);
|
||||
uint typeInfo = mobj->d.data[handle + 1];
|
||||
if (!(typeInfo & IsUnresolvedType))
|
||||
t = typeInfo;
|
||||
else {
|
||||
typeName = rawStringData(mobj, typeInfo & TypeNameIndexMask);
|
||||
t = QMetaType::type(typeName);
|
||||
}
|
||||
if (t == QMetaType::UnknownType) {
|
||||
// Try to register the type and try again before reporting an error.
|
||||
t = registerPropertyType();
|
||||
if (t == QMetaType::UnknownType) {
|
||||
qWarning("QMetaProperty::read: Unable to handle unregistered datatype '%s' for property '%s::%s'", typeName, mobj->className(), name());
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// the status variable is changed by qt_metacall to indicate what it did
|
||||
// this feature is currently only used by Qt D-Bus and should not be depended
|
||||
// upon. Don't change it without looking into QDBusAbstractInterface first
|
||||
@ -3135,10 +3080,11 @@ QVariant QMetaProperty::read(const QObject *object) const
|
||||
int status = -1;
|
||||
QVariant value;
|
||||
void *argv[] = { nullptr, &value, &status };
|
||||
if (t == QMetaType::QVariant) {
|
||||
QMetaType t(mobj->d.metaTypes[idx]);
|
||||
if (t == QMetaType::fromType<QVariant>()) {
|
||||
argv[0] = &value;
|
||||
} else {
|
||||
value = QVariant(t, (void*)nullptr);
|
||||
value = QVariant(t, nullptr);
|
||||
argv[0] = value.data();
|
||||
}
|
||||
if (priv(mobj->d.data)->flags & PropertyAccessInStaticMetaCall && mobj->d.static_metacall) {
|
||||
@ -3150,9 +3096,9 @@ QVariant QMetaProperty::read(const QObject *object) const
|
||||
|
||||
if (status != -1)
|
||||
return value;
|
||||
if (t != QMetaType::QVariant && argv[0] != value.data())
|
||||
if (t != QMetaType::fromType<QVariant>() && argv[0] != value.data())
|
||||
// pointer or reference
|
||||
return QVariant((QVariant::Type)t, argv[0]);
|
||||
return QVariant(t, argv[0]);
|
||||
return value;
|
||||
}
|
||||
|
||||
@ -3173,9 +3119,10 @@ bool QMetaProperty::write(QObject *object, const QVariant &value) const
|
||||
return false;
|
||||
|
||||
QVariant v = value;
|
||||
uint t = QMetaType::UnknownType;
|
||||
if (isEnumType()) {
|
||||
if (v.userType() == QMetaType::QString) {
|
||||
QMetaType t(mobj->d.metaTypes[idx]);
|
||||
if (t != QMetaType::fromType<QVariant>() && t != v.metaType()) {
|
||||
if (isEnumType() && !t.metaObject() && v.userType() == QMetaType::QString) {
|
||||
// Assigning a string to a property of type Q_ENUMS (instead of Q_ENUM)
|
||||
bool ok;
|
||||
if (isFlagType())
|
||||
v = QVariant(menum.keysToValue(value.toByteArray(), &ok));
|
||||
@ -3183,39 +3130,14 @@ bool QMetaProperty::write(QObject *object, const QVariant &value) const
|
||||
v = QVariant(menum.keyToValue(value.toByteArray(), &ok));
|
||||
if (!ok)
|
||||
return false;
|
||||
} else if (v.userType() != QMetaType::Int && v.userType() != QMetaType::UInt) {
|
||||
int enumMetaTypeId = QMetaType::type(qualifiedName(menum));
|
||||
if ((enumMetaTypeId == QMetaType::UnknownType) || (v.userType() != enumMetaTypeId) || !v.constData())
|
||||
return false;
|
||||
v = QVariant(*reinterpret_cast<const int *>(v.constData()));
|
||||
}
|
||||
v.convert(QMetaType::Int);
|
||||
} else {
|
||||
int handle = priv(mobj->d.data)->propertyData + 3*idx;
|
||||
const char *typeName = nullptr;
|
||||
Q_ASSERT(priv(mobj->d.data)->revision >= 7);
|
||||
uint typeInfo = mobj->d.data[handle + 1];
|
||||
if (!(typeInfo & IsUnresolvedType))
|
||||
t = typeInfo;
|
||||
else {
|
||||
typeName = rawStringData(mobj, typeInfo & TypeNameIndexMask);
|
||||
t = QMetaType::type(typeName);
|
||||
if (t == QMetaType::UnknownType)
|
||||
t = registerPropertyType();
|
||||
if (t == QMetaType::UnknownType)
|
||||
return false;
|
||||
}
|
||||
if (t != QMetaType::QVariant && int(t) != value.userType()) {
|
||||
if (!value.isValid()) {
|
||||
if (isResettable())
|
||||
return reset(object);
|
||||
v = QVariant(t, nullptr);
|
||||
} else if (!v.convert(t)) {
|
||||
return false;
|
||||
}
|
||||
} else if (!value.isValid()) {
|
||||
if (isResettable())
|
||||
return reset(object);
|
||||
v = QVariant(t, nullptr);
|
||||
} else if (!v.convert(t.id())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// the status variable is changed by qt_metacall to indicate what it did
|
||||
// this feature is currently only used by Qt D-Bus and should not be depended
|
||||
// upon. Don't change it without looking into QDBusAbstractInterface first
|
||||
@ -3226,7 +3148,7 @@ bool QMetaProperty::write(QObject *object, const QVariant &value) const
|
||||
// interception of property writes.
|
||||
int flags = 0;
|
||||
void *argv[] = { nullptr, &v, &status, &flags };
|
||||
if (t == QMetaType::QVariant)
|
||||
if (t == QMetaType::fromType<QVariant>())
|
||||
argv[0] = &v;
|
||||
else
|
||||
argv[0] = v.data();
|
||||
|
@ -250,6 +250,7 @@ public:
|
||||
const char *typeName() const;
|
||||
QVariant::Type type() const;
|
||||
int userType() const;
|
||||
QMetaType metaType() const;
|
||||
int propertyIndex() const;
|
||||
int relativePropertyIndex() const;
|
||||
|
||||
|
@ -1196,6 +1196,7 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf,
|
||||
if (!relocatable) meta->d.superdata = d->superClass;
|
||||
meta->d.relatedMetaObjects = nullptr;
|
||||
meta->d.extradata = nullptr;
|
||||
meta->d.metaTypes = nullptr;
|
||||
meta->d.static_metacall = d->staticMetacallFunction;
|
||||
}
|
||||
|
||||
@ -1474,6 +1475,20 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf,
|
||||
size += sizeof(SuperData) * (d->relatedMetaObjects.size() + 1);
|
||||
}
|
||||
|
||||
if (d->properties.size() > 0) {
|
||||
ALIGN(size, QtPrivate::QMetaTypeInterface *);
|
||||
auto types = reinterpret_cast<QtPrivate::QMetaTypeInterface **>(buf + size);
|
||||
if (buf) {
|
||||
meta->d.metaTypes = types;
|
||||
for (const auto &prop : d->properties) {
|
||||
QMetaType mt(QMetaType::type(prop.type));
|
||||
*types = reinterpret_cast<QtPrivate::QMetaTypeInterface *&>(mt);
|
||||
types++;
|
||||
}
|
||||
}
|
||||
size += sizeof(QMetaType) * d->properties.size();
|
||||
}
|
||||
|
||||
// Align the final size and return it.
|
||||
ALIGN(size, void *);
|
||||
Q_ASSERT(!buf || size == expectedSize);
|
||||
|
@ -2764,6 +2764,11 @@ QMetaType QMetaType::fromType()
|
||||
return QMetaType(QtPrivate::qMetaTypeIntefaceForType<T>());
|
||||
}
|
||||
|
||||
template<typename... T>
|
||||
QtPrivate::QMetaTypeInterface *const qt_metaTypeArray[] = {
|
||||
QtPrivate::qMetaTypeIntefaceForType<T>()...
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QMETATYPE_H
|
||||
|
@ -101,6 +101,10 @@ class QMetaEnum;
|
||||
class QMetaProperty;
|
||||
class QMetaClassInfo;
|
||||
|
||||
namespace QtPrivate {
|
||||
class QMetaTypeInterface;
|
||||
}
|
||||
|
||||
struct QMethodRawArguments
|
||||
{
|
||||
void **arguments;
|
||||
@ -428,6 +432,7 @@ struct Q_CORE_EXPORT QMetaObject
|
||||
typedef void (*StaticMetacallFunction)(QObject *, QMetaObject::Call, int, void **);
|
||||
StaticMetacallFunction static_metacall;
|
||||
const SuperData *relatedMetaObjects;
|
||||
QtPrivate::QMetaTypeInterface *const *metaTypes;
|
||||
void *extradata; //reserved for future use
|
||||
} d;
|
||||
|
||||
|
@ -521,6 +521,9 @@ void QDBusMetaObjectGenerator::write(QDBusMetaObject *obj)
|
||||
offset += methodParametersDataSize;
|
||||
Q_ASSERT(offset == header->propertyData);
|
||||
|
||||
QMetaType *metaTypes = new QMetaType[properties.count()];
|
||||
int propertyId = 0;
|
||||
|
||||
// add each property
|
||||
signatureOffset = header->propertyDBusData;
|
||||
for (QMap<QByteArray, Property>::ConstIterator it = properties.constBegin();
|
||||
@ -535,6 +538,8 @@ void QDBusMetaObjectGenerator::write(QDBusMetaObject *obj)
|
||||
|
||||
idata[signatureOffset++] = strings.enter(mp.signature);
|
||||
idata[signatureOffset++] = mp.type;
|
||||
|
||||
metaTypes[propertyId++] = QMetaType(mp.type);
|
||||
}
|
||||
|
||||
Q_ASSERT(offset == header->propertyDBusData);
|
||||
@ -553,6 +558,7 @@ void QDBusMetaObjectGenerator::write(QDBusMetaObject *obj)
|
||||
obj->d.extradata = nullptr;
|
||||
obj->d.stringdata = reinterpret_cast<const uint *>(string_data);
|
||||
obj->d.superdata = &QDBusAbstractInterface::staticMetaObject;
|
||||
obj->d.metaTypes = reinterpret_cast<QtPrivate::QMetaTypeInterface *const *>(metaTypes);
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
@ -77,6 +77,7 @@ struct Q_DBUS_EXPORT QDBusMetaObject: public QMetaObject
|
||||
{
|
||||
delete [] reinterpret_cast<const char *>(d.stringdata);
|
||||
delete [] d.data;
|
||||
delete [] reinterpret_cast<const QMetaType *>(d.metaTypes);
|
||||
}
|
||||
|
||||
// methods (slots & signals):
|
||||
|
@ -83,6 +83,7 @@ class QDBusTrayIcon: public QPlatformSystemTrayIcon
|
||||
Q_PROPERTY(QString attentionIconName READ attentionIconName NOTIFY attention)
|
||||
Q_PROPERTY(QIcon attentionIcon READ attentionIcon NOTIFY attention)
|
||||
Q_PROPERTY(QDBusPlatformMenu *menu READ menu NOTIFY menuChanged)
|
||||
Q_MOC_INCLUDE("qdbusplatformmenu_p.h")
|
||||
|
||||
public:
|
||||
QDBusTrayIcon();
|
||||
|
@ -552,6 +552,18 @@ void Generator::generateCode()
|
||||
fprintf(out, " nullptr,\n");
|
||||
else
|
||||
fprintf(out, " qt_meta_extradata_%s,\n", qualifiedClassNameIdentifier.constData());
|
||||
|
||||
if (cdef->propertyList.isEmpty()) {
|
||||
fprintf(out, " nullptr,\n");
|
||||
} else {
|
||||
fprintf(out, "qt_metaTypeArray<\n");
|
||||
for (int i = 0; i < cdef->propertyList.count(); ++i) {
|
||||
const PropertyDef &p = cdef->propertyList.at(i);
|
||||
fprintf(out, "%s%s", i == 0 ? "" : ", ", p.type.data());
|
||||
}
|
||||
fprintf(out, ">,\n");
|
||||
}
|
||||
|
||||
fprintf(out, " nullptr\n} };\n\n");
|
||||
|
||||
if (!cdef->hasQObject)
|
||||
|
@ -1446,13 +1446,15 @@ void tst_QMetaObject::customPropertyType()
|
||||
QMetaProperty prop = metaObject()->property(metaObject()->indexOfProperty("value3"));
|
||||
|
||||
QCOMPARE(prop.type(), QVariant::UserType);
|
||||
QCOMPARE(prop.userType(), 0);
|
||||
QCOMPARE(prop.userType(), QMetaType::fromType<MyStruct>().id());
|
||||
QCOMPARE(prop.metaType(), QMetaType::fromType<MyStruct>());
|
||||
|
||||
qRegisterMetaType<MyStruct>("MyStruct");
|
||||
QCOMPARE(prop.userType(), QMetaType::type("MyStruct"));
|
||||
|
||||
prop = metaObject()->property(metaObject()->indexOfProperty("value4"));
|
||||
QCOMPARE(prop.type(), QVariant::List);
|
||||
QCOMPARE(prop.metaType(), QMetaType::fromType<QList<QVariant>>());
|
||||
|
||||
prop = metaObject()->property(metaObject()->indexOfProperty("value5"));
|
||||
QCOMPARE(prop.type(), QVariant::List);
|
||||
|
@ -138,6 +138,7 @@ void tst_QMetaProperty::gadget()
|
||||
const QMetaObject *mo = &MyGadget::staticMetaObject;
|
||||
QMetaProperty valueProp = mo->property(mo->indexOfProperty("value"));
|
||||
QVERIFY(valueProp.isValid());
|
||||
QCOMPARE(valueProp.metaType(), QMetaType::fromType<QString>());
|
||||
{
|
||||
MyGadget g;
|
||||
QString hello = QLatin1String("hello");
|
||||
|
@ -1914,7 +1914,7 @@ void tst_QObject::property()
|
||||
property = mo->property(mo->indexOfProperty("alpha"));
|
||||
QVERIFY(property.isEnumType());
|
||||
QCOMPARE(property.typeName(), "Alpha");
|
||||
QCOMPARE(property.type(), QVariant::Int);
|
||||
QCOMPARE(property.userType(), QMetaType::fromType<PropertyObject::Alpha>().id());
|
||||
|
||||
QVariant var = object.property("alpha");
|
||||
QVERIFY(!var.isNull());
|
||||
@ -1925,7 +1925,8 @@ void tst_QObject::property()
|
||||
QCOMPARE(object.property("alpha").toInt(), int(PropertyObject::Alpha2));
|
||||
QVERIFY(object.setProperty("alpha", "Alpha1"));
|
||||
QCOMPARE(object.property("alpha").toInt(), int(PropertyObject::Alpha1));
|
||||
QVERIFY(!object.setProperty("alpha", QVariant()));
|
||||
QVERIFY(object.setProperty("alpha", QVariant()));
|
||||
QCOMPARE(object.property("alpha").toInt(), 0);
|
||||
|
||||
QVERIFY(mo->indexOfProperty("number") != -1);
|
||||
QCOMPARE(object.property("number").toInt(), 0);
|
||||
@ -1995,7 +1996,7 @@ void tst_QObject::property()
|
||||
property = mo->property(mo->indexOfProperty("priority"));
|
||||
QVERIFY(property.isEnumType());
|
||||
QCOMPARE(property.typeName(), "Priority");
|
||||
QCOMPARE(property.type(), QVariant::Int);
|
||||
QCOMPARE(property.userType(), QMetaType::fromType<PropertyObject::Priority>().id());
|
||||
|
||||
var = object.property("priority");
|
||||
QVERIFY(!var.isNull());
|
||||
@ -2006,7 +2007,8 @@ void tst_QObject::property()
|
||||
QCOMPARE(object.property("priority").toInt(), int(PropertyObject::VeryHigh));
|
||||
QVERIFY(object.setProperty("priority", "High"));
|
||||
QCOMPARE(object.property("priority").toInt(), int(PropertyObject::High));
|
||||
QVERIFY(!object.setProperty("priority", QVariant()));
|
||||
QVERIFY(object.setProperty("priority", QVariant()));
|
||||
QCOMPARE(object.property("priority").toInt(), 0);
|
||||
|
||||
// now it's registered, so it works as expected
|
||||
int priorityMetaTypeId = qRegisterMetaType<PropertyObject::Priority>("PropertyObject::Priority");
|
||||
@ -2028,7 +2030,8 @@ void tst_QObject::property()
|
||||
QCOMPARE(qvariant_cast<PropertyObject::Priority>(object.property("priority")), PropertyObject::VeryHigh);
|
||||
QVERIFY(object.setProperty("priority", "High"));
|
||||
QCOMPARE(qvariant_cast<PropertyObject::Priority>(object.property("priority")), PropertyObject::High);
|
||||
QVERIFY(!object.setProperty("priority", QVariant()));
|
||||
QVERIFY(object.setProperty("priority", QVariant()));
|
||||
QCOMPARE(object.property("priority").toInt(), 0);
|
||||
|
||||
var = object.property("priority");
|
||||
QCOMPARE(qvariant_cast<PropertyObject::Priority>(var), PropertyObject::High);
|
||||
|
@ -3945,7 +3945,7 @@ void tst_Moc::testQNamespace()
|
||||
|
||||
EnumFromNamespaceClass obj;
|
||||
const QVariant prop = obj.property("prop");
|
||||
QCOMPARE(prop.type(), QMetaType::Int);
|
||||
QCOMPARE(prop.userType(), QMetaType::fromType<FooNamespace::Enum1>().id());
|
||||
QCOMPARE(prop.toInt(), int(FooNamespace::Enum1::Key2));
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user