kalarm

daemon.cpp

00001 /*
00002  *  daemon.cpp  -  interface with alarm daemon
00003  *  Program:  kalarm
00004  *  Copyright © 2001-2007 by David Jarvie <software@astrojar.org.uk>
00005  *
00006  *  This program is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation; either version 2 of the License, or
00009  *  (at your option) any later version.
00010  *
00011  *  This program is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00014  *  GNU General Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU General Public License along
00017  *  with this program; if not, write to the Free Software Foundation, Inc.,
00018  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  */
00020 
00021 #include "kalarm.h"
00022 
00023 #include <tqtimer.h>
00024 #include <tqiconset.h>
00025 
00026 #include <kstandarddirs.h>
00027 #include <tdeconfig.h>
00028 #include <tdeaboutdata.h>
00029 #include <tdemessagebox.h>
00030 #include <dcopclient.h>
00031 #include <kdebug.h>
00032 
00033 #include "kalarmd/kalarmd.h"
00034 #include "kalarmd/alarmdaemoniface.h"
00035 #include "kalarmd/alarmdaemoniface_stub.h"
00036 #include "kalarmd/alarmguiiface.h"
00037 
00038 #include "alarmcalendar.h"
00039 #include "kalarmapp.h"
00040 #include "preferences.h"
00041 #include "daemon.moc"
00042 
00043 
00044 static const int    REGISTER_TIMEOUT = 20;     // seconds to wait before assuming registration with daemon has failed
00045 static const char*  NOTIFY_DCOP_OBJECT  = "notify";    // DCOP name of KAlarm's interface for notification by alarm daemon
00046 
00047 static TQString expandURL(const TQString& urlString);
00048 
00049 
00050 /*=============================================================================
00051 =  Class: NotificationHandler
00052 =  Handles the the alarm daemon's client notification DCOP interface.
00053 =============================================================================*/
00054 
00055 class NotificationHandler : public TQObject, virtual public AlarmGuiIface
00056 {
00057     public:
00058         NotificationHandler();
00059     private:
00060         // DCOP interface
00061         void  alarmDaemonUpdate(int calendarStatus, const TQString& calendarURL);
00062         void  handleEvent(const TQString& calendarURL, const TQString& eventID);
00063         void  registered(bool reregister, int result, int version);
00064 };
00065 
00066 
00067 Daemon*              Daemon::mInstance = 0;
00068 NotificationHandler* Daemon::mDcopHandler = 0;
00069 TQValueList<TQString>  Daemon::mQueuedEvents;
00070 TQValueList<TQString>  Daemon::mSavingEvents;
00071 TQTimer*              Daemon::mStartTimer = 0;
00072 TQTimer*              Daemon::mRegisterTimer = 0;
00073 TQTimer*              Daemon::mStatusTimer = 0;
00074 int                  Daemon::mStatusTimerCount = 0;
00075 int                  Daemon::mStatusTimerInterval;
00076 int                  Daemon::mStartTimeout = 0;
00077 Daemon::Status       Daemon::mStatus = Daemon::STOPPED;
00078 bool                 Daemon::mRunning = false;
00079 bool                 Daemon::mCalendarDisabled = false;
00080 bool                 Daemon::mEnableCalPending = false;
00081 bool                 Daemon::mRegisterFailMsg = false;
00082 
00083 // How frequently to check the daemon's status after starting it.
00084 // This is equal to the length of time we wait after the daemon is registered with DCOP
00085 // before we assume that it is ready to accept DCOP calls.
00086 static const int startCheckInterval = 500;     // 500 milliseconds
00087 
00088 
00089 /******************************************************************************
00090 * Initialise.
00091 * A Daemon instance needs to be constructed only in order for slots to work.
00092 * All external access is via static methods.
00093 */
00094 void Daemon::initialise()
00095 {
00096     if (!mInstance)
00097         mInstance = new Daemon();
00098     connect(AlarmCalendar::activeCalendar(), TQT_SIGNAL(calendarSaved(AlarmCalendar*)), mInstance, TQT_SLOT(slotCalendarSaved(AlarmCalendar*)));
00099 }
00100 
00101 /******************************************************************************
00102 * Initialise the daemon status timer.
00103 */
00104 void Daemon::createDcopHandler()
00105 {
00106     if (mDcopHandler)
00107         return;
00108     mDcopHandler = new NotificationHandler();
00109     // Check if the alarm daemon is running, but don't start it yet, since
00110     // the program is still initialising.
00111     mRunning = isRunning(false);
00112 
00113     mStatusTimerInterval = Preferences::daemonTrayCheckInterval();
00114     Preferences::connect(TQT_SIGNAL(preferencesChanged()), mInstance, TQT_SLOT(slotPreferencesChanged()));
00115 
00116     mStatusTimer = new TQTimer(mInstance);
00117     connect(mStatusTimer, TQT_SIGNAL(timeout()), mInstance, TQT_SLOT(timerCheckIfRunning()));
00118     mStatusTimer->start(mStatusTimerInterval * 1000);  // check regularly if daemon is running
00119 }
00120 
00121 /******************************************************************************
00122 * Start the alarm daemon if necessary, and register this application with it.
00123 * Reply = false if the daemon definitely couldn't be started or registered with.
00124 */
00125 bool Daemon::start()
00126 {
00127     kdDebug(5950) << "Daemon::start()\n";
00128     updateRegisteredStatus();
00129     switch (mStatus)
00130     {
00131         case STOPPED:
00132         {
00133             if (mStartTimer)
00134                 return true;     // we're currently waiting for the daemon to start
00135             // Start the alarm daemon. It is a KUniqueApplication, which means that
00136             // there is automatically only one instance of the alarm daemon running.
00137             TQString execStr = locate("exe", TQString::fromLatin1(DAEMON_APP_NAME));
00138             if (execStr.isEmpty())
00139             {
00140                 KMessageBox::error(0, i18n("Alarm daemon not found."));
00141                 kdError() << "Daemon::startApp(): " DAEMON_APP_NAME " not found" << endl;
00142                 return false;
00143             }
00144             TDEApplication::tdeinitExec(execStr);
00145             kdDebug(5950) << "Daemon::start(): Alarm daemon started" << endl;
00146             mStartTimeout = 5000/startCheckInterval + 1;    // check daemon status for 5 seconds before giving up
00147             mStartTimer = new TQTimer(mInstance);
00148             connect(mStartTimer, TQT_SIGNAL(timeout()), mInstance, TQT_SLOT(checkIfStarted()));
00149             mStartTimer->start(startCheckInterval);
00150             mInstance->checkIfStarted();
00151             return true;
00152         }
00153         case RUNNING:
00154             return true;     // we're waiting for the daemon to be completely ready
00155         case READY:
00156             // Daemon is ready. Register this application with it.
00157             if (!registerWith(false))
00158                 return false;
00159             break;
00160         case REGISTERED:
00161             break;
00162     }
00163     return true;
00164 }
00165 
00166 /******************************************************************************
00167 * Register this application with the alarm daemon, and tell it to load the
00168 * calendar.
00169 * Set 'reregister' true in order to notify the daemon of a change in the
00170 * 'disable alarms if stopped' setting.
00171 */
00172 bool Daemon::registerWith(bool reregister)
00173 {
00174     if (mRegisterTimer)
00175         return true;
00176     switch (mStatus)
00177     {
00178         case STOPPED:
00179         case RUNNING:
00180             return false;
00181         case REGISTERED:
00182             if (!reregister)
00183                 return true;
00184             break;
00185         case READY:
00186             break;
00187     }
00188 
00189     bool disabledIfStopped = theApp()->alarmsDisabledIfStopped();
00190     kdDebug(5950) << (reregister ? "Daemon::reregisterWith(): " : "Daemon::registerWith(): ") << (disabledIfStopped ? "NO_START" : "COMMAND_LINE") << endl;
00191     TQCString appname  = kapp->aboutData()->appName();
00192     AlarmDaemonIface_stub s(DAEMON_APP_NAME, DAEMON_DCOP_OBJECT);
00193     if (reregister)
00194         s.registerChange(appname, !disabledIfStopped);
00195     else
00196         s.registerApp(appname, kapp->aboutData()->programName(), TQCString(NOTIFY_DCOP_OBJECT), AlarmCalendar::activeCalendar()->urlString(), !disabledIfStopped);
00197     if (!s.ok())
00198     {
00199         kdError(5950) << "Daemon::registerWith(" << reregister << "): DCOP error" << endl;
00200         registrationResult(reregister, KAlarmd::FAILURE);
00201         return false;
00202     }
00203     mRegisterTimer = new TQTimer(mInstance);
00204     connect(mRegisterTimer, TQT_SIGNAL(timeout()), mInstance, TQT_SLOT(registerTimerExpired()));
00205     mRegisterTimer->start(REGISTER_TIMEOUT * 1000);     // wait for the reply
00206     return true;
00207 }
00208 
00209 /******************************************************************************
00210 * Called when the daemon has notified us of the result of the register() DCOP call.
00211 */
00212 void Daemon::registrationResult(bool reregister, int result, int version)
00213 {
00214     kdDebug(5950) << "Daemon::registrationResult(" << reregister << ") version: " << version << endl;
00215     delete mRegisterTimer;
00216     mRegisterTimer = 0;
00217     bool failed = false;
00218     TQString errmsg;
00219     if (version  &&  version != DAEMON_VERSION_NUM)
00220     {
00221         failed = true;
00222         kdError(5950) << "Daemon::registrationResult(" << reregister << "): kalarmd reports incompatible version " << version << endl;
00223         errmsg = i18n("Cannot enable alarms.\nInstallation or configuration error: Alarm Daemon (%1) version is incompatible.")
00224                       .arg(TQString::fromLatin1(DAEMON_APP_NAME));
00225     }
00226     else
00227     {
00228         switch (result)
00229         {
00230             case KAlarmd::SUCCESS:
00231                 break;
00232             case KAlarmd::NOT_FOUND:
00233                 // We've successfully registered with the daemon, but the daemon can't
00234                 // find the KAlarm executable so won't be able to restart KAlarm if
00235                 // KAlarm exits.
00236                 kdError(5950) << "Daemon::registrationResult(" << reregister << "): registerApp dcop call: " << kapp->aboutData()->appName() << " not found\n";
00237                 KMessageBox::error(0, i18n("Alarms will be disabled if you stop KAlarm.\n"
00238                                "(Installation or configuration error: %1 cannot locate %2 executable.)")
00239                                .arg(TQString::fromLatin1(DAEMON_APP_NAME))
00240                                .arg(kapp->aboutData()->appName()));
00241                 break;
00242             case KAlarmd::FAILURE:
00243             default:
00244                 // Either the daemon reported an error in the registration DCOP call,
00245                 // there was a DCOP error calling the daemon, or a timeout on the reply.
00246                 kdError(5950) << "Daemon::registrationResult(" << reregister << "): registerApp dcop call failed -> " << result << endl;
00247                 failed = true;
00248                 if (!reregister)
00249                 {
00250                     errmsg = i18n("Cannot enable alarms:\nFailed to register with Alarm Daemon (%1)")
00251                                   .arg(TQString::fromLatin1(DAEMON_APP_NAME));
00252                 }
00253                 break;
00254         }
00255     }
00256 
00257     if (failed)
00258     {
00259         if (!errmsg.isEmpty())
00260         {
00261             if (mStatus == REGISTERED)
00262                 mStatus = READY;
00263             if (!mRegisterFailMsg)
00264             {
00265                 mRegisterFailMsg = true;
00266                 KMessageBox::error(0, errmsg);
00267             }
00268         }
00269         return;
00270     }
00271 
00272     if (!reregister)
00273     {
00274         // The alarm daemon has loaded the calendar
00275         mStatus = REGISTERED;
00276         mRegisterFailMsg = false;
00277         kdDebug(5950) << "Daemon::start(): daemon startup complete" << endl;
00278     }
00279 }
00280 
00281 /******************************************************************************
00282 * Check whether the alarm daemon has started yet, and if so, register with it.
00283 */
00284 void Daemon::checkIfStarted()
00285 {
00286     updateRegisteredStatus();
00287     bool err = false;
00288     switch (mStatus)
00289     {
00290         case STOPPED:
00291             if (--mStartTimeout > 0)
00292                 return;     // wait a bit more to check again
00293             // Output error message, but delete timer first to prevent
00294             // multiple messages.
00295             err = true;
00296             break;
00297         case RUNNING:
00298         case READY:
00299         case REGISTERED:
00300             break;
00301     }
00302     delete mStartTimer;
00303     mStartTimer = 0;
00304     if (err)
00305     {
00306         kdError(5950) << "Daemon::checkIfStarted(): failed to start daemon" << endl;
00307         KMessageBox::error(0, i18n("Cannot enable alarms:\nFailed to start Alarm Daemon (%1)").arg(TQString::fromLatin1(DAEMON_APP_NAME)));
00308     }
00309 }
00310 
00311 /******************************************************************************
00312 * Check whether the alarm daemon has started yet, and if so, whether it is
00313 * ready to accept DCOP calls.
00314 */
00315 void Daemon::updateRegisteredStatus(bool timeout)
00316 {
00317     if (!kapp->dcopClient()->isApplicationRegistered(DAEMON_APP_NAME))
00318     {
00319         mStatus = STOPPED;
00320         mRegisterFailMsg = false;
00321     }
00322     else
00323     {
00324         switch (mStatus)
00325         {
00326             case STOPPED:
00327                 // The daemon has newly been detected as registered with DCOP.
00328                 // Wait for a short time to ensure that it is ready for DCOP calls.
00329                 mStatus = RUNNING;
00330                 TQTimer::singleShot(startCheckInterval, mInstance, TQT_SLOT(slotStarted()));
00331                 break;
00332             case RUNNING:
00333                 if (timeout)
00334                 {
00335                     mStatus = READY;
00336                     start();
00337                 }
00338                 break;
00339             case READY:
00340             case REGISTERED:
00341                 break;
00342         }
00343     }
00344     kdDebug(5950) << "Daemon::updateRegisteredStatus() -> " << mStatus << endl;
00345 }
00346 
00347 /******************************************************************************
00348 * Stop the alarm daemon if it is running.
00349 */
00350 bool Daemon::stop()
00351 {
00352     kdDebug(5950) << "Daemon::stop()" << endl;
00353     if (kapp->dcopClient()->isApplicationRegistered(DAEMON_APP_NAME))
00354     {
00355         AlarmDaemonIface_stub s(DAEMON_APP_NAME, DAEMON_DCOP_OBJECT);
00356         s.quit();
00357         if (!s.ok())
00358         {
00359             kdError(5950) << "Daemon::stop(): dcop call failed" << endl;
00360             return false;
00361         }
00362     }
00363     return true;
00364 }
00365 
00366 /******************************************************************************
00367 * Reset the alarm daemon.
00368 * Reply = true if daemon was told to reset
00369 *       = false if daemon is not running.
00370 */
00371 bool Daemon::reset()
00372 {
00373     kdDebug(5950) << "Daemon::reset()" << endl;
00374     if (!kapp->dcopClient()->isApplicationRegistered(DAEMON_APP_NAME))
00375         return false;
00376     AlarmDaemonIface_stub s(DAEMON_APP_NAME, DAEMON_DCOP_OBJECT);
00377     s.resetCalendar(TQCString(kapp->aboutData()->appName()), AlarmCalendar::activeCalendar()->urlString());
00378     if (!s.ok())
00379         kdError(5950) << "Daemon::reset(): resetCalendar dcop send failed" << endl;
00380     return true;
00381 }
00382 
00383 /******************************************************************************
00384 * Tell the alarm daemon to reread the calendar file.
00385 */
00386 void Daemon::reload()
00387 {
00388     kdDebug(5950) << "Daemon::reload()\n";
00389     AlarmDaemonIface_stub s(DAEMON_APP_NAME, DAEMON_DCOP_OBJECT);
00390     s.reloadCalendar(TQCString(kapp->aboutData()->appName()), AlarmCalendar::activeCalendar()->urlString());
00391     if (!s.ok())
00392         kdError(5950) << "Daemon::reload(): reloadCalendar dcop send failed" << endl;
00393 }
00394 
00395 /******************************************************************************
00396 * Tell the alarm daemon to enable/disable monitoring of the calendar file.
00397 */
00398 void Daemon::enableCalendar(bool enable)
00399 {
00400     AlarmDaemonIface_stub s(DAEMON_APP_NAME, DAEMON_DCOP_OBJECT);
00401     s.enableCalendar(AlarmCalendar::activeCalendar()->urlString(), enable);
00402     mEnableCalPending = false;
00403 }
00404 
00405 /******************************************************************************
00406 * Tell the alarm daemon to enable/disable autostart at login.
00407 */
00408 void Daemon::enableAutoStart(bool enable)
00409 {
00410     // Tell the alarm daemon in case it is running.
00411     AlarmDaemonIface_stub s(DAEMON_APP_NAME, DAEMON_DCOP_OBJECT);
00412     s.enableAutoStart(enable);
00413 
00414     // The return status doesn't report failure even if the daemon isn't running,
00415     // so in case of failure, rewrite the config file in any case.
00416     TDEConfig adconfig(locate("config", DAEMON_APP_NAME"rc"));
00417     adconfig.setGroup(TQString::fromLatin1(DAEMON_AUTOSTART_SECTION));
00418     adconfig.writeEntry(TQString::fromLatin1(DAEMON_AUTOSTART_KEY), enable);
00419     adconfig.sync();
00420 }
00421 
00422 /******************************************************************************
00423 * Notify the alarm daemon that the start-of-day time for date-only alarms has
00424 * changed.
00425 */
00426 void Daemon::notifyTimeChanged()
00427 {
00428     AlarmDaemonIface_stub s(DAEMON_APP_NAME, DAEMON_DCOP_OBJECT);
00429     s.timeConfigChanged();
00430     if (!s.ok())
00431         kdError(5950) << "Daemon::timeConfigChanged(): dcop send failed" << endl;
00432 }
00433 
00434 /******************************************************************************
00435 * Read the alarm daemon's autostart-at-login setting.
00436 */
00437 bool Daemon::autoStart()
00438 {
00439     TDEConfig adconfig(locate("config", DAEMON_APP_NAME"rc"));
00440     adconfig.setGroup(TQString::fromLatin1(DAEMON_AUTOSTART_SECTION));
00441     return adconfig.readBoolEntry(TQString::fromLatin1(DAEMON_AUTOSTART_KEY), true);
00442 }
00443 
00444 /******************************************************************************
00445 * Notification that the alarm daemon has enabled/disabled monitoring of the
00446 * calendar file.
00447 */
00448 void Daemon::calendarIsEnabled(bool enabled)
00449 {
00450     mCalendarDisabled = !enabled;
00451     emit mInstance->daemonRunning(enabled);
00452 }
00453 
00454 /******************************************************************************
00455 * Tell the alarm daemon to stop or start monitoring the calendar file as
00456 * appropriate.
00457 */
00458 void Daemon::setAlarmsEnabled(bool enable)
00459 {
00460     kdDebug(5950) << "Daemon::setAlarmsEnabled(" << enable << ")\n";
00461     if (enable  &&  !checkIfRunning())
00462     {
00463         // The daemon is not running, so start it
00464         if (!start())
00465         {
00466             emit daemonRunning(false);
00467             return;
00468         }
00469         mEnableCalPending = true;
00470         setFastCheck();
00471     }
00472 
00473     // If the daemon is now running, tell it to enable/disable the calendar
00474     if (checkIfRunning())
00475         enableCalendar(enable);
00476 }
00477 
00478 /******************************************************************************
00479 * Return whether the alarm daemon is monitoring alarms.
00480 */
00481 bool Daemon::monitoringAlarms()
00482 {
00483     bool ok = !mCalendarDisabled  &&  isRunning();
00484     emit mInstance->daemonRunning(ok);
00485     return ok;
00486 }
00487 
00488 /******************************************************************************
00489 * Check whether the alarm daemon is currently running and available.
00490 */
00491 bool Daemon::isRunning(bool startdaemon)
00492 {
00493     static bool runState = false;
00494     updateRegisteredStatus();
00495     bool newRunState = (mStatus == READY  ||  mStatus == REGISTERED);
00496     if (newRunState != runState)
00497     {
00498         // Daemon's status has changed
00499         runState = newRunState;
00500         if (runState  &&  startdaemon)
00501             start();      // re-register with the daemon
00502     }
00503     return runState  &&  (mStatus == REGISTERED);
00504 }
00505 
00506 /******************************************************************************
00507 * Called by the timer to check whether the daemon is running.
00508 */
00509 void Daemon::timerCheckIfRunning()
00510 {
00511     checkIfRunning();
00512     // Limit how long we check at the fast rate
00513     if (mStatusTimerCount > 0  &&  --mStatusTimerCount <= 0)
00514         mStatusTimer->changeInterval(mStatusTimerInterval * 1000);
00515 }
00516 
00517 /******************************************************************************
00518 * Check whether the alarm daemon is currently running.
00519 * If its status has changed, trigger GUI updates.
00520 */
00521 bool Daemon::checkIfRunning()
00522 {
00523     bool newstatus = isRunning();
00524     if (newstatus != mRunning)
00525     {
00526         mRunning = newstatus;
00527         int status = mRunning  &&  !mCalendarDisabled;
00528         emit mInstance->daemonRunning(status);
00529         mStatusTimer->changeInterval(mStatusTimerInterval * 1000);   // exit from fast checking
00530         mStatusTimerCount = 0;
00531         if (mRunning)
00532         {
00533             // The alarm daemon has started up
00534             if (mEnableCalPending)
00535                 enableCalendar(true);  // tell it to monitor the calendar, if appropriate
00536         }
00537     }
00538     return mRunning;
00539 }
00540 
00541 /******************************************************************************
00542 * Starts checking at a faster rate whether the daemon is running.
00543 */
00544 void Daemon::setFastCheck()
00545 {
00546     mStatusTimer->start(500);    // check new status every half second
00547     mStatusTimerCount = 20;      // don't check at this rate for more than 10 seconds
00548 }
00549 
00550 /******************************************************************************
00551 * Called when a program setting has changed.
00552 * If the system tray icon update interval has changed, reset the timer.
00553 */
00554 void Daemon::slotPreferencesChanged()
00555 {
00556     int newInterval = Preferences::daemonTrayCheckInterval();
00557     if (newInterval != mStatusTimerInterval)
00558     {
00559         // Daemon check interval has changed
00560         mStatusTimerInterval = newInterval;
00561         if (mStatusTimerCount <= 0)   // don't change if on fast rate
00562             mStatusTimer->changeInterval(mStatusTimerInterval * 1000);
00563     }
00564 }
00565 
00566 /******************************************************************************
00567 * Create an "Alarms Enabled/Enable Alarms" action.
00568 */
00569 AlarmEnableAction* Daemon::createAlarmEnableAction(TDEActionCollection* actions, const char* name)
00570 {
00571     AlarmEnableAction* a = new AlarmEnableAction(0, actions, name);
00572     connect(a, TQT_SIGNAL(userClicked(bool)), mInstance, TQT_SLOT(setAlarmsEnabled(bool)));
00573     connect(mInstance, TQT_SIGNAL(daemonRunning(bool)), a, TQT_SLOT(setCheckedActual(bool)));
00574     return a;
00575 }
00576 
00577 /******************************************************************************
00578 * Called when a calendar has been saved.
00579 * If it's the active alarm calendar, notify the alarm daemon.
00580 */
00581 void Daemon::slotCalendarSaved(AlarmCalendar* cal)
00582 {
00583     if (cal == AlarmCalendar::activeCalendar())
00584     {
00585         int n = mSavingEvents.count();
00586         if (n)
00587         {
00588             // We have just saved a modified event originally triggered by the daemon.
00589             // Notify the daemon of the event, and tell it to reload the calendar.
00590             for (int i = 0;  i < n - 1;  ++i)
00591                 notifyEventHandled(mSavingEvents[i], false);
00592             notifyEventHandled(mSavingEvents[n - 1], true);
00593             mSavingEvents.clear();
00594         }
00595         else
00596             reload();
00597     }
00598 }
00599 
00600 /******************************************************************************
00601 * Note an event ID which has been triggered by the alarm daemon.
00602 */
00603 void Daemon::queueEvent(const TQString& eventId)
00604 {
00605     mQueuedEvents += eventId;
00606 }
00607 
00608 /******************************************************************************
00609 * Note an event ID which is currently being saved in the calendar file, if the
00610 * event was originally triggered by the alarm daemon.
00611 */
00612 void Daemon::savingEvent(const TQString& eventId)
00613 {
00614     if (mQueuedEvents.remove(eventId) > 0)
00615         mSavingEvents += eventId;
00616 }
00617 
00618 /******************************************************************************
00619 * If the event ID has been triggered by the alarm daemon, tell the daemon that
00620 * it has been processed, and whether to reload its calendar.
00621 */
00622 void Daemon::eventHandled(const TQString& eventId, bool reloadCal)
00623 {
00624     if (mQueuedEvents.remove(eventId) > 0)
00625         notifyEventHandled(eventId, reloadCal);    // it's a daemon event, so tell daemon that it's been handled
00626     else if (reloadCal)
00627         reload();    // not a daemon event, so simply tell the daemon to reload the calendar
00628 }
00629 
00630 /******************************************************************************
00631 * Tell the daemon that an event has been processed, and whether to reload its
00632 * calendar.
00633 */
00634 void Daemon::notifyEventHandled(const TQString& eventId, bool reloadCal)
00635 {
00636     kdDebug(5950) << "Daemon::notifyEventHandled(" << eventId << (reloadCal ? "): reload" : ")") << endl;
00637     AlarmDaemonIface_stub s(DAEMON_APP_NAME, DAEMON_DCOP_OBJECT);
00638     s.eventHandled(TQCString(kapp->aboutData()->appName()), AlarmCalendar::activeCalendar()->urlString(), eventId, reloadCal);
00639     if (!s.ok())
00640         kdError(5950) << "Daemon::notifyEventHandled(): eventHandled dcop send failed" << endl;
00641 }
00642 
00643 /******************************************************************************
00644 * Return the maximum time (in seconds) elapsed since the last time the alarm
00645 * daemon must have checked alarms.
00646 */
00647 int Daemon::maxTimeSinceCheck()
00648 {
00649     return DAEMON_CHECK_INTERVAL;
00650 }
00651 
00652 
00653 /*=============================================================================
00654 =  Class: NotificationHandler
00655 =============================================================================*/
00656 
00657 NotificationHandler::NotificationHandler()
00658     : DCOPObject(NOTIFY_DCOP_OBJECT), 
00659       TQObject()
00660 {
00661     kdDebug(5950) << "NotificationHandler::NotificationHandler()\n";
00662 }
00663 
00664 /******************************************************************************
00665  * DCOP call from the alarm daemon to notify a change.
00666  * The daemon notifies calendar statuses when we first register as a GUI, and whenever
00667  * a calendar status changes. So we don't need to read its config files.
00668  */
00669 void NotificationHandler::alarmDaemonUpdate(int calendarStatus, const TQString& calendarURL)
00670 {
00671     kdDebug(5950) << "NotificationHandler::alarmDaemonUpdate(" << calendarStatus << ")\n";
00672     KAlarmd::CalendarStatus status = KAlarmd::CalendarStatus(calendarStatus);
00673     if (expandURL(calendarURL) != AlarmCalendar::activeCalendar()->urlString())
00674         return;     // it's not a notification about KAlarm's calendar
00675     bool enabled = false;
00676     switch (status)
00677     {
00678         case KAlarmd::CALENDAR_UNAVAILABLE:
00679             // Calendar is not available for monitoring
00680             kdDebug(5950) << "NotificationHandler::alarmDaemonUpdate(CALENDAR_UNAVAILABLE)\n";
00681             break;
00682         case KAlarmd::CALENDAR_DISABLED:
00683             // Calendar is available for monitoring but is not currently being monitored
00684             kdDebug(5950) << "NotificationHandler::alarmDaemonUpdate(DISABLE_CALENDAR)\n";
00685             break;
00686         case KAlarmd::CALENDAR_ENABLED:
00687             // Calendar is currently being monitored
00688             kdDebug(5950) << "NotificationHandler::alarmDaemonUpdate(ENABLE_CALENDAR)\n";
00689             enabled = true;
00690             break;
00691         default:
00692             return;
00693     }
00694     Daemon::calendarIsEnabled(enabled);
00695 }
00696 
00697 /******************************************************************************
00698  * DCOP call from the alarm daemon to notify that an alarm is due.
00699  */
00700 void NotificationHandler::handleEvent(const TQString& url, const TQString& eventId)
00701 {
00702     TQString id = eventId;
00703     if (id.startsWith(TQString::fromLatin1("ad:")))
00704     {
00705         // It's a notification from the alarm deamon
00706         id = id.mid(3);
00707         Daemon::queueEvent(id);
00708     }
00709     theApp()->handleEvent(url, id);
00710 }
00711 
00712 /******************************************************************************
00713  * DCOP call from the alarm daemon to notify the success or failure of a
00714  * registration request from KAlarm.
00715  */
00716 void NotificationHandler::registered(bool reregister, int result, int version)
00717 {
00718     Daemon::registrationResult(reregister, result, version);
00719 }
00720 
00721 
00722 /*=============================================================================
00723 =  Class: AlarmEnableAction
00724 =============================================================================*/
00725 
00726 AlarmEnableAction::AlarmEnableAction(int accel, TQObject* parent, const char* name)
00727     : TDEToggleAction(i18n("Enable &Alarms"), accel, parent, name),
00728       mInitialised(false)
00729 {
00730     setCheckedState(i18n("Disable &Alarms"));
00731     setCheckedActual(false);    // set the correct text
00732     mInitialised = true;
00733 }
00734 
00735 /******************************************************************************
00736 *  Set the checked status and the correct text for the Alarms Enabled action.
00737 */
00738 void AlarmEnableAction::setCheckedActual(bool running)
00739 {
00740     kdDebug(5950) << "AlarmEnableAction::setCheckedActual(" << running << ")\n";
00741     if (running != isChecked()  ||  !mInitialised)
00742     {
00743         TDEToggleAction::setChecked(running);
00744         emit switched(running);
00745     }
00746 }
00747 
00748 /******************************************************************************
00749 *  Request a change in the checked status.
00750 *  The status is only actually changed when the alarm daemon run state changes.
00751 */
00752 void AlarmEnableAction::setChecked(bool check)
00753 {
00754     kdDebug(5950) << "AlarmEnableAction::setChecked(" << check << ")\n";
00755     if (check != isChecked())
00756     {
00757         if (check)
00758             Daemon::allowRegisterFailMsg();
00759         emit userClicked(check);
00760     }
00761 }
00762 
00763 
00764 /******************************************************************************
00765  * Expand a DCOP call parameter URL to a full URL.
00766  * (We must store full URLs in the calendar data since otherwise later calls to
00767  *  reload or remove calendars won't necessarily find a match.)
00768  */
00769 TQString expandURL(const TQString& urlString)
00770 {
00771     if (urlString.isEmpty())
00772         return TQString();
00773     return KURL(urlString).url();
00774 }