File indexing completed on 2024-11-24 04:42:27

0001 /*
0002  *  synchtimer.h  -  timers which synchronize to time boundaries
0003  *  Program:  kalarm
0004  *  SPDX-FileCopyrightText: 2004-2020 David Jarvie <djarvie@kde.org>
0005  *
0006  *  SPDX-License-Identifier: GPL-2.0-or-later
0007  */
0008 
0009 #pragma once
0010 
0011 /* @file synchtimer.h - timers which synchronize to time boundaries */
0012 
0013 #include <QByteArray>
0014 #include <QDate>
0015 #include <QList>
0016 #include <QObject>
0017 #include <QTime>
0018 class QTimer;
0019 
0020 /** SynchTimer is a virtual base class for application-wide timers synchronized
0021  *  to a time boundary.
0022  *
0023  *  @author David Jarvie <djarvie@kde.org>
0024  */
0025 class SynchTimer : public QObject
0026 {
0027     Q_OBJECT
0028 public:
0029     ~SynchTimer() override;
0030     // Prevent copying.
0031     SynchTimer(const SynchTimer&) = delete;
0032     SynchTimer& operator=(const SynchTimer&) = delete;
0033 
0034     struct Connection
0035     {
0036         Connection() = default;
0037         Connection(QObject* r, const char* s) : receiver(r), slot(s) { }
0038         bool operator==(const Connection& c) const  { return receiver == c.receiver && slot == c.slot; }
0039         QObject*   receiver;
0040         QByteArray slot;
0041     };
0042 protected:
0043     SynchTimer();
0044     virtual void      start() = 0;
0045     void              connecT(QObject* receiver, const char* member);
0046     virtual void      disconnecT(QObject* receiver, const char* member = nullptr);
0047     bool              hasConnections() const   { return !mConnections.isEmpty(); }
0048 
0049     QTimer*           mTimer;
0050 
0051 protected Q_SLOTS:
0052     virtual void      slotTimer() = 0;
0053 
0054 private Q_SLOTS:
0055     void              slotReceiverGone(QObject* r)  { disconnecT(r); }
0056 
0057 private:
0058     QList<Connection> mConnections; // list of current clients
0059 };
0060 
0061 
0062 /** MinuteTimer is an application-wide timer synchronized to the minute boundary.
0063  *
0064  *  @author David Jarvie <djarvie@kde.org>
0065  */
0066 class MinuteTimer : public SynchTimer
0067 {
0068     Q_OBJECT
0069 public:
0070     ~MinuteTimer() override  { mInstance = nullptr; }
0071 
0072     /** Connect to the timer signal.
0073      *  @param receiver Receiving object.
0074      *  @param member Slot to activate.
0075      */
0076     static void connect(QObject* receiver, const char* member)
0077                        { instance()->connecT(receiver, member); }
0078 
0079     /** Disconnect from the timer signal.
0080      *  @param receiver Receiving object.
0081      *  @param member Slot to disconnect. If null, all slots belonging to
0082      *                @p receiver will be disconnected.
0083      */
0084     static void disconnect(QObject* receiver, const char* member = nullptr)
0085                        { if (mInstance) mInstance->disconnecT(receiver, member); }
0086 
0087 protected:
0088     MinuteTimer() = default;
0089     static MinuteTimer* instance();
0090     void        start() override    { slotTimer(); }
0091 
0092 protected Q_SLOTS:
0093     void        slotTimer() override;
0094 
0095 private:
0096     static MinuteTimer* mInstance;     // the one and only instance
0097 };
0098 
0099 
0100 /** DailyTimer is an application-wide timer synchronized to a specified time of day, local time.
0101  *
0102  *  Daily timers come in two flavors: fixed, which can only be accessed through
0103  *  static methods, and variable, whose time can be adjusted and which are
0104  *  accessed through non-static methods.
0105  *
0106  *  @author David Jarvie <djarvie@kde.org>
0107  */
0108 class DailyTimer : public SynchTimer
0109 {
0110     Q_OBJECT
0111 public:
0112     ~DailyTimer() override;
0113 
0114     /** Connect to the timer signal which triggers at the given fixed time of day.
0115      *  A new timer is created if necessary.
0116      *  @param timeOfDay Time at which the timer is to trigger.
0117      *  @param receiver Receiving object.
0118      *  @param member Slot to activate.
0119      */
0120     static void connect(const QTime& timeOfDay, QObject* receiver, const char* member)
0121                        { fixedInstance(timeOfDay)->connecT(receiver, member); }
0122 
0123     /** Disconnect from the timer signal which triggers at the given fixed time of day.
0124      *  If there are no remaining connections to that timer, it is destroyed.
0125      *  @param timeOfDay Time at which the timer triggers.
0126      *  @param receiver Receiving object.
0127      *  @param member Slot to disconnect. If null, all slots belonging to
0128      *                @p receiver will be disconnected.
0129      */
0130     static void disconnect(const QTime& timeOfDay, QObject* receiver, const char* member = nullptr);
0131 
0132 protected:
0133     /** Construct an instance.
0134      *  The constructor is protected to ensure that for variable timers, only
0135      *  derived classes can construct instances. This ensures that multiple
0136      *  timers are not created for the same use.
0137      */
0138     DailyTimer(const QTime&, bool fixed);
0139 
0140     void disconnecT(QObject* receiver, const char* member = nullptr) override;
0141 
0142     /** Change the time at which this variable timer triggers.
0143      *  @param newTimeOfDay New time at which the timer should trigger.
0144      *  @param triggerMissed If true, and if @p newTimeOfDay < @p oldTimeOfDay, and if the current
0145      *                       time is between @p newTimeOfDay and @p oldTimeOfDay, the timer will be
0146      *                       triggered immediately so as to avoid missing today's trigger.
0147      */
0148     void changeTime(const QTime& newTimeOfDay, bool triggerMissed = true);
0149 
0150     /** Return the current time of day at which this variable timer triggers. */
0151     QTime timeOfDay() const  { return mTime; }
0152 
0153     /** Return the instance which triggers at the specified fixed time of day,
0154      *  optionally creating a new instance if necessary.
0155      *  @param timeOfDay Time at which the timer triggers.
0156      *  @param create    If true, create a new instance if none already exists
0157      *                   for @p timeOfDay.
0158      *  @return The instance for @p timeOfDay, or 0 if it does not exist.
0159      */
0160     static DailyTimer* fixedInstance(const QTime& timeOfDay, bool create = true);
0161 
0162     void start() override;
0163 
0164 protected Q_SLOTS:
0165     void slotTimer() override;
0166 
0167 private:
0168     static QList<DailyTimer*> mFixedTimers;  // list of timers whose trigger time is fixed
0169     QTime mTime;
0170     QDate mLastDate;  // the date on which the timer was last triggered
0171     bool  mFixed;     // the time at which the timer triggers cannot be changed
0172 };
0173 
0174 
0175 /** MidnightTimer is an application-wide timer synchronized to midnight, local time.
0176  *
0177  *  @author David Jarvie <djarvie@kde.org>
0178  */
0179 class MidnightTimer
0180 {
0181 public:
0182     /** Connect to the timer signal.
0183      *  @param receiver Receiving object.
0184      *  @param member Slot to activate.
0185      */
0186     static void connect(QObject* receiver, const char* member)
0187                        { DailyTimer::connect(QTime(0,0), receiver, member); }
0188 
0189     /** Disconnect from the timer signal.
0190      *  @param receiver Receiving object.
0191      *  @param member Slot to disconnect. If null, all slots belonging to
0192      *                @p receiver will be disconnected.
0193      */
0194     static void disconnect(QObject* receiver, const char* member = nullptr)
0195                        { DailyTimer::disconnect(QTime(0,0), receiver, member); }
0196 };
0197 
0198 // vim: et sw=4: