1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtCore module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qsignaltransition.h"
41#include "qsignaltransition_p.h"
42#include "qstate.h"
43#include "qstate_p.h"
44#include "qstatemachine.h"
45#include "qstatemachine_p.h"
46#include <qdebug.h>
47
48QT_BEGIN_NAMESPACE
49
50/*!
51 \class QSignalTransition
52 \inmodule QtCore
53
54 \brief The QSignalTransition class provides a transition based on a Qt signal.
55
56 \since 4.6
57 \ingroup statemachine
58
59 Typically you would use the overload of QState::addTransition() that takes a
60 sender and signal as arguments, rather than creating QSignalTransition
61 objects directly. QSignalTransition is part of \l{The State Machine
62 Framework}.
63
64 You can subclass QSignalTransition and reimplement eventTest() to make a
65 signal transition conditional; the event object passed to eventTest() will
66 be a QStateMachine::SignalEvent object. Example:
67
68 \code
69 class CheckedTransition : public QSignalTransition
70 {
71 public:
72 CheckedTransition(QCheckBox *check)
73 : QSignalTransition(check, SIGNAL(stateChanged(int))) {}
74 protected:
75 bool eventTest(QEvent *e) {
76 if (!QSignalTransition::eventTest(e))
77 return false;
78 QStateMachine::SignalEvent *se = static_cast<QStateMachine::SignalEvent*>(e);
79 return (se->arguments().at(0).toInt() == Qt::Checked);
80 }
81 };
82
83 ...
84
85 QCheckBox *check = new QCheckBox();
86 check->setTristate(true);
87
88 QState *s1 = new QState();
89 QState *s2 = new QState();
90 CheckedTransition *t1 = new CheckedTransition(check);
91 t1->setTargetState(s2);
92 s1->addTransition(t1);
93 \endcode
94*/
95
96/*!
97 \property QSignalTransition::senderObject
98
99 \brief the sender object that this signal transition is associated with
100*/
101
102/*!
103 \property QSignalTransition::signal
104
105 \brief the signal that this signal transition is associated with
106*/
107
108QSignalTransitionPrivate::QSignalTransitionPrivate()
109{
110 sender = nullptr;
111 signalIndex = -1;
112}
113
114void QSignalTransitionPrivate::unregister()
115{
116 Q_Q(QSignalTransition);
117 if ((signalIndex == -1) || !machine())
118 return;
119 QStateMachinePrivate::get(q: machine())->unregisterSignalTransition(transition: q);
120}
121
122void QSignalTransitionPrivate::maybeRegister()
123{
124 Q_Q(QSignalTransition);
125 if (QStateMachine *mach = machine())
126 QStateMachinePrivate::get(q: mach)->maybeRegisterSignalTransition(transition: q);
127}
128
129/*!
130 Constructs a new signal transition with the given \a sourceState.
131*/
132QSignalTransition::QSignalTransition(QState *sourceState)
133 : QAbstractTransition(*new QSignalTransitionPrivate, sourceState)
134{
135}
136
137/*!
138 Constructs a new signal transition associated with the given \a signal of
139 the given \a sender, and with the given \a sourceState.
140*/
141QSignalTransition::QSignalTransition(const QObject *sender, const char *signal,
142 QState *sourceState)
143 : QAbstractTransition(*new QSignalTransitionPrivate, sourceState)
144{
145 Q_D(QSignalTransition);
146 d->sender = sender;
147 d->signal = signal;
148 d->maybeRegister();
149}
150
151/*!
152 \fn template <typename PointerToMemberFunction> QSignalTransition::QSignalTransition(const QObject *sender, PointerToMemberFunction signal, QState *sourceState)
153 \since 5.7
154 \overload
155
156 Constructs a new signal transition associated with the given \a signal of
157 the given \a sender object and with the given \a sourceState.
158 This constructor is enabled if the compiler supports delegating constructors,
159 as indicated by the presence of the macro Q_COMPILER_DELEGATING_CONSTRUCTORS.
160*/
161
162/*!
163 Destroys this signal transition.
164*/
165QSignalTransition::~QSignalTransition()
166{
167}
168
169/*!
170 Returns the sender object associated with this signal transition.
171*/
172QObject *QSignalTransition::senderObject() const
173{
174 Q_D(const QSignalTransition);
175 return const_cast<QObject *>(d->sender);
176}
177
178/*!
179 Sets the \a sender object associated with this signal transition.
180*/
181void QSignalTransition::setSenderObject(const QObject *sender)
182{
183 Q_D(QSignalTransition);
184 if (sender == d->sender)
185 return;
186 d->unregister();
187 d->sender = sender;
188 d->maybeRegister();
189 emit senderObjectChanged(QPrivateSignal());
190}
191
192/*!
193 Returns the signal associated with this signal transition.
194*/
195QByteArray QSignalTransition::signal() const
196{
197 Q_D(const QSignalTransition);
198 return d->signal;
199}
200
201/*!
202 Sets the \a signal associated with this signal transition.
203*/
204void QSignalTransition::setSignal(const QByteArray &signal)
205{
206 Q_D(QSignalTransition);
207 if (signal == d->signal)
208 return;
209 d->unregister();
210 d->signal = signal;
211 d->maybeRegister();
212 emit signalChanged(QPrivateSignal());
213}
214
215/*!
216 \reimp
217
218 The default implementation returns \c true if the \a event is a
219 QStateMachine::SignalEvent object and the event's sender and signal index
220 match this transition, and returns \c false otherwise.
221*/
222bool QSignalTransition::eventTest(QEvent *event)
223{
224 Q_D(const QSignalTransition);
225 if (event->type() == QEvent::StateMachineSignal) {
226 if (d->signalIndex == -1)
227 return false;
228 QStateMachine::SignalEvent *se = static_cast<QStateMachine::SignalEvent*>(event);
229 return (se->sender() == d->sender)
230 && (se->signalIndex() == d->signalIndex);
231 }
232 return false;
233}
234
235/*!
236 \reimp
237*/
238void QSignalTransition::onTransition(QEvent *event)
239{
240 Q_UNUSED(event);
241}
242
243/*!
244 \reimp
245*/
246bool QSignalTransition::event(QEvent *e)
247{
248 return QAbstractTransition::event(e);
249}
250
251/*!
252 \fn QSignalTransition::senderObjectChanged()
253 \since 5.4
254
255 This signal is emitted when the senderObject property is changed.
256
257 \sa QSignalTransition::senderObject
258*/
259
260/*!
261 \fn QSignalTransition::signalChanged()
262 \since 5.4
263
264 This signal is emitted when the signal property is changed.
265
266 \sa QSignalTransition::signal
267*/
268
269void QSignalTransitionPrivate::callOnTransition(QEvent *e)
270{
271 Q_Q(QSignalTransition);
272
273 if (e->type() == QEvent::StateMachineSignal) {
274 QStateMachine::SignalEvent *se = static_cast<QStateMachine::SignalEvent *>(e);
275 int savedSignalIndex = se->m_signalIndex;
276 se->m_signalIndex = originalSignalIndex;
277 q->onTransition(event: e);
278 se->m_signalIndex = savedSignalIndex;
279 } else {
280 q->onTransition(event: e);
281 }
282}
283
284
285QT_END_NAMESPACE
286
287#include "moc_qsignaltransition.cpp"
288

source code of qtbase/src/corelib/statemachine/qsignaltransition.cpp