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 
32 SynchTimer::SynchTimer()
33 {
34  mTimer = new TQTimer(this, "mTimer");
35 }
36 
37 SynchTimer::~SynchTimer()
38 {
39  delete mTimer;
40  mTimer = 0;
41 }
42 
43 /******************************************************************************
44 * Connect to the timer. The timer is started if necessary.
45 */
46 void 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 */
63 void 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 
94 MinuteTimer* MinuteTimer::mInstance = 0;
95 
96 MinuteTimer* 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 */
109 void 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 
122 TQValueList<DailyTimer*> DailyTimer::mFixedTimers;
123 
124 DailyTimer::DailyTimer(const TQTime& timeOfDay, bool fixed)
125  : mTime(timeOfDay),
126  mFixed(fixed)
127 {
128  if (fixed)
129  mFixedTimers.append(this);
130 }
131 
132 DailyTimer::~DailyTimer()
133 {
134  if (mFixed)
135  mFixedTimers.remove(this);
136 }
137 
138 DailyTimer* 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 */
150 void 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 */
163 void 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 */
196 void 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 */
224 void 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