std::chrono overload added to QStateMachine::postDelayedEvent()

Some Qt classes already accept std::chrono durations in their methods
(see, for example, QTimer). The proposed change adds an overload
with std::chrono::milliseconds to QStateMachine::postDelayedEvent().

Change-Id: I360fd2bb54fedc7415e9ec17e096095be3604d41
Reviewed-by: Erik Verbruggen <erik.verbruggen@me.com>
This commit is contained in:
Dmitriy Purgin 2020-01-07 15:50:40 +01:00 committed by Dmitriy Purgin
parent f415c5ad23
commit 9557715016
3 changed files with 193 additions and 0 deletions

View File

@ -3273,6 +3273,26 @@ QStateMachine::WrappedEvent::~WrappedEvent()
\sa QStateMachine::running
*/
/*!
\fn QStateMachine::postDelayedEvent(QEvent *event, std::chrono::milliseconds delay)
\since 5.15
\overload
\threadsafe
Posts the given \a event for processing by this state machine, with the
given \a delay in milliseconds. Returns an identifier associated with the
delayed event, or -1 if the event could not be posted.
This function returns immediately. When the delay has expired, the event
will be added to the state machine's event queue for processing. The state
machine takes ownership of the event and deletes it once it has been
processed.
You can only post events when the state machine is running.
\sa cancelDelayedEvent(), postEvent()
*/
QT_END_NAMESPACE
#include "qstatemachine.moc"

View File

@ -48,6 +48,10 @@
#include <QtCore/qset.h>
#include <QtCore/qvariant.h>
#if __has_include(<chrono>)
# include <chrono>
#endif
QT_REQUIRE_CONFIG(statemachine);
QT_BEGIN_NAMESPACE
@ -145,6 +149,13 @@ public:
bool eventFilter(QObject *watched, QEvent *event) override;
#endif
#if __has_include(<chrono>) || defined(Q_QDOC)
int postDelayedEvent(QEvent *event, std::chrono::milliseconds delay)
{
return postDelayedEvent(event, int(delay.count()));
}
#endif
public Q_SLOTS:
void start();
void stop();

View File

@ -253,6 +253,10 @@ private slots:
void qtbug_46703();
void postEventFromBeginSelectTransitions();
void dontProcessSlotsWhenMachineIsNotRunning();
void cancelDelayedEventWithChrono();
void postDelayedEventWithChronoAndStop();
void postDelayedEventWithChronoFromThread();
};
class TestState : public QState
@ -6702,5 +6706,163 @@ void tst_QStateMachine::dontProcessSlotsWhenMachineIsNotRunning()
QTRY_VERIFY(emitter.thread.isFinished());
}
void tst_QStateMachine::cancelDelayedEventWithChrono()
{
#if __has_include(<chrono>)
QStateMachine machine;
QTest::ignoreMessage(QtWarningMsg,
"QStateMachine::cancelDelayedEvent: the machine is not running");
QVERIFY(!machine.cancelDelayedEvent(-1));
QState *s1 = new QState(&machine);
DEFINE_ACTIVE_SPY(s1);
QFinalState *s2 = new QFinalState(&machine);
s1->addTransition(new StringTransition("a", s2));
machine.setInitialState(s1);
QSignalSpy startedSpy(&machine, &QStateMachine::started);
QSignalSpy runningSpy(&machine, &QStateMachine::runningChanged);
QVERIFY(startedSpy.isValid());
QVERIFY(runningSpy.isValid());
machine.start();
QTRY_COMPARE(startedSpy.count(), 1);
TEST_RUNNING_CHANGED(true);
TEST_ACTIVE_CHANGED(s1, 1);
QCOMPARE(machine.configuration().size(), 1);
QVERIFY(machine.configuration().contains(s1));
int id1 = machine.postDelayedEvent(new StringEvent("c"), std::chrono::seconds{50});
QVERIFY(id1 != -1);
int id2 = machine.postDelayedEvent(new StringEvent("b"), std::chrono::seconds{25});
QVERIFY(id2 != -1);
QVERIFY(id2 != id1);
int id3 = machine.postDelayedEvent(new StringEvent("a"), std::chrono::milliseconds{100});
QVERIFY(id3 != -1);
QVERIFY(id3 != id2);
QVERIFY(machine.cancelDelayedEvent(id1));
QVERIFY(!machine.cancelDelayedEvent(id1));
QVERIFY(machine.cancelDelayedEvent(id2));
QVERIFY(!machine.cancelDelayedEvent(id2));
QSignalSpy finishedSpy(&machine, &QStateMachine::finished);
QVERIFY(finishedSpy.isValid());
QTRY_COMPARE(finishedSpy.count(), 1);
TEST_RUNNING_CHANGED(false);
TEST_ACTIVE_CHANGED(s1, 2);
QCOMPARE(machine.configuration().size(), 1);
QVERIFY(machine.configuration().contains(s2));
#endif
}
void tst_QStateMachine::postDelayedEventWithChronoAndStop()
{
#if __has_include(<chrono>)
QStateMachine machine;
QState *s1 = new QState(&machine);
DEFINE_ACTIVE_SPY(s1);
QFinalState *s2 = new QFinalState(&machine);
s1->addTransition(new StringTransition("a", s2));
machine.setInitialState(s1);
QSignalSpy runningSpy(&machine, &QStateMachine::runningChanged);
QVERIFY(runningSpy.isValid());
QSignalSpy startedSpy(&machine, &QStateMachine::started);
QVERIFY(startedSpy.isValid());
machine.start();
QTRY_COMPARE(startedSpy.count(), 1);
TEST_RUNNING_CHANGED(true);
TEST_ACTIVE_CHANGED(s1, 1);
QCOMPARE(machine.configuration().size(), 1);
QVERIFY(machine.configuration().contains(s1));
int id1 = machine.postDelayedEvent(new StringEvent("a"), std::chrono::milliseconds{0});
QVERIFY(id1 != -1);
QSignalSpy stoppedSpy(&machine, &QStateMachine::stopped);
QVERIFY(stoppedSpy.isValid());
machine.stop();
QTRY_COMPARE(stoppedSpy.count(), 1);
TEST_RUNNING_CHANGED(false);
TEST_ACTIVE_CHANGED(s1, 1);
QCOMPARE(machine.configuration().size(), 1);
QVERIFY(machine.configuration().contains(s1));
machine.start();
QTRY_COMPARE(startedSpy.count(), 2);
TEST_RUNNING_CHANGED(true);
TEST_ACTIVE_CHANGED(s1, 3);
QCOMPARE(machine.configuration().size(), 1);
QVERIFY(machine.configuration().contains(s1));
int id2 = machine.postDelayedEvent(new StringEvent("a"), std::chrono::seconds{1});
QVERIFY(id2 != -1);
machine.stop();
QTRY_COMPARE(stoppedSpy.count(), 2);
TEST_RUNNING_CHANGED(false);
TEST_ACTIVE_CHANGED(s1, 3);
machine.start();
QTRY_COMPARE(startedSpy.count(), 3);
TEST_RUNNING_CHANGED(true);
QTestEventLoop::instance().enterLoop(2);
QCOMPARE(machine.configuration().size(), 1);
QVERIFY(machine.configuration().contains(s1));
TEST_ACTIVE_CHANGED(s1, 5);
QVERIFY(machine.isRunning());
#endif
}
class DelayedEventWithChronoPosterThread : public QThread
{
Q_OBJECT
public:
DelayedEventWithChronoPosterThread(QStateMachine *machine, QObject *parent = 0)
: QThread(parent), firstEventWasCancelled(false), m_machine(machine)
{
moveToThread(this);
QObject::connect(m_machine, SIGNAL(started()), this, SLOT(postEvent()));
}
mutable bool firstEventWasCancelled;
private Q_SLOTS:
void postEvent()
{
#if __has_include(<chrono>)
int id = m_machine->postDelayedEvent(new QEvent(QEvent::User), std::chrono::seconds{1});
firstEventWasCancelled = m_machine->cancelDelayedEvent(id);
m_machine->postDelayedEvent(new QEvent(QEvent::User), std::chrono::milliseconds{1});
quit();
#endif
}
private:
QStateMachine *m_machine;
};
void tst_QStateMachine::postDelayedEventWithChronoFromThread()
{
#if __has_include(<chrono>)
QStateMachine machine;
QState *s1 = new QState(&machine);
DEFINE_ACTIVE_SPY(s1);
QFinalState *f = new QFinalState(&machine);
s1->addTransition(new EventTransition(QEvent::User, f));
machine.setInitialState(s1);
DelayedEventWithChronoPosterThread poster(&machine);
poster.start();
QSignalSpy runningSpy(&machine, &QStateMachine::runningChanged);
QVERIFY(runningSpy.isValid());
QSignalSpy finishedSpy(&machine, &QStateMachine::finished);
QVERIFY(finishedSpy.isValid());
machine.start();
QTRY_COMPARE(finishedSpy.count(), 1);
TEST_RUNNING_CHANGED_STARTED_STOPPED;
TEST_ACTIVE_CHANGED(s1, 2);
QVERIFY(poster.firstEventWasCancelled);
#endif
}
QTEST_MAIN(tst_QStateMachine)
#include "tst_qstatemachine.moc"