From 7dde3df279ec407b26fac35d12b3fa91cafeedaa Mon Sep 17 00:00:00 2001
From: vincent <vincent@groupe-sa.fr>
Date: Mon, 4 Jan 2016 17:06:27 +0100
Subject: [PATCH] QCron emit signals when entering or exiting a pattern's valid
 date.

---
 src/qcron.cpp       | 59 +++++++++++++++++++++++++++++++++------------
 src/qcron.hpp       | 17 ++++++-------
 test/qcron_test.cpp | 34 ++++++++++++++++++++++++--
 test/qcron_test.hpp |  5 ++++
 4 files changed, 89 insertions(+), 26 deletions(-)

diff --git a/src/qcron.cpp b/src/qcron.cpp
index bb1a155..7b43e24 100644
--- a/src/qcron.cpp
+++ b/src/qcron.cpp
@@ -3,8 +3,9 @@
 
 #include <cmath>
 
+#include <QDateTime>
 #include <QDebug>
-#include <QTime>
+#include <QTimer>
 
 /******************************************************************************/
 
@@ -17,10 +18,11 @@ QCron()
 /******************************************************************************/
 
 QCron::
-QCron(QString & pattern)
+QCron(const QString & pattern)
 {
     _init();
     _parsePattern(pattern);
+    _checkState();
 }
 
 /******************************************************************************/
@@ -37,6 +39,7 @@ QCron::
 _init()
 {
     _is_valid = true;
+    _is_active = false;
     _fields[0].setField(MINUTE);
     _fields[1].setField(HOUR);
     _fields[2].setField(DOM);
@@ -47,6 +50,34 @@ _init()
 
 /******************************************************************************/
 
+void
+QCron::
+_checkState()
+{
+    int interval_ms = 0;
+    if (match(QDateTime::currentDateTime()))
+    {
+        emit activated();
+        _is_active = true;
+        interval_ms = 1000 * 60; // one minute
+    }
+    else
+    {
+        if (_is_active)
+        {
+            emit deactivated();
+            _is_active = false;
+        }
+        interval_ms = QDateTime::currentDateTime().secsTo(next()) * 1000;
+    }
+    QTimer::singleShot(interval_ms,
+                       Qt::VeryCoarseTimer,
+                       this,
+                       SLOT(_checkState()));
+}
+
+/******************************************************************************/
+
 void
 QCron::
 _setError(const QString & error)
@@ -59,7 +90,7 @@ _setError(const QString & error)
 
 void
 QCron::
-_parsePattern(QString & pattern)
+_parsePattern(const QString & pattern)
 {
     if (pattern.contains("\n"))
     {
@@ -213,7 +244,7 @@ catchUp(QDateTime & dt, EField field, int value)
 
 void
 QCron::
-chiche(QDateTime & dt, EField field)
+_process(QDateTime & dt, EField field)
 {
     QCronNode * node = _fields[field].getRoot();
     if (NULL == node)
@@ -223,6 +254,14 @@ chiche(QDateTime & dt, EField field)
     node->process(this, dt, field);
 }
 
+/******************************************************************************/
+
+QDateTime
+QCron::
+next()
+{
+    return next(QDateTime::currentDateTime());
+}
 
 /******************************************************************************/
 
@@ -236,7 +275,7 @@ next(QDateTime dt)
         //qDebug() << dt << "doesn't match";
         for (int i = YEAR; i >= 0; --i)
         {
-            chiche(dt, (EField)i);
+            _process(dt, (EField)i);
             if (!dt.isValid())
             {
                 return dt;
@@ -254,16 +293,6 @@ next(QDateTime dt)
 
 /******************************************************************************/
 
-QDateTime
-QCron::
-next(int n)
-{
-    Q_UNUSED(n);
-    return next(_beginning);
-}
-
-/******************************************************************************/
-
 bool
 QCron::
 match(const QDateTime & dt) const
diff --git a/src/qcron.hpp b/src/qcron.hpp
index e0cba5c..903937e 100644
--- a/src/qcron.hpp
+++ b/src/qcron.hpp
@@ -11,13 +11,10 @@ class QCron : public QObject
 
 public:
     QCron();
-    QCron(QString & pattern);
+    QCron(const QString & pattern);
     ~QCron();
 
     // Accessors.
-    void setBeginning(const QDateTime & date_time)
-        { _beginning = date_time; }
-
     bool isValid() const
         { return _is_valid; }
 
@@ -26,30 +23,32 @@ public:
 
     // Features.
 
-    QDateTime next(int n = 1);
+    QDateTime next();
     QDateTime next(QDateTime dt);
     void catchUp(QDateTime & dt, EField field, int value);
     bool match(const QDateTime & dt) const;
     void add(QDateTime & dt, EField field, int value);
 
-
 signals:
     void activated();
     void deactivated();
 
 private:
     bool _is_valid;
+    bool _is_active;
     QString _error;
     QCronField _fields[6];
-    QDateTime _beginning;
 
     void _init();
     void _setError(const QString & error);
-    void _parsePattern(QString & pattern);
+    void _parsePattern(const QString & pattern);
     void _parseField(QString & field_str,
                      EField field);
     QString _validCharacters(EField field);
-    void chiche(QDateTime & dt, EField field);
+    void _process(QDateTime & dt, EField field);
+
+private slots:
+    void _checkState();
 };
 
 #endif
diff --git a/test/qcron_test.cpp b/test/qcron_test.cpp
index fa7e4f6..e425a1b 100644
--- a/test/qcron_test.cpp
+++ b/test/qcron_test.cpp
@@ -22,8 +22,7 @@ QCronTest::
 actual(QString & pattern)
 {
     QCron c(pattern);
-    c.setBeginning(QDateTime(_dnow, _tnow));
-    return c.next();
+    return c.next(QDateTime(_dnow, _tnow));
 }
 
 /******************************************************************************/
@@ -392,4 +391,35 @@ excludeHolidays()
 
 /******************************************************************************/
 
+void
+QCronTest::
+signalUse()
+{
+    QCron c("*/2 * * * * *");
+    connect(&c, SIGNAL(activated()),
+            this, SLOT(cronActivated()));
+    connect(&c, SIGNAL(deactivated()),
+            this, SLOT(cronDeactivated()));
+    // Too long to test
+}
+
+/******************************************************************************/
+
+void
+QCronTest::
+cronActivated()
+{
+    qDebug() << "ACTIVATED";
+}
+
+/******************************************************************************/
+
+void QCronTest::
+cronDeactivated()
+{
+    qDebug() << "DEACTIVATED";
+}
+
+/******************************************************************************/
+
 QTEST_MAIN(QCronTest)
diff --git a/test/qcron_test.hpp b/test/qcron_test.hpp
index 8c87eec..6d3398d 100644
--- a/test/qcron_test.hpp
+++ b/test/qcron_test.hpp
@@ -8,6 +8,10 @@ class QCronTest : public QObject
 {
     Q_OBJECT
 
+public slots:
+    void cronActivated();
+    void cronDeactivated();
+
 private slots:
     void init();
     void years();
@@ -17,6 +21,7 @@ private slots:
     void realLife();
     void holidays();
     void excludeHolidays();
+    void signalUse();
 
 private:
     QDate _dnow;