diff options
-rw-r--r-- | src/corelib/kernel/qtimer.cpp | 72 | ||||
-rw-r--r-- | src/corelib/kernel/qtimer.h | 93 | ||||
-rw-r--r-- | tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp | 98 |
3 files changed, 245 insertions, 18 deletions
diff --git a/src/corelib/kernel/qtimer.cpp b/src/corelib/kernel/qtimer.cpp index 80accc0cb8..8ba494ec3d 100644 --- a/src/corelib/kernel/qtimer.cpp +++ b/src/corelib/kernel/qtimer.cpp @@ -533,6 +533,78 @@ void QTimer::singleShot(int msec, Qt::TimerType timerType, const QObject *receiv */ /*! + \fn void QTimer::singleShot(std::chrono::duration<Rep, Period> value, const QObject *receiver, const char *member) + \since 5.8 + \overload + \reentrant + + This static function calls a slot after a given time interval. + + It is very convenient to use this function because you do not need + to bother with a \l{QObject::timerEvent()}{timerEvent} or + create a local QTimer object. + + The \a receiver is the receiving object and the \a member is the slot. The + time interval is given in the duration object \a value. + + \sa start() +*/ + +/*! + \fn void QTimer::singleShot(std::chrono::duration<Rep, Period> value, Qt::TimerType timerType, const QObject *receiver, const char *member) + \since 5.8 + \overload + \reentrant + + This static function calls a slot after a given time interval. + + It is very convenient to use this function because you do not need + to bother with a \l{QObject::timerEvent()}{timerEvent} or + create a local QTimer object. + + The \a receiver is the receiving object and the \a member is the slot. The + time interval is given in the duration object \a value. The \a timerType affects the + accuracy of the timer. + + \sa start() +*/ + +/*! + \fn void QTimer::start(std::chrono::duration<Rep, Period> value) + \since 5.8 + \overload + + Starts or restarts the timer with a timeout of duration \a value. + + If the timer is already running, it will be + \l{QTimer::stop()}{stopped} and restarted. + + If \l singleShot is true, the timer will be activated only once. +*/ + +/*! + \fn std::chrono::milliseconds QTimer::intervalAsDuration() const + \since 5.8 + + Returns the interval of this timer as a \c std::chrono::milliseconds object. + + \sa interval +*/ + +/*! + \fn std::chrono::milliseconds QTimer::remainingTimeAsDuration() const + \since 5.8 + + Returns the time remaining in this timer object as a \c + std::chrono::milliseconds object. If this timer is due or overdue, the + returned value is \c std::chrono::milliseconds::zero(). If the remaining + time could not be found or the timer is not active, this function returns a + negative duration. + + \sa remainingTime() +*/ + +/*! \property QTimer::singleShot \brief whether the timer is a single-shot timer diff --git a/src/corelib/kernel/qtimer.h b/src/corelib/kernel/qtimer.h index d97fe933b9..1567fe760c 100644 --- a/src/corelib/kernel/qtimer.h +++ b/src/corelib/kernel/qtimer.h @@ -47,6 +47,10 @@ #include <QtCore/qbasictimer.h> // conceptual inheritance #include <QtCore/qobject.h> +#if QT_HAS_INCLUDE(<chrono>) +# include <chrono> +#endif + QT_BEGIN_NAMESPACE @@ -94,13 +98,13 @@ public: static void singleShot(int msec, Qt::TimerType timerType, const QObject *context, Functor functor); #else // singleShot to a QObject slot - template <typename Func1> - static inline void singleShot(int msec, const typename QtPrivate::FunctionPointer<Func1>::Object *receiver, Func1 slot) + template <typename Duration, typename Func1> + static inline void singleShot(Duration interval, const typename QtPrivate::FunctionPointer<Func1>::Object *receiver, Func1 slot) { - singleShot(msec, msec >= 2000 ? Qt::CoarseTimer : Qt::PreciseTimer, receiver, slot); + singleShot(interval, defaultTypeFor(interval), receiver, slot); } - template <typename Func1> - static inline void singleShot(int msec, Qt::TimerType timerType, const typename QtPrivate::FunctionPointer<Func1>::Object *receiver, + template <typename Duration, typename Func1> + static inline void singleShot(Duration interval, Qt::TimerType timerType, const typename QtPrivate::FunctionPointer<Func1>::Object *receiver, Func1 slot) { typedef QtPrivate::FunctionPointer<Func1> SlotType; @@ -109,42 +113,42 @@ public: Q_STATIC_ASSERT_X(int(SlotType::ArgumentCount) == 0, "The slot must not have any arguments."); - singleShotImpl(msec, timerType, receiver, + singleShotImpl(interval, timerType, receiver, new QtPrivate::QSlotObject<Func1, typename SlotType::Arguments, void>(slot)); } // singleShot to a functor or function pointer (without context) - template <typename Func1> + template <typename Duration, typename Func1> static inline typename QtPrivate::QEnableIf<!QtPrivate::FunctionPointer<Func1>::IsPointerToMemberFunction && !QtPrivate::is_same<const char*, Func1>::value, void>::Type - singleShot(int msec, Func1 slot) + singleShot(Duration interval, Func1 slot) { - singleShot(msec, msec >= 2000 ? Qt::CoarseTimer : Qt::PreciseTimer, Q_NULLPTR, slot); + singleShot(interval, defaultTypeFor(interval), nullptr, slot); } - template <typename Func1> + template <typename Duration, typename Func1> static inline typename QtPrivate::QEnableIf<!QtPrivate::FunctionPointer<Func1>::IsPointerToMemberFunction && !QtPrivate::is_same<const char*, Func1>::value, void>::Type - singleShot(int msec, Qt::TimerType timerType, Func1 slot) + singleShot(Duration interval, Qt::TimerType timerType, Func1 slot) { - singleShot(msec, timerType, Q_NULLPTR, slot); + singleShot(interval, timerType, nullptr, slot); } // singleShot to a functor or function pointer (with context) - template <typename Func1> + template <typename Duration, typename Func1> static inline typename QtPrivate::QEnableIf<!QtPrivate::FunctionPointer<Func1>::IsPointerToMemberFunction && !QtPrivate::is_same<const char*, Func1>::value, void>::Type - singleShot(int msec, QObject *context, Func1 slot) + singleShot(Duration interval, QObject *context, Func1 slot) { - singleShot(msec, msec >= 2000 ? Qt::CoarseTimer : Qt::PreciseTimer, context, slot); + singleShot(interval, defaultTypeFor(interval), context, slot); } - template <typename Func1> + template <typename Duration, typename Func1> static inline typename QtPrivate::QEnableIf<!QtPrivate::FunctionPointer<Func1>::IsPointerToMemberFunction && !QtPrivate::is_same<const char*, Func1>::value, void>::Type - singleShot(int msec, Qt::TimerType timerType, QObject *context, Func1 slot) + singleShot(Duration interval, Qt::TimerType timerType, QObject *context, Func1 slot) { //compilation error if the slot has arguments. typedef QtPrivate::FunctionPointer<Func1> SlotType; Q_STATIC_ASSERT_X(int(SlotType::ArgumentCount) <= 0, "The slot must not have any arguments."); - singleShotImpl(msec, timerType, context, + singleShotImpl(interval, timerType, context, new QtPrivate::QFunctorSlotObject<Func1, 0, typename QtPrivate::List_Left<void, 0>::Value, void>(slot)); } @@ -159,6 +163,43 @@ public Q_SLOTS: Q_SIGNALS: void timeout(QPrivateSignal); +public: +#if QT_HAS_INCLUDE(<chrono>) || defined(Q_QDOC) + template <class Rep, class Period> + void setInterval(std::chrono::duration<Rep, Period> value) + { + setInterval(std::chrono::duration_cast<std::chrono::milliseconds>(value).count()); + } + + std::chrono::milliseconds intervalAsDuration() const + { + return std::chrono::milliseconds(interval()); + } + + std::chrono::milliseconds remainingTimeAsDuration() const + { + return std::chrono::milliseconds(remainingTime()); + } + + template <class Rep, class Period> + static void singleShot(std::chrono::duration<Rep, Period> value, const QObject *receiver, const char *member) + { + singleShot(int(std::chrono::duration_cast<std::chrono::milliseconds>(value).count()), receiver, member); + } + + template <class Rep, class Period> + static void singleShot(std::chrono::duration<Rep, Period> value, Qt::TimerType timerType, const QObject *receiver, const char *member) + { + singleShot(int(std::chrono::duration_cast<std::chrono::milliseconds>(value).count()), timerType, receiver, member); + } + + template <class Rep, class Period> + void start(std::chrono::duration<Rep, Period> value) + { + start(int(std::chrono::duration_cast<std::chrono::milliseconds>(value).count())); + } +#endif + protected: void timerEvent(QTimerEvent *) Q_DECL_OVERRIDE; @@ -168,9 +209,25 @@ private: inline int startTimer(int){ return -1;} inline void killTimer(int){} + static Q_DECL_CONSTEXPR Qt::TimerType defaultTypeFor(int msecs) Q_DECL_NOTHROW + { return msecs >= 2000 ? Qt::CoarseTimer : Qt::PreciseTimer; } static void singleShotImpl(int msec, Qt::TimerType timerType, const QObject *receiver, QtPrivate::QSlotObjectBase *slotObj); +#if QT_HAS_INCLUDE(<chrono>) + template <class Rep, class Period> + static Qt::TimerType defaultTypeFor(std::chrono::duration<Rep, Period> interval) + { return defaultTypeFor(int(std::chrono::duration_cast<std::chrono::milliseconds>(interval).count())); } + + template <class Rep, class Period> + static void singleShotImpl(std::chrono::duration<Rep, Period> interval, Qt::TimerType timerType, + const QObject *receiver, QtPrivate::QSlotObjectBase *slotObj) + { + singleShotImpl(int(std::chrono::duration_cast<std::chrono::milliseconds>(interval).count()), + timerType, receiver, slotObj); + } +#endif + int id, inter, del; uint single : 1; uint nulltimer : 1; diff --git a/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp b/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp index de7a3721d8..28df01cc16 100644 --- a/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp +++ b/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp @@ -52,6 +52,7 @@ private slots: void remainingTime(); void remainingTimeDuringActivation_data(); void remainingTimeDuringActivation(); + void basic_chrono(); void livelock_data(); void livelock(); void timerInfiniteRecursion_data(); @@ -68,6 +69,7 @@ private slots: void singleShotStaticFunctionZeroTimeout(); void recurseOnTimeoutAndStopTimer(); void singleShotToFunctors(); + void singleShot_chrono(); void crossThreadSingleShotToFunctor(); void dontBlockEvents(); @@ -214,6 +216,57 @@ void tst_QTimer::remainingTimeDuringActivation() } } +void tst_QTimer::basic_chrono() +{ +#if !QT_HAS_INCLUDE(<chrono>) + QSKIP("This test requires C++11 <chrono> support"); +#else + // duplicates zeroTimer, singleShotTimeout, interval and remainingTime + using namespace std::chrono; + TimerHelper helper; + QTimer timer; + timer.setInterval(nanoseconds(0)); + timer.start(); + QCOMPARE(timer.intervalAsDuration().count(), milliseconds::rep(0)); + QCOMPARE(timer.remainingTimeAsDuration().count(), milliseconds::rep(0)); + + connect(&timer, SIGNAL(timeout()), &helper, SLOT(timeout())); + + QCoreApplication::processEvents(); + + QCOMPARE(helper.count, 1); + + helper.count = 0; + timer.start(milliseconds(100)); + QCOMPARE(helper.count, 0); + + QTest::qWait(TIMEOUT_TIMEOUT); + QVERIFY(helper.count > 0); + int oldCount = helper.count; + + QTest::qWait(TIMEOUT_TIMEOUT); + QVERIFY(helper.count > oldCount); + + helper.count = 0; + timer.start(microseconds(200000)); + QCOMPARE(timer.intervalAsDuration().count(), milliseconds::rep(200)); + QTest::qWait(50); + QCOMPARE(helper.count, 0); + + milliseconds rt = timer.remainingTimeAsDuration(); + QVERIFY2(qAbs(rt.count() - 150) < 50, qPrintable(QString::number(rt.count()))); + + helper.count = 0; + timer.setSingleShot(true); + timer.start(milliseconds(100)); + QTest::qWait(500); + QCOMPARE(helper.count, 1); + QTest::qWait(500); + QCOMPARE(helper.count, 1); + helper.count = 0; +#endif +} + void tst_QTimer::livelock_data() { QTest::addColumn<int>("interval"); @@ -787,6 +840,51 @@ void tst_QTimer::singleShotToFunctors() _t = Q_NULLPTR; } +void tst_QTimer::singleShot_chrono() +{ +#if !QT_HAS_INCLUDE(<chrono>) + QSKIP("This test requires C++11 <chrono> support"); +#else + // duplicates singleShotStaticFunctionZeroTimeout and singleShotToFunctors + using namespace std::chrono; + TimerHelper helper; + + QTimer::singleShot(hours(0), &helper, SLOT(timeout())); + QTest::qWait(500); + QCOMPARE(helper.count, 1); + QTest::qWait(500); + QCOMPARE(helper.count, 1); + + TimerHelper nhelper; + + QTimer::singleShot(seconds(0), &nhelper, &TimerHelper::timeout); + QCoreApplication::processEvents(); + QCOMPARE(nhelper.count, 1); + QCoreApplication::processEvents(); + QCOMPARE(nhelper.count, 1); + + int count = 0; + QTimer::singleShot(microseconds(0), CountedStruct(&count)); + QCoreApplication::processEvents(); + QCOMPARE(count, 1); + + _e.reset(new QEventLoop); + QTimer::singleShot(0, &StaticEventLoop::quitEventLoop); + QCOMPARE(_e->exec(), 0); + + QObject c3; + QTimer::singleShot(milliseconds(500), &c3, CountedStruct(&count)); + QTest::qWait(800); + QCOMPARE(count, 2); + + QTimer::singleShot(0, [&count] { ++count; }); + QCoreApplication::processEvents(); + QCOMPARE(count, 3); + + _e.reset(); +#endif +} + class DontBlockEvents : public QObject { Q_OBJECT |