QObject: port to new property system
Extended QObjectPrivate::ExtraData to store a pointer to its parent, and reimplemented qGetBindingStorage() function for QObjectPrivate::ExtraData. This allows to use Q_OBJECT_COMPAT_PROPERTY macro for a property, stored in QObjectPrivate::ExtraData and solves all the problems with calling a custom setter. Task-number: QTBUG-85520 Change-Id: I40e01c29430846359ef9160fa1ae97c702be9a18 Reviewed-by: Edward Welbourne <edward.welbourne@qt.io> Reviewed-by: Sona Kurazyan <sona.kurazyan@qt.io>
This commit is contained in:
parent
696f5ffc64
commit
1a65a4faf5
@ -67,7 +67,7 @@ quintptr Q_CORE_EXPORT qtHookData[] = {
|
|||||||
// The required sizes and offsets are tested in tests/auto/other/toolsupport.
|
// The required sizes and offsets are tested in tests/auto/other/toolsupport.
|
||||||
// When this fails and the change was intentional, adjust the test and
|
// When this fails and the change was intentional, adjust the test and
|
||||||
// adjust this value here.
|
// adjust this value here.
|
||||||
20
|
21
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(QHooks::LastHookIndex == sizeof(qtHookData) / sizeof(qtHookData[0]));
|
static_assert(QHooks::LastHookIndex == sizeof(qtHookData) / sizeof(qtHookData[0]));
|
||||||
|
@ -1214,6 +1214,11 @@ QObjectPrivate::Connection::~Connection()
|
|||||||
QString QObject::objectName() const
|
QString QObject::objectName() const
|
||||||
{
|
{
|
||||||
Q_D(const QObject);
|
Q_D(const QObject);
|
||||||
|
if (!d->extraData && QtPrivate::isAnyBindingEvaluating()) {
|
||||||
|
QObjectPrivate *dd = const_cast<QObjectPrivate *>(d);
|
||||||
|
// extraData is mutable, so this should be safe
|
||||||
|
dd->extraData = new QObjectPrivate::ExtraData(dd);
|
||||||
|
}
|
||||||
return d->extraData ? d->extraData->objectName : QString();
|
return d->extraData ? d->extraData->objectName : QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1223,15 +1228,28 @@ QString QObject::objectName() const
|
|||||||
void QObject::setObjectName(const QString &name)
|
void QObject::setObjectName(const QString &name)
|
||||||
{
|
{
|
||||||
Q_D(QObject);
|
Q_D(QObject);
|
||||||
|
|
||||||
if (!d->extraData)
|
if (!d->extraData)
|
||||||
d->extraData = new QObjectPrivate::ExtraData;
|
d->extraData = new QObjectPrivate::ExtraData(d);
|
||||||
|
|
||||||
|
d->extraData->objectName.removeBindingUnlessInWrapper();
|
||||||
|
|
||||||
if (d->extraData->objectName != name) {
|
if (d->extraData->objectName != name) {
|
||||||
d->extraData->objectName = name;
|
d->extraData->objectName.setValueBypassingBindings(name);
|
||||||
emit objectNameChanged(d->extraData->objectName, QPrivateSignal());
|
d->extraData->objectName.notify(); // also emits a signal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QBindable<QString> QObject::bindableObjectName()
|
||||||
|
{
|
||||||
|
Q_D(QObject);
|
||||||
|
|
||||||
|
if (!d->extraData)
|
||||||
|
d->extraData = new QObjectPrivate::ExtraData(d);
|
||||||
|
|
||||||
|
return QBindable<QString>(&d->extraData->objectName);
|
||||||
|
}
|
||||||
|
|
||||||
/*! \fn void QObject::objectNameChanged(const QString &objectName)
|
/*! \fn void QObject::objectNameChanged(const QString &objectName)
|
||||||
|
|
||||||
This signal is emitted after the object's name has been changed. The new object name is passed as \a objectName.
|
This signal is emitted after the object's name has been changed. The new object name is passed as \a objectName.
|
||||||
@ -1731,7 +1749,7 @@ int QObject::startTimer(int interval, Qt::TimerType timerType)
|
|||||||
}
|
}
|
||||||
int timerId = thisThreadData->eventDispatcher.loadRelaxed()->registerTimer(interval, timerType, this);
|
int timerId = thisThreadData->eventDispatcher.loadRelaxed()->registerTimer(interval, timerType, this);
|
||||||
if (!d->extraData)
|
if (!d->extraData)
|
||||||
d->extraData = new QObjectPrivate::ExtraData;
|
d->extraData = new QObjectPrivate::ExtraData(d);
|
||||||
d->extraData->runningTimers.append(timerId);
|
d->extraData->runningTimers.append(timerId);
|
||||||
return timerId;
|
return timerId;
|
||||||
}
|
}
|
||||||
@ -2164,7 +2182,7 @@ void QObject::installEventFilter(QObject *obj)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!d->extraData)
|
if (!d->extraData)
|
||||||
d->extraData = new QObjectPrivate::ExtraData;
|
d->extraData = new QObjectPrivate::ExtraData(d);
|
||||||
|
|
||||||
// clean up unused items in the list
|
// clean up unused items in the list
|
||||||
d->extraData->eventFilters.removeAll((QObject *)nullptr);
|
d->extraData->eventFilters.removeAll((QObject *)nullptr);
|
||||||
@ -3971,7 +3989,7 @@ bool QObject::setProperty(const char *name, const QVariant &value)
|
|||||||
int id = meta->indexOfProperty(name);
|
int id = meta->indexOfProperty(name);
|
||||||
if (id < 0) {
|
if (id < 0) {
|
||||||
if (!d->extraData)
|
if (!d->extraData)
|
||||||
d->extraData = new QObjectPrivate::ExtraData;
|
d->extraData = new QObjectPrivate::ExtraData(d);
|
||||||
|
|
||||||
const int idx = d->extraData->propertyNames.indexOf(name);
|
const int idx = d->extraData->propertyNames.indexOf(name);
|
||||||
|
|
||||||
|
@ -120,7 +120,8 @@ class Q_CORE_EXPORT QObject
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
Q_PROPERTY(QString objectName READ objectName WRITE setObjectName NOTIFY objectNameChanged)
|
Q_PROPERTY(QString objectName READ objectName WRITE setObjectName NOTIFY objectNameChanged
|
||||||
|
BINDABLE bindableObjectName)
|
||||||
Q_DECLARE_PRIVATE(QObject)
|
Q_DECLARE_PRIVATE(QObject)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -137,6 +138,7 @@ public:
|
|||||||
|
|
||||||
QString objectName() const;
|
QString objectName() const;
|
||||||
void setObjectName(const QString &name);
|
void setObjectName(const QString &name);
|
||||||
|
QBindable<QString> bindableObjectName();
|
||||||
|
|
||||||
inline bool isWidgetType() const { return d_ptr->isWidget; }
|
inline bool isWidgetType() const { return d_ptr->isWidget; }
|
||||||
inline bool isWindowType() const { return d_ptr->isWindow; }
|
inline bool isWindowType() const { return d_ptr->isWindow; }
|
||||||
|
@ -61,6 +61,7 @@
|
|||||||
#include "QtCore/qsharedpointer.h"
|
#include "QtCore/qsharedpointer.h"
|
||||||
#include "QtCore/qvariant.h"
|
#include "QtCore/qvariant.h"
|
||||||
#include "QtCore/qproperty.h"
|
#include "QtCore/qproperty.h"
|
||||||
|
#include "QtCore/private/qproperty_p.h"
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
@ -102,12 +103,26 @@ class Q_CORE_EXPORT QObjectPrivate : public QObjectData
|
|||||||
public:
|
public:
|
||||||
struct ExtraData
|
struct ExtraData
|
||||||
{
|
{
|
||||||
ExtraData() {}
|
ExtraData(QObjectPrivate *ptr) : parent(ptr) { }
|
||||||
|
|
||||||
|
inline void setObjectNameForwarder(const QString &name)
|
||||||
|
{
|
||||||
|
parent->q_func()->setObjectName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void nameChangedForwarder(const QString &name)
|
||||||
|
{
|
||||||
|
emit parent->q_func()->objectNameChanged(name, QObject::QPrivateSignal());
|
||||||
|
}
|
||||||
|
|
||||||
QList<QByteArray> propertyNames;
|
QList<QByteArray> propertyNames;
|
||||||
QList<QVariant> propertyValues;
|
QList<QVariant> propertyValues;
|
||||||
QList<int> runningTimers;
|
QList<int> runningTimers;
|
||||||
QList<QPointer<QObject>> eventFilters;
|
QList<QPointer<QObject>> eventFilters;
|
||||||
QString objectName;
|
Q_OBJECT_COMPAT_PROPERTY(QObjectPrivate::ExtraData, QString, objectName,
|
||||||
|
&QObjectPrivate::ExtraData::setObjectNameForwarder,
|
||||||
|
&QObjectPrivate::ExtraData::nameChangedForwarder)
|
||||||
|
QObjectPrivate *parent;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef void (*StaticMetaCallFunction)(QObject *, QMetaObject::Call, int, void **);
|
typedef void (*StaticMetaCallFunction)(QObject *, QMetaObject::Call, int, void **);
|
||||||
@ -369,8 +384,9 @@ public:
|
|||||||
cd->ref.ref();
|
cd->ref.ref();
|
||||||
connections.storeRelaxed(cd);
|
connections.storeRelaxed(cd);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ExtraData *extraData; // extra data set by the user
|
mutable ExtraData *extraData; // extra data set by the user
|
||||||
// This atomic requires acquire/release semantics in a few places,
|
// This atomic requires acquire/release semantics in a few places,
|
||||||
// e.g. QObject::moveToThread must synchronize with QCoreApplication::postEvent,
|
// e.g. QObject::moveToThread must synchronize with QCoreApplication::postEvent,
|
||||||
// because postEvent is thread-safe.
|
// because postEvent is thread-safe.
|
||||||
@ -619,7 +635,14 @@ inline QBindingStorage *qGetBindingStorage(QObjectPrivate *o)
|
|||||||
{
|
{
|
||||||
return &o->bindingStorage;
|
return &o->bindingStorage;
|
||||||
}
|
}
|
||||||
|
inline const QBindingStorage *qGetBindingStorage(const QObjectPrivate::ExtraData *ed)
|
||||||
|
{
|
||||||
|
return &ed->parent->bindingStorage;
|
||||||
|
}
|
||||||
|
inline QBindingStorage *qGetBindingStorage(QObjectPrivate::ExtraData *ed)
|
||||||
|
{
|
||||||
|
return &ed->parent->bindingStorage;
|
||||||
|
}
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
@ -9,9 +9,10 @@ qt_internal_add_test(tst_qobject
|
|||||||
tst_qobject.cpp
|
tst_qobject.cpp
|
||||||
DEFINES
|
DEFINES
|
||||||
QT_DISABLE_DEPRECATED_BEFORE=0
|
QT_DISABLE_DEPRECATED_BEFORE=0
|
||||||
PUBLIC_LIBRARIES
|
LIBRARIES
|
||||||
Qt::CorePrivate
|
Qt::CorePrivate
|
||||||
Qt::Network
|
Qt::Network
|
||||||
|
Qt::TestPrivate
|
||||||
)
|
)
|
||||||
|
|
||||||
## Scopes:
|
## Scopes:
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
**
|
**
|
||||||
** Copyright (C) 2016 The Qt Company Ltd.
|
** Copyright (C) 2021 The Qt Company Ltd.
|
||||||
** Copyright (C) 2015 Olivier Goffart <ogoffart@woboq.com>
|
** Copyright (C) 2015 Olivier Goffart <ogoffart@woboq.com>
|
||||||
** Contact: https://www.qt.io/licensing/
|
** Contact: https://www.qt.io/licensing/
|
||||||
**
|
**
|
||||||
@ -28,6 +28,7 @@
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#include <QTest>
|
#include <QTest>
|
||||||
|
#include <QtTest/private/qpropertytesthelper_p.h>
|
||||||
#include <QStringListModel>
|
#include <QStringListModel>
|
||||||
#include <QAbstractEventDispatcher>
|
#include <QAbstractEventDispatcher>
|
||||||
#include <QScopedValueRollback>
|
#include <QScopedValueRollback>
|
||||||
@ -161,6 +162,7 @@ private slots:
|
|||||||
void functorReferencesConnection();
|
void functorReferencesConnection();
|
||||||
void disconnectDisconnects();
|
void disconnectDisconnects();
|
||||||
void singleShotConnection();
|
void singleShotConnection();
|
||||||
|
void objectNameBinding();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct QObjectCreatedOnShutdown
|
struct QObjectCreatedOnShutdown
|
||||||
@ -8115,6 +8117,13 @@ void tst_QObject::singleShotConnection()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QObject::objectNameBinding()
|
||||||
|
{
|
||||||
|
QObject obj;
|
||||||
|
QTestPrivate::testReadWritePropertyBasics<QObject, QString>(obj, "test1", "test2",
|
||||||
|
"objectName");
|
||||||
|
}
|
||||||
|
|
||||||
// Test for QtPrivate::HasQ_OBJECT_Macro
|
// Test for QtPrivate::HasQ_OBJECT_Macro
|
||||||
static_assert(QtPrivate::HasQ_OBJECT_Macro<tst_QObject>::Value);
|
static_assert(QtPrivate::HasQ_OBJECT_Macro<tst_QObject>::Value);
|
||||||
static_assert(!QtPrivate::HasQ_OBJECT_Macro<SiblingDeleter>::Value);
|
static_assert(!QtPrivate::HasQ_OBJECT_Macro<SiblingDeleter>::Value);
|
||||||
|
@ -109,7 +109,7 @@ void tst_toolsupport::offsets_data()
|
|||||||
QTestData &data = QTest::newRow("sizeof(QObjectPrivate::ExtraData)")
|
QTestData &data = QTest::newRow("sizeof(QObjectPrivate::ExtraData)")
|
||||||
<< sizeof(QObjectPrivate::ExtraData);
|
<< sizeof(QObjectPrivate::ExtraData);
|
||||||
// Please heed the comment at the top of this file when changing this line:
|
// Please heed the comment at the top of this file when changing this line:
|
||||||
data << 60 << 120; // 4 * QList + 1 * QString
|
data << 64 << 128; // 4 * QList + 1 * QString + ptr
|
||||||
}
|
}
|
||||||
|
|
||||||
#if RUN_MEMBER_OFFSET_TEST
|
#if RUN_MEMBER_OFFSET_TEST
|
||||||
|
Loading…
x
Reference in New Issue
Block a user