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#include "qsignaltransition.h"
5#include "qsignaltransition_p.h"
6#include "qstate.h"
7#include "qstate_p.h"
8#include "qstatemachine.h"
9#include "qstatemachine_p.h"
10#include <qdebug.h>
11
12QT_BEGIN_NAMESPACE
13
14/*!
15 \class QSignalTransition
16 \inmodule QtStateMachine
17
18 \brief The QSignalTransition class provides a transition based on a Qt signal.
19
20 \since 4.6
21 \ingroup statemachine
22
23 Typically you would use the overload of QState::addTransition() that takes a
24 sender and signal as arguments, rather than creating QSignalTransition
25 objects directly. QSignalTransition is part of \l{Qt State Machine Overview}
26 {Qt State Machine Framework}.
27
28 You can subclass QSignalTransition and reimplement eventTest() to make a
29 signal transition conditional; the event object passed to eventTest() will
30 be a QStateMachine::SignalEvent object. Example:
31
32 \code
33 class CheckedTransition : public QSignalTransition
34 {
35 public:
36 CheckedTransition(QCheckBox *check)
37 : QSignalTransition(check, SIGNAL(stateChanged(int))) {}
38 protected:
39 bool eventTest(QEvent *e) {
40 if (!QSignalTransition::eventTest(e))
41 return false;
42 QStateMachine::SignalEvent *se = static_cast<QStateMachine::SignalEvent*>(e);
43 return (se->arguments().at(0).toInt() == Qt::Checked);
44 }
45 };
46
47 ...
48
49 QCheckBox *check = new QCheckBox();
50 check->setTristate(true);
51
52 QState *s1 = new QState();
53 QState *s2 = new QState();
54 CheckedTransition *t1 = new CheckedTransition(check);
55 t1->setTargetState(s2);
56 s1->addTransition(t1);
57 \endcode
58*/
59
60/*!
61 \property QSignalTransition::senderObject
62
63 \brief the sender object that this signal transition is associated with
64*/
65
66/*!
67 \property QSignalTransition::signal
68
69 \brief the signal that this signal transition is associated with
70*/
71
72QSignalTransitionPrivate::QSignalTransitionPrivate()
73{
74 signalIndex = -1;
75}
76
77void QSignalTransitionPrivate::unregister()
78{
79 Q_Q(QSignalTransition);
80 if ((signalIndex == -1) || !machine())
81 return;
82 QStateMachinePrivate::get(q: machine())->unregisterSignalTransition(transition: q);
83}
84
85void QSignalTransitionPrivate::maybeRegister()
86{
87 Q_Q(QSignalTransition);
88 if (QStateMachine *mach = machine())
89 QStateMachinePrivate::get(q: mach)->maybeRegisterSignalTransition(transition: q);
90}
91
92/*!
93 Constructs a new signal transition with the given \a sourceState.
94*/
95QSignalTransition::QSignalTransition(QState *sourceState)
96 : QAbstractTransition(*new QSignalTransitionPrivate, sourceState)
97{
98}
99
100/*!
101 Constructs a new signal transition associated with the given \a signal of
102 the given \a sender, and with the given \a sourceState.
103*/
104QSignalTransition::QSignalTransition(const QObject *sender, const char *signal,
105 QState *sourceState)
106 : QAbstractTransition(*new QSignalTransitionPrivate, sourceState)
107{
108 Q_D(QSignalTransition);
109 d->senderObject.setValueBypassingBindings(sender);
110 d->signal.setValueBypassingBindings(signal);
111 d->maybeRegister();
112}
113
114/*!
115 \fn template <typename PointerToMemberFunction> QSignalTransition::QSignalTransition(const QObject *sender, PointerToMemberFunction signal, QState *sourceState)
116 \since 5.7
117 \overload
118
119 Constructs a new signal transition associated with the given \a signal of
120 the given \a sender object and with the given \a sourceState.
121 This constructor is enabled if the compiler supports delegating constructors,
122 as indicated by the presence of the macro Q_COMPILER_DELEGATING_CONSTRUCTORS.
123*/
124
125/*!
126 Destroys this signal transition.
127*/
128QSignalTransition::~QSignalTransition()
129{
130}
131
132/*!
133 Returns the sender object associated with this signal transition.
134*/
135const QObject *QSignalTransition::senderObject() const
136{
137 Q_D(const QSignalTransition);
138 return d->senderObject;
139}
140
141/*!
142 Sets the \a sender object associated with this signal transition.
143*/
144void QSignalTransition::setSenderObject(const QObject *sender)
145{
146 Q_D(QSignalTransition);
147 if (sender == d->senderObject.value()) {
148 d->senderObject.removeBindingUnlessInWrapper();
149 return;
150 }
151 d->unregister();
152 d->senderObject = sender;
153 d->maybeRegister();
154 d->senderObject.notify();
155 emit senderObjectChanged(QPrivateSignal());
156}
157
158QBindable<const QObject*> QSignalTransition::bindableSenderObject()
159{
160 Q_D(QSignalTransition);
161 return &d->senderObject;
162}
163
164/*!
165 Returns the signal associated with this signal transition.
166*/
167QByteArray QSignalTransition::signal() const
168{
169 Q_D(const QSignalTransition);
170 return d->signal;
171}
172
173/*!
174 Sets the \a signal associated with this signal transition.
175*/
176void QSignalTransition::setSignal(const QByteArray &signal)
177{
178 Q_D(QSignalTransition);
179 if (signal == d->signal.value()) {
180 d->signal.removeBindingUnlessInWrapper();
181 return;
182 }
183 d->unregister();
184 d->signal = signal;
185 d->maybeRegister();
186 d->signal.notify();
187 emit signalChanged(QPrivateSignal());
188}
189
190QBindable<QByteArray> QSignalTransition::bindableSignal()
191{
192 Q_D(QSignalTransition);
193 return &d->signal;
194}
195
196/*!
197 \reimp
198
199 The default implementation returns \c true if the \a event is a
200 QStateMachine::SignalEvent object and the event's sender and signal index
201 match this transition, and returns \c false otherwise.
202*/
203bool QSignalTransition::eventTest(QEvent *event)
204{
205 Q_D(const QSignalTransition);
206 if (event->type() == QEvent::StateMachineSignal) {
207 if (d->signalIndex == -1)
208 return false;
209 QStateMachine::SignalEvent *se = static_cast<QStateMachine::SignalEvent*>(event);
210 return (se->sender() == d->senderObject.value())
211 && (se->signalIndex() == d->signalIndex);
212 }
213 return false;
214}
215
216/*!
217 \reimp
218*/
219void QSignalTransition::onTransition(QEvent *event)
220{
221 Q_UNUSED(event);
222}
223
224/*!
225 \reimp
226*/
227bool QSignalTransition::event(QEvent *e)
228{
229 return QAbstractTransition::event(e);
230}
231
232/*!
233 \fn QSignalTransition::senderObjectChanged()
234 \since 5.4
235
236 This signal is emitted when the senderObject property is changed.
237
238 \sa QSignalTransition::senderObject
239*/
240
241/*!
242 \fn QSignalTransition::signalChanged()
243 \since 5.4
244
245 This signal is emitted when the signal property is changed.
246
247 \sa QSignalTransition::signal
248*/
249
250void QSignalTransitionPrivate::callOnTransition(QEvent *e)
251{
252 Q_Q(QSignalTransition);
253
254 if (e->type() == QEvent::StateMachineSignal) {
255 QStateMachine::SignalEvent *se = static_cast<QStateMachine::SignalEvent *>(e);
256 int savedSignalIndex = se->m_signalIndex;
257 se->m_signalIndex = originalSignalIndex;
258 q->onTransition(event: e);
259 se->m_signalIndex = savedSignalIndex;
260 } else {
261 q->onTransition(event: e);
262 }
263}
264
265
266QT_END_NAMESPACE
267
268#include "moc_qsignaltransition.cpp"
269

source code of qtscxml/src/statemachine/qsignaltransition.cpp