Add private API to connect to slots in QObjectPrivate
Change-Id: I16ffbf91ff4c6e9fca6fe7984800d2c24e70701b Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
b997481fcb
commit
ab59a7ef09
@ -1,6 +1,7 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Copyright (C) 2013 Olivier Goffart <ogoffart@woboq.com>
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the QtCore module of the Qt Toolkit.
|
||||
@ -198,6 +199,14 @@ public:
|
||||
inline void connectNotify(const QMetaMethod &signal);
|
||||
inline void disconnectNotify(const QMetaMethod &signal);
|
||||
|
||||
template <typename Func1, typename Func2>
|
||||
static inline QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
|
||||
const typename QtPrivate::FunctionPointer<Func2>::Object *receiverPrivate, Func2 slot,
|
||||
Qt::ConnectionType type = Qt::AutoConnection);
|
||||
|
||||
template <typename Func1, typename Func2>
|
||||
static inline bool disconnect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
|
||||
const typename QtPrivate::FunctionPointer<Func2>::Object *receiverPrivate, Func2 slot);
|
||||
public:
|
||||
ExtraData *extraData; // extra data set by the user
|
||||
QThreadData *threadData; // id of the thread that owns the object
|
||||
@ -267,6 +276,74 @@ inline void QObjectPrivate::disconnectNotify(const QMetaMethod &signal)
|
||||
q_ptr->disconnectNotify(signal);
|
||||
}
|
||||
|
||||
namespace QtPrivate {
|
||||
template<typename Func, typename Args, typename R> class QPrivateSlotObject : public QSlotObjectBase
|
||||
{
|
||||
typedef QtPrivate::FunctionPointer<Func> FuncType;
|
||||
Func function;
|
||||
static void impl(int which, QSlotObjectBase *this_, QObject *r, void **a, bool *ret)
|
||||
{
|
||||
switch (which) {
|
||||
case Destroy:
|
||||
delete static_cast<QPrivateSlotObject*>(this_);
|
||||
break;
|
||||
case Call:
|
||||
FuncType::template call<Args, R>(static_cast<QPrivateSlotObject*>(this_)->function,
|
||||
static_cast<typename FuncType::Object *>(QObjectPrivate::get(r)), a);
|
||||
break;
|
||||
case Compare:
|
||||
*ret = *reinterpret_cast<Func *>(a) == static_cast<QPrivateSlotObject*>(this_)->function;
|
||||
break;
|
||||
case NumOperations: ;
|
||||
}
|
||||
}
|
||||
public:
|
||||
explicit QPrivateSlotObject(Func f) : QSlotObjectBase(&impl), function(f) {}
|
||||
};
|
||||
} //namespace QtPrivate
|
||||
|
||||
template <typename Func1, typename Func2>
|
||||
inline QMetaObject::Connection QObjectPrivate::connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
|
||||
const typename QtPrivate::FunctionPointer<Func2>::Object *receiverPrivate, Func2 slot,
|
||||
Qt::ConnectionType type)
|
||||
{
|
||||
typedef QtPrivate::FunctionPointer<Func1> SignalType;
|
||||
typedef QtPrivate::FunctionPointer<Func2> SlotType;
|
||||
reinterpret_cast<typename SignalType::Object *>(0)->qt_check_for_QOBJECT_macro(*reinterpret_cast<typename SignalType::Object *>(0));
|
||||
|
||||
//compilation error if the arguments does not match.
|
||||
Q_STATIC_ASSERT_X(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount),
|
||||
"The slot requires more arguments than the signal provides.");
|
||||
Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value),
|
||||
"Signal and slot arguments are not compatible.");
|
||||
Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible<typename SlotType::ReturnType, typename SignalType::ReturnType>::value),
|
||||
"Return type of the slot is not compatible with the return type of the signal.");
|
||||
|
||||
const int *types = 0;
|
||||
if (type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection)
|
||||
types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types();
|
||||
|
||||
return QObject::connectImpl(sender, reinterpret_cast<void **>(&signal),
|
||||
receiverPrivate->q_func(), reinterpret_cast<void **>(&slot),
|
||||
new QtPrivate::QPrivateSlotObject<Func2, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value,
|
||||
typename SignalType::ReturnType>(slot),
|
||||
type, types, &SignalType::Object::staticMetaObject);
|
||||
}
|
||||
|
||||
template <typename Func1, typename Func2>
|
||||
bool QObjectPrivate::disconnect(const typename QtPrivate::FunctionPointer< Func1 >::Object* sender, Func1 signal,
|
||||
const typename QtPrivate::FunctionPointer< Func2 >::Object* receiverPrivate, Func2 slot)
|
||||
{
|
||||
typedef QtPrivate::FunctionPointer<Func1> SignalType;
|
||||
typedef QtPrivate::FunctionPointer<Func2> SlotType;
|
||||
reinterpret_cast<typename SignalType::Object *>(0)->qt_check_for_QOBJECT_macro(*reinterpret_cast<typename SignalType::Object *>(0));
|
||||
//compilation error if the arguments does not match.
|
||||
Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value),
|
||||
"Signal and slot arguments are not compatible.");
|
||||
return QObject::disconnectImpl(sender, reinterpret_cast<void **>(&signal),
|
||||
receiverPrivate->q_func(), reinterpret_cast<void **>(&slot),
|
||||
&SignalType::Object::staticMetaObject);
|
||||
}
|
||||
|
||||
Q_DECLARE_TYPEINFO(QObjectPrivate::Connection, Q_MOVABLE_TYPE);
|
||||
Q_DECLARE_TYPEINFO(QObjectPrivate::Sender, Q_MOVABLE_TYPE);
|
||||
|
@ -141,6 +141,7 @@ private slots:
|
||||
void returnValue2_data();
|
||||
void returnValue2();
|
||||
void connectVirtualSlots();
|
||||
void connectPrivateSlots();
|
||||
void connectFunctorArgDifference();
|
||||
void disconnectDoesNotLeakFunctor();
|
||||
};
|
||||
@ -5565,6 +5566,72 @@ void tst_QObject::connectVirtualSlots()
|
||||
*/
|
||||
}
|
||||
|
||||
#ifndef QT_BUILD_INTERNAL
|
||||
void tst_QObject::connectPrivateSlots()
|
||||
{QSKIP("Needs QT_BUILD_INTERNAL");}
|
||||
#else
|
||||
class ConnectToPrivateSlotPrivate;
|
||||
|
||||
class ConnectToPrivateSlot :public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
ConnectToPrivateSlot();
|
||||
void test(SenderObject *obj1) ;
|
||||
Q_DECLARE_PRIVATE(ConnectToPrivateSlot)
|
||||
};
|
||||
|
||||
class ConnectToPrivateSlotPrivate : public QObjectPrivate {
|
||||
public:
|
||||
Q_DECLARE_PUBLIC(ConnectToPrivateSlot)
|
||||
int receivedCount;
|
||||
QVariant receivedValue;
|
||||
|
||||
void thisIsAPrivateSlot() {
|
||||
receivedCount++;
|
||||
};
|
||||
|
||||
void thisIsAPrivateSlotWithArg(const QVariant &v) {
|
||||
receivedCount++;
|
||||
receivedValue = v;
|
||||
};
|
||||
};
|
||||
|
||||
ConnectToPrivateSlot::ConnectToPrivateSlot(): QObject(*new ConnectToPrivateSlotPrivate) {}
|
||||
|
||||
void ConnectToPrivateSlot::test(SenderObject* obj1) {
|
||||
Q_D(ConnectToPrivateSlot);
|
||||
d->receivedCount = 0;
|
||||
QVERIFY(QObjectPrivate::connect(obj1, &SenderObject::signal1, d, &ConnectToPrivateSlotPrivate::thisIsAPrivateSlot));
|
||||
QVERIFY(QObjectPrivate::connect(obj1, &SenderObject::signal7, d, &ConnectToPrivateSlotPrivate::thisIsAPrivateSlotWithArg));
|
||||
QCOMPARE(d->receivedCount, 0);
|
||||
obj1->signal1();
|
||||
QCOMPARE(d->receivedCount, 1);
|
||||
QCOMPARE(d->receivedValue, QVariant());
|
||||
obj1->signal7(666, QLatin1Literal("_"));
|
||||
QCOMPARE(d->receivedCount, 2);
|
||||
QCOMPARE(d->receivedValue, QVariant(666));
|
||||
QVERIFY(QObjectPrivate::connect(obj1, &SenderObject::signal2, d, &ConnectToPrivateSlotPrivate::thisIsAPrivateSlot, Qt::UniqueConnection));
|
||||
QVERIFY(!QObjectPrivate::connect(obj1, &SenderObject::signal2, d, &ConnectToPrivateSlotPrivate::thisIsAPrivateSlot, Qt::UniqueConnection));
|
||||
obj1->signal2();
|
||||
QCOMPARE(d->receivedCount, 3);
|
||||
QVERIFY(QObjectPrivate::disconnect(obj1, &SenderObject::signal2, d, &ConnectToPrivateSlotPrivate::thisIsAPrivateSlot));
|
||||
obj1->signal2();
|
||||
QCOMPARE(d->receivedCount, 3);
|
||||
QVERIFY(!QObjectPrivate::disconnect(obj1, &SenderObject::signal2, d, &ConnectToPrivateSlotPrivate::thisIsAPrivateSlot));
|
||||
}
|
||||
|
||||
void tst_QObject::connectPrivateSlots()
|
||||
{
|
||||
SenderObject sender;
|
||||
{
|
||||
ConnectToPrivateSlot o;
|
||||
o.test(&sender);
|
||||
}
|
||||
sender.signal7(777, QLatin1String("check that deleting the object properly disconnected"));
|
||||
sender.signal1();
|
||||
}
|
||||
#endif
|
||||
|
||||
struct SlotFunctor
|
||||
{
|
||||
void operator()() {}
|
||||
|
Loading…
Reference in New Issue
Block a user