• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdepim
  • Sitemap
  • Contact Us
 

kalarm

functions.cpp

Go to the documentation of this file.
00001 /*  functions.cpp  -  miscellaneous functions
00002  *  Program:  kalarm
00003  *  Copyright © 2001-2008 by David Jarvie <djarvie@kde.org>
00004  *
00005  *  This program is free software; you can redistribute it and/or modify
00006  *  it under the terms of the GNU General Public License as published by
00007  *  the Free Software Foundation; either version 2 of the License, or
00008  *  (at your option) any later version.
00009  *
00010  *  This program is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00013  *  GNU General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU General Public License along
00016  *  with this program; if not, write to the Free Software Foundation, Inc.,
00017  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00018  */
00019 
00020 #include "kalarm.h"   //krazy:exclude=includes (kalarm.h must be first)
00021 #include "functions.h"
00022 
00023 #include "alarmcalendar.h"
00024 #include "alarmevent.h"
00025 #include "eventlistmodel.h"
00026 #include "alarmlistview.h"
00027 #include "alarmresources.h"
00028 #include "editdlg.h"
00029 #include "kalarmapp.h"
00030 #include "kamail.h"
00031 #include "mainwindow.h"
00032 #include "messagewin.h"
00033 #include "preferences.h"
00034 #include "shellprocess.h"
00035 #include "templatelistview.h"
00036 #include "templatemenuaction.h"
00037 
00038 #include <QDir>
00039 #include <QRegExp>
00040 #include <QDesktopWidget>
00041 #include <QtDBus/QtDBus>
00042 
00043 #include <kconfiggroup.h>
00044 #include <kaction.h>
00045 #include <ktoggleaction.h>
00046 #include <kactioncollection.h>
00047 #include <kglobal.h>
00048 #include <klocale.h>
00049 #include <kstandarddirs.h>
00050 #include <ksystemtimezone.h>
00051 #include <KStandardGuiItem>
00052 #include <kstandardshortcut.h>
00053 #include <kmessagebox.h>
00054 #include <kfiledialog.h>
00055 #include <kwindowsystem.h>
00056 #include <kicon.h>
00057 #include <kdebug.h>
00058 
00059 #include <kcal/event.h>
00060 #include <kcal/icalformat.h>
00061 #include <kpimidentities/identitymanager.h>
00062 #include <kpimidentities/identity.h>
00063 #include <kcal/person.h>
00064 #include <libkholidays/kholidays.h>
00065 #include <ktoolinvocation.h>
00066 
00067 
00068 namespace
00069 {
00070 bool          refreshAlarmsQueued = false;
00071 QString       korganizerName    = "korganizer";
00072 QString       korgStartError;
00073 QDBusInterface* korgInterface = 0;
00074 
00075 const char*   KMAIL_DBUS_SERVICE      = "org.kde.kmail";
00076 //const char*   KMAIL_DBUS_IFACE        = "org.kde.kmail.kmail";
00077 const char*   KMAIL_DBUS_WINDOW_PATH  = "/kmail/kmail_mainwindow_1";
00078 const char*   KORG_DBUS_SERVICE       = "org.kde.korganizer";
00079 const char*   KORG_DBUS_IFACE         = "org.kde.korganizer.Korganizer";
00080 const char*   KORG_DBUS_PATH          = "/";    // D-Bus object path of KOrganizer's notification interface
00081 const char*   KORG_DBUS_WINDOW_PATH   = "/korganizer/MainWindow_1";
00082 const QString KORGANIZER_UID         = QString::fromLatin1("-korg");
00083 
00084 const char*   ALARM_OPTS_FILE        = "alarmopts";
00085 const char*   DONT_SHOW_ERRORS_GROUP = "DontShowErrors";
00086 
00087 bool sendToKOrganizer(const KAEvent*);
00088 bool deleteFromKOrganizer(const QString& eventID);
00089 bool runKOrganizer();
00090 QString uidKOrganizer(const QString& eventID);
00091 }
00092 
00093 
00094 namespace KAlarm
00095 {
00096 
00097 void doEditNewAlarm(EditAlarmDlg*);
00098 
00099 
00100 /******************************************************************************
00101 *  Display a main window with the specified event selected.
00102 */
00103 MainWindow* displayMainWindowSelected(const QString& eventID)
00104 {
00105     MainWindow* win = MainWindow::firstWindow();
00106     if (!win)
00107     {
00108         if (theApp()->checkCalendar())    // ensure calendar is open
00109         {
00110             win = MainWindow::create();
00111             win->show();
00112         }
00113     }
00114     else
00115     {
00116         // There is already a main window, so make it the active window
00117         bool visible = win->isVisible();
00118         if (visible)
00119             win->hide();        // in case it's on a different desktop
00120         if (!visible  ||  win->isMinimized())
00121         {
00122             win->setWindowState(win->windowState() & ~Qt::WindowMinimized);
00123             win->show();
00124         }
00125         win->raise();
00126         win->activateWindow();
00127     }
00128     if (win  &&  !eventID.isEmpty())
00129         win->selectEvent(eventID);
00130     return win;
00131 }
00132 
00133 /******************************************************************************
00134 * Create an "Alarms Enabled/Enable Alarms" action.
00135 */
00136 KToggleAction* createAlarmEnableAction(QObject* parent)
00137 {
00138     KToggleAction* action = new KToggleAction(i18nc("@action", "Enable &Alarms"), parent);
00139     action->setChecked(theApp()->alarmsEnabled());
00140     QObject::connect(action, SIGNAL(toggled(bool)), theApp(), SLOT(setAlarmsEnabled(bool)));
00141     // The following line ensures that all instances are kept in the same state
00142     QObject::connect(theApp(), SIGNAL(alarmEnabledToggled(bool)), action, SLOT(setChecked(bool)));
00143     return action;
00144 }
00145 
00146 /******************************************************************************
00147 * Create a New From Template QAction.
00148 */
00149 TemplateMenuAction* createNewFromTemplateAction(const QString& label, KActionCollection* actions, const QString& name)
00150 {
00151     return new TemplateMenuAction(KIcon(QLatin1String("document-new-from-template")), label, actions, name);
00152 }
00153 
00154 /******************************************************************************
00155 * Add a new active (non-archived) alarm.
00156 * Save it in the calendar file and add it to every main window instance.
00157 * Parameters: msgParent = parent widget for any resource selection prompt or
00158 * error message.
00159 * 'event' is updated with the actual event ID.
00160 */
00161 UpdateStatus addEvent(KAEvent& event, AlarmResource* resource, QWidget* msgParent, int options, bool showKOrgErr)
00162 {
00163     kDebug() << event.id();
00164     bool cancelled = false;
00165     UpdateStatus status = UPDATE_OK;
00166     if (!theApp()->checkCalendar())    // ensure calendar is open
00167         status = UPDATE_FAILED;
00168     else
00169     {
00170         // Save the event details in the calendar file, and get the new event ID
00171         AlarmCalendar* cal = AlarmCalendar::resources();
00172         KAEvent* newev = new KAEvent(event);
00173         if (!cal->addEvent(newev, msgParent, (options & USE_EVENT_ID), resource, (options & NO_RESOURCE_PROMPT), &cancelled))
00174         {
00175             delete newev;
00176             status = UPDATE_FAILED;
00177         }
00178         else
00179         {
00180             event = *newev;   // update event ID etc.
00181             if (!cal->save())
00182                 status = SAVE_FAILED;
00183         }
00184         if (status == UPDATE_OK)
00185         {
00186             if ((options & ALLOW_KORG_UPDATE)  &&  event.copyToKOrganizer())
00187             {
00188                 if (!sendToKOrganizer(newev))    // tell KOrganizer to show the event
00189                     status = UPDATE_KORG_ERR;
00190             }
00191 
00192             // Update the window lists
00193             EventListModel::alarms()->addEvent(newev);
00194         }
00195     }
00196 
00197     if (status != UPDATE_OK  &&  !cancelled  &&  msgParent)
00198         displayUpdateError(msgParent, status, ERR_ADD, 1, 1, showKOrgErr);
00199     return status;
00200 }
00201 
00202 /******************************************************************************
00203 * Add a list of new active (non-archived) alarms.
00204 * Save them in the calendar file and add them to every main window instance.
00205 * The events are updated with their actual event IDs.
00206 */
00207 UpdateStatus addEvents(QList<KAEvent>& events, QWidget* msgParent, bool allowKOrgUpdate, bool showKOrgErr)
00208 {
00209     kDebug() << events.count();
00210     if (events.isEmpty())
00211         return UPDATE_OK;
00212     int warnErr = 0;
00213     int warnKOrg = 0;
00214     UpdateStatus status = UPDATE_OK;
00215     AlarmResource* resource;
00216     if (!theApp()->checkCalendar())    // ensure calendar is open
00217         status = UPDATE_FAILED;
00218     else
00219     {
00220         resource = AlarmResources::instance()->destination(KCalEvent::ACTIVE, msgParent);
00221         if (!resource)
00222         {
00223             kDebug() << "No resource";
00224             status = UPDATE_FAILED;
00225         }
00226     }
00227     if (status == UPDATE_OK)
00228     {
00229         QString selectID;
00230         AlarmCalendar* cal = AlarmCalendar::resources();
00231         for (int i = 0, end = events.count();  i < end;  ++i)
00232         {
00233             // Save the event details in the calendar file, and get the new event ID
00234             KAEvent* newev = new KAEvent(events[i]);
00235             if (!cal->addEvent(newev, msgParent, false, resource))
00236             {
00237                 delete newev;
00238                 status = UPDATE_ERROR;
00239                 ++warnErr;
00240                 continue;
00241             }
00242             events[i] = *newev;   // update event ID etc.
00243             if (allowKOrgUpdate  &&  newev->copyToKOrganizer())
00244             {
00245                 if (!sendToKOrganizer(newev))    // tell KOrganizer to show the event
00246                 {
00247                     ++warnKOrg;
00248                     if (status == UPDATE_OK)
00249                         status = UPDATE_KORG_ERR;
00250                 }
00251             }
00252 
00253             // Update the window lists, but not yet which item is selected
00254             EventListModel::alarms()->addEvent(newev);
00255 //          selectID = newev->id();
00256         }
00257         if (warnErr == events.count())
00258             status = UPDATE_FAILED;
00259         else if (!cal->save())
00260         {
00261             status = SAVE_FAILED;
00262             warnErr = 0;    // everything failed
00263         }
00264     }
00265 
00266     if (status != UPDATE_OK  &&  msgParent)
00267         displayUpdateError(msgParent, status, ERR_ADD, (warnErr ? warnErr : events.count()), warnKOrg, showKOrgErr);
00268     return status;
00269 }
00270 
00271 /******************************************************************************
00272 * Save the event in the archived resource and adjust every main window instance.
00273 * The event's ID is changed to an archived ID if necessary.
00274 */
00275 bool addArchivedEvent(KAEvent& event, AlarmResource* resource)
00276 {
00277     kDebug() << event.id();
00278     QString oldid = event.id();
00279     bool archiving = (event.category() == KCalEvent::ACTIVE);
00280     if (archiving  &&  !Preferences::archivedKeepDays())
00281         return false;   // expired alarms aren't being kept
00282     KAEvent* newev = new KAEvent(event);
00283     if (archiving)
00284     {
00285         newev->setCategory(KCalEvent::ARCHIVED);    // this changes the event ID
00286         newev->setSaveDateTime(KDateTime::currentUtcDateTime());   // time stamp to control purging
00287     }
00288     AlarmCalendar* cal = AlarmCalendar::resources();
00289     // Note that archived resources are automatically saved after changes are made
00290     if (!cal->addEvent(newev, 0, false, resource))
00291     {
00292         delete newev;     // failed to add to calendar - leave event in its original state
00293         return false;
00294     }
00295     event = *newev;   // update event ID etc.
00296 
00297     // Update window lists.
00298     // Note: updateEvent() is not used here since that doesn't trigger refiltering
00299     // of the alarm list, resulting in the archived event still remaining visible
00300     // even if archived events are supposed to be hidden.
00301     if (archiving)
00302         EventListModel::alarms()->removeEvent(oldid);
00303     EventListModel::alarms()->addEvent(newev);
00304     return true;
00305 }
00306 
00307 /******************************************************************************
00308 * Add a new template.
00309 * Save it in the calendar file and add it to every template list view.
00310 * 'event' is updated with the actual event ID.
00311 * Parameters: promptParent = parent widget for any resource selection prompt.
00312 */
00313 UpdateStatus addTemplate(KAEvent& event, AlarmResource* resource, QWidget* msgParent)
00314 {
00315     kDebug() << event.id();
00316     UpdateStatus status = UPDATE_OK;
00317 
00318     // Add the template to the calendar file
00319     KAEvent* newev = new KAEvent(event);
00320     AlarmCalendar* cal = AlarmCalendar::resources();
00321     if (!cal->addEvent(newev, msgParent, false, resource))
00322     {
00323         delete newev;
00324         status = UPDATE_FAILED;
00325     }
00326     else
00327     {
00328         event = *newev;   // update event ID etc.
00329         if (!cal->save())
00330             status = SAVE_FAILED;
00331         else
00332         {
00333             cal->emitEmptyStatus();
00334 
00335             // Update the window lists
00336             EventListModel::templates()->addEvent(newev);
00337             return UPDATE_OK;
00338         }
00339     }
00340 
00341     if (msgParent)
00342         displayUpdateError(msgParent, status, ERR_TEMPLATE, 1);
00343     return status;
00344 }
00345 
00346 /******************************************************************************
00347 * Modify an active (non-archived) alarm in the calendar file and in every main
00348 * window instance.
00349 * The new event must have a different event ID from the old one.
00350 */
00351 UpdateStatus modifyEvent(KAEvent& oldEvent, KAEvent& newEvent, QWidget* msgParent, bool showKOrgErr)
00352 {
00353     kDebug() << oldEvent.id();
00354 
00355     UpdateStatus status = UPDATE_OK;
00356     if (!newEvent.valid())
00357     {
00358         deleteEvent(oldEvent, true);
00359         status = UPDATE_FAILED;
00360     }
00361     else
00362     {
00363         QString oldId = oldEvent.id();
00364         if (oldEvent.copyToKOrganizer())
00365         {
00366             // Tell KOrganizer to delete its old event.
00367             // But ignore errors, because the user could have manually
00368             // deleted it since KAlarm asked KOrganizer to set it up.
00369             deleteFromKOrganizer(oldId);
00370         }
00371         // Delete from the window lists to prevent the event's invalid
00372         // pointer being accessed.
00373         EventListModel::alarms()->removeEvent(oldId);
00374 
00375         // Update the event in the calendar file, and get the new event ID
00376         KAEvent* newev = new KAEvent(newEvent);
00377         AlarmCalendar* cal = AlarmCalendar::resources();
00378         if (!cal->modifyEvent(oldId, newev))
00379         {
00380             delete newev;
00381             status = UPDATE_FAILED;
00382         }
00383         else
00384         {
00385             newEvent = *newev;
00386             if (!cal->save())
00387                 status = SAVE_FAILED;
00388             if (status == UPDATE_OK)
00389             {
00390                 if (newev->copyToKOrganizer())
00391                 {
00392                     if (!sendToKOrganizer(newev))    // tell KOrganizer to show the new event
00393                         status = UPDATE_KORG_ERR;
00394                 }
00395 
00396                 // Remove "Don't show error messages again" for the old alarm
00397                 setDontShowErrors(oldId);
00398 
00399                 // Update the window lists
00400                 EventListModel::alarms()->addEvent(newev);
00401             }
00402         }
00403     }
00404 
00405     if (status != UPDATE_OK  &&  msgParent)
00406         displayUpdateError(msgParent, status, ERR_MODIFY, 1, 1, showKOrgErr);
00407     return status;
00408 }
00409 
00410 /******************************************************************************
00411 * Update an active (non-archived) alarm from the calendar file and from every
00412 * main window instance.
00413 * The new event will have the same event ID as the old one.
00414 * The event is not updated in KOrganizer, since this function is called when an
00415 * existing alarm is rescheduled (due to recurrence or deferral).
00416 */
00417 UpdateStatus updateEvent(KAEvent& event, QWidget* msgParent, bool archiveOnDelete)
00418 {
00419     kDebug() << event.id();
00420 
00421     if (!event.valid())
00422         deleteEvent(event, archiveOnDelete);
00423     else
00424     {
00425         // Update the event in the calendar file.
00426         AlarmCalendar* cal = AlarmCalendar::resources();
00427         KAEvent* newEvent = cal->updateEvent(event);
00428         if (!cal->save())
00429         {
00430             if (msgParent)
00431                 displayUpdateError(msgParent, SAVE_FAILED, ERR_ADD, 1);
00432             return SAVE_FAILED;
00433         }
00434 
00435         // Update the window lists
00436         EventListModel::alarms()->updateEvent(newEvent);
00437     }
00438     return UPDATE_OK;
00439 }
00440 
00441 /******************************************************************************
00442 * Update a template in the calendar file and in every template list view.
00443 * If 'selectionView' is non-null, the selection highlight is moved to the
00444 * updated event in that listView instance.
00445 */
00446 UpdateStatus updateTemplate(KAEvent& event, QWidget* msgParent)
00447 {
00448     AlarmCalendar* cal = AlarmCalendar::resources();
00449     KAEvent* newEvent = cal->updateEvent(event);
00450     UpdateStatus status = UPDATE_OK;
00451     if (!newEvent)
00452         status = UPDATE_FAILED;
00453     else if (!cal->save())
00454         status = SAVE_FAILED;
00455     if (status != UPDATE_OK)
00456     {
00457         if (msgParent)
00458             displayUpdateError(msgParent, SAVE_FAILED, ERR_TEMPLATE, 1);
00459         return status;
00460     }
00461 
00462     EventListModel::templates()->updateEvent(newEvent);
00463     return UPDATE_OK;
00464 }
00465 
00466 /******************************************************************************
00467 * Delete alarms from the calendar file and from every main window instance.
00468 * If the events are archived, the events' IDs are changed to archived IDs if necessary.
00469 */
00470 UpdateStatus deleteEvent(KAEvent& event, bool archive, QWidget* msgParent, bool showKOrgErr)
00471 {
00472     KAEvent::List events;
00473     events += &event;
00474     return deleteEvents(events, archive, msgParent, showKOrgErr);
00475 }
00476 
00477 UpdateStatus deleteEvents(KAEvent::List& events, bool archive, QWidget* msgParent, bool showKOrgErr)
00478 {
00479     kDebug() << events.count();
00480     if (events.isEmpty())
00481         return UPDATE_OK;
00482     int warnErr = 0;
00483     int warnKOrg = 0;
00484     UpdateStatus status = UPDATE_OK;
00485     AlarmCalendar* cal = AlarmCalendar::resources();
00486     for (int i = 0, end = events.count();  i < end;  ++i)
00487     {
00488         // Save the event details in the calendar file, and get the new event ID
00489         KAEvent* event = events[i];
00490         QString id = event->id();
00491 
00492         // Update the window lists
00493         EventListModel::alarms()->removeEvent(id);
00494 
00495         // Delete the event from the calendar file
00496         if (event->category() != KCalEvent::ARCHIVED)
00497         {
00498             if (event->copyToKOrganizer())
00499             {
00500                 // The event was shown in KOrganizer, so tell KOrganizer to
00501                 // delete it. But ignore errors, because the user could have
00502                 // manually deleted it from KOrganizer since it was set up.
00503                 if (!deleteFromKOrganizer(id))
00504                 {
00505                     ++warnKOrg;
00506                     if (status == UPDATE_OK)
00507                         status = UPDATE_KORG_ERR;
00508                 }
00509             }
00510             if (archive  &&  event->toBeArchived())
00511                 addArchivedEvent(*event);     // this changes the event ID to an archived ID
00512         }
00513         if (!cal->deleteEvent(id, false))   // don't save calendar after deleting
00514         {
00515             status = UPDATE_ERROR;
00516             ++warnErr;
00517         }
00518 
00519         // Remove "Don't show error messages again" for this alarm
00520         setDontShowErrors(id);
00521     }
00522 
00523     if (warnErr == events.count())
00524         status = UPDATE_FAILED;
00525     else if (!cal->save())      // save the calendars now
00526     {
00527         status = SAVE_FAILED;
00528         warnErr = events.count();
00529     }
00530     if (status != UPDATE_OK  &&  msgParent)
00531         displayUpdateError(msgParent, status, ERR_DELETE, warnErr, warnKOrg, showKOrgErr);
00532     return status;
00533 }
00534 
00535 /******************************************************************************
00536 * Delete templates from the calendar file and from every template list view.
00537 */
00538 UpdateStatus deleteTemplates(const QStringList& eventIDs, QWidget* msgParent)
00539 {
00540     kDebug() << eventIDs.count();
00541     if (eventIDs.isEmpty())
00542         return UPDATE_OK;
00543     int warnErr = 0;
00544     UpdateStatus status = UPDATE_OK;
00545     AlarmCalendar* cal = AlarmCalendar::resources();
00546     for (int i = 0, end = eventIDs.count();  i < end;  ++i)
00547     {
00548         // Update the window lists
00549         QString id = eventIDs[i];
00550         EventListModel::templates()->removeEvent(id);
00551 
00552         // Delete the template from the calendar file
00553         AlarmCalendar* cal = AlarmCalendar::resources();
00554         if (!cal->deleteEvent(id, false))    // don't save calendar after deleting
00555         {
00556             status = UPDATE_ERROR;
00557             ++warnErr;
00558         }
00559     }
00560 
00561     if (warnErr == eventIDs.count())
00562         status = UPDATE_FAILED;
00563     else if (!cal->save())      // save the calendars now
00564     {
00565         status = SAVE_FAILED;
00566         warnErr = eventIDs.count();
00567     }
00568     cal->emitEmptyStatus();
00569     if (status != UPDATE_OK  &&  msgParent)
00570         displayUpdateError(msgParent, status, ERR_TEMPLATE, warnErr);
00571     return status;
00572 }
00573 
00574 /******************************************************************************
00575 * Delete an alarm from the display calendar.
00576 */
00577 void deleteDisplayEvent(const QString& eventID)
00578 {
00579     kDebug() << eventID;
00580     AlarmCalendar* cal = AlarmCalendar::displayCalendarOpen();
00581     if (cal)
00582         cal->deleteEvent(eventID, true);   // save calendar after deleting
00583 }
00584 
00585 /******************************************************************************
00586 * Undelete archived alarms, and update every main window instance.
00587 * The archive bit is set to ensure that they get re-archived if deleted again.
00588 * 'ineligibleIDs' is filled in with the IDs of any ineligible events.
00589 */
00590 UpdateStatus reactivateEvent(KAEvent& event, AlarmResource* resource, QWidget* msgParent, bool showKOrgErr)
00591 {
00592     QStringList ids;
00593     KAEvent::List events;
00594     events += &event;
00595     return reactivateEvents(events, ids, resource, msgParent, showKOrgErr);
00596 }
00597 
00598 UpdateStatus reactivateEvents(KAEvent::List& events, QStringList& ineligibleIDs, AlarmResource* resource, QWidget* msgParent, bool showKOrgErr)
00599 {
00600     kDebug() << events.count();
00601     ineligibleIDs.clear();
00602     if (events.isEmpty())
00603         return UPDATE_OK;
00604     int warnErr = 0;
00605     int warnKOrg = 0;
00606     UpdateStatus status = UPDATE_OK;
00607     if (!resource)
00608         resource = AlarmResources::instance()->destination(KCalEvent::ACTIVE, msgParent);
00609     if (!resource)
00610     {
00611         kDebug() << "No resource";
00612         status = UPDATE_FAILED;
00613         warnErr = events.count();
00614     }
00615     else
00616     {
00617         QString selectID;
00618         int count = 0;
00619         AlarmCalendar* cal = AlarmCalendar::resources();
00620         KDateTime now = KDateTime::currentUtcDateTime();
00621         for (int i = 0, end = events.count();  i < end;  ++i)
00622         {
00623             // Delete the event from the archived resource
00624             KAEvent* event = events[i];
00625             if (event->category() != KCalEvent::ARCHIVED
00626             ||  !event->occursAfter(now, true))
00627             {
00628                 ineligibleIDs += event->id();
00629                 continue;
00630             }
00631             ++count;
00632 
00633             KAEvent* newev = new KAEvent(*event);
00634             QString oldid = event->id();
00635             newev->setCategory(KCalEvent::ACTIVE);    // this changes the event ID
00636             if (newev->recurs()  ||  newev->repeatCount())
00637                 newev->setNextOccurrence(now);   // skip any recurrences in the past
00638             newev->setArchive();    // ensure that it gets re-archived if it is deleted
00639 
00640             // Save the event details in the calendar file.
00641             // This converts the event ID.
00642             if (!cal->addEvent(newev, msgParent, true, resource))
00643             {
00644                 delete newev;
00645                 status = UPDATE_ERROR;
00646                 ++warnErr;
00647                 continue;
00648             }
00649             if (newev->copyToKOrganizer())
00650             {
00651                 if (!sendToKOrganizer(newev))    // tell KOrganizer to show the event
00652                 {
00653                     ++warnKOrg;
00654                     if (status == UPDATE_OK)
00655                         status = UPDATE_KORG_ERR;
00656                 }
00657             }
00658 
00659             // Update the window lists
00660             EventListModel::alarms()->updateEvent(oldid, newev);
00661 //          selectID = newev->id();
00662 
00663             if (cal->event(oldid)    // no error if event doesn't exist in archived resource
00664             &&  !cal->deleteEvent(oldid, false))   // don't save calendar after deleting
00665             {
00666                 status = UPDATE_ERROR;
00667                 ++warnErr;
00668             }
00669             events[i] = newev;
00670         }
00671 
00672         if (warnErr == count)
00673             status = UPDATE_FAILED;
00674         // Save the calendars, even if all events failed, since more than one calendar was updated
00675         if (!cal->save()  &&  status != UPDATE_FAILED)
00676         {
00677             status = SAVE_FAILED;
00678             warnErr = count;
00679         }
00680     }
00681     if (status != UPDATE_OK  &&  msgParent)
00682         displayUpdateError(msgParent, status, ERR_REACTIVATE, warnErr, warnKOrg, showKOrgErr);
00683     return status;
00684 }
00685 
00686 /******************************************************************************
00687 * Enable or disable alarms in the calendar file and in every main window instance.
00688 * The new events will have the same event IDs as the old ones.
00689 */
00690 UpdateStatus enableEvents(KAEvent::List& events, bool enable, QWidget* msgParent)
00691 {
00692     kDebug() << events.count();
00693     if (events.isEmpty())
00694         return UPDATE_OK;
00695     UpdateStatus status = UPDATE_OK;
00696     AlarmCalendar* cal = AlarmCalendar::resources();
00697     for (int i = 0, end = events.count();  i < end;  ++i)
00698     {
00699         KAEvent* event = events[i];
00700         if (enable != event->enabled())
00701         {
00702             event->setEnabled(enable);
00703 
00704             // Update the event in the calendar file
00705             KAEvent* newev = cal->updateEvent(event);
00706 
00707             // If we're disabling a display alarm, close any message window
00708             if (!enable  &&  event->displayAction())
00709             {
00710                 MessageWin* win = MessageWin::findEvent(event->id());
00711                 delete win;
00712             }
00713 
00714             // Update the window lists
00715             EventListModel::alarms()->updateEvent(newev);
00716         }
00717     }
00718 
00719     if (!cal->save())
00720         status = SAVE_FAILED;
00721     if (status != UPDATE_OK  &&  msgParent)
00722         displayUpdateError(msgParent, status, ERR_ADD, events.count(), 0);
00723     return status;
00724 }
00725 
00726 /******************************************************************************
00727 * This method must only be called from the main KAlarm queue processing loop,
00728 * to prevent asynchronous calendar operations interfering with one another.
00729 *
00730 * Purge all archived events from the default archived alarm resource whose end
00731 * time is longer ago than 'purgeDays'. All events are deleted if 'purgeDays' is
00732 * zero.
00733 */
00734 void purgeArchive(int purgeDays)
00735 {
00736     if (purgeDays < 0)
00737         return;
00738     kDebug() << purgeDays;
00739     QDate cutoff = QDate::currentDate().addDays(-purgeDays);
00740     AlarmResource* resource = AlarmResources::instance()->getStandardResource(AlarmResource::ARCHIVED);
00741     if (!resource)
00742         return;
00743     KAEvent::List events = AlarmCalendar::resources()->events(resource);
00744     for (int i = 0;  i < events.count();  )
00745     {
00746         KAEvent* event = events[i];
00747         KCal::Incidence* kcalIncidence = resource->incidence(event->id());
00748         if (purgeDays  &&  kcalIncidence  &&  kcalIncidence->created().date() >= cutoff)
00749             events.removeAt(i);
00750         else
00751             EventListModel::alarms()->removeEvent(events[i++]);   // update the window lists
00752     }
00753     if (!events.isEmpty())
00754         AlarmCalendar::resources()->purgeEvents(events);   // delete the events and save the calendar
00755 }
00756 
00757 /******************************************************************************
00758 * Display an error message about an error when saving an event.
00759 */
00760 void displayUpdateError(QWidget* parent, UpdateStatus status, UpdateError code, int nAlarms, int nKOrgAlarms, bool showKOrgError)
00761 {
00762     QString errmsg;
00763     if (status > UPDATE_KORG_ERR)
00764     {
00765         switch (code)
00766         {
00767             case ERR_ADD:
00768             case ERR_MODIFY:
00769                 errmsg = (nAlarms > 1) ? i18nc("@info", "Error saving alarms")
00770                                        : i18nc("@info", "Error saving alarm");
00771                 break;
00772             case ERR_DELETE:
00773                 errmsg = (nAlarms > 1) ? i18nc("@info", "Error deleting alarms")
00774                                        : i18nc("@info", "Error deleting alarm");
00775                 break;
00776             case ERR_REACTIVATE:
00777                 errmsg = (nAlarms > 1) ? i18nc("@info", "Error saving reactivated alarms")
00778                                        : i18nc("@info", "Error saving reactivated alarm");
00779                 break;
00780             case ERR_TEMPLATE:
00781                 errmsg = (nAlarms > 1) ? i18nc("@info", "Error saving alarm templates")
00782                                        : i18nc("@info", "Error saving alarm template");
00783                 break;
00784         }
00785         KMessageBox::error(parent, errmsg);
00786     }
00787     else if (showKOrgError)
00788         displayKOrgUpdateError(parent, code, nKOrgAlarms);
00789 }
00790 
00791 /******************************************************************************
00792 * Display an error message corresponding to a specified alarm update error code.
00793 */
00794 void displayKOrgUpdateError(QWidget* parent, UpdateError code, int nAlarms)
00795 {
00796     QString errmsg;
00797     switch (code)
00798     {
00799         case ERR_ADD:
00800         case ERR_REACTIVATE:
00801             errmsg = (nAlarms > 1) ? i18nc("@info", "Unable to show alarms in KOrganizer")
00802                                    : i18nc("@info", "Unable to show alarm in KOrganizer");
00803             break;
00804         case ERR_MODIFY:
00805             errmsg = i18nc("@info", "Unable to update alarm in KOrganizer");
00806             break;
00807         case ERR_DELETE:
00808             errmsg = (nAlarms > 1) ? i18nc("@info", "Unable to delete alarms from KOrganizer")
00809                                    : i18nc("@info", "Unable to delete alarm from KOrganizer");
00810             break;
00811         case ERR_TEMPLATE:
00812             return;
00813     }
00814     KMessageBox::error(parent, errmsg);
00815 }
00816 
00817 /******************************************************************************
00818 * Execute a New Alarm dialog for the specified alarm type.
00819 */
00820 void editNewAlarm(EditAlarmDlg::Type type, QWidget* parent)
00821 {
00822     EditAlarmDlg* editDlg = EditAlarmDlg::create(false, type, true, parent);
00823     doEditNewAlarm(editDlg);
00824     delete editDlg;
00825 }
00826 
00827 /******************************************************************************
00828 * Execute a New Alarm dialog for the specified alarm type.
00829 */
00830 void editNewAlarm(KAEvent::Action action, QWidget* parent, const AlarmText* text)
00831 {
00832     bool setAction = false;
00833     EditAlarmDlg::Type type;
00834     switch (action)
00835     {
00836         case KAEvent::MESSAGE:
00837         case KAEvent::FILE:
00838             type = EditAlarmDlg::DISPLAY;
00839             setAction = true;
00840             break;
00841         case KAEvent::COMMAND:
00842             type = EditAlarmDlg::COMMAND;
00843             break;
00844         case KAEvent::EMAIL:
00845             type = EditAlarmDlg::EMAIL;
00846             break;
00847     }
00848     EditAlarmDlg* editDlg = EditAlarmDlg::create(false, type, true, parent);
00849     if (setAction  ||  text)
00850         editDlg->setAction(action, *text);
00851     doEditNewAlarm(editDlg);
00852     delete editDlg;
00853 }
00854 
00855 /******************************************************************************
00856 * Execute a New Alarm dialog, optionally either presetting it to the supplied
00857 * event, or setting the action and text.
00858 */
00859 void editNewAlarm(const KAEvent* preset, QWidget* parent)
00860 {
00861     EditAlarmDlg* editDlg = EditAlarmDlg::create(false, preset, true, parent);
00862     doEditNewAlarm(editDlg);
00863     delete editDlg;
00864 }
00865 
00866 /******************************************************************************
00867 * Common code for editNewAlarm() variants.
00868 */
00869 void doEditNewAlarm(EditAlarmDlg* editDlg)
00870 {
00871     if (editDlg->exec() == QDialog::Accepted)
00872     {
00873         KAEvent event;
00874         AlarmResource* resource;
00875         editDlg->getEvent(event, resource);
00876 
00877         // Add the alarm to the displayed lists and to the calendar file
00878         switch (addEvent(event, resource, editDlg))
00879         {
00880             case UPDATE_FAILED:
00881                 return;
00882             case UPDATE_KORG_ERR:
00883                 displayKOrgUpdateError(editDlg, ERR_ADD, 1);
00884                 break;
00885             default:
00886                 break;
00887         }
00888         Undo::saveAdd(event, resource);
00889 
00890         outputAlarmWarnings(editDlg, &event);
00891     }
00892 }
00893 
00894 /******************************************************************************
00895 * Display the alarm edit dialog to edit a new alarm, preset with a template.
00896 */
00897 bool editNewAlarm(const QString& templateName, QWidget* parent)
00898 {
00899     if (!templateName.isEmpty())
00900     {
00901         KAEvent* templateEvent = AlarmCalendar::resources()->templateEvent(templateName);
00902         if (templateEvent->valid())
00903         {
00904             editNewAlarm(templateEvent, parent);
00905             return true;
00906         }
00907         kWarning() << templateName << ": template not found";
00908     }
00909     return false;
00910 }
00911 
00912 /******************************************************************************
00913 * Create a new template.
00914 */
00915 void editNewTemplate(EditAlarmDlg::Type type, QWidget* parent)
00916 {
00917     EditAlarmDlg* editDlg = EditAlarmDlg::create(true, type, true, parent);
00918     if (editDlg->exec() == QDialog::Accepted)
00919     {
00920         KAEvent event;
00921         AlarmResource* resource;
00922         editDlg->getEvent(event, resource);
00923 
00924         // Add the template to the displayed lists and to the calendar file
00925         addTemplate(event, resource, editDlg);
00926         Undo::saveAdd(event, resource);
00927     }
00928     delete editDlg;
00929 }
00930 
00931 /******************************************************************************
00932 * Create a new template, based