kalarm/lib

synchtimer.cpp
1/*
2 * synchtimer.cpp - timers which synchronise to time boundaries
3 * Program: kalarm
4 * Copyright (C) 2004, 2005 by David Jarvie <software@astrojar.org.uk>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20
21#include "kalarm.h"
22#include <tqtimer.h>
23#include <kdebug.h>
24#include "synchtimer.moc"
25
26
27/*=============================================================================
28= Class: SynchTimer
29= Virtual base class for application-wide timer synchronised to a time boundary.
30=============================================================================*/
31
32SynchTimer::SynchTimer()
33{
34 mTimer = new TQTimer(this, "mTimer");
35}
36
37SynchTimer::~SynchTimer()
38{
39 delete mTimer;
40 mTimer = 0;
41}
42
43/******************************************************************************
44* Connect to the timer. The timer is started if necessary.
45*/
46void SynchTimer::connecT(TQObject* receiver, const char* member)
47{
48 Connection connection(receiver, member);
49 if (mConnections.find(connection) != mConnections.end())
50 return; // the slot is already connected, so ignore request
51 connect(mTimer, TQ_SIGNAL(timeout()), receiver, member);
52 mConnections.append(connection);
53 if (!mTimer->isActive())
54 {
55 connect(mTimer, TQ_SIGNAL(timeout()), this, TQ_SLOT(slotTimer()));
56 start();
57 }
58}
59
60/******************************************************************************
61* Disconnect from the timer. The timer is stopped if no longer needed.
62*/
63void SynchTimer::disconnecT(TQObject* receiver, const char* member)
64{
65 if (mTimer)
66 {
67 mTimer->disconnect(receiver, member);
68 if (member)
69 mConnections.remove(Connection(receiver, member));
70 else
71 {
72 for (TQValueList<Connection>::Iterator it = mConnections.begin(); it != mConnections.end(); )
73 {
74 if ((*it).receiver == receiver)
75 it = mConnections.remove(it);
76 else
77 ++it;
78 }
79 }
80 if (mConnections.isEmpty())
81 {
82 mTimer->disconnect();
83 mTimer->stop();
84 }
85 }
86}
87
88
89/*=============================================================================
90= Class: MinuteTimer
91= Application-wide timer synchronised to the minute boundary.
92=============================================================================*/
93
94MinuteTimer* MinuteTimer::mInstance = 0;
95
96MinuteTimer* MinuteTimer::instance()
97{
98 if (!mInstance)
99 mInstance = new MinuteTimer;
100 return mInstance;
101}
102
103/******************************************************************************
104* Called when the timer triggers, or to start the timer.
105* Timers can under some circumstances wander off from the correct trigger time,
106* so rather than setting a 1 minute interval, calculate the correct next
107* interval each time it triggers.
108*/
109void MinuteTimer::slotTimer()
110{
111 kdDebug(5950) << "MinuteTimer::slotTimer()" << endl;
112 int interval = 62 - TQTime::currentTime().second();
113 mTimer->start(interval * 1000, true); // execute a single shot
114}
115
116
117/*=============================================================================
118= Class: DailyTimer
119= Application-wide timer synchronised to midnight.
120=============================================================================*/
121
122TQValueList<DailyTimer*> DailyTimer::mFixedTimers;
123
124DailyTimer::DailyTimer(const TQTime& timeOfDay, bool fixed)
125 : mTime(timeOfDay),
126 mFixed(fixed)
127{
128 if (fixed)
129 mFixedTimers.append(this);
130}
131
132DailyTimer::~DailyTimer()
133{
134 if (mFixed)
135 mFixedTimers.remove(this);
136}
137
138DailyTimer* DailyTimer::fixedInstance(const TQTime& timeOfDay, bool create)
139{
140 for (TQValueList<DailyTimer*>::Iterator it = mFixedTimers.begin(); it != mFixedTimers.end(); ++it)
141 if ((*it)->mTime == timeOfDay)
142 return *it;
143 return create ? new DailyTimer(timeOfDay, true) : 0;
144}
145
146/******************************************************************************
147* Disconnect from the timer signal which triggers at the given fixed time of day.
148* If there are no remaining connections to that timer, it is destroyed.
149*/
150void DailyTimer::disconnect(const TQTime& timeOfDay, TQObject* receiver, const char* member)
151{
152 DailyTimer* timer = fixedInstance(timeOfDay, false);
153 if (!timer)
154 return;
155 timer->disconnecT(receiver, member);
156 if (!timer->hasConnections())
157 delete timer;
158}
159
160/******************************************************************************
161* Change the time at which the variable timer triggers.
162*/
163void DailyTimer::changeTime(const TQTime& newTimeOfDay, bool triggerMissed)
164{
165 if (mFixed)
166 return;
167 if (mTimer->isActive())
168 {
169 mTimer->stop();
170 bool triggerNow = false;
171 if (triggerMissed)
172 {
173 TQTime now = TQTime::currentTime();
174 if (now >= newTimeOfDay && now < mTime)
175 {
176 // The trigger time is now earlier and it has already arrived today.
177 // Trigger a timer event immediately.
178 triggerNow = true;
179 }
180 }
181 mTime = newTimeOfDay;
182 if (triggerNow)
183 mTimer->start(0, true); // trigger immediately
184 else
185 start();
186 }
187 else
188 mTime = newTimeOfDay;
189}
190
191/******************************************************************************
192* Initialise the timer to trigger at the specified time.
193* This will either be today or tomorrow, depending on whether the trigger time
194* has already passed.
195*/
196void DailyTimer::start()
197{
198 // TIMEZONE = local time
199 TQDateTime now = TQDateTime::currentDateTime();
200 // Find out whether to trigger today or tomorrow.
201 // In preference, use the last trigger date to determine this, since
202 // that will avoid possible errors due to daylight savings time changes.
203 bool today;
204 if (mLastDate.isValid())
205 today = (mLastDate < now.date());
206 else
207 today = (now.time() < mTime);
208 TQDateTime next;
209 if (today)
210 next = TQDateTime(now.date(), mTime);
211 else
212 next = TQDateTime(now.date().addDays(1), mTime);
213 uint interval = next.toTime_t() - now.toTime_t();
214 mTimer->start(interval * 1000, true); // execute a single shot
215 kdDebug(5950) << "DailyTimer::start(at " << mTime.hour() << ":" << mTime.minute() << "): interval = " << interval/3600 << ":" << (interval/60)%60 << ":" << interval%60 << endl;
216}
217
218/******************************************************************************
219* Called when the timer triggers.
220* Set the timer to trigger again tomorrow at the specified time.
221* Note that if daylight savings time changes occur, this will not be 24 hours
222* from now.
223*/
224void DailyTimer::slotTimer()
225{
226 // TIMEZONE = local time
227 TQDateTime now = TQDateTime::currentDateTime();
228 mLastDate = now.date();
229 TQDateTime next = TQDateTime(mLastDate.addDays(1), mTime);
230 uint interval = next.toTime_t() - now.toTime_t();
231 mTimer->start(interval * 1000, true); // execute a single shot
232 kdDebug(5950) << "DailyTimer::slotTimer(at " << mTime.hour() << ":" << mTime.minute() << "): interval = " << interval/3600 << ":" << (interval/60)%60 << ":" << interval%60 << endl;
233}
DailyTimer is an application-wide timer synchronised to a specified time of day, local time.
Definition: synchtimer.h:118
TQTime timeOfDay() const
Return the current time of day at which this variable timer triggers.
Definition: synchtimer.h:147
static void disconnect(const TQTime &timeOfDay, TQObject *receiver, const char *member=0)
Disconnect from the timer signal which triggers at the given fixed time of day.
Definition: synchtimer.cpp:150
static DailyTimer * fixedInstance(const TQTime &timeOfDay, bool create=true)
Return the instance which triggers at the specified fixed time of day, optionally creating a new inst...
Definition: synchtimer.cpp:138
DailyTimer(const TQTime &, bool fixed)
Construct an instance.
Definition: synchtimer.cpp:124
void changeTime(const TQTime &newTimeOfDay, bool triggerMissed=true)
Change the time at which this variable timer triggers.
Definition: synchtimer.cpp:163
MinuteTimer is an application-wide timer synchronised to the minute boundary.
Definition: synchtimer.h:78