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 
48 QT_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 
QSignalTransitionPrivate()108 QSignalTransitionPrivate::QSignalTransitionPrivate()
109 {
110     sender = nullptr;
111     signalIndex = -1;
112 }
113 
unregister()114 void QSignalTransitionPrivate::unregister()
115 {
116     Q_Q(QSignalTransition);
117     if ((signalIndex == -1) || !machine())
118         return;
119     QStateMachinePrivate::get(machine())->unregisterSignalTransition(q);
120 }
121 
maybeRegister()122 void QSignalTransitionPrivate::maybeRegister()
123 {
124     Q_Q(QSignalTransition);
125     if (QStateMachine *mach = machine())
126         QStateMachinePrivate::get(mach)->maybeRegisterSignalTransition(q);
127 }
128 
129 /*!
130   Constructs a new signal transition with the given \a sourceState.
131 */
QSignalTransition(QState * sourceState)132 QSignalTransition::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 */
QSignalTransition(const QObject * sender,const char * signal,QState * sourceState)141 QSignalTransition::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 */
~QSignalTransition()165 QSignalTransition::~QSignalTransition()
166 {
167 }
168 
169 /*!
170   Returns the sender object associated with this signal transition.
171 */
senderObject() const172 QObject *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 */
setSenderObject(const QObject * sender)181 void 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 */
signal() const195 QByteArray 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 */
setSignal(const QByteArray & signal)204 void 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 */
eventTest(QEvent * event)222 bool 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 */
onTransition(QEvent * event)238 void QSignalTransition::onTransition(QEvent *event)
239 {
240     Q_UNUSED(event);
241 }
242 
243 /*!
244   \reimp
245 */
event(QEvent * e)246 bool 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 
callOnTransition(QEvent * e)269 void 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(e);
278         se->m_signalIndex = savedSignalIndex;
279     } else {
280         q->onTransition(e);
281     }
282 }
283 
284 
285 QT_END_NAMESPACE
286 
287 #include "moc_qsignaltransition.cpp"
288