Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qsignalspy.h
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QSIGNALSPY_H
5#define QSIGNALSPY_H
6
7#include <QtCore/qbytearray.h>
8#include <QtCore/qlist.h>
9#include <QtCore/qobject.h>
10#include <QtCore/qmetaobject.h>
11#include <QtTest/qtesteventloop.h>
12#include <QtCore/qvariant.h>
13
15
16
17class QVariant;
18
19class QSignalSpy: public QObject, public QList<QList<QVariant> >
20{
21public:
22 explicit QSignalSpy(const QObject *obj, const char *aSignal)
23 : m_waiting(false)
24 {
25 if (!isObjectValid(obj))
26 return;
27
28 if (!aSignal) {
29 qWarning("QSignalSpy: Null signal name is not valid");
30 return;
31 }
32
33 if (((aSignal[0] - '0') & 0x03) != QSIGNAL_CODE) {
34 qWarning("QSignalSpy: Not a valid signal, use the SIGNAL macro");
35 return;
36 }
37
39 const QMetaObject * const mo = obj->metaObject();
40 const int sigIndex = mo->indexOfMethod(ba.constData());
41 if (sigIndex < 0) {
42 qWarning("QSignalSpy: No such signal: '%s'", ba.constData());
43 return;
44 }
45
46 if (!connectToSignal(obj, sigIndex))
47 return;
48
49 sig = ba;
50 initArgs(mo->method(sigIndex), obj);
51 }
52
53#ifdef Q_QDOC
54 template <typename PointerToMemberFunction>
55 QSignalSpy(const QObject *object, PointerToMemberFunction signal);
56#else
57 template <typename Func>
59 : m_waiting(false)
60 {
61 if (!isObjectValid(obj))
62 return;
63
64 if (!signal0) {
65 qWarning("QSignalSpy: Null signal name is not valid");
66 return;
67 }
68
69 const QMetaObject * const mo = obj->metaObject();
70 const QMetaMethod signalMetaMethod = QMetaMethod::fromSignal(signal0);
71 const int sigIndex = signalMetaMethod.methodIndex();
72
73 if (!isSignalMetaMethodValid(signalMetaMethod))
74 return;
75
76 if (!connectToSignal(obj, sigIndex))
77 return;
78
79 sig = signalMetaMethod.methodSignature();
80 initArgs(mo->method(sigIndex), obj);
81 }
82#endif // Q_QDOC
83
85 : m_waiting(false)
86 {
87 if (isObjectValid(obj) && isSignalMetaMethodValid(signal) &&
88 connectToSignal(obj, signal.methodIndex())) {
89 sig = signal.methodSignature();
90 initArgs(signal, obj);
91 }
92 }
93
94 inline bool isValid() const { return !sig.isEmpty(); }
95 inline QByteArray signal() const { return sig; }
96
97 bool wait(int timeout)
98 { return wait(std::chrono::milliseconds{timeout}); }
99
100 bool wait(std::chrono::milliseconds timeout = std::chrono::seconds{5})
101 {
102 Q_ASSERT(!m_waiting);
103 const qsizetype origCount = size();
104 m_waiting = true;
105 m_loop.enterLoop(timeout);
106 m_waiting = false;
107 return size() > origCount;
108 }
109
110 int qt_metacall(QMetaObject::Call call, int methodId, void **a) override
111 {
112 methodId = QObject::qt_metacall(call, methodId, a);
113 if (methodId < 0)
114 return methodId;
115
116 if (call == QMetaObject::InvokeMetaMethod) {
117 if (methodId == 0) {
118 appendArgs(a);
119 }
120 --methodId;
121 }
122 return methodId;
123 }
124
125private:
126 bool connectToSignal(const QObject *sender, int sigIndex)
127 {
128 static const int memberOffset = QObject::staticMetaObject.methodCount();
129 const bool connected = QMetaObject::connect(
130 sender, sigIndex, this, memberOffset, Qt::DirectConnection, nullptr);
131
132 if (!connected)
133 qWarning("QSignalSpy: QMetaObject::connect returned false. Unable to connect.");
134
135 return connected;
136 }
137
138 static bool isSignalMetaMethodValid(const QMetaMethod &signal)
139 {
140 const bool valid = signal.isValid() && signal.methodType() == QMetaMethod::Signal;
141
142 if (!valid)
143 qWarning("QSignalSpy: Not a valid signal: '%s'", signal.methodSignature().constData());
144
145 return valid;
146 }
147
148 static bool isObjectValid(const QObject *object)
149 {
150 const bool valid = !!object;
151
152 if (!valid)
153 qWarning("QSignalSpy: Cannot spy on a null object");
154
155 return valid;
156 }
157
158 void initArgs(const QMetaMethod &member, const QObject *obj)
159 {
160 args.reserve(member.parameterCount());
161 for (int i = 0; i < member.parameterCount(); ++i) {
162 QMetaType tp = member.parameterMetaType(i);
163 if (!tp.isValid() && obj) {
164 void *argv[] = { &tp, &i };
165 QMetaObject::metacall(const_cast<QObject*>(obj),
167 member.methodIndex(), argv);
168 }
169 if (!tp.isValid()) {
170 qWarning("QSignalSpy: Unable to handle parameter '%s' of type '%s' of method '%s',"
171 " use qRegisterMetaType to register it.",
172 member.parameterNames().at(i).constData(),
173 member.parameterTypes().at(i).constData(),
174 member.name().constData());
175 }
176 args << tp.id();
177 }
178 }
179
180 void appendArgs(void **a)
181 {
183 list.reserve(args.size());
184 for (int i = 0; i < args.size(); ++i) {
185 const QMetaType::Type type = static_cast<QMetaType::Type>(args.at(i));
187 list << *reinterpret_cast<QVariant *>(a[i + 1]);
188 else
189 list << QVariant(QMetaType(type), a[i + 1]);
190 }
191 append(list);
192
193 if (m_waiting)
194 m_loop.exitLoop();
195 }
196
197 // the full, normalized signal name
198 QByteArray sig;
199 // holds the QMetaType types for the argument list of the signal
200 QList<int> args;
201
202 QTestEventLoop m_loop;
203 bool m_waiting;
204};
205
207
208#endif
bool connected
\inmodule QtCore
Definition qbytearray.h:57
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:122
bool isEmpty() const noexcept
Returns true if the byte array has size 0; otherwise returns false.
Definition qbytearray.h:106
Definition qlist.h:74
qsizetype size() const noexcept
Definition qlist.h:386
const_pointer constData() const noexcept
Definition qlist.h:416
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
void reserve(qsizetype size)
Definition qlist.h:746
void append(parameter_type t)
Definition qlist.h:441
\inmodule QtCore
Definition qmetaobject.h:18
static QMetaMethod fromSignal(PointerToMemberFunction signal)
int parameterCount() const
int methodIndex() const
QList< QByteArray > parameterTypes() const
Returns a list of parameter types.
QByteArray methodSignature() const
QMetaType parameterMetaType(int index) const
QByteArray name() const
QList< QByteArray > parameterNames() const
Returns a list of parameter names.
\inmodule QtCore
Definition qmetatype.h:320
bool isValid() const
int id(int=0) const
Definition qmetatype.h:454
Type
\macro Q_DECLARE_OPAQUE_POINTER(PointerType)
Definition qmetatype.h:324
friend class QVariant
Definition qmetatype.h:775
\inmodule QtCore
Definition qobject.h:90
QObject * sender() const
Returns a pointer to the object that sent the signal, if called in a slot activated by a signal; othe...
Definition qobject.cpp:2521
QSignalSpy(const typename QtPrivate::FunctionPointer< Func >::Object *obj, Func signal0)
Definition qsignalspy.h:58
QSignalSpy(const QObject *obj, const QMetaMethod &signal)
Definition qsignalspy.h:84
bool wait(int timeout)
Definition qsignalspy.h:97
QSignalSpy(const QObject *obj, const char *aSignal)
Definition qsignalspy.h:22
bool isValid() const
Definition qsignalspy.h:94
bool wait(std::chrono::milliseconds timeout=std::chrono::seconds{5})
Definition qsignalspy.h:100
QByteArray signal() const
Definition qsignalspy.h:95
int qt_metacall(QMetaObject::Call call, int methodId, void **a) override
Definition qsignalspy.h:110
void enterLoop(int secs)
\inmodule QtCore
Definition qvariant.h:64
auto mo
[7]
Combined button and popup list for selecting options.
@ DirectConnection
#define qWarning
Definition qlogging.h:162
#define QSIGNAL_CODE
Definition qobjectdefs.h:41
GLboolean GLboolean GLboolean GLboolean a
[7]
GLuint object
[3]
GLbitfield GLuint64 timeout
[4]
GLenum type
GLhandleARB obj
[2]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
ptrdiff_t qsizetype
Definition qtypes.h:70
QList< int > list
[14]
QByteArray ba
[0]
\inmodule QtCore
static int metacall(QObject *, Call, int, void **)
static QByteArray normalizedSignature(const char *method)
Normalizes the signature of the given method.
static Connection connect(const QObject *sender, int signal_index, const QObject *receiver, int method_index, int type=0, int *types=nullptr)
Definition qobject.cpp:3419
@ RegisterMethodArgumentMetaType