Skip to content

Commit

Permalink
QObject: port to new property system
Browse files Browse the repository at this point in the history
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 <[email protected]>
Reviewed-by: Sona Kurazyan <[email protected]>
  • Loading branch information
isolovev committed Apr 21, 2021
1 parent 696f5ff commit 1a65a4f
Show file tree
Hide file tree
Showing 7 changed files with 68 additions and 15 deletions.
2 changes: 1 addition & 1 deletion src/corelib/global/qhooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ quintptr Q_CORE_EXPORT qtHookData[] = {
// The required sizes and offsets are tested in tests/auto/other/toolsupport.
// When this fails and the change was intentional, adjust the test and
// adjust this value here.
20
21
};

static_assert(QHooks::LastHookIndex == sizeof(qtHookData) / sizeof(qtHookData[0]));
Expand Down
30 changes: 24 additions & 6 deletions src/corelib/kernel/qobject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1214,6 +1214,11 @@ QObjectPrivate::Connection::~Connection()
QString QObject::objectName() const
{
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();
}

Expand All @@ -1223,15 +1228,28 @@ QString QObject::objectName() const
void QObject::setObjectName(const QString &name)
{
Q_D(QObject);

if (!d->extraData)
d->extraData = new QObjectPrivate::ExtraData;
d->extraData = new QObjectPrivate::ExtraData(d);

d->extraData->objectName.removeBindingUnlessInWrapper();

if (d->extraData->objectName != name) {
d->extraData->objectName = name;
emit objectNameChanged(d->extraData->objectName, QPrivateSignal());
d->extraData->objectName.setValueBypassingBindings(name);
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)
This signal is emitted after the object's name has been changed. The new object name is passed as \a objectName.
Expand Down Expand Up @@ -1731,7 +1749,7 @@ int QObject::startTimer(int interval, Qt::TimerType timerType)
}
int timerId = thisThreadData->eventDispatcher.loadRelaxed()->registerTimer(interval, timerType, this);
if (!d->extraData)
d->extraData = new QObjectPrivate::ExtraData;
d->extraData = new QObjectPrivate::ExtraData(d);
d->extraData->runningTimers.append(timerId);
return timerId;
}
Expand Down Expand Up @@ -2164,7 +2182,7 @@ void QObject::installEventFilter(QObject *obj)
}

if (!d->extraData)
d->extraData = new QObjectPrivate::ExtraData;
d->extraData = new QObjectPrivate::ExtraData(d);

// clean up unused items in the list
d->extraData->eventFilters.removeAll((QObject *)nullptr);
Expand Down Expand Up @@ -3971,7 +3989,7 @@ bool QObject::setProperty(const char *name, const QVariant &value)
int id = meta->indexOfProperty(name);
if (id < 0) {
if (!d->extraData)
d->extraData = new QObjectPrivate::ExtraData;
d->extraData = new QObjectPrivate::ExtraData(d);

const int idx = d->extraData->propertyNames.indexOf(name);

Expand Down
4 changes: 3 additions & 1 deletion src/corelib/kernel/qobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,8 @@ class Q_CORE_EXPORT QObject
{
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)

public:
Expand All @@ -137,6 +138,7 @@ class Q_CORE_EXPORT QObject

QString objectName() const;
void setObjectName(const QString &name);
QBindable<QString> bindableObjectName();

inline bool isWidgetType() const { return d_ptr->isWidget; }
inline bool isWindowType() const { return d_ptr->isWindow; }
Expand Down
31 changes: 27 additions & 4 deletions src/corelib/kernel/qobject_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
#include "QtCore/qsharedpointer.h"
#include "QtCore/qvariant.h"
#include "QtCore/qproperty.h"
#include "QtCore/private/qproperty_p.h"

QT_BEGIN_NAMESPACE

Expand Down Expand Up @@ -102,12 +103,26 @@ class Q_CORE_EXPORT QObjectPrivate : public QObjectData
public:
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<QVariant> propertyValues;
QList<int> runningTimers;
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 **);
Expand Down Expand Up @@ -369,8 +384,9 @@ class Q_CORE_EXPORT QObjectPrivate : public QObjectData
cd->ref.ref();
connections.storeRelaxed(cd);
}

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,
// e.g. QObject::moveToThread must synchronize with QCoreApplication::postEvent,
// because postEvent is thread-safe.
Expand Down Expand Up @@ -619,7 +635,14 @@ inline QBindingStorage *qGetBindingStorage(QObjectPrivate *o)
{
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

Expand Down
3 changes: 2 additions & 1 deletion tests/auto/corelib/kernel/qobject/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ qt_internal_add_test(tst_qobject
tst_qobject.cpp
DEFINES
QT_DISABLE_DEPRECATED_BEFORE=0
PUBLIC_LIBRARIES
LIBRARIES
Qt::CorePrivate
Qt::Network
Qt::TestPrivate
)

## Scopes:
Expand Down
11 changes: 10 additions & 1 deletion tests/auto/corelib/kernel/qobject/tst_qobject.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2021 The Qt Company Ltd.
** Copyright (C) 2015 Olivier Goffart <[email protected]>
** Contact: https://www.qt.io/licensing/
**
Expand Down Expand Up @@ -28,6 +28,7 @@
****************************************************************************/

#include <QTest>
#include <QtTest/private/qpropertytesthelper_p.h>
#include <QStringListModel>
#include <QAbstractEventDispatcher>
#include <QScopedValueRollback>
Expand Down Expand Up @@ -161,6 +162,7 @@ private slots:
void functorReferencesConnection();
void disconnectDisconnects();
void singleShotConnection();
void objectNameBinding();
};

struct QObjectCreatedOnShutdown
Expand Down Expand Up @@ -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
static_assert(QtPrivate::HasQ_OBJECT_Macro<tst_QObject>::Value);
static_assert(!QtPrivate::HasQ_OBJECT_Macro<SiblingDeleter>::Value);
Expand Down
2 changes: 1 addition & 1 deletion tests/auto/other/toolsupport/tst_toolsupport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ void tst_toolsupport::offsets_data()
QTestData &data = QTest::newRow("sizeof(QObjectPrivate::ExtraData)")
<< sizeof(QObjectPrivate::ExtraData);
// 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
Expand Down

0 comments on commit 1a65a4f

Please sign in to comment.