// Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qsignaltransition.h" #include "qsignaltransition_p.h" #include "qstate.h" #include "qstate_p.h" #include "qstatemachine.h" #include "qstatemachine_p.h" #include QT_BEGIN_NAMESPACE /*! \class QSignalTransition \inmodule QtStateMachine \brief The QSignalTransition class provides a transition based on a Qt signal. \since 4.6 \ingroup statemachine Typically you would use the overload of QState::addTransition() that takes a sender and signal as arguments, rather than creating QSignalTransition objects directly. QSignalTransition is part of \l{Qt State Machine Overview} {Qt State Machine Framework}. You can subclass QSignalTransition and reimplement eventTest() to make a signal transition conditional; the event object passed to eventTest() will be a QStateMachine::SignalEvent object. Example: \code class CheckedTransition : public QSignalTransition { public: CheckedTransition(QCheckBox *check) : QSignalTransition(check, SIGNAL(stateChanged(int))) {} protected: bool eventTest(QEvent *e) { if (!QSignalTransition::eventTest(e)) return false; QStateMachine::SignalEvent *se = static_cast(e); return (se->arguments().at(0).toInt() == Qt::Checked); } }; ... QCheckBox *check = new QCheckBox(); check->setTristate(true); QState *s1 = new QState(); QState *s2 = new QState(); CheckedTransition *t1 = new CheckedTransition(check); t1->setTargetState(s2); s1->addTransition(t1); \endcode */ /*! \property QSignalTransition::senderObject \brief the sender object that this signal transition is associated with */ /*! \property QSignalTransition::signal \brief the signal that this signal transition is associated with */ QSignalTransitionPrivate::QSignalTransitionPrivate() { signalIndex = -1; } void QSignalTransitionPrivate::unregister() { Q_Q(QSignalTransition); if ((signalIndex == -1) || !machine()) return; QStateMachinePrivate::get(machine())->unregisterSignalTransition(q); } void QSignalTransitionPrivate::maybeRegister() { Q_Q(QSignalTransition); if (QStateMachine *mach = machine()) QStateMachinePrivate::get(mach)->maybeRegisterSignalTransition(q); } /*! Constructs a new signal transition with the given \a sourceState. */ QSignalTransition::QSignalTransition(QState *sourceState) : QAbstractTransition(*new QSignalTransitionPrivate, sourceState) { } /*! Constructs a new signal transition associated with the given \a signal of the given \a sender, and with the given \a sourceState. */ QSignalTransition::QSignalTransition(const QObject *sender, const char *signal, QState *sourceState) : QAbstractTransition(*new QSignalTransitionPrivate, sourceState) { Q_D(QSignalTransition); d->senderObject.setValueBypassingBindings(sender); d->signal.setValueBypassingBindings(signal); d->maybeRegister(); } /*! \fn template QSignalTransition::QSignalTransition(const QObject *sender, PointerToMemberFunction signal, QState *sourceState) \since 5.7 \overload Constructs a new signal transition associated with the given \a signal of the given \a sender object and with the given \a sourceState. This constructor is enabled if the compiler supports delegating constructors, as indicated by the presence of the macro Q_COMPILER_DELEGATING_CONSTRUCTORS. */ /*! Destroys this signal transition. */ QSignalTransition::~QSignalTransition() { } /*! Returns the sender object associated with this signal transition. */ const QObject *QSignalTransition::senderObject() const { Q_D(const QSignalTransition); return d->senderObject; } /*! Sets the \a sender object associated with this signal transition. */ void QSignalTransition::setSenderObject(const QObject *sender) { Q_D(QSignalTransition); d->senderObject.removeBindingUnlessInWrapper(); if (sender == d->senderObject.valueBypassingBindings()) return; d->unregister(); d->senderObject.setValueBypassingBindings(sender); d->maybeRegister(); d->senderObject.notify(); emit senderObjectChanged(QPrivateSignal()); } QBindable QSignalTransition::bindableSenderObject() { Q_D(QSignalTransition); return &d->senderObject; } /*! Returns the signal associated with this signal transition. */ QByteArray QSignalTransition::signal() const { Q_D(const QSignalTransition); return d->signal; } /*! Sets the \a signal associated with this signal transition. */ void QSignalTransition::setSignal(const QByteArray &signal) { Q_D(QSignalTransition); d->signal.removeBindingUnlessInWrapper(); if (signal == d->signal.valueBypassingBindings()) return; d->unregister(); d->signal.setValueBypassingBindings(signal); d->maybeRegister(); d->signal.notify(); emit signalChanged(QPrivateSignal()); } QBindable QSignalTransition::bindableSignal() { Q_D(QSignalTransition); return &d->signal; } /*! \reimp The default implementation returns \c true if the \a event is a QStateMachine::SignalEvent object and the event's sender and signal index match this transition, and returns \c false otherwise. */ bool QSignalTransition::eventTest(QEvent *event) { Q_D(const QSignalTransition); if (event->type() == QEvent::StateMachineSignal) { if (d->signalIndex == -1) return false; QStateMachine::SignalEvent *se = static_cast(event); return (se->sender() == d->senderObject.value()) && (se->signalIndex() == d->signalIndex); } return false; } /*! \reimp */ void QSignalTransition::onTransition(QEvent *event) { Q_UNUSED(event); } /*! \reimp */ bool QSignalTransition::event(QEvent *e) { return QAbstractTransition::event(e); } /*! \fn QSignalTransition::senderObjectChanged() \since 5.4 This signal is emitted when the senderObject property is changed. \sa QSignalTransition::senderObject */ /*! \fn QSignalTransition::signalChanged() \since 5.4 This signal is emitted when the signal property is changed. \sa QSignalTransition::signal */ void QSignalTransitionPrivate::callOnTransition(QEvent *e) { Q_Q(QSignalTransition); if (e->type() == QEvent::StateMachineSignal) { QStateMachine::SignalEvent *se = static_cast(e); int savedSignalIndex = se->m_signalIndex; se->m_signalIndex = originalSignalIndex; q->onTransition(e); se->m_signalIndex = savedSignalIndex; } else { q->onTransition(e); } } QT_END_NAMESPACE #include "moc_qsignaltransition.cpp"