|
|
|
/*
|
|
|
|
* synchtimer.cpp - timers which synchronise to time boundaries
|
|
|
|
* Program: kalarm
|
|
|
|
* Copyright (C) 2004, 2005 by David Jarvie <software@astrojar.org.uk>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "kalarm.h"
|
|
|
|
#include <tqtimer.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include "synchtimer.moc"
|
|
|
|
|
|
|
|
|
|
|
|
/*=============================================================================
|
|
|
|
= Class: SynchTimer
|
|
|
|
= Virtual base class for application-wide timer synchronised to a time boundary.
|
|
|
|
=============================================================================*/
|
|
|
|
|
|
|
|
SynchTimer::SynchTimer()
|
|
|
|
{
|
|
|
|
mTimer = new TQTimer(this, "mTimer");
|
|
|
|
}
|
|
|
|
|
|
|
|
SynchTimer::~SynchTimer()
|
|
|
|
{
|
|
|
|
delete mTimer;
|
|
|
|
mTimer = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
* Connect to the timer. The timer is started if necessary.
|
|
|
|
*/
|
|
|
|
void SynchTimer::connecT(TQObject* receiver, const char* member)
|
|
|
|
{
|
|
|
|
Connection connection(receiver, member);
|
|
|
|
if (mConnections.tqfind(connection) != mConnections.end())
|
|
|
|
return; // the slot is already connected, so ignore request
|
|
|
|
connect(mTimer, TQT_SIGNAL(timeout()), receiver, member);
|
|
|
|
mConnections.append(connection);
|
|
|
|
if (!mTimer->isActive())
|
|
|
|
{
|
|
|
|
connect(mTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotTimer()));
|
|
|
|
start();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
* Disconnect from the timer. The timer is stopped if no longer needed.
|
|
|
|
*/
|
|
|
|
void SynchTimer::disconnecT(TQObject* receiver, const char* member)
|
|
|
|
{
|
|
|
|
if (mTimer)
|
|
|
|
{
|
|
|
|
mTimer->disconnect(receiver, member);
|
|
|
|
if (member)
|
|
|
|
mConnections.remove(Connection(receiver, member));
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (TQValueList<Connection>::Iterator it = mConnections.begin(); it != mConnections.end(); )
|
|
|
|
{
|
|
|
|
if ((*it).receiver == receiver)
|
|
|
|
it = mConnections.remove(it);
|
|
|
|
else
|
|
|
|
++it;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (mConnections.isEmpty())
|
|
|
|
{
|
|
|
|
mTimer->disconnect();
|
|
|
|
mTimer->stop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*=============================================================================
|
|
|
|
= Class: MinuteTimer
|
|
|
|
= Application-wide timer synchronised to the minute boundary.
|
|
|
|
=============================================================================*/
|
|
|
|
|
|
|
|
MinuteTimer* MinuteTimer::mInstance = 0;
|
|
|
|
|
|
|
|
MinuteTimer* MinuteTimer::instance()
|
|
|
|
{
|
|
|
|
if (!mInstance)
|
|
|
|
mInstance = new MinuteTimer;
|
|
|
|
return mInstance;
|
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
* Called when the timer triggers, or to start the timer.
|
|
|
|
* Timers can under some circumstances wander off from the correct trigger time,
|
|
|
|
* so rather than setting a 1 minute interval, calculate the correct next
|
|
|
|
* interval each time it triggers.
|
|
|
|
*/
|
|
|
|
void MinuteTimer::slotTimer()
|
|
|
|
{
|
|
|
|
kdDebug(5950) << "MinuteTimer::slotTimer()" << endl;
|
|
|
|
int interval = 62 - TQTime::currentTime().second();
|
|
|
|
mTimer->start(interval * 1000, true); // execute a single shot
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*=============================================================================
|
|
|
|
= Class: DailyTimer
|
|
|
|
= Application-wide timer synchronised to midnight.
|
|
|
|
=============================================================================*/
|
|
|
|
|
|
|
|
TQValueList<DailyTimer*> DailyTimer::mFixedTimers;
|
|
|
|
|
|
|
|
DailyTimer::DailyTimer(const TQTime& timeOfDay, bool fixed)
|
|
|
|
: mTime(timeOfDay),
|
|
|
|
mFixed(fixed)
|
|
|
|
{
|
|
|
|
if (fixed)
|
|
|
|
mFixedTimers.append(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
DailyTimer::~DailyTimer()
|
|
|
|
{
|
|
|
|
if (mFixed)
|
|
|
|
mFixedTimers.remove(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
DailyTimer* DailyTimer::fixedInstance(const TQTime& timeOfDay, bool create)
|
|
|
|
{
|
|
|
|
for (TQValueList<DailyTimer*>::Iterator it = mFixedTimers.begin(); it != mFixedTimers.end(); ++it)
|
|
|
|
if ((*it)->mTime == timeOfDay)
|
|
|
|
return *it;
|
|
|
|
return create ? new DailyTimer(timeOfDay, true) : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
* Disconnect from the timer signal which triggers at the given fixed time of day.
|
|
|
|
* If there are no remaining connections to that timer, it is destroyed.
|
|
|
|
*/
|
|
|
|
void DailyTimer::disconnect(const TQTime& timeOfDay, TQObject* receiver, const char* member)
|
|
|
|
{
|
|
|
|
DailyTimer* timer = fixedInstance(timeOfDay, false);
|
|
|
|
if (!timer)
|
|
|
|
return;
|
|
|
|
timer->disconnecT(receiver, member);
|
|
|
|
if (!timer->hasConnections())
|
|
|
|
delete timer;
|
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
* Change the time at which the variable timer triggers.
|
|
|
|
*/
|
|
|
|
void DailyTimer::changeTime(const TQTime& newTimeOfDay, bool triggerMissed)
|
|
|
|
{
|
|
|
|
if (mFixed)
|
|
|
|
return;
|
|
|
|
if (mTimer->isActive())
|
|
|
|
{
|
|
|
|
mTimer->stop();
|
|
|
|
bool triggerNow = false;
|
|
|
|
if (triggerMissed)
|
|
|
|
{
|
|
|
|
TQTime now = TQTime::currentTime();
|
|
|
|
if (now >= newTimeOfDay && now < mTime)
|
|
|
|
{
|
|
|
|
// The trigger time is now earlier and it has already arrived today.
|
|
|
|
// Trigger a timer event immediately.
|
|
|
|
triggerNow = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mTime = newTimeOfDay;
|
|
|
|
if (triggerNow)
|
|
|
|
mTimer->start(0, true); // trigger immediately
|
|
|
|
else
|
|
|
|
start();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
mTime = newTimeOfDay;
|
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
* Initialise the timer to trigger at the specified time.
|
|
|
|
* This will either be today or tomorrow, depending on whether the trigger time
|
|
|
|
* has already passed.
|
|
|
|
*/
|
|
|
|
void DailyTimer::start()
|
|
|
|
{
|
|
|
|
// TIMEZONE = local time
|
|
|
|
TQDateTime now = TQDateTime::tqcurrentDateTime();
|
|
|
|
// Find out whether to trigger today or tomorrow.
|
|
|
|
// In preference, use the last trigger date to determine this, since
|
|
|
|
// that will avoid possible errors due to daylight savings time changes.
|
|
|
|
bool today;
|
|
|
|
if (mLastDate.isValid())
|
|
|
|
today = (mLastDate < now.date());
|
|
|
|
else
|
|
|
|
today = (now.time() < mTime);
|
|
|
|
TQDateTime next;
|
|
|
|
if (today)
|
|
|
|
next = TQDateTime(now.date(), mTime);
|
|
|
|
else
|
|
|
|
next = TQDateTime(now.date().addDays(1), mTime);
|
|
|
|
uint interval = next.toTime_t() - now.toTime_t();
|
|
|
|
mTimer->start(interval * 1000, true); // execute a single shot
|
|
|
|
kdDebug(5950) << "DailyTimer::start(at " << mTime.hour() << ":" << mTime.minute() << "): interval = " << interval/3600 << ":" << (interval/60)%60 << ":" << interval%60 << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
* Called when the timer triggers.
|
|
|
|
* Set the timer to trigger again tomorrow at the specified time.
|
|
|
|
* Note that if daylight savings time changes occur, this will not be 24 hours
|
|
|
|
* from now.
|
|
|
|
*/
|
|
|
|
void DailyTimer::slotTimer()
|
|
|
|
{
|
|
|
|
// TIMEZONE = local time
|
|
|
|
TQDateTime now = TQDateTime::tqcurrentDateTime();
|
|
|
|
mLastDate = now.date();
|
|
|
|
TQDateTime next = TQDateTime(mLastDate.addDays(1), mTime);
|
|
|
|
uint interval = next.toTime_t() - now.toTime_t();
|
|
|
|
mTimer->start(interval * 1000, true); // execute a single shot
|
|
|
|
kdDebug(5950) << "DailyTimer::slotTimer(at " << mTime.hour() << ":" << mTime.minute() << "): interval = " << interval/3600 << ":" << (interval/60)%60 << ":" << interval%60 << endl;
|
|
|
|
}
|