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

kalarm

  • sources
  • kde-4.12
  • kdepim
  • kalarm
functions.cpp
Go to the documentation of this file.
1 /*
2  * functions.cpp - miscellaneous functions
3  * Program: kalarm
4  * Copyright © 2001-2014 by David Jarvie <djarvie@kde.org>
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" //krazy:exclude=includes (kalarm.h must be first)
22 #include "functions.h"
23 #include "functions_p.h"
24 
25 #ifdef USE_AKONADI
26 #include "collectionmodel.h"
27 #include "collectionsearch.h"
28 #else
29 #include "alarmresources.h"
30 #include "eventlistmodel.h"
31 #endif
32 #include "alarmcalendar.h"
33 #include "alarmtime.h"
34 #include "autoqpointer.h"
35 #include "alarmlistview.h"
36 #include "editdlg.h"
37 #include "kalarmapp.h"
38 #include "kamail.h"
39 #include "mainwindow.h"
40 #include "messagebox.h"
41 #include "messagewin.h"
42 #include "preferences.h"
43 #include "shellprocess.h"
44 #include "templatelistview.h"
45 #include "templatemenuaction.h"
46 
47 #include <kalarmcal/identities.h>
48 #include <kalarmcal/kaevent.h>
49 
50 #ifdef USE_AKONADI
51 #include <kcalcore/event.h>
52 #include <kcalcore/icalformat.h>
53 #include <kcalcore/person.h>
54 #include <kcalcore/duration.h>
55 using namespace KCalCore;
56 #else
57 #include <kcal/event.h>
58 #include <kcal/icalformat.h>
59 #include <kcal/person.h>
60 #include <kcal/duration.h>
61 using namespace KCal;
62 #endif
63 #include <kpimidentities/identitymanager.h>
64 #include <kpimidentities/identity.h>
65 #include <kholidays/holidays.h>
66 
67 #include <kconfiggroup.h>
68 #include <kaction.h>
69 #include <ktoggleaction.h>
70 #include <kactioncollection.h>
71 #include <kdbusservicestarter.h>
72 #include <kglobal.h>
73 #include <klocale.h>
74 #include <kstandarddirs.h>
75 #include <kauth.h>
76 #include <ksystemtimezone.h>
77 #include <kstandardguiitem.h>
78 #include <kstandardshortcut.h>
79 #include <kfiledialog.h>
80 #include <kicon.h>
81 #include <kio/netaccess.h>
82 #include <kfileitem.h>
83 #include <kdebug.h>
84 #include <ktoolinvocation.h>
85 
86 #ifdef Q_WS_X11
87 #include <kwindowsystem.h>
88 #include <kxmessages.h>
89 #include <kstartupinfo.h>
90 #include <netwm.h>
91 #include <QX11Info>
92 #endif
93 
94 #include <QDir>
95 #include <QRegExp>
96 #include <QDesktopWidget>
97 #include <QtDBus/QtDBus>
98 #include <QTimer>
99 #include <qglobal.h>
100 
101 #ifdef USE_AKONADI
102 using namespace Akonadi;
103 #endif
104 
105 
106 namespace
107 {
108 bool refreshAlarmsQueued = false;
109 QDBusInterface* korgInterface = 0;
110 
111 const QLatin1String KMAIL_DBUS_SERVICE("org.kde.kmail");
112 //const QLatin1String KMAIL_DBUS_IFACE("org.kde.kmail.kmail");
113 //const QLatin1String KMAIL_DBUS_WINDOW_PATH("/kmail/kmail_mainwindow_1");
114 const QLatin1String KORG_DBUS_SERVICE("org.kde.korganizer");
115 const QLatin1String KORG_DBUS_IFACE("org.kde.korganizer.Korganizer");
116 // D-Bus object path of KOrganizer's notification interface
117 #define KORG_DBUS_PATH "/Korganizer"
118 #define KORG_DBUS_LOAD_PATH "/korganizer_PimApplication"
119 //const QLatin1String KORG_DBUS_WINDOW_PATH("/korganizer/MainWindow_1");
120 #ifdef USE_AKONADI
121 const QLatin1String KORG_MIME_TYPE("application/x-vnd.akonadi.calendar.event");
122 #endif
123 const QLatin1String KORGANIZER_UID("-korg");
124 
125 const QLatin1String ALARM_OPTS_FILE("alarmopts");
126 const char* DONT_SHOW_ERRORS_GROUP = "DontShowErrors";
127 
128 void editNewTemplate(EditAlarmDlg::Type, const KAEvent* preset, QWidget* parent);
129 KAlarm::UpdateStatus sendToKOrganizer(const KAEvent&);
130 KAlarm::UpdateStatus deleteFromKOrganizer(const QString& eventID);
131 KAlarm::UpdateStatus runKOrganizer();
132 QString uidKOrganizer(const QString& eventID);
133 }
134 
135 
136 namespace KAlarm
137 {
138 
139 Private* Private::mInstance = 0;
140 
141 /******************************************************************************
142 * Display a main window with the specified event selected.
143 */
144 #ifdef USE_AKONADI
145 MainWindow* displayMainWindowSelected(Akonadi::Item::Id eventId)
146 #else
147 MainWindow* displayMainWindowSelected(const QString& eventId)
148 #endif
149 {
150  MainWindow* win = MainWindow::firstWindow();
151  if (!win)
152  {
153  if (theApp()->checkCalendar()) // ensure calendar is open
154  {
155  win = MainWindow::create();
156  win->show();
157  }
158  }
159  else
160  {
161  // There is already a main window, so make it the active window
162  win->hide(); // in case it's on a different desktop
163  win->setWindowState(win->windowState() & ~Qt::WindowMinimized);
164  win->show();
165  win->raise();
166  win->activateWindow();
167  }
168 #ifdef USE_AKONADI
169  if (win && eventId >= 0)
170  win->selectEvent(eventId);
171 #else
172  if (win && !eventId.isEmpty())
173  win->selectEvent(eventId);
174 #endif
175  return win;
176 }
177 
178 /******************************************************************************
179 * Create an "Alarms Enabled/Enable Alarms" action.
180 */
181 KToggleAction* createAlarmEnableAction(QObject* parent)
182 {
183  KToggleAction* action = new KToggleAction(i18nc("@action", "Enable &Alarms"), parent);
184  action->setChecked(theApp()->alarmsEnabled());
185  QObject::connect(action, SIGNAL(toggled(bool)), theApp(), SLOT(setAlarmsEnabled(bool)));
186  // The following line ensures that all instances are kept in the same state
187  QObject::connect(theApp(), SIGNAL(alarmEnabledToggled(bool)), action, SLOT(setChecked(bool)));
188  return action;
189 }
190 
191 /******************************************************************************
192 * Create a "Stop Play" action.
193 */
194 KAction* createStopPlayAction(QObject* parent)
195 {
196  KAction* action = new KAction(KIcon(QLatin1String("media-playback-stop")), i18nc("@action", "Stop Play"), parent);
197  action->setEnabled(MessageWin::isAudioPlaying());
198  QObject::connect(action, SIGNAL(triggered(bool)), theApp(), SLOT(stopAudio()));
199  // The following line ensures that all instances are kept in the same state
200  QObject::connect(theApp(), SIGNAL(audioPlaying(bool)), action, SLOT(setEnabled(bool)));
201  return action;
202 }
203 
204 /******************************************************************************
205 * Create a "Spread Windows" action.
206 */
207 KToggleAction* createSpreadWindowsAction(QObject* parent)
208 {
209  KToggleAction* action = new KToggleAction(i18nc("@action", "Spread Windows"), parent);
210  QObject::connect(action, SIGNAL(triggered(bool)), theApp(), SLOT(spreadWindows(bool)));
211  // The following line ensures that all instances are kept in the same state
212  QObject::connect(theApp(), SIGNAL(spreadWindowsToggled(bool)), action, SLOT(setChecked(bool)));
213  return action;
214 }
215 
216 /******************************************************************************
217 * Add a new active (non-archived) alarm.
218 * Save it in the calendar file and add it to every main window instance.
219 * Parameters: msgParent = parent widget for any calendar selection prompt or
220 * error message.
221 * event - is updated with the actual event ID.
222 */
223 #ifdef USE_AKONADI
224 UpdateStatus addEvent(KAEvent& event, Collection* calendar, QWidget* msgParent, int options, bool showKOrgErr)
225 #else
226 UpdateStatus addEvent(KAEvent& event, AlarmResource* calendar, QWidget* msgParent, int options, bool showKOrgErr)
227 #endif
228 {
229  kDebug() << event.id();
230  bool cancelled = false;
231  UpdateStatus status = UPDATE_OK;
232  if (!theApp()->checkCalendar()) // ensure calendar is open
233  status = UPDATE_FAILED;
234  else
235  {
236  // Save the event details in the calendar file, and get the new event ID
237  AlarmCalendar* cal = AlarmCalendar::resources();
238 #ifdef USE_AKONADI
239  // Note that AlarmCalendar::addEvent() updates 'event'.
240  if (!cal->addEvent(event, msgParent, (options & USE_EVENT_ID), calendar, (options & NO_RESOURCE_PROMPT), &cancelled))
241 #else
242  KAEvent* newev = new KAEvent(event);
243  if (!cal->addEvent(newev, msgParent, (options & USE_EVENT_ID), calendar, (options & NO_RESOURCE_PROMPT), &cancelled))
244 #endif
245  {
246 #ifndef USE_AKONADI
247  delete newev;
248 #endif
249  status = UPDATE_FAILED;
250  }
251  else
252  {
253 #ifndef USE_AKONADI
254  event = *newev; // update event ID etc.
255 #endif
256  if (!cal->save())
257  status = SAVE_FAILED;
258  }
259  if (status == UPDATE_OK)
260  {
261  if ((options & ALLOW_KORG_UPDATE) && event.copyToKOrganizer())
262  {
263  UpdateStatus st = sendToKOrganizer(event); // tell KOrganizer to show the event
264  if (st > status)
265  status = st;
266  }
267 
268 #ifndef USE_AKONADI
269  // Update the window lists
270  EventListModel::alarms()->addEvent(newev);
271 #endif
272  }
273  }
274 
275  if (status != UPDATE_OK && !cancelled && msgParent)
276  displayUpdateError(msgParent, status, ERR_ADD, 1, 1, showKOrgErr);
277  return status;
278 }
279 
280 /******************************************************************************
281 * Add a list of new active (non-archived) alarms.
282 * Save them in the calendar file and add them to every main window instance.
283 * The events are updated with their actual event IDs.
284 */
285 UpdateStatus addEvents(QVector<KAEvent>& events, QWidget* msgParent, bool allowKOrgUpdate, bool showKOrgErr)
286 {
287  kDebug() << events.count();
288  if (events.isEmpty())
289  return UPDATE_OK;
290  int warnErr = 0;
291  int warnKOrg = 0;
292  UpdateStatus status = UPDATE_OK;
293 #ifdef USE_AKONADI
294  Collection collection;
295 #else
296  AlarmResource* resource;
297 #endif
298  if (!theApp()->checkCalendar()) // ensure calendar is open
299  status = UPDATE_FAILED;
300  else
301  {
302 #ifdef USE_AKONADI
303  collection = CollectionControlModel::instance()->destination(CalEvent::ACTIVE, msgParent);
304  if (!collection.isValid())
305 #else
306  resource = AlarmResources::instance()->destination(CalEvent::ACTIVE, msgParent);
307  if (!resource)
308 #endif
309  {
310  kDebug() << "No calendar";
311  status = UPDATE_FAILED;
312  }
313  }
314  if (status == UPDATE_OK)
315  {
316  QString selectID;
317  AlarmCalendar* cal = AlarmCalendar::resources();
318  for (int i = 0, end = events.count(); i < end; ++i)
319  {
320  // Save the event details in the calendar file, and get the new event ID
321 #ifdef USE_AKONADI
322  if (!cal->addEvent(events[i], msgParent, false, &collection))
323 #else
324  KAEvent* newev = new KAEvent(events[i]);
325  if (!cal->addEvent(newev, msgParent, false, resource))
326 #endif
327  {
328 #ifndef USE_AKONADI
329  delete newev;
330 #endif
331  status = UPDATE_ERROR;
332  ++warnErr;
333  continue;
334  }
335 #ifndef USE_AKONADI
336  events[i] = *newev; // update event ID etc.
337 #endif
338  if (allowKOrgUpdate && events[i].copyToKOrganizer())
339  {
340  UpdateStatus st = sendToKOrganizer(events[i]); // tell KOrganizer to show the event
341  if (st != UPDATE_OK)
342  {
343  ++warnKOrg;
344  if (st > status)
345  status = st;
346  }
347  }
348 
349 #ifndef USE_AKONADI
350  // Update the window lists, but not yet which item is selected
351  EventListModel::alarms()->addEvent(newev);
352 // selectID = newev->id();
353 #endif
354  }
355  if (warnErr == events.count())
356  status = UPDATE_FAILED;
357  else if (!cal->save())
358  {
359  status = SAVE_FAILED;
360  warnErr = 0; // everything failed
361  }
362  }
363 
364  if (status != UPDATE_OK && msgParent)
365  displayUpdateError(msgParent, status, ERR_ADD, (warnErr ? warnErr : events.count()), warnKOrg, showKOrgErr);
366  return status;
367 }
368 
369 /******************************************************************************
370 * Save the event in the archived calendar and adjust every main window instance.
371 * The event's ID is changed to an archived ID if necessary.
372 */
373 #ifdef USE_AKONADI
374 bool addArchivedEvent(KAEvent& event, Collection* collection)
375 #else
376 bool addArchivedEvent(KAEvent& event, AlarmResource* resource)
377 #endif
378 {
379  kDebug() << event.id();
380  QString oldid = event.id();
381  bool archiving = (event.category() == CalEvent::ACTIVE);
382  if (archiving && !Preferences::archivedKeepDays())
383  return false; // expired alarms aren't being kept
384  AlarmCalendar* cal = AlarmCalendar::resources();
385 #ifdef USE_AKONADI
386  KAEvent newevent(event);
387  newevent.setItemId(-1); // invalidate the Akonadi item ID since it's a new item
388  KAEvent* const newev = &newevent;
389 #else
390  KAEvent* newev = new KAEvent(event);
391 #endif
392  if (archiving)
393  {
394  newev->setCategory(CalEvent::ARCHIVED); // this changes the event ID
395  newev->setCreatedDateTime(KDateTime::currentUtcDateTime()); // time stamp to control purging
396  }
397  // Note that archived resources are automatically saved after changes are made
398 #ifdef USE_AKONADI
399  if (!cal->addEvent(newevent, 0, false, collection))
400  return false;
401 #else
402  if (!cal->addEvent(newev, 0, false, resource))
403  {
404  delete newev; // failed to add to calendar - leave event in its original state
405  return false;
406  }
407 #endif
408  event = *newev; // update event ID etc.
409 
410 #ifndef USE_AKONADI
411  // Update window lists.
412  // Note: updateEvent() is not used here since that doesn't trigger refiltering
413  // of the alarm list, resulting in the archived event still remaining visible
414  // even if archived events are supposed to be hidden.
415  if (archiving)
416  EventListModel::alarms()->removeEvent(oldid);
417  EventListModel::alarms()->addEvent(newev);
418 #endif
419  return true;
420 }
421 
422 /******************************************************************************
423 * Add a new template.
424 * Save it in the calendar file and add it to every template list view.
425 * 'event' is updated with the actual event ID.
426 * Parameters: promptParent = parent widget for any calendar selection prompt.
427 */
428 #ifdef USE_AKONADI
429 UpdateStatus addTemplate(KAEvent& event, Collection* collection, QWidget* msgParent)
430 #else
431 UpdateStatus addTemplate(KAEvent& event, AlarmResource* resource, QWidget* msgParent)
432 #endif
433 {
434  kDebug() << event.id();
435  UpdateStatus status = UPDATE_OK;
436 
437  // Add the template to the calendar file
438  AlarmCalendar* cal = AlarmCalendar::resources();
439 #ifdef USE_AKONADI
440  KAEvent newev(event);
441  if (!cal->addEvent(newev, msgParent, false, collection))
442  status = UPDATE_FAILED;
443 #else
444  KAEvent* newev = new KAEvent(event);
445  if (!cal->addEvent(newev, msgParent, false, resource))
446  {
447  delete newev;
448  status = UPDATE_FAILED;
449  }
450 #endif
451  else
452  {
453 #ifdef USE_AKONADI
454  event = newev; // update event ID etc.
455 #else
456  event = *newev; // update event ID etc.
457 #endif
458  if (!cal->save())
459  status = SAVE_FAILED;
460  else
461  {
462 #ifndef USE_AKONADI
463  // Update the window lists
464  EventListModel::templates()->addEvent(newev);
465 #endif
466  return UPDATE_OK;
467  }
468  }
469 
470  if (msgParent)
471  displayUpdateError(msgParent, status, ERR_TEMPLATE, 1);
472  return status;
473 }
474 
475 /******************************************************************************
476 * Modify an active (non-archived) alarm in the calendar file and in every main
477 * window instance.
478 * The new event must have a different event ID from the old one.
479 */
480 UpdateStatus modifyEvent(KAEvent& oldEvent, KAEvent& newEvent, QWidget* msgParent, bool showKOrgErr)
481 {
482  kDebug() << oldEvent.id();
483 
484  UpdateStatus status = UPDATE_OK;
485  if (!newEvent.isValid())
486  {
487  deleteEvent(oldEvent, true);
488  status = UPDATE_FAILED;
489  }
490  else
491  {
492 #ifdef USE_AKONADI
493  EventId oldId(oldEvent);
494 #else
495  QString oldId = oldEvent.id();
496 #endif
497  if (oldEvent.copyToKOrganizer())
498  {
499  // Tell KOrganizer to delete its old event.
500  // But ignore errors, because the user could have manually
501  // deleted it since KAlarm asked KOrganizer to set it up.
502 #ifdef USE_AKONADI
503  deleteFromKOrganizer(oldId.eventId());
504 #else
505  deleteFromKOrganizer(oldId);
506 #endif
507  }
508 #ifdef USE_AKONADI
509  // Update the event in the calendar file, and get the new event ID
510  AlarmCalendar* cal = AlarmCalendar::resources();
511  if (!cal->modifyEvent(oldId, newEvent))
512  status = UPDATE_FAILED;
513 #else
514  // Delete from the window lists to prevent the event's invalid
515  // pointer being accessed.
516  EventListModel::alarms()->removeEvent(oldId);
517 
518  // Update the event in the calendar file, and get the new event ID
519  KAEvent* newev = new KAEvent(newEvent);
520  AlarmCalendar* cal = AlarmCalendar::resources();
521  if (!cal->modifyEvent(oldId, newev))
522  {
523  delete newev;
524  status = UPDATE_FAILED;
525  }
526 #endif
527  else
528  {
529 #ifndef USE_AKONADI
530  newEvent = *newev;
531 #endif
532  if (!cal->save())
533  status = SAVE_FAILED;
534  if (status == UPDATE_OK)
535  {
536  if (newEvent.copyToKOrganizer())
537  {
538  UpdateStatus st = sendToKOrganizer(newEvent); // tell KOrganizer to show the new event
539  if (st > status)
540  status = st;
541  }
542 
543  // Remove "Don't show error messages again" for the old alarm
544  setDontShowErrors(oldId);
545 
546 #ifndef USE_AKONADI
547  // Update the window lists
548  EventListModel::alarms()->addEvent(newev);
549 #endif
550  }
551  }
552  }
553 
554  if (status != UPDATE_OK && msgParent)
555  displayUpdateError(msgParent, status, ERR_MODIFY, 1, 1, showKOrgErr);
556  return status;
557 }
558 
559 /******************************************************************************
560 * Update an active (non-archived) alarm from the calendar file and from every
561 * main window instance.
562 * The new event will have the same event ID as the old one.
563 * The event is not updated in KOrganizer, since this function is called when an
564 * existing alarm is rescheduled (due to recurrence or deferral).
565 */
566 UpdateStatus updateEvent(KAEvent& event, QWidget* msgParent, bool archiveOnDelete)
567 {
568  kDebug() << event.id();
569 
570  if (!event.isValid())
571  deleteEvent(event, archiveOnDelete);
572  else
573  {
574  // Update the event in the calendar file.
575  AlarmCalendar* cal = AlarmCalendar::resources();
576 #ifdef USE_AKONADI
577  cal->updateEvent(event);
578 #else
579  KAEvent* newEvent = cal->updateEvent(event);
580 #endif
581  if (!cal->save())
582  {
583  if (msgParent)
584  displayUpdateError(msgParent, SAVE_FAILED, ERR_ADD, 1);
585  return SAVE_FAILED;
586  }
587 
588 #ifndef USE_AKONADI
589  // Update the window lists
590  EventListModel::alarms()->updateEvent(newEvent);
591 #endif
592  }
593  return UPDATE_OK;
594 }
595 
596 /******************************************************************************
597 * Update a template in the calendar file and in every template list view.
598 * If 'selectionView' is non-null, the selection highlight is moved to the
599 * updated event in that listView instance.
600 */
601 UpdateStatus updateTemplate(KAEvent& event, QWidget* msgParent)
602 {
603  AlarmCalendar* cal = AlarmCalendar::resources();
604  KAEvent* newEvent = cal->updateEvent(event);
605  UpdateStatus status = UPDATE_OK;
606  if (!newEvent)
607  status = UPDATE_FAILED;
608  else if (!cal->save())
609  status = SAVE_FAILED;
610  if (status != UPDATE_OK)
611  {
612  if (msgParent)
613  displayUpdateError(msgParent, SAVE_FAILED, ERR_TEMPLATE, 1);
614  return status;
615  }
616 
617 #ifndef USE_AKONADI
618  EventListModel::templates()->updateEvent(newEvent);
619 #endif
620  return UPDATE_OK;
621 }
622 
623 /******************************************************************************
624 * Delete alarms from the calendar file and from every main window instance.
625 * If the events are archived, the events' IDs are changed to archived IDs if necessary.
626 */
627 UpdateStatus deleteEvent(KAEvent& event, bool archive, QWidget* msgParent, bool showKOrgErr)
628 {
629 #ifdef USE_AKONADI
630  QVector<KAEvent> events(1, event);
631 #else
632  KAEvent::List events;
633  events += &event;
634 #endif
635  return deleteEvents(events, archive, msgParent, showKOrgErr);
636 }
637 
638 #ifdef USE_AKONADI
639 UpdateStatus deleteEvents(QVector<KAEvent>& events, bool archive, QWidget* msgParent, bool showKOrgErr)
640 #else
641 UpdateStatus deleteEvents(KAEvent::List& events, bool archive, QWidget* msgParent, bool showKOrgErr)
642 #endif
643 {
644  kDebug() << events.count();
645  if (events.isEmpty())
646  return UPDATE_OK;
647  int warnErr = 0;
648  int warnKOrg = 0;
649  UpdateStatus status = UPDATE_OK;
650  AlarmCalendar* cal = AlarmCalendar::resources();
651  bool deleteWakeFromSuspendAlarm = false;
652  QString wakeFromSuspendId = checkRtcWakeConfig().value(0);
653  for (int i = 0, end = events.count(); i < end; ++i)
654  {
655  // Save the event details in the calendar file, and get the new event ID
656 #ifdef USE_AKONADI
657  KAEvent* event = &events[i];
658 #else
659  KAEvent* event = events[i];
660 #endif
661  QString id = event->id();
662 
663 #ifndef USE_AKONADI
664  // Update the window lists and clear stored command errors
665  EventListModel::alarms()->removeEvent(id);
666  event->setCommandError(KAEvent::CMD_NO_ERROR);
667 #endif
668 
669  // Delete the event from the calendar file
670  if (event->category() != CalEvent::ARCHIVED)
671  {
672  if (event->copyToKOrganizer())
673  {
674  // The event was shown in KOrganizer, so tell KOrganizer to
675  // delete it. But ignore errors, because the user could have
676  // manually deleted it from KOrganizer since it was set up.
677  UpdateStatus st = deleteFromKOrganizer(id);
678  if (st != UPDATE_OK)
679  {
680  ++warnKOrg;
681  if (st > status)
682  status = st;
683  }
684  }
685  if (archive && event->toBeArchived())
686  {
687  KAEvent ev(*event);
688  addArchivedEvent(ev); // this changes the event ID to an archived ID
689  }
690  }
691 #ifdef USE_AKONADI
692  if (!cal->deleteEvent(*event, false)) // don't save calendar after deleting
693 #else
694  if (!cal->deleteEvent(id, false)) // don't save calendar after deleting
695 #endif
696  {
697  status = UPDATE_ERROR;
698  ++warnErr;
699  }
700 
701  if (id == wakeFromSuspendId)
702  deleteWakeFromSuspendAlarm = true;
703 
704  // Remove "Don't show error messages again" for this alarm
705 #ifdef USE_AKONADI
706  setDontShowErrors(EventId(*event));
707 #else
708  setDontShowErrors(id);
709 #endif
710  }
711 
712  if (warnErr == events.count())
713  status = UPDATE_FAILED;
714  else if (!cal->save()) // save the calendars now
715  {
716  status = SAVE_FAILED;
717  warnErr = events.count();
718  }
719  if (status != UPDATE_OK && msgParent)
720  displayUpdateError(msgParent, status, ERR_DELETE, warnErr, warnKOrg, showKOrgErr);
721 
722  // Remove any wake-from-suspend scheduled for a deleted alarm
723  if (deleteWakeFromSuspendAlarm && !wakeFromSuspendId.isEmpty())
724  cancelRtcWake(msgParent, wakeFromSuspendId);
725 
726  return status;
727 }
728 
729 /******************************************************************************
730 * Delete templates from the calendar file and from every template list view.
731 */
732 #ifdef USE_AKONADI
733 UpdateStatus deleteTemplates(const KAEvent::List& events, QWidget* msgParent)
734 #else
735 UpdateStatus deleteTemplates(const QStringList& eventIDs, QWidget* msgParent)
736 #endif
737 {
738 #ifdef USE_AKONADI
739  int count = events.count();
740 #else
741  int count = eventIDs.count();
742 #endif
743  kDebug() << count;
744  if (!count)
745  return UPDATE_OK;
746  int warnErr = 0;
747  UpdateStatus status = UPDATE_OK;
748  AlarmCalendar* cal = AlarmCalendar::resources();
749  for (int i = 0, end = count; i < end; ++i)
750  {
751  // Update the window lists
752 #ifndef USE_AKONADI
753  QString id = eventIDs[i];
754  EventListModel::templates()->removeEvent(id);
755 #endif
756 
757  // Delete the template from the calendar file
758  AlarmCalendar* cal = AlarmCalendar::resources();
759 #ifdef USE_AKONADI
760  if (!cal->deleteEvent(*events[i], false)) // don't save calendar after deleting
761 #else
762  if (!cal->deleteEvent(id, false)) // don't save calendar after deleting
763 #endif
764  {
765  status = UPDATE_ERROR;
766  ++warnErr;
767  }
768  }
769 
770  if (warnErr == count)
771  status = UPDATE_FAILED;
772  else if (!cal->save()) // save the calendars now
773  {
774  status = SAVE_FAILED;
775  warnErr = count;
776  }
777  if (status != UPDATE_OK && msgParent)
778  displayUpdateError(msgParent, status, ERR_TEMPLATE, warnErr);
779  return status;
780 }
781 
782 /******************************************************************************
783 * Delete an alarm from the display calendar.
784 */
785 void deleteDisplayEvent(const QString& eventID)
786 {
787  kDebug() << eventID;
788  AlarmCalendar* cal = AlarmCalendar::displayCalendarOpen();
789  if (cal)
790 #ifdef USE_AKONADI
791  cal->deleteDisplayEvent(eventID, true); // save calendar after deleting
792 #else
793  cal->deleteEvent(eventID, true); // save calendar after deleting
794 #endif
795 }
796 
797 /******************************************************************************
798 * Undelete archived alarms, and update every main window instance.
799 * The archive bit is set to ensure that they get re-archived if deleted again.
800 * 'ineligibleIDs' is filled in with the IDs of any ineligible events.
801 */
802 #ifdef USE_AKONADI
803 UpdateStatus reactivateEvent(KAEvent& event, Collection* calendar, QWidget* msgParent, bool showKOrgErr)
804 #else
805 UpdateStatus reactivateEvent(KAEvent& event, AlarmResource* calendar, QWidget* msgParent, bool showKOrgErr)
806 #endif
807 {
808 #ifdef USE_AKONADI
809  QVector<EventId> ids;
810  QVector<KAEvent> events(1, event);
811 #else
812  QStringList ids;
813  KAEvent::List events;
814  events += &event;
815 #endif
816  return reactivateEvents(events, ids, calendar, msgParent, showKOrgErr);
817 }
818 
819 #ifdef USE_AKONADI
820 UpdateStatus reactivateEvents(QVector<KAEvent>& events, QVector<EventId>& ineligibleIDs, Collection* col, QWidget* msgParent, bool showKOrgErr)
821 #else
822 UpdateStatus reactivateEvents(KAEvent::List& events, QStringList& ineligibleIDs, AlarmResource* resource, QWidget* msgParent, bool showKOrgErr)
823 #endif
824 {
825  kDebug() << events.count();
826  ineligibleIDs.clear();
827  if (events.isEmpty())
828  return UPDATE_OK;
829  int warnErr = 0;
830  int warnKOrg = 0;
831  UpdateStatus status = UPDATE_OK;
832 #ifdef USE_AKONADI
833  Collection collection;
834  if (col)
835  collection = *col;
836  if (!collection.isValid())
837  collection = CollectionControlModel::instance()->destination(CalEvent::ACTIVE, msgParent);
838  if (!collection.isValid())
839 #else
840  if (!resource)
841  resource = AlarmResources::instance()->destination(CalEvent::ACTIVE, msgParent);
842  if (!resource)
843 #endif
844  {
845  kDebug() << "No calendar";
846  status = UPDATE_FAILED;
847  warnErr = events.count();
848  }
849  else
850  {
851  QString selectID;
852  int count = 0;
853  AlarmCalendar* cal = AlarmCalendar::resources();
854  KDateTime now = KDateTime::currentUtcDateTime();
855  for (int i = 0, end = events.count(); i < end; ++i)
856  {
857  // Delete the event from the archived resource
858 #ifdef USE_AKONADI
859  KAEvent* event = &events[i];
860 #else
861  KAEvent* event = events[i];
862 #endif
863  if (event->category() != CalEvent::ARCHIVED
864  || !event->occursAfter(now, true))
865  {
866 #ifdef USE_AKONADI
867  ineligibleIDs += EventId(*event);
868 #else
869  ineligibleIDs += event->id();
870 #endif
871  continue;
872  }
873  ++count;
874 
875 #ifdef USE_AKONADI
876  KAEvent newevent(*event);
877  KAEvent* const newev = &newevent;
878 #else
879  KAEvent* newev = new KAEvent(*event);
880  QString oldid = event->id();
881 #endif
882  newev->setCategory(CalEvent::ACTIVE); // this changes the event ID
883  if (newev->recurs() || newev->repetition())
884  newev->setNextOccurrence(now); // skip any recurrences in the past
885  newev->setArchive(); // ensure that it gets re-archived if it is deleted
886 
887  // Save the event details in the calendar file.
888  // This converts the event ID.
889 #ifdef USE_AKONADI
890  if (!cal->addEvent(newevent, msgParent, true, &collection))
891 #else
892  if (!cal->addEvent(newev, msgParent, true, resource))
893 #endif
894  {
895 #ifndef USE_AKONADI
896  delete newev;
897 #endif
898  status = UPDATE_ERROR;
899  ++warnErr;
900  continue;
901  }
902  if (newev->copyToKOrganizer())
903  {
904  UpdateStatus st = sendToKOrganizer(*newev); // tell KOrganizer to show the event
905  if (st != UPDATE_OK)
906  {
907  ++warnKOrg;
908  if (st > status)
909  status = st;
910  }
911  }
912 
913 #ifndef USE_AKONADI
914  // Update the window lists
915  EventListModel::alarms()->updateEvent(oldid, newev);
916 // selectID = newev->id();
917 #endif
918 
919 #ifdef USE_AKONADI
920  if (cal->event(EventId(*event)) // no error if event doesn't exist in archived resource
921  && !cal->deleteEvent(*event, false)) // don't save calendar after deleting
922 #else
923  if (cal->event(oldid) // no error if event doesn't exist in archived resource
924  && !cal->deleteEvent(oldid, false)) // don't save calendar after deleting
925 #endif
926  {
927  status = UPDATE_ERROR;
928  ++warnErr;
929  }
930 #ifdef USE_AKONADI
931  events[i] = newevent;
932 #else
933  events[i] = newev;
934 #endif
935  }
936 
937  if (warnErr == count)
938  status = UPDATE_FAILED;
939  // Save the calendars, even if all events failed, since more than one calendar was updated
940  if (!cal->save() && status != UPDATE_FAILED)
941  {
942  status = SAVE_FAILED;
943  warnErr = count;
944  }
945  }
946  if (status != UPDATE_OK && msgParent)
947  displayUpdateError(msgParent, status, ERR_REACTIVATE, warnErr, warnKOrg, showKOrgErr);
948  return status;
949 }
950 
951 /******************************************************************************
952 * Enable or disable alarms in the calendar file and in every main window instance.
953 * The new events will have the same event IDs as the old ones.
954 */
955 #ifdef USE_AKONADI
956 UpdateStatus enableEvents(QVector<KAEvent>& events, bool enable, QWidget* msgParent)
957 #else
958 UpdateStatus enableEvents(KAEvent::List& events, bool enable, QWidget* msgParent)
959 #endif
960 {
961  kDebug() << events.count();
962  if (events.isEmpty())
963  return UPDATE_OK;
964  UpdateStatus status = UPDATE_OK;
965  AlarmCalendar* cal = AlarmCalendar::resources();
966  bool deleteWakeFromSuspendAlarm = false;
967  QString wakeFromSuspendId = checkRtcWakeConfig().value(0);
968  for (int i = 0, end = events.count(); i < end; ++i)
969  {
970 #ifdef USE_AKONADI
971  KAEvent* event = &events[i];
972 #else
973  KAEvent* event = events[i];
974 #endif
975  if (event->category() == CalEvent::ACTIVE
976  && enable != event->enabled())
977  {
978  event->setEnabled(enable);
979 
980  if (!enable && event->id() == wakeFromSuspendId)
981  deleteWakeFromSuspendAlarm = true;
982 
983  // Update the event in the calendar file
984  KAEvent* newev = cal->updateEvent(event);
985  if (!newev)
986  kError() << "Error updating event in calendar:" << event->id();
987  else
988  {
989  cal->disabledChanged(newev);
990 
991  // If we're disabling a display alarm, close any message window
992  if (!enable && (event->actionTypes() & KAEvent::ACT_DISPLAY))
993  {
994 #ifdef USE_AKONADI
995  MessageWin* win = MessageWin::findEvent(EventId(*event));
996 #else
997  MessageWin* win = MessageWin::findEvent(event->id());
998 #endif
999  delete win;
1000  }
1001 
1002 #ifndef USE_AKONADI
1003  // Update the window lists
1004  EventListModel::alarms()->updateEvent(newev);
1005 #endif
1006  }
1007  }
1008  }
1009 
1010  if (!cal->save())
1011  status = SAVE_FAILED;
1012  if (status != UPDATE_OK && msgParent)
1013  displayUpdateError(msgParent, status, ERR_ADD, events.count(), 0);
1014 
1015  // Remove any wake-from-suspend scheduled for a disabled alarm
1016  if (deleteWakeFromSuspendAlarm && !wakeFromSuspendId.isEmpty())
1017  cancelRtcWake(msgParent, wakeFromSuspendId);
1018 
1019  return status;
1020 }
1021 
1022 /******************************************************************************
1023 * This method must only be called from the main KAlarm queue processing loop,
1024 * to prevent asynchronous calendar operations interfering with one another.
1025 *
1026 * Purge all archived events from the default archived alarm resource whose end
1027 * time is longer ago than 'purgeDays'. All events are deleted if 'purgeDays' is
1028 * zero.
1029 */
1030 void purgeArchive(int purgeDays)
1031 {
1032  if (purgeDays < 0)
1033  return;
1034  kDebug() << purgeDays;
1035  QDate cutoff = KDateTime::currentLocalDate().addDays(-purgeDays);
1036 #ifdef USE_AKONADI
1037  Collection collection = CollectionControlModel::getStandard(CalEvent::ARCHIVED);
1038  if (!collection.isValid())
1039  return;
1040  KAEvent::List events = AlarmCalendar::resources()->events(collection);
1041  for (int i = 0; i < events.count(); )
1042  {
1043  if (purgeDays && events[i]->createdDateTime().date() >= cutoff)
1044  events.remove(i);
1045  else
1046  ++i;
1047  }
1048 #else
1049  AlarmResource* resource = AlarmResources::instance()->getStandardResource(CalEvent::ARCHIVED);
1050  if (!resource)
1051  return;
1052  KAEvent::List events = AlarmCalendar::resources()->events(resource);
1053  for (int i = 0; i < events.count(); )
1054  {
1055  KAEvent* event = events[i];
1056  Incidence* kcalIncidence = resource->incidence(event->id());
1057  if (purgeDays && kcalIncidence && kcalIncidence->created().date() >= cutoff)
1058  events.remove(i);
1059  else
1060  EventListModel::alarms()->removeEvent(events[i++]); // update the window lists
1061  }
1062 #endif
1063  if (!events.isEmpty())
1064  AlarmCalendar::resources()->purgeEvents(events); // delete the events and save the calendar
1065 }
1066 
1067 #ifdef USE_AKONADI
1068 /******************************************************************************
1069 * Display an error message about an error when saving an event.
1070 * If 'model' is non-null, the AlarmListModel* which it points to is used; if
1071 * that is null, it is created.
1072 */
1073 QVector<KAEvent> getSortedActiveEvents(QObject* parent, AlarmListModel** model)
1074 {
1075  AlarmListModel* mdl = 0;
1076  if (!model)
1077  model = &mdl;
1078  if (!*model)
1079  {
1080  *model = new AlarmListModel(parent);
1081  (*model)->setEventTypeFilter(CalEvent::ACTIVE);
1082  (*model)->sort(AlarmListModel::TimeColumn);
1083  }
1084  QVector<KAEvent> result;
1085  for (int i = 0, count = (*model)->rowCount(); i < count; ++i)
1086  {
1087  KAEvent event = (*model)->event(i);
1088  if (event.enabled() && !event.expired())
1089  result += event;
1090  }
1091  return result;
1092 }
1093 #else
1094 /******************************************************************************
1095 * Display an error message about an error when saving an event.
1096 */
1097 KAEvent::List getSortedActiveEvents(const KDateTime& startTime, const KDateTime& endTime)
1098 {
1099  KAEvent::List events;
1100  if (endTime.isValid())
1101  events = AlarmCalendar::resources()->events(startTime, endTime, CalEvent::ACTIVE);
1102  else
1103  events = AlarmCalendar::resources()->events(CalEvent::ACTIVE);
1104  KAEvent::List result;
1105  for (int i = 0, count = events.count(); i < count; ++i)
1106  {
1107  KAEvent* event = events[i];
1108  if (event->enabled() && !event->expired())
1109  result += event;
1110  }
1111  return result;
1112 }
1113 #endif
1114 
1115 /******************************************************************************
1116 * Display an error message about an error when saving an event.
1117 */
1118 void displayUpdateError(QWidget* parent, UpdateStatus status, UpdateError code, int nAlarms, int nKOrgAlarms, bool showKOrgError)
1119 {
1120  QString errmsg;
1121  if (status > UPDATE_KORG_ERR)
1122  {
1123  switch (code)
1124  {
1125  case ERR_ADD:
1126  case ERR_MODIFY:
1127  errmsg = (nAlarms > 1) ? i18nc("@info", "Error saving alarms")
1128  : i18nc("@info", "Error saving alarm");
1129  break;
1130  case ERR_DELETE:
1131  errmsg = (nAlarms > 1) ? i18nc("@info", "Error deleting alarms")
1132  : i18nc("@info", "Error deleting alarm");
1133  break;
1134  case ERR_REACTIVATE:
1135  errmsg = (nAlarms > 1) ? i18nc("@info", "Error saving reactivated alarms")
1136  : i18nc("@info", "Error saving reactivated alarm");
1137  break;
1138  case ERR_TEMPLATE:
1139  errmsg = (nAlarms > 1) ? i18nc("@info", "Error saving alarm templates")
1140  : i18nc("@info", "Error saving alarm template");
1141  break;
1142  }
1143  KAMessageBox::error(parent, errmsg);
1144  }
1145  else if (showKOrgError)
1146  displayKOrgUpdateError(parent, code, status, nKOrgAlarms);
1147 }
1148 
1149 /******************************************************************************
1150 * Display an error message corresponding to a specified alarm update error code.
1151 */
1152 void displayKOrgUpdateError(QWidget* parent, UpdateError code, UpdateStatus korgError, int nAlarms)
1153 {
1154  QString errmsg;
1155  switch (code)
1156  {
1157  case ERR_ADD:
1158  case ERR_REACTIVATE:
1159  errmsg = (nAlarms > 1) ? i18nc("@info", "Unable to show alarms in KOrganizer")
1160  : i18nc("@info", "Unable to show alarm in KOrganizer");
1161  break;
1162  case ERR_MODIFY:
1163  errmsg = i18nc("@info", "Unable to update alarm in KOrganizer");
1164  break;
1165  case ERR_DELETE:
1166  errmsg = (nAlarms > 1) ? i18nc("@info", "Unable to delete alarms from KOrganizer")
1167  : i18nc("@info", "Unable to delete alarm from KOrganizer");
1168  break;
1169  case ERR_TEMPLATE:
1170  return;
1171  }
1172  QString msg;
1173  if (korgError == UPDATE_KORG_ERRSTART)
1174  msg = i18nc("@info", "<para>%1</para><para>(KOrganizer not fully started)</para>", errmsg);
1175  else if (korgError == UPDATE_KORG_ERR)
1176  msg = i18nc("@info", "<para>%1</para><para>(Error communicating with KOrganizer)</para>", errmsg);
1177  else
1178  msg = errmsg;
1179  KAMessageBox::error(parent, msg);
1180 }
1181 
1182 /******************************************************************************
1183 * Execute a New Alarm dialog for the specified alarm type.
1184 */
1185 void editNewAlarm(EditAlarmDlg::Type type, QWidget* parent)
1186 {
1187  execNewAlarmDlg(EditAlarmDlg::create(false, type, parent));
1188 }
1189 
1190 /******************************************************************************
1191 * Execute a New Alarm dialog for the specified alarm type.
1192 */
1193 void editNewAlarm(KAEvent::SubAction action, QWidget* parent, const AlarmText* text)
1194 {
1195  bool setAction = false;
1196  EditAlarmDlg::Type type;
1197  switch (action)
1198  {
1199  case KAEvent::MESSAGE:
1200  case KAEvent::FILE:
1201  type = EditAlarmDlg::DISPLAY;
1202  setAction = true;
1203  break;
1204  case KAEvent::COMMAND:
1205  type = EditAlarmDlg::COMMAND;
1206  break;
1207  case KAEvent::EMAIL:
1208  type = EditAlarmDlg::EMAIL;
1209  break;
1210  case KAEvent::AUDIO:
1211  type = EditAlarmDlg::AUDIO;
1212  break;
1213  default:
1214  return;
1215  }
1216  EditAlarmDlg* editDlg = EditAlarmDlg::create(false, type, parent);
1217  if (setAction || text)
1218  editDlg->setAction(action, *text);
1219  execNewAlarmDlg(editDlg);
1220 }
1221 
1222 /******************************************************************************
1223 * Execute a New Alarm dialog, optionally either presetting it to the supplied
1224 * event, or setting the action and text.
1225 */
1226 void editNewAlarm(const KAEvent* preset, QWidget* parent)
1227 {
1228  execNewAlarmDlg(EditAlarmDlg::create(false, preset, true, parent));
1229 }
1230 
1231 /******************************************************************************
1232 * Common code for editNewAlarm() variants.
1233 */
1234 void execNewAlarmDlg(EditAlarmDlg* editDlg)
1235 {
1236  // Create a PrivateNewAlarmDlg parented by editDlg.
1237  // It will be deleted when editDlg is closed.
1238  new PrivateNewAlarmDlg(editDlg);
1239  editDlg->show();
1240  editDlg->raise();
1241  editDlg->activateWindow();
1242 }
1243 
1244 PrivateNewAlarmDlg::PrivateNewAlarmDlg(EditAlarmDlg* dlg)
1245  : QObject(dlg)
1246 {
1247  connect(dlg, SIGNAL(accepted()), SLOT(okClicked()));
1248  connect(dlg, SIGNAL(rejected()), SLOT(cancelClicked()));
1249 }
1250 
1251 /******************************************************************************
1252 * Called when the dialogue is accepted (e.g. by clicking the OK button).
1253 * Creates the event specified in the instance's dialogue.
1254 */
1255 void PrivateNewAlarmDlg::okClicked()
1256 {
1257  accept(static_cast<EditAlarmDlg*>(parent()));
1258 }
1259 
1260 /******************************************************************************
1261 * Creates the event specified in a given dialogue.
1262 */
1263 void PrivateNewAlarmDlg::accept(EditAlarmDlg* editDlg)
1264 {
1265  KAEvent event;
1266 #ifdef USE_AKONADI
1267  Collection calendar;
1268 #else
1269  AlarmResource* calendar;
1270 #endif
1271  editDlg->getEvent(event, calendar);
1272 
1273  // Add the alarm to the displayed lists and to the calendar file
1274 #ifdef USE_AKONADI
1275  UpdateStatus status = addEvent(event, &calendar, editDlg);
1276 #else
1277  UpdateStatus status = addEvent(event, calendar, editDlg);
1278 #endif
1279  switch (status)
1280  {
1281  case UPDATE_FAILED:
1282  return;
1283  case UPDATE_KORG_ERR:
1284  case UPDATE_KORG_ERRSTART:
1285  case UPDATE_KORG_FUNCERR:
1286  displayKOrgUpdateError(editDlg, ERR_ADD, status, 1);
1287  break;
1288  default:
1289  break;
1290  }
1291  Undo::saveAdd(event, calendar);
1292 
1293  outputAlarmWarnings(editDlg, &event);
1294 
1295  editDlg->deleteLater();
1296 }
1297 
1298 /******************************************************************************
1299 * Called when the dialogue is rejected (e.g. by clicking the Cancel button).
1300 */
1301 void PrivateNewAlarmDlg::cancelClicked()
1302 {
1303  static_cast<EditAlarmDlg*>(parent())->deleteLater();
1304 }
1305 
1306 /******************************************************************************
1307 * Display the alarm edit dialog to edit a new alarm, preset with a template.
1308 */
1309 bool editNewAlarm(const QString& templateName, QWidget* parent)
1310 {
1311  if (!templateName.isEmpty())
1312  {
1313  KAEvent* templateEvent = AlarmCalendar::resources()->templateEvent(templateName);
1314  if (templateEvent->isValid())
1315  {
1316  editNewAlarm(templateEvent, parent);
1317  return true;
1318  }
1319  kWarning() << templateName << ": template not found";
1320  }
1321  return false;
1322 }
1323 
1324 /******************************************************************************
1325 * Create a new template.
1326 */
1327 void editNewTemplate(EditAlarmDlg::Type type, QWidget* parent)
1328 {
1329  ::editNewTemplate(type, 0, parent);
1330 }
1331 
1332 /******************************************************************************
1333 * Create a new template, based on an existing event or template.
1334 */
1335 void editNewTemplate(const KAEvent* preset, QWidget* parent)
1336 {
1337  ::editNewTemplate(EditAlarmDlg::Type(0), preset, parent);
1338 }
1339 
1340 /******************************************************************************
1341 * Check the config as to whether there is a wake-on-suspend alarm pending, and
1342 * if so, delete it from the config if it has expired.
1343 * If 'checkExists' is true, the config entry will only be returned if the
1344 * event exists.
1345 * Reply = config entry: [0] = event's collection ID (Akonadi only),
1346 * [1] = event ID,
1347 * [2] = trigger time (time_t).
1348 * = empty list if none or expired.
1349 */
1350 QStringList checkRtcWakeConfig(bool checkEventExists)
1351 {
1352  KConfigGroup config(KGlobal::config(), "General");
1353  QStringList params = config.readEntry("RtcWake", QStringList());
1354 #ifdef USE_AKONADI
1355  if (params.count() == 3 && params[2].toUInt() > KDateTime::currentUtcDateTime().toTime_t())
1356 #else
1357  if (params.count() == 2 && params[1].toUInt() > KDateTime::currentUtcDateTime().toTime_t())
1358 #endif
1359  {
1360 #ifdef USE_AKONADI
1361  if (checkEventExists && !AlarmCalendar::getEvent(EventId(params[0].toLongLong(), params[1])))
1362 #else
1363  if (checkEventExists && !AlarmCalendar::getEvent(params[0]))
1364 #endif
1365  return QStringList();
1366  return params; // config entry is valid
1367  }
1368  if (!params.isEmpty())
1369  {
1370  config.deleteEntry("RtcWake"); // delete the expired config entry
1371  config.sync();
1372  }
1373  return QStringList();
1374 }
1375 
1376 /******************************************************************************
1377 * Delete any wake-on-suspend alarm from the config.
1378 */
1379 void deleteRtcWakeConfig()
1380 {
1381  KConfigGroup config(KGlobal::config(), "General");
1382  config.deleteEntry("RtcWake");
1383  config.sync();
1384 }
1385 
1386 /******************************************************************************
1387 * Delete any wake-on-suspend alarm, optionally only for a specified event.
1388 */
1389 void cancelRtcWake(QWidget* msgParent, const QString& eventId)
1390 {
1391  QStringList wakeup = checkRtcWakeConfig();
1392  if (!wakeup.isEmpty() && (eventId.isEmpty() || wakeup[0] == eventId))
1393  {
1394  Private::instance()->mMsgParent = msgParent ? msgParent : MainWindow::mainMainWindow();
1395  QTimer::singleShot(0, Private::instance(), SLOT(cancelRtcWake()));
1396  }
1397 }
1398 
1399 /******************************************************************************
1400 * Delete any wake-on-suspend alarm.
1401 */
1402 void Private::cancelRtcWake()
1403 {
1404  // setRtcWakeTime will only work with a parent window specified
1405  setRtcWakeTime(0, mMsgParent);
1406  deleteRtcWakeConfig();
1407  KAMessageBox::information(mMsgParent, i18nc("info", "The scheduled Wake from Suspend has been cancelled."));
1408 }
1409 
1410 /******************************************************************************
1411 * Set the wakeup time for the system.
1412 * Set 'triggerTime' to zero to cancel the wakeup.
1413 * Reply = true if successful.
1414 */
1415 bool setRtcWakeTime(unsigned triggerTime, QWidget* parent)
1416 {
1417  QVariantMap args;
1418  args[QLatin1String("time")] = triggerTime;
1419  KAuth::Action action(QLatin1String("org.kde.kalarmrtcwake.settimer"));
1420  action.setHelperID(QLatin1String("org.kde.kalarmrtcwake"));
1421  action.setParentWidget(parent);
1422  action.setArguments(args);
1423  KAuth::ActionReply reply = action.execute();
1424  if (reply.failed())
1425  {
1426  QString errmsg = reply.errorDescription();
1427  kDebug() << "Error code=" << reply.errorCode() << errmsg;
1428  if (errmsg.isEmpty())
1429  {
1430  int errcode = reply.errorCode();
1431  switch (reply.type())
1432  {
1433  case KAuth::ActionReply::KAuthError:
1434  kDebug() << "Authorisation error:" << errcode;
1435  switch (errcode)
1436  {
1437  case KAuth::ActionReply::AuthorizationDenied:
1438  case KAuth::ActionReply::UserCancelled:
1439  return false; // the user should already know about this
1440  default:
1441  break;
1442  }
1443  break;
1444  case KAuth::ActionReply::HelperError:
1445  kDebug() << "Helper error:" << errcode;
1446  errcode += 100; // make code distinguishable from KAuthError type
1447  break;
1448  default:
1449  break;
1450  }
1451  errmsg = i18nc("@info", "Error obtaining authorization (%1)", errcode);
1452  }
1453  KAMessageBox::information(parent, errmsg);
1454  return false;
1455  }
1456  return true;
1457 }
1458 
1459 } // namespace KAlarm
1460 namespace
1461 {
1462 
1463 /******************************************************************************
1464 * Create a new template.
1465 * 'preset' is non-null to base it on an existing event or template; otherwise,
1466 * the alarm type is set to 'type'.
1467 */
1468 void editNewTemplate(EditAlarmDlg::Type type, const KAEvent* preset, QWidget* parent)
1469 {
1470 #ifdef USE_AKONADI
1471  if (CollectionControlModel::enabledCollections(CalEvent::TEMPLATE, true).isEmpty())
1472 #else
1473  if (!AlarmResources::instance()->activeCount(CalEvent::TEMPLATE, true))
1474 #endif
1475  {
1476  KAMessageBox::sorry(parent, i18nc("@info", "You must enable a template calendar to save the template in"));
1477  return;
1478  }
1479  // Use AutoQPointer to guard against crash on application exit while
1480  // the dialogue is still open. It prevents double deletion (both on
1481  // deletion of parent, and on return from this function).
1482  AutoQPointer<EditAlarmDlg> editDlg;
1483  if (preset)
1484  editDlg = EditAlarmDlg::create(true, preset, true, parent);
1485  else
1486  editDlg = EditAlarmDlg::create(true, type, parent);
1487  if (editDlg->exec() == QDialog::Accepted)
1488  {
1489  KAEvent event;
1490 #ifdef USE_AKONADI
1491  Akonadi::Collection calendar;
1492 #else
1493  AlarmResource* calendar;
1494 #endif
1495  editDlg->getEvent(event, calendar);
1496 
1497  // Add the template to the displayed lists and to the calendar file
1498 #ifdef USE_AKONADI
1499  KAlarm::addTemplate(event, &calendar, editDlg);
1500 #else
1501  KAlarm::addTemplate(event, calendar, editDlg);
1502 #endif
1503  Undo::saveAdd(event, calendar);
1504  }
1505 }
1506 
1507 } // namespace
1508 namespace KAlarm
1509 {
1510 
1511 /******************************************************************************
1512 * Open the Edit Alarm dialog to edit the specified alarm.
1513 * If the alarm is read-only or archived, the dialog is opened read-only.
1514 */
1515 void editAlarm(KAEvent* event, QWidget* parent)
1516 {
1517 #ifdef USE_AKONADI
1518  if (event->expired() || AlarmCalendar::resources()->eventReadOnly(event->itemId()))
1519 #else
1520  if (event->expired() || AlarmCalendar::resources()->eventReadOnly(event->id()))
1521 #endif
1522  {
1523  viewAlarm(event, parent);
1524  return;
1525  }
1526 #ifdef USE_AKONADI
1527  EventId id(*event);
1528 #else
1529  QString id = event->id();
1530 #endif
1531  // Use AutoQPointer to guard against crash on application exit while
1532  // the dialogue is still open. It prevents double deletion (both on
1533  // deletion of parent, and on return from this function).
1534  AutoQPointer<EditAlarmDlg> editDlg = EditAlarmDlg::create(false, event, false, parent, EditAlarmDlg::RES_USE_EVENT_ID);
1535  if (editDlg->exec() == QDialog::Accepted)
1536  {
1537  if (!AlarmCalendar::resources()->event(id))
1538  {
1539  // Event has been deleted while the user was editing the alarm,
1540  // so treat it as a new alarm.
1541  PrivateNewAlarmDlg().accept(editDlg);
1542  return;
1543  }
1544  KAEvent newEvent;
1545 #ifdef USE_AKONADI
1546  Collection calendar;
1547 #else
1548  AlarmResource* calendar;
1549 #endif
1550  bool changeDeferral = !editDlg->getEvent(newEvent, calendar);
1551 
1552  // Update the event in the displays and in the calendar file
1553  Undo::Event undo(*event, calendar);
1554  if (changeDeferral)
1555  {
1556  // The only change has been to an existing deferral
1557  if (updateEvent(newEvent, editDlg, true) != UPDATE_OK) // keep the same event ID
1558  return; // failed to save event
1559  }
1560  else
1561  {
1562  UpdateStatus status = modifyEvent(*event, newEvent, editDlg);
1563  if (status != UPDATE_OK && status <= UPDATE_KORG_ERR)
1564  displayKOrgUpdateError(editDlg, ERR_MODIFY, status, 1);
1565  }
1566  Undo::saveEdit(undo, newEvent);
1567 
1568  outputAlarmWarnings(editDlg, &newEvent);
1569  }
1570 }
1571 
1572 /******************************************************************************
1573 * Display the alarm edit dialog to edit the alarm with the specified ID.
1574 * An error occurs if the alarm is not found, if there is more than one alarm
1575 * with the same ID, or if it is read-only or expired.
1576 */
1577 #ifdef USE_AKONADI
1578 bool editAlarmById(const EventId& id, QWidget* parent)
1579 #else
1580 bool editAlarmById(const QString& eventID, QWidget* parent)
1581 #endif
1582 {
1583 #ifdef USE_AKONADI
1584  const QString eventID(id.eventId());
1585  KAEvent* event = AlarmCalendar::resources()->event(id, true);
1586  if (!event)
1587  {
1588  if (id.collectionId() != -1)
1589  kWarning() << "Event ID not found, or duplicated:" << eventID;
1590  else
1591  kWarning() << "Event ID not found:" << eventID;
1592  return false;
1593  }
1594  if (AlarmCalendar::resources()->eventReadOnly(event->itemId()))
1595 #else
1596  KAEvent* event = AlarmCalendar::resources()->event(eventID);
1597  if (!event)
1598  {
1599  kError() << eventID << ": event ID not found";
1600  return false;
1601  }
1602  if (AlarmCalendar::resources()->eventReadOnly(eventID))
1603 #endif
1604  {
1605  kError() << eventID << ": read-only";
1606  return false;
1607  }
1608  switch (event->category())
1609  {
1610  case CalEvent::ACTIVE:
1611  case CalEvent::TEMPLATE:
1612  break;
1613  default:
1614  kError() << eventID << ": event not active or template";
1615  return false;
1616  }
1617  editAlarm(event, parent);
1618  return true;
1619 }
1620 
1621 /******************************************************************************
1622 * Open the Edit Alarm dialog to edit the specified template.
1623 * If the template is read-only, the dialog is opened read-only.
1624 */
1625 void editTemplate(KAEvent* event, QWidget* parent)
1626 {
1627 #ifdef USE_AKONADI
1628  if (AlarmCalendar::resources()->eventReadOnly(event->itemId()))
1629 #else
1630  if (AlarmCalendar::resources()->eventReadOnly(event->id()))
1631 #endif
1632  {
1633  // The template is read-only, so make the dialogue read-only.
1634  // Use AutoQPointer to guard against crash on application exit while
1635  // the dialogue is still open. It prevents double deletion (both on
1636  // deletion of parent, and on return from this function).
1637  AutoQPointer<EditAlarmDlg> editDlg = EditAlarmDlg::create(true, event, false, parent, EditAlarmDlg::RES_PROMPT, true);
1638  editDlg->exec();
1639  return;
1640  }
1641  // Use AutoQPointer to guard against crash on application exit while
1642  // the dialogue is still open. It prevents double deletion (both on
1643  // deletion of parent, and on return from this function).
1644  AutoQPointer<EditAlarmDlg> editDlg = EditAlarmDlg::create(true, event, false, parent, EditAlarmDlg::RES_USE_EVENT_ID);
1645  if (editDlg->exec() == QDialog::Accepted)
1646  {
1647  KAEvent newEvent;
1648 #ifdef USE_AKONADI
1649  Akonadi::Collection calendar;
1650 #else
1651  AlarmResource* calendar;
1652 #endif
1653  editDlg->getEvent(newEvent, calendar);
1654  QString id = event->id();
1655  newEvent.setEventId(id);
1656 #ifdef USE_AKONADI
1657  newEvent.setCollectionId(event->collectionId());
1658  newEvent.setItemId(event->itemId());
1659 #endif
1660 
1661  // Update the event in the displays and in the calendar file
1662  Undo::Event undo(*event, calendar);
1663  updateTemplate(newEvent, editDlg);
1664  Undo::saveEdit(undo, newEvent);
1665  }
1666 }
1667 
1668 /******************************************************************************
1669 * Open the Edit Alarm dialog to view the specified alarm (read-only).
1670 */
1671 void viewAlarm(const KAEvent* event, QWidget* parent)
1672 {
1673  // Use AutoQPointer to guard against crash on application exit while
1674  // the dialogue is still open. It prevents double deletion (both on
1675  // deletion of parent, and on return from this function).
1676  AutoQPointer<EditAlarmDlg> editDlg = EditAlarmDlg::create(false, event, false, parent, EditAlarmDlg::RES_PROMPT, true);
1677  editDlg->exec();
1678 }
1679 
1680 /******************************************************************************
1681 * Called when OK is clicked in the alarm edit dialog invoked by the Edit button
1682 * in an alarm message window.
1683 * Updates the alarm calendar and closes the dialog.
1684 */
1685 #ifdef USE_AKONADI
1686 void updateEditedAlarm(EditAlarmDlg* editDlg, KAEvent& event, Collection& calendar)
1687 #else
1688 void updateEditedAlarm(EditAlarmDlg* editDlg, KAEvent& event, AlarmResource* calendar)
1689 #endif
1690 {
1691  kDebug();
1692  KAEvent newEvent;
1693 #ifdef USE_AKONADI
1694  Akonadi::Collection cal;
1695 #else
1696  AlarmResource* cal;
1697 #endif
1698  editDlg->getEvent(newEvent, cal);
1699 
1700  // Update the displayed lists and the calendar file
1701  UpdateStatus status;
1702 #ifdef USE_AKONADI
1703  if (AlarmCalendar::resources()->event(EventId(event)))
1704 #else
1705  if (AlarmCalendar::resources()->event(event.id()))
1706 #endif
1707  {
1708  // The old alarm hasn't expired yet, so replace it
1709  Undo::Event undo(event, calendar);
1710  status = modifyEvent(event, newEvent, editDlg);
1711  Undo::saveEdit(undo, newEvent);
1712  }
1713  else
1714  {
1715  // The old event has expired, so simply create a new one
1716 #ifdef USE_AKONADI
1717  status = addEvent(newEvent, &calendar, editDlg);
1718 #else
1719  status = addEvent(newEvent, calendar, editDlg);
1720 #endif
1721  Undo::saveAdd(newEvent, calendar);
1722  }
1723 
1724  if (status != UPDATE_OK && status <= UPDATE_KORG_ERR)
1725  displayKOrgUpdateError(editDlg, ERR_MODIFY, status, 1);
1726  outputAlarmWarnings(editDlg, &newEvent);
1727 
1728  editDlg->close();
1729 }
1730 
1731 /******************************************************************************
1732 * Returns a list of all alarm templates.
1733 * If shell commands are disabled, command alarm templates are omitted.
1734 */
1735 KAEvent::List templateList()
1736 {
1737  KAEvent::List templates;
1738  bool includeCmdAlarms = ShellProcess::authorised();
1739  KAEvent::List events = AlarmCalendar::resources()->events(CalEvent::TEMPLATE);
1740  for (int i = 0, end = events.count(); i < end; ++i)
1741  {
1742  KAEvent* event = events[i];
1743  if (includeCmdAlarms || !(event->actionTypes() & KAEvent::ACT_COMMAND))
1744  templates.append(event);
1745  }
1746  return templates;
1747 }
1748 
1749 /******************************************************************************
1750 * To be called after an alarm has been edited.
1751 * Prompt the user to re-enable alarms if they are currently disabled, and if
1752 * it's an email alarm, warn if no 'From' email address is configured.
1753 */
1754 void outputAlarmWarnings(QWidget* parent, const KAEvent* event)
1755 {
1756  if (event && event->actionTypes() == KAEvent::ACT_EMAIL
1757  && Preferences::emailAddress().isEmpty())
1758  KAMessageBox::information(parent, i18nc("@info Please set the 'From' email address...",
1759  "<para>%1</para><para>Please set it in the Configuration dialog.</para>", KAMail::i18n_NeedFromEmailAddress()));
1760 
1761  if (!theApp()->alarmsEnabled())
1762  {
1763  if (KAMessageBox::warningYesNo(parent, i18nc("@info", "<para>Alarms are currently disabled.</para><para>Do you want to enable alarms now?</para>"),
1764  QString(), KGuiItem(i18nc("@action:button", "Enable")), KGuiItem(i18nc("@action:button", "Keep Disabled")),
1765  QLatin1String("EditEnableAlarms"))
1766  == KMessageBox::Yes)
1767  theApp()->setAlarmsEnabled(true);
1768  }
1769 }
1770 
1771 /******************************************************************************
1772 * Reload the calendar.
1773 */
1774 void refreshAlarms()
1775 {
1776  kDebug();
1777  if (!refreshAlarmsQueued)
1778  {
1779  refreshAlarmsQueued = true;
1780  theApp()->processQueue();
1781  }
1782 }
1783 
1784 /******************************************************************************
1785 * This method must only be called from the main KAlarm queue processing loop,
1786 * to prevent asynchronous calendar operations interfering with one another.
1787 *
1788 * If refreshAlarms() has been called, reload the calendars.
1789 */
1790 void refreshAlarmsIfQueued()
1791 {
1792  if (refreshAlarmsQueued)
1793  {
1794  kDebug();
1795  AlarmCalendar::resources()->reload();
1796 
1797  // Close any message windows for alarms which are now disabled
1798  KAEvent::List events = AlarmCalendar::resources()->events(CalEvent::ACTIVE);
1799  for (int i = 0, end = events.count(); i < end; ++i)
1800  {
1801  KAEvent* event = events[i];
1802  if (!event->enabled() && (event->actionTypes() & KAEvent::ACT_DISPLAY))
1803  {
1804 #ifdef USE_AKONADI
1805  MessageWin* win = MessageWin::findEvent(EventId(*event));
1806 #else
1807  MessageWin* win = MessageWin::findEvent(event->id());
1808 #endif
1809  delete win;
1810  }
1811  }
1812 
1813  MainWindow::refresh();
1814  refreshAlarmsQueued = false;
1815  }
1816 }
1817 
1818 /******************************************************************************
1819 * Start KMail if it isn't already running, optionally minimised.
1820 * Reply = reason for failure to run KMail (which may be the empty string)
1821 * = null string if success.
1822 */
1823 QString runKMail(bool minimise)
1824 {
1825  QDBusReply<bool> reply = QDBusConnection::sessionBus().interface()->isServiceRegistered(KMAIL_DBUS_SERVICE);
1826  if (!reply.isValid() || !reply.value())
1827  {
1828  // Program is not already running, so start it
1829  QString errmsg;
1830  if (minimise && Private::startKMailMinimised())
1831  return QString();
1832  if (KToolInvocation::startServiceByDesktopName(QLatin1String("kmail"), QString(), &errmsg))
1833  {
1834  kError() << "Couldn't start KMail (" << errmsg << ")";
1835  return i18nc("@info", "Unable to start <application>KMail</application><nl/>(<message>%1</message>)", errmsg);
1836  }
1837  }
1838  return QString();
1839 }
1840 
1841 /******************************************************************************
1842 * Start KMail, minimised.
1843 * This code is taken from kstart in kdebase.
1844 */
1845 bool Private::startKMailMinimised()
1846 {
1847 #ifdef Q_WS_X11
1848  NETRootInfo i(QX11Info::display(), NET::Supported);
1849  if (i.isSupported(NET::WM2KDETemporaryRules))
1850  {
1851  kDebug() << "using rules";
1852  KXMessages msg;
1853  QString message = QLatin1String("wmclass=kmail\nwmclassmatch=1\n" // 1 = exact match
1854  "wmclasscomplete=false\n"
1855  "minimize=true\nminimizerule=3\n"
1856  "type=") + QString().setNum(NET::Normal) + QLatin1String("\ntyperule=2");
1857  msg.broadcastMessage("_KDE_NET_WM_TEMPORARY_RULES", message, -1, false);
1858  qApp->flush();
1859  }
1860  else
1861  {
1862  // Connect to window add to get the NEW windows
1863  kDebug() << "connecting to window add";
1864  connect(KWindowSystem::self(), SIGNAL(windowAdded(WId)), instance(), SLOT(windowAdded(WId)));
1865  }
1866  // Propagate the app startup notification info to the started app.
1867  // We are not using KApplication, so the env remained set.
1868  KStartupInfoId id = KStartupInfo::currentStartupIdEnv();
1869  KProcess* proc = new KProcess;
1870  (*proc) << QLatin1String("kmail");
1871  int pid = proc->startDetached();
1872  if (!pid)
1873  {
1874  KStartupInfo::sendFinish(id); // failed to start
1875  return false;
1876  }
1877  KStartupInfoData data;
1878  data.addPid(pid);
1879  data.setName(QLatin1String("kmail"));
1880  data.setBin(QLatin1String("kmail"));
1881  KStartupInfo::sendChange(id, data);
1882  return true;
1883 #else
1884  return false;
1885 #endif
1886 }
1887 
1888 /******************************************************************************
1889 * Called when a window is created, to minimise it.
1890 * This code is taken from kstart in kdebase.
1891 */
1892 void Private::windowAdded(WId w)
1893 {
1894 #ifdef Q_WS_X11
1895  static const int SUPPORTED_TYPES = NET::NormalMask | NET::DesktopMask | NET::DockMask
1896  | NET::ToolbarMask | NET::MenuMask | NET::DialogMask
1897  | NET::OverrideMask | NET::TopMenuMask | NET::UtilityMask | NET::SplashMask;
1898  KWindowInfo kwinfo = KWindowSystem::windowInfo(w, NET::WMWindowType | NET::WMName);
1899  if (kwinfo.windowType(SUPPORTED_TYPES) == NET::TopMenu
1900  || kwinfo.windowType(SUPPORTED_TYPES) == NET::Toolbar
1901  || kwinfo.windowType(SUPPORTED_TYPES) == NET::Desktop)
1902  return; // always ignore these window types
1903 
1904  QX11Info qxinfo;
1905  XWithdrawWindow(QX11Info::display(), w, qxinfo.screen());
1906  QApplication::flush();
1907 
1908  NETWinInfo info(QX11Info::display(), w, QX11Info::appRootWindow(), NET::WMState);
1909  XWMHints* hints = XGetWMHints(QX11Info::display(), w);
1910  if (hints)
1911  {
1912  hints->flags |= StateHint;
1913  hints->initial_state = IconicState;
1914  XSetWMHints(QX11Info::display(), w, hints);
1915  XFree(hints);
1916  }
1917  info.setWindowType(NET::Normal);
1918 
1919  XSync(QX11Info::display(), False);
1920  XMapWindow(QX11Info::display(), w);
1921  XSync(QX11Info::display(), False);
1922  QApplication::flush();
1923 #endif
1924 }
1925 
1926 /******************************************************************************
1927 * The "Don't show again" option for error messages is personal to the user on a
1928 * particular computer. For example, he may want to inhibit error messages only
1929 * on his laptop. So the status is not stored in the alarm calendar, but in the
1930 * user's local KAlarm data directory.
1931 ******************************************************************************/
1932 
1933 /******************************************************************************
1934 * Return the Don't-show-again error message tags set for a specified alarm ID.
1935 */
1936 #ifdef USE_AKONADI
1937 QStringList dontShowErrors(const EventId& eventId)
1938 #else
1939 QStringList dontShowErrors(const QString& eventId)
1940 #endif
1941 {
1942  if (eventId.isEmpty())
1943  return QStringList();
1944  KConfig config(KStandardDirs::locateLocal("appdata", ALARM_OPTS_FILE));
1945  KConfigGroup group(&config, DONT_SHOW_ERRORS_GROUP);
1946 #ifdef USE_AKONADI
1947  const QString id = QString::fromLatin1("%1:%2").arg(eventId.collectionId()).arg(eventId.eventId());
1948 #else
1949  const QString id(eventId);
1950 #endif
1951  return group.readEntry(id, QStringList());
1952 }
1953 
1954 /******************************************************************************
1955 * Check whether the specified Don't-show-again error message tag is set for an
1956 * alarm ID.
1957 */
1958 #ifdef USE_AKONADI
1959 bool dontShowErrors(const EventId& eventId, const QString& tag)
1960 #else
1961 bool dontShowErrors(const QString& eventId, const QString& tag)
1962 #endif
1963 {
1964  if (tag.isEmpty())
1965  return false;
1966  QStringList tags = dontShowErrors(eventId);
1967  return tags.indexOf(tag) >= 0;
1968 }
1969 
1970 /******************************************************************************
1971 * Reset the Don't-show-again error message tags for an alarm ID.
1972 * If 'tags' is empty, the config entry is deleted.
1973 */
1974 #ifdef USE_AKONADI
1975 void setDontShowErrors(const EventId& eventId, const QStringList& tags)
1976 #else
1977 void setDontShowErrors(const QString& eventId, const QStringList& tags)
1978 #endif
1979 {
1980  if (eventId.isEmpty())
1981  return;
1982  KConfig config(KStandardDirs::locateLocal("appdata", ALARM_OPTS_FILE));
1983  KConfigGroup group(&config, DONT_SHOW_ERRORS_GROUP);
1984 #ifdef USE_AKONADI
1985  const QString id = QString::fromLatin1("%1:%2").arg(eventId.collectionId()).arg(eventId.eventId());
1986 #else
1987  const QString id(eventId);
1988 #endif
1989  if (tags.isEmpty())
1990  group.deleteEntry(id);
1991  else
1992  group.writeEntry(id, tags);
1993  group.sync();
1994 }
1995 
1996 /******************************************************************************
1997 * Set the specified Don't-show-again error message tag for an alarm ID.
1998 * Existing tags are unaffected.
1999 */
2000 #ifdef USE_AKONADI
2001 void setDontShowErrors(const EventId& eventId, const QString& tag)
2002 #else
2003 void setDontShowErrors(const QString& eventId, const QString& tag)
2004 #endif
2005 {
2006  if (eventId.isEmpty() || tag.isEmpty())
2007  return;
2008  KConfig config(KStandardDirs::locateLocal("appdata", ALARM_OPTS_FILE));
2009  KConfigGroup group(&config, DONT_SHOW_ERRORS_GROUP);
2010 #ifdef USE_AKONADI
2011  const QString id = QString::fromLatin1("%1:%2").arg(eventId.collectionId()).arg(eventId.eventId());
2012 #else
2013  const QString id(eventId);
2014 #endif
2015  QStringList tags = group.readEntry(id, QStringList());
2016  if (tags.indexOf(tag) < 0)
2017  {
2018  tags += tag;
2019  group.writeEntry(id, tags);
2020  group.sync();
2021  }
2022 }
2023 
2024 /******************************************************************************
2025 * Read the size for the specified window from the config file, for the
2026 * current screen resolution.
2027 * Reply = true if size set in the config file, in which case 'result' is set
2028 * = false if no size is set, in which case 'result' is unchanged.
2029 */
2030 bool readConfigWindowSize(const char* window, QSize& result, int* splitterWidth)
2031 {
2032  KConfigGroup config(KGlobal::config(), window);
2033  QWidget* desktop = KApplication::desktop();
2034  QSize s = QSize(config.readEntry(QString::fromLatin1("Width %1").arg(desktop->width()), (int)0),
2035  config.readEntry(QString::fromLatin1("Height %1").arg(desktop->height()), (int)0));
2036  if (s.isEmpty())
2037  return false;
2038  result = s;
2039  if (splitterWidth)
2040  *splitterWidth = config.readEntry(QString::fromLatin1("Splitter %1").arg(desktop->width()), -1);
2041  return true;
2042 }
2043 
2044 /******************************************************************************
2045 * Write the size for the specified window to the config file, for the
2046 * current screen resolution.
2047 */
2048 void writeConfigWindowSize(const char* window, const QSize& size, int splitterWidth)
2049 {
2050  KConfigGroup config(KGlobal::config(), window);
2051  QWidget* desktop = KApplication::desktop();
2052  config.writeEntry(QString::fromLatin1("Width %1").arg(desktop->width()), size.width());
2053  config.writeEntry(QString::fromLatin1("Height %1").arg(desktop->height()), size.height());
2054  if (splitterWidth >= 0)
2055  config.writeEntry(QString::fromLatin1("Splitter %1").arg(desktop->width()), splitterWidth);
2056  config.sync();
2057 }
2058 
2059 /******************************************************************************
2060 * Check from its mime type whether a file appears to be a text or image file.
2061 * If a text file, its type is distinguished.
2062 * Reply = file type.
2063 */
2064 FileType fileType(const KMimeType::Ptr& mimetype)
2065 {
2066  if (mimetype->is(QLatin1String("text/html")))
2067  return TextFormatted;
2068  if (mimetype->is(QLatin1String("application/x-executable")))
2069  return TextApplication;
2070  if (mimetype->is(QLatin1String("text/plain")))
2071  return TextPlain;
2072  if (mimetype->name().startsWith(QLatin1String("image/")))
2073  return Image;
2074  return Unknown;
2075 }
2076 
2077 /******************************************************************************
2078 * Check that a file exists and is a plain readable file.
2079 * Updates 'filename' and 'url' even if an error occurs, since 'filename' may
2080 * be needed subsequently by showFileErrMessage().
2081 */
2082 FileErr checkFileExists(QString& filename, KUrl& url)
2083 {
2084  url = KUrl();
2085  FileErr err = FileErr_None;
2086  QString file = filename;
2087  QRegExp f(QLatin1String("^file:/+"));
2088  if (f.indexIn(file) >= 0)
2089  file = file.mid(f.matchedLength() - 1);
2090  // Convert any relative file path to absolute
2091  // (using home directory as the default)
2092  int i = file.indexOf(QLatin1Char('/'));
2093  if (i > 0 && file[i - 1] == QLatin1Char(':'))
2094  {
2095  url = file;
2096  url.cleanPath();
2097  filename = url.prettyUrl();
2098  KIO::UDSEntry uds;
2099  if (!KIO::NetAccess::stat(url, uds, MainWindow::mainMainWindow()))
2100  err = FileErr_Nonexistent;
2101  else
2102  {
2103  KFileItem fi(uds, url);
2104  if (fi.isDir()) err = FileErr_Directory;
2105  else if (!fi.isReadable()) err = FileErr_Unreadable;
2106  }
2107  }
2108  else if (file.isEmpty())
2109  err = FileErr_Blank; // blank file name
2110  else
2111  {
2112  // It's a local file - convert to absolute path & check validity
2113  QFileInfo info(file);
2114  QDir::setCurrent(QDir::homePath());
2115  filename = info.absoluteFilePath();
2116  url.setPath(filename);
2117  if (info.isDir()) err = FileErr_Directory;
2118  else if (!info.exists()) err = FileErr_Nonexistent;
2119  else if (!info.isReadable()) err = FileErr_Unreadable;
2120  }
2121  return err;
2122 }
2123 
2124 /******************************************************************************
2125 * Display an error message appropriate to 'err'.
2126 * Display a Continue/Cancel error message if 'errmsgParent' non-null.
2127 * Reply = true to continue, false to cancel.
2128 */
2129 bool showFileErrMessage(const QString& filename, FileErr err, FileErr blankError, QWidget* errmsgParent)
2130 {
2131  if (err != FileErr_None)
2132  {
2133  // If file is a local file, remove "file://" from name
2134  QString file = filename;
2135  QRegExp f(QLatin1String("^file:/+"));
2136  if (f.indexIn(file) >= 0)
2137  file = file.mid(f.matchedLength() - 1);
2138 
2139  QString errmsg;
2140  switch (err)
2141  {
2142  case FileErr_Blank:
2143  if (blankError == FileErr_BlankDisplay)
2144  errmsg = i18nc("@info", "Please select a file to display");
2145  else if (blankError == FileErr_BlankPlay)
2146  errmsg = i18nc("@info", "Please select a file to play");
2147  else
2148  kFatal() << "Program error";
2149  KAMessageBox::sorry(errmsgParent, errmsg);
2150  return false;
2151  case FileErr_Directory:
2152  KAMessageBox::sorry(errmsgParent, i18nc("@info", "<filename>%1</filename> is a folder", file));
2153  return false;
2154  case FileErr_Nonexistent: errmsg = i18nc("@info", "<filename>%1</filename> not found", file); break;
2155  case FileErr_Unreadable: errmsg = i18nc("@info", "<filename>%1</filename> is not readable", file); break;
2156  case FileErr_NotTextImage: errmsg = i18nc("@info", "<filename>%1</filename> appears not to be a text or image file", file); break;
2157  default:
2158  break;
2159  }
2160  if (KAMessageBox::warningContinueCancel(errmsgParent, errmsg)
2161  == KMessageBox::Cancel)
2162  return false;
2163  }
2164  return true;
2165 }
2166 
2167 /******************************************************************************
2168 * If a url string is a local file, strip off the 'file:/' prefix.
2169 */
2170 QString pathOrUrl(const QString& url)
2171 {
2172  static const QRegExp localfile(QLatin1String("^file:/+"));
2173  return (localfile.indexIn(url) >= 0) ? url.mid(localfile.matchedLength() - 1) : url;
2174 }
2175 
2176 /******************************************************************************
2177 * Display a modal dialog to choose an existing file, initially highlighting
2178 * any specified file.
2179 * @param initialFile The file to initially highlight - must be a full path name or URL.
2180 * @param defaultDir The directory to start in if @p initialFile is empty. If empty,
2181 * the user's home directory will be used. Updated to the
2182 * directory containing the selected file, if a file is chosen.
2183 * @param mode OR of KFile::Mode values, e.g. ExistingOnly, LocalOnly.
2184 * Reply = URL selected.
2185 * = empty, non-null string if no file was selected.
2186 * = null string if dialogue was deleted while visible (indicating that
2187 * the parent widget was probably also deleted).
2188 */
2189 QString browseFile(const QString& caption, QString& defaultDir, const QString& initialFile,
2190  const QString& filter, KFile::Modes mode, QWidget* parent)
2191 {
2192  QString initialDir = !initialFile.isEmpty() ? QString(initialFile).remove(QRegExp(QLatin1String("/[^/]*$")))
2193  : !defaultDir.isEmpty() ? defaultDir
2194  : QDir::homePath();
2195  // Use AutoQPointer to guard against crash on application exit while
2196  // the dialogue is still open. It prevents double deletion (both on
2197  // deletion of parent, and on return from this function).
2198  AutoQPointer<KFileDialog> fileDlg = new KFileDialog(initialDir, filter, parent);
2199  fileDlg->setOperationMode(mode & KFile::ExistingOnly ? KFileDialog::Opening : KFileDialog::Saving);
2200  fileDlg->setMode(KFile::File | mode);
2201  fileDlg->setCaption(caption);
2202  if (!initialFile.isEmpty())
2203  fileDlg->setSelection(initialFile);
2204  if (fileDlg->exec() != QDialog::Accepted)
2205  return fileDlg ? QLatin1String("") : QString(); // return null only if dialog was deleted
2206  KUrl url = fileDlg->selectedUrl();
2207  if (url.isEmpty())
2208  return QLatin1String(""); // return empty, non-null string
2209  defaultDir = url.isLocalFile() ? url.upUrl().toLocalFile() : url.directory();
2210  return (mode & KFile::LocalOnly) ? url.pathOrUrl() : url.prettyUrl();
2211 }
2212 
2213 /******************************************************************************
2214 * Return a prompt string to ask the user whether to convert the calendar to the
2215 * current format.
2216 * If 'whole' is true, the whole calendar needs to be converted; else only some
2217 * alarms may need to be converted.
2218 *
2219 * Note: This method is defined here to avoid duplicating the i18n string
2220 * definition between the Akonadi and KResources code.
2221 */
2222 QString conversionPrompt(const QString& calendarName, const QString& calendarVersion, bool whole)
2223 {
2224  QString msg = whole
2225  ? i18nc("@info", "Calendar <resource>%1</resource> is in an old format (<application>KAlarm</application> version %2), "
2226  "and will be read-only unless you choose to update it to the current format.",
2227  calendarName, calendarVersion)
2228  : i18nc("@info", "Some or all of the alarms in calendar <resource>%1</resource> are in an old <application>KAlarm</application> format, "
2229  "and will be read-only unless you choose to update them to the current format.",
2230  calendarName);
2231  return i18nc("@info", "<para>%1</para><para>"
2232  "<warning>Do not update the calendar if it is also used with an older version of <application>KAlarm</application> "
2233  "(e.g. on another computer). If you do so, the calendar may become unusable there.</warning></para>"
2234  "<para>Do you wish to update the calendar?</para>", msg);
2235 }
2236 
2237 #ifndef NDEBUG
2238 /******************************************************************************
2239 * Set up KAlarm test conditions based on environment variables.
2240 * KALARM_TIME: specifies current system time (format [[[yyyy-]mm-]dd-]hh:mm [TZ]).
2241 */
2242 void setTestModeConditions()
2243 {
2244  const QByteArray newTime = qgetenv("KALARM_TIME");
2245  if (!newTime.isEmpty())
2246  {
2247  KDateTime dt;
2248  if (AlarmTime::convertTimeString(newTime, dt, KDateTime::realCurrentLocalDateTime(), true))
2249  setSimulatedSystemTime(dt);
2250  }
2251 }
2252 
2253 /******************************************************************************
2254 * Set the simulated system time.
2255 */
2256 void setSimulatedSystemTime(const KDateTime& dt)
2257 {
2258  KDateTime::setSimulatedSystemTime(dt);
2259  kDebug() << "New time =" << qPrintable(KDateTime::currentLocalDateTime().toString(QLatin1String("%Y-%m-%d %H:%M %:Z")));
2260 }
2261 #endif
2262 
2263 } // namespace KAlarm
2264 namespace
2265 {
2266 
2267 /******************************************************************************
2268 * Tell KOrganizer to put an alarm in its calendar.
2269 * It will be held by KOrganizer as a simple event, without alarms - KAlarm
2270 * is still responsible for alarming.
2271 */
2272 KAlarm::UpdateStatus sendToKOrganizer(const KAEvent& event)
2273 {
2274 #ifdef USE_AKONADI
2275  Event::Ptr kcalEvent(new KCalCore::Event);
2276  event.updateKCalEvent(kcalEvent, KAEvent::UID_IGNORE);
2277 #else
2278  Event* kcalEvent = AlarmCalendar::resources()->createKCalEvent(&event);
2279 #endif
2280  // Change the event ID to avoid duplicating the same unique ID as the original event
2281  QString uid = uidKOrganizer(event.id());
2282  kcalEvent->setUid(uid);
2283  kcalEvent->clearAlarms();
2284  QString userEmail;
2285  switch (event.actionTypes())
2286  {
2287  case KAEvent::ACT_DISPLAY:
2288  case KAEvent::ACT_COMMAND:
2289  case KAEvent::ACT_DISPLAY_COMMAND:
2290  kcalEvent->setSummary(event.cleanText());
2291  userEmail = Preferences::emailAddress();
2292  break;
2293  case KAEvent::ACT_EMAIL:
2294  {
2295  QString from = event.emailFromId()
2296  ? Identities::identityManager()->identityForUoid(event.emailFromId()).fullEmailAddr()
2297  : Preferences::emailAddress();
2298  AlarmText atext;
2299  atext.setEmail(event.emailAddresses(QLatin1String(", ")), from, QString(), QString(), event.emailSubject(), QString());
2300  kcalEvent->setSummary(atext.displayText());
2301  userEmail = from;
2302  break;
2303  }
2304  case KAEvent::ACT_AUDIO:
2305  kcalEvent->setSummary(event.audioFile());
2306  break;
2307  default:
2308  break;
2309  }
2310 #ifdef USE_AKONADI
2311  Person::Ptr person(new Person(QString(), userEmail));
2312  kcalEvent->setOrganizer(person);
2313 #else
2314  kcalEvent->setOrganizer(KCal::Person(QString(), userEmail));
2315 #endif
2316  kcalEvent->setDuration(Duration(Preferences::kOrgEventDuration() * 60, Duration::Seconds));
2317 
2318  // Translate the event into string format
2319  ICalFormat format;
2320  format.setTimeSpec(Preferences::timeZone(true));
2321  QString iCal = format.toICalString(kcalEvent);
2322 #ifndef USE_AKONADI
2323  delete kcalEvent;
2324 #endif
2325 
2326  // Send the event to KOrganizer
2327  KAlarm::UpdateStatus st = runKOrganizer(); // start KOrganizer if it isn't already running, and create its D-Bus interface
2328  if (st != KAlarm::UPDATE_OK)
2329  return st;
2330  QList<QVariant> args;
2331  args << iCal;
2332  QDBusReply<bool> reply = korgInterface->callWithArgumentList(QDBus::Block, QLatin1String("addIncidence"), args);
2333  if (!reply.isValid())
2334  {
2335  if (reply.error().type() == QDBusError::UnknownObject)
2336  {
2337  kError()<<"addIncidence() D-Bus error: still starting";
2338  return KAlarm::UPDATE_KORG_ERRSTART;
2339  }
2340  kError() << "addIncidence(" << uid << ") D-Bus call failed:" << reply.error().message();
2341  return KAlarm::UPDATE_KORG_ERR;
2342  }
2343  if (!reply.value())
2344  {
2345  kDebug() << "addIncidence(" << uid << ") D-Bus call returned false";
2346  return KAlarm::UPDATE_KORG_FUNCERR;
2347  }
2348  kDebug() << uid << ": success";
2349  return KAlarm::UPDATE_OK;
2350 }
2351 
2352 /******************************************************************************
2353 * Tell KOrganizer to delete an event from its calendar.
2354 */
2355 KAlarm::UpdateStatus deleteFromKOrganizer(const QString& eventID)
2356 {
2357  const QString newID = uidKOrganizer(eventID);
2358 #if defined(USE_AKONADI) && KDE_IS_VERSION(4,12,4) // kdepimlibs/kdepim-runtime 4.12.4 are required
2359  new CollectionSearch(KORG_MIME_TYPE, newID, true); // this auto-deletes when complete
2360  // Ignore errors
2361 #else
2362  KAlarm::UpdateStatus st = runKOrganizer(); // start KOrganizer if it isn't already running, and create its D-Bus interface
2363  if (st != KAlarm::UPDATE_OK)
2364  return st;
2365  QList<QVariant> args;
2366  args << newID << true;
2367  QDBusReply<bool> reply = korgInterface->callWithArgumentList(QDBus::Block, QLatin1String("deleteIncidence"), args);
2368  if (!reply.isValid())
2369  {
2370  if (reply.error().type() == QDBusError::UnknownObject)
2371  {
2372  kError()<<"deleteIncidence() D-Bus error: still starting";
2373  return KAlarm::UPDATE_KORG_ERRSTART;
2374  }
2375  kError() << "deleteIncidence(" << newID << ") D-Bus call failed:" << reply.error().message();
2376  return KAlarm::UPDATE_KORG_ERR;
2377  }
2378  if (!reply.value())
2379  {
2380  kDebug() << "deleteIncidence(" << newID << ") D-Bus call returned false";
2381  return KAlarm::UPDATE_KORG_FUNCERR;
2382  }
2383  kDebug() << newID << ": success";
2384 #endif
2385  return KAlarm::UPDATE_OK;
2386 }
2387 
2388 /******************************************************************************
2389 * Start KOrganizer if not already running, and create its D-Bus interface.
2390 */
2391 KAlarm::UpdateStatus runKOrganizer()
2392 {
2393  QString error, dbusService;
2394  int result = KDBusServiceStarter::self()->findServiceFor(QLatin1String("DBUS/Organizer"), QString(), &error, &dbusService);
2395  if (result)
2396  {
2397  kWarning() << "Unable to start DBUS/Organizer:" << dbusService << error;
2398  return KAlarm::UPDATE_KORG_ERR;
2399  }
2400  // If Kontact is running, there is be a load() method which needs to be called
2401  // to load KOrganizer into Kontact. But if KOrganizer is running independently,
2402  // the load() method doesn't exist.
2403  QDBusInterface iface(KORG_DBUS_SERVICE, QLatin1String(KORG_DBUS_LOAD_PATH), QLatin1String("org.kde.KUniqueApplication"));
2404  if (!iface.isValid())
2405  {
2406  kWarning() << "Unable to access "KORG_DBUS_LOAD_PATH" D-Bus interface:" << iface.lastError().message();
2407  return KAlarm::UPDATE_KORG_ERR;
2408  }
2409  QDBusReply<bool> reply = iface.call(QLatin1String("load"));
2410  if ((!reply.isValid() || !reply.value())
2411  && iface.lastError().type() != QDBusError::UnknownMethod)
2412  {
2413  kWarning() << "Loading KOrganizer failed:" << iface.lastError().message();
2414  return KAlarm::UPDATE_KORG_ERR;
2415  }
2416 
2417  // KOrganizer has been started, but it may not have the necessary
2418  // D-Bus interface available yet.
2419  if (!korgInterface || !korgInterface->isValid())
2420  {
2421  delete korgInterface;
2422  korgInterface = new QDBusInterface(KORG_DBUS_SERVICE, QLatin1String(KORG_DBUS_PATH), KORG_DBUS_IFACE);
2423  if (!korgInterface->isValid())
2424  {
2425  kWarning() << "Unable to access "KORG_DBUS_PATH" D-Bus interface:" << korgInterface->lastError().message();
2426  delete korgInterface;
2427  korgInterface = 0;
2428  return KAlarm::UPDATE_KORG_ERRSTART;
2429  }
2430  }
2431  return KAlarm::UPDATE_OK;
2432 }
2433 
2434 /******************************************************************************
2435 * Insert a KOrganizer string after the hyphen in the supplied event ID.
2436 */
2437 QString uidKOrganizer(const QString& id)
2438 {
2439  QString result = id;
2440  int i = result.lastIndexOf(QLatin1Char('-'));
2441  if (i < 0)
2442  i = result.length();
2443  return result.insert(i, KORGANIZER_UID);
2444 }
2445 
2446 } // namespace
2447 
2448 /******************************************************************************
2449 * Case insensitive comparison for use by qSort().
2450 */
2451 bool caseInsensitiveLessThan(const QString& s1, const QString& s2)
2452 {
2453  return s1.toLower() < s2.toLower();
2454 }
2455 
2456 // vim: et sw=4:
CollectionControlModel::getStandard
static Akonadi::Collection getStandard(CalEvent::Type, bool useDefault=false)
Return the standard collection for a specified mime type.
Definition: collectionmodel.cpp:991
KAlarmApp::setAlarmsEnabled
void setAlarmsEnabled(bool)
Definition: kalarmapp.cpp:1294
KProcess
AlarmCalendar::deleteEvent
bool deleteEvent(const QString &eventID, bool save=false)
Definition: alarmcalendar.cpp:1656
EditAlarmDlg::RES_PROMPT
Definition: editdlg.h:67
EventListModel::alarms
static EventListModel * alarms()
Definition: eventlistmodel.cpp:56
EditAlarmDlg::EMAIL
Definition: editdlg.h:65
AlarmCalendar::disabledChanged
void disabledChanged(const KAEvent *)
Definition: alarmcalendar.cpp:2131
KAlarmApp::alarmsEnabled
bool alarmsEnabled() const
Definition: kalarmapp.h:63
EditAlarmDlg::DISPLAY
Definition: editdlg.h:65
EditAlarmDlg::COMMAND
Definition: editdlg.h:65
KAlarm::Private::instance
static Private * instance()
Definition: functions_p.h:40
MessageWin::isAudioPlaying
static bool isAudioPlaying()
Definition: messagewin.cpp:1517
AlarmCalendar::eventReadOnly
bool eventReadOnly(const QString &uniqueID) const
Definition: alarmcalendar.cpp:2093
text
virtual QByteArray text(quint32 serialNumber) const =0
caseInsensitiveLessThan
bool caseInsensitiveLessThan(const QString &s1, const QString &s2)
Definition: functions.cpp:2451
AlarmCalendar::updateEvent
KAEvent * updateEvent(const KAEvent &)
Definition: alarmcalendar.cpp:1585
AlarmCalendar::resources
static AlarmCalendar * resources()
Definition: alarmcalendar.h:130
alarmtime.h
QWidget
ShellProcess::authorised
static bool authorised()
KAMessageBox::error
static void error(QWidget *parent, const QString &text, const QString &caption=QString(), Options options=Options(Notify|WindowModal))
AlarmCalendar::reload
bool reload()
Definition: alarmcalendar.cpp:401
functions_p.h
editdlg.h
AlarmCalendar::addEvent
bool addEvent(KAEvent *, QWidget *promptParent=0, bool useEventID=false, AlarmResource *=0, bool noPrompt=false, bool *cancelled=0)
Definition: alarmcalendar.cpp:1261
Undo::saveEdit
static void saveEdit(const Event &oldEvent, const KAEvent &newEvent)
Definition: undo.cpp:329
alarmcalendar.h
PreferencesBase::kOrgEventDuration
static int kOrgEventDuration()
Get KOrganizer event duration.
Definition: kalarmconfig.h:953
EventListModel::removeEvent
void removeEvent(const KAEvent *event)
Definition: eventlistmodel.h:76
from
QString from() const
QObject
MainWindow::firstWindow
static MainWindow * firstWindow()
Definition: mainwindow.h:100
AlarmCalendar::templateEvent
KAEvent * templateEvent(const QString &templateName)
Definition: alarmcalendar.cpp:1871
Undo::Event
Definition: undo.h:51
PreferencesBase::archivedKeepDays
static int archivedKeepDays()
Get Days to keep expired alarms.
Definition: kalarmconfig.h:926
KAlarm::Private::startKMailMinimised
static bool startKMailMinimised()
Definition: functions.cpp:1845
KFileDialog
AlarmCalendar::getEvent
static KAEvent * getEvent(const QString &uniqueId)
Definition: alarmcalendar.cpp:150
kalarmapp.h
the KAlarm application object
AlarmTime::convertTimeString
static bool convertTimeString(const QByteArray &timeString, KDateTime &dateTime, const KDateTime &defaultDt=KDateTime(), bool allowTZ=true)
Definition: alarmtime.cpp:111
MessageWin
MessageWin: A window to display an alarm or error message.
Definition: messagewin.h:61
AlarmCalendar::modifyEvent
bool modifyEvent(const QString &oldEventId, KAEvent *newEvent)
Definition: alarmcalendar.cpp:1507
CollectionControlModel::instance
static CollectionControlModel * instance()
Definition: collectionmodel.cpp:653
AlarmCalendar::purgeEvents
void purgeEvents(const KAEvent::List &)
Definition: alarmcalendar.cpp:1229
KAlarm::Private::cancelRtcWake
void cancelRtcWake()
Definition: functions.cpp:1402
autoqpointer.h
Preferences::timeZone
static KTimeZone timeZone(bool reload=false)
Definition: preferences.cpp:122
CollectionControlModel::destination
static Akonadi::Collection destination(CalEvent::Type, QWidget *promptParent=0, bool noPrompt=false, bool *cancelled=0)
Find the collection to be used to store an event of a given type.
Definition: collectionmodel.cpp:1178
MainWindow::selectEvent
void selectEvent(const QString &eventID)
Definition: mainwindow.cpp:704
KAlarm::Private::mMsgParent
QWidget * mMsgParent
Definition: functions_p.h:47
EditAlarmDlg::setAction
virtual void setAction(KAEvent::SubAction, const AlarmText &=AlarmText())=0
messagewin.h
displays an alarm message
mainwindow.h
main application window
eventlistmodel.h
KAlarmApp::checkCalendar
bool checkCalendar()
Definition: kalarmapp.h:61
EditAlarmDlg::create
static EditAlarmDlg * create(bool Template, Type, QWidget *parent=0, GetResourceType=RES_PROMPT)
Definition: editdlg.cpp:106
EditAlarmDlg::getEvent
bool getEvent(KAEvent &, AlarmResource *&)
Definition: editdlg.cpp:743
KAMail::i18n_NeedFromEmailAddress
static QString i18n_NeedFromEmailAddress()
Definition: kamail.cpp:90
MainWindow::create
static MainWindow * create(bool restored=false)
Definition: mainwindow.cpp:137
messagebox.h
theApp
KAlarmApp * theApp()
Definition: kalarmapp.h:259
MessageWin::findEvent
static MessageWin * findEvent(const QString &eventId)
Definition: messagewin.cpp:1417
AlarmCalendar::createKCalEvent
KCal::Event * createKCalEvent(const KAEvent *e) const
Definition: alarmcalendar.h:85
AutoQPointer
preferences.h
CollectionControlModel::enabledCollections
static Akonadi::Collection::List enabledCollections(CalEvent::Type, bool writable)
Return the enabled collections which contain a specified mime type.
Definition: collectionmodel.cpp:1227
EventListModel::templates
static EventListModel * templates()
Definition: eventlistmodel.cpp:69
templatemenuaction.h
EventListModel::updateEvent
bool updateEvent(KAEvent *event)
Definition: eventlistmodel.h:73
KAlarm::PrivateNewAlarmDlg::accept
void accept(EditAlarmDlg *)
Definition: functions.cpp:1263
Undo::saveAdd
static void saveAdd(const KAEvent &, AlarmResource *, const QString &name=QString())
Definition: undo.cpp:311
collectionmodel.h
kamail.h
EventId
Unique event identifier for Akonadi.
Definition: eventid.h:38
KAMessageBox::warningContinueCancel
static int warningContinueCancel(QWidget *parent, ButtonCode defaultButton, const QString &text, const QString &caption=QString(), const KGuiItem &buttonContinue=KStandardGuiItem::cont(), const QString &dontAskAgainName=QString())
KAMessageBox::warningYesNo
static int warningYesNo(QWidget *parent, const QString &text, const QString &caption=QString(), const KGuiItem &buttonYes=KStandardGuiItem::yes(), const KGuiItem &buttonNo=KStandardGuiItem::no(), const QString &dontAskAgainName=QString(), Options options=Options(Notify|Dangerous|WindowModal))
EditAlarmDlg::Type
Type
Definition: editdlg.h:65
functions.h
miscellaneous functions
KAMessageBox::sorry
static void sorry(QWidget *parent, const QString &text, const QString &caption=QString(), Options options=Options(Notify|WindowModal))
EditAlarmDlg
Definition: editdlg.h:61
KORG_DBUS_LOAD_PATH
#define KORG_DBUS_LOAD_PATH
Definition: functions.cpp:118
Preferences::emailAddress
static QString emailAddress()
Definition: preferences.cpp:227
alarmlistview.h
EditAlarmDlg::RES_USE_EVENT_ID
Definition: editdlg.h:68
kalarm.h
KORG_DBUS_PATH
#define KORG_DBUS_PATH
Definition: functions.cpp:117
MainWindow::refresh
static void refresh()
Definition: mainwindow.cpp:676
AlarmCalendar
Provides read and write access to calendar files and resources.
Definition: alarmcalendar.h:58
AlarmCalendar::displayCalendarOpen
static AlarmCalendar * displayCalendarOpen()
Definition: alarmcalendar.cpp:130
AlarmCalendar::events
KAEvent::List events(CalEvent::Types s=CalEvent::EMPTY) const
Definition: alarmcalendar.h:96
shellprocess.h
EditAlarmDlg::AUDIO
Definition: editdlg.h:65
AlarmCalendar::event
KAEvent * event(const QString &uniqueId)
Definition: alarmcalendar.cpp:1820
AlarmCalendar::save
bool save()
Definition: alarmcalendar.cpp:1212
MainWindow::show
virtual void show()
Definition: mainwindow.cpp:429
MainWindow::mainMainWindow
static MainWindow * mainMainWindow()
Definition: mainwindow.cpp:288
MainWindow
Definition: mainwindow.h:71
collectionsearch.h
AlarmListModel
Definition: itemlistmodel.h:87
KAlarm::Private::windowAdded
void windowAdded(WId)
Definition: functions.cpp:1892
KAlarmApp::processQueue
void processQueue()
Definition: kalarmapp.cpp:871
AlarmListModel::TimeColumn
Definition: itemlistmodel.h:92
EventListModel::addEvent
void addEvent(KAEvent *)
Definition: eventlistmodel.cpp:726
QList
templatelistview.h
KAMessageBox::information
static void information(QWidget *parent, const QString &text, const QString &caption=QString(), const QString &dontShowAgainName=QString(), Options options=Options(Notify|WindowModal))
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:59:10 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

kalarm

Skip menu "kalarm"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members

kdepim API Reference

Skip menu "kdepim API Reference"
  • akonadi_next
  • akregator
  • blogilo
  • calendarsupport
  • console
  •   kabcclient
  •   konsolekalendar
  • kaddressbook
  • kalarm
  •   lib
  • kdgantt2
  • kjots
  • kleopatra
  • kmail
  • knode
  • knotes
  • kontact
  • korgac
  • korganizer
  • ktimetracker
  • libkdepim
  • libkleo
  • libkpgp
  • mailcommon
  • messagelist
  • messageviewer

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal