22 #include "kalarmapp.moc"
47 #include "kspeechinterface.h"
49 #include <kalarmcal/datetime.h>
50 #include <kalarmcal/karecurrence.h>
53 #include <kstandarddirs.h>
55 #include <kaboutdata.h>
56 #include <ktemporaryfile.h>
57 #include <kfileitem.h>
59 #include <kstandardguiitem.h>
60 #include <kservicetypetrader.h>
62 #include <ktoolinvocation.h>
66 #include <ksystemtrayicon.h>
67 #include <ksystemtimezone.h>
74 #include <QTextStream>
75 #include <QtDBus/QtDBus>
86 static const int AKONADI_TIMEOUT = 30;
99 static const int LATENESS_LEEWAY = 5;
100 int lc = (lateCancel >= 1) ? (lateCancel - 1)*60 : 0;
101 return LATENESS_LEEWAY + lc;
106 int KAlarmApp::mActiveCount = 0;
107 int KAlarmApp::mFatalError = 0;
108 QString KAlarmApp::mFatalMessage;
119 mLoginAlarmsDone(false),
123 mArchivedPurgeDays(-1),
124 mPurgeDaysQueued(-1),
127 mCancelRtcWake(false),
128 mProcessingQueue(false),
129 mSessionClosingDown(false),
130 mAlarmsEnabled(true),
131 mSpeechEnabled(false)
133 KGlobal::locale()->insertCatalog(QLatin1String(
"libkdepim"));
134 KGlobal::locale()->insertCatalog(QLatin1String(
"libkpimutils"));
137 KAlarm::setTestModeConditions();
140 setQuitOnLastWindowClosed(
false);
148 Preferences::connect(SIGNAL(workTimeChanged(QTime,QTime,QBitArray)),
this, SLOT(slotWorkTimeChanged(QTime,QTime,QBitArray)));
149 Preferences::connect(SIGNAL(holidaysChanged(KHolidays::HolidayRegion)),
this, SLOT(slotHolidaysChanged(KHolidays::HolidayRegion)));
151 Preferences::connect(SIGNAL(showInSystemTrayChanged(
bool)),
this, SLOT(slotShowInSystemTrayChanged()));
153 Preferences::connect(SIGNAL(messageFontChanged(QFont)),
this, SLOT(slotMessageFontChanged(QFont)));
156 connect(QDBusConnection::sessionBus().interface(), SIGNAL(serviceUnregistered(QString)),
157 SLOT(slotDBusServiceUnregistered(QString)));
166 SLOT(purgeNewArchivedDefault(Akonadi::Collection)));
168 SLOT(checkWritableCalendar()));
170 SLOT(checkWritableCalendar()));
173 KConfigGroup config(KGlobal::config(),
"General");
174 mNoSystemTray = config.readEntry(
"NoSystemTray",
false);
181 mSpeechEnabled = (KServiceTypeTrader::self()->query(QLatin1String(
"DBUS/Text-to-Speech"), QLatin1String(
"Name == 'KTTSD'")).count() > 0);
182 if (!mSpeechEnabled) { kDebug() <<
"Speech synthesis disabled (KTTSD not found)"; }
184 const QString korg = QLatin1String(
"korganizer");
185 mKOrganizerEnabled = !KStandardDirs::locate(
"exe", korg).isNull() || !KStandardDirs::findExe(korg).isNull();
186 if (!mKOrganizerEnabled) { kDebug() <<
"KOrganizer options disabled (KOrganizer not found)"; }
193 while (!mCommandProcesses.isEmpty())
195 ProcData* pd = mCommandProcesses[0];
196 mCommandProcesses.pop_front();
213 theInstance->quitFatal();
226 bool KAlarmApp::initialise()
230 mAlarmTimer =
new QTimer(
this);
231 mAlarmTimer->setSingleShot(
true);
232 connect(mAlarmTimer, SIGNAL(timeout()), SLOT(checkNextDueAlarm()));
236 kDebug() <<
"initialising calendars";
254 if (!isSessionRestored())
263 kDebug() <<
"Restoring";
269 kapp->sessionConfig();
278 if (!initCheck(
true))
285 for (
int i = 1; KMainWindow::canBeRestored(i); ++i)
287 QString type = KMainWindow::classNameOfToplevel(i);
288 if (type == QLatin1String(
"MainWindow"))
291 win->restore(i,
false);
297 else if (type == QLatin1String(
"MessageWin"))
300 win->restore(i,
false);
312 kWarning() <<
"no main window to be restored!?";
328 QTimer::singleShot(0,
this, SLOT(checkKtimezoned()));
348 static bool firstInstance =
true;
349 bool dontRedisplay =
false;
350 if (!firstInstance || !isSessionRestored())
370 if (!initCheck(
true,
true, options.
eventId().collectionId()))
372 if (!initCheck(
true))
378 dontRedisplay =
true;
380 if (!handleEvent(options.
eventId(),
function,
true))
382 if (!handleEvent(options.
eventId(),
function))
401 if (!initCheck(
true,
true))
403 if (!initCheck(
true))
408 dontRedisplay =
true;
409 QStringList alarms = scheduledAlarmList();
410 for (
int i = 0, count = alarms.count(); i < count; ++i)
411 std::cout << alarms[i].toUtf8().constData() << std::endl;
418 if (!initCheck(
false,
true, options.
eventId().collectionId()))
423 else if (!KAlarm::editAlarmById(options.
eventId()))
449 else if (options.
flags() & KAEvent::REPEAT_AT_LOGIN)
450 editDlg->setRepeatAtLogin();
451 editDlg->setAction(options.
editAction(), AlarmText(options.
text()));
454 if (options.
flags() & KAEvent::COPY_KORGANIZER)
455 editDlg->setShowInKOrganizer(
true);
467 || options.
flags() & (KAEvent::BEEP | KAEvent::SPEAK))
469 KAEvent::Flags flags = options.
flags();
477 if (options.
flags() & KAEvent::CONFIRM_ACK)
479 if (options.
flags() & KAEvent::AUTO_CLOSE)
491 || !options.
subject().isEmpty()
494 if (options.
flags() & KAEvent::EMAIL_BCC)
509 KAlarm::execNewAlarmDlg(editDlg);
556 win->setWindowState(win->windowState() | Qt::WindowMinimized);
570 if (firstInstance && !dontRedisplay && !exitCode)
583 firstInstance =
false;
591 QTimer::singleShot(0,
this, SLOT(checkKtimezoned()));
596 void KAlarmApp::checkKtimezoned()
599 static bool done =
false;
603 #if KDE_IS_VERSION(4,5,70)
604 if (!KSystemTimeZones::isTimeZoneDaemonAvailable())
606 kDebug() <<
"ktimezoned not running: using UTC only";
608 i18nc(
"@info",
"Time zones are not accessible:<nl/>KAlarm will use the UTC time zone.<nl/><nl/>(The KDE time zone service is not available:<nl/>check that <application>ktimezoned</application> is installed.)"),
609 QString(), QLatin1String(
"tzunavailable"));
635 mPendingQuit =
false;
640 if (mwcount > 1 || (mwcount && (!mw->isHidden() || !mw->
isTrayParent())))
648 if (checkSystemTray())
651 if (!mActionQueue.isEmpty() || !mCommandProcesses.isEmpty())
655 mPendingQuitCode = exitCode;
664 kDebug() << exitCode <<
": quitting";
668 KAlarm::setRtcWakeTime(0, 0);
669 KAlarm::deleteRtcWakeConfig();
673 mInitialised =
false;
688 i18nc(
"@info",
"Quitting will disable alarms (once any alarm message windows are closed)."),
690 ) != KMessageBox::Yes)
692 if (!KAlarm::checkRtcWakeConfig(
true).isEmpty())
696 i18nc(
"@info",
"Quitting will cancel the scheduled Wake from Suspend."),
697 QString(), KStandardGuiItem::quit()
698 ) != KMessageBox::Yes)
700 mCancelRtcWake =
true;
704 int option = KMessageBox::No;
708 i18nc(
"@info",
"Do you want to start KAlarm at login?<nl/>"
709 "(Note that alarms will be disabled if KAlarm is not started.)"),
710 QString(), KStandardGuiItem::yes(), KStandardGuiItem::no(),
715 case KMessageBox::Yes:
719 case KMessageBox::No:
722 case KMessageBox::Cancel:
736 mSessionClosingDown =
true;
737 KUniqueApplication::commitData(sm);
738 mSessionClosingDown =
false;
750 mFatalMessage = message;
752 QTimer::singleShot(0, theInstance, SLOT(quitFatal()));
759 void KAlarmApp::quitFatal()
768 KMessageBox::error(0, mFatalMessage);
773 theInstance->
quitIf(1,
true);
776 QTimer::singleShot(1000,
this, SLOT(quitFatal()));
784 void KAlarmApp::checkNextDueAlarm()
792 KDateTime nextDt = nextEvent->nextTrigger(KAEvent::ALL_TRIGGER).effectiveKDateTime();
794 qint64 interval = now.secsTo_long(nextDt);
795 kDebug() <<
"now:" << qPrintable(now.toString(QLatin1String(
"%Y-%m-%d %H:%M %:Z"))) <<
", next:" << qPrintable(nextDt.toString(QLatin1String(
"%Y-%m-%d %H:%M %:Z"))) <<
", due:" << interval;
799 queueAlarmId(*nextEvent);
800 kDebug() << nextEvent->id() <<
": due now";
807 #ifndef HIBERNATION_SIGNAL
820 if (interval > INT_MAX)
822 kDebug() << nextEvent->id() <<
"wait" << interval/1000 <<
"seconds";
823 mAlarmTimer->start(static_cast<int>(interval));
832 void KAlarmApp::queueAlarmId(
const KAEvent& event)
837 const QString id(event.id());
839 for (
int i = 0, end = mActionQueue.count(); i < end; ++i)
841 if (mActionQueue[i].
function == EVENT_HANDLE && mActionQueue[i].eventId ==
id)
844 mActionQueue.enqueue(ActionQEntry(EVENT_HANDLE,
id));
850 void KAlarmApp::startProcessQueue()
873 if (mInitialised && !mProcessingQueue)
876 mProcessingQueue =
true;
879 KAlarm::refreshAlarmsIfQueued();
881 if (!mLoginAlarmsDone)
887 for (
int i = 0, end = events.count(); i < end; ++i)
889 KAEvent
event = *events[i];
890 if (!cancelReminderAndDeferral(event))
896 mLoginAlarmsDone =
true;
900 while (!mActionQueue.isEmpty())
902 ActionQEntry& entry = mActionQueue.head();
903 if (entry.eventId.isEmpty())
906 switch (entry.function)
909 execAlarm(entry.event, entry.event.firstAlarm(),
false);
912 KAlarm::addEvent(entry.event, 0, 0, KAlarm::ALLOW_KORG_UPDATE | KAlarm::NO_RESOURCE_PROMPT);
919 handleEvent(entry.eventId, entry.function);
920 mActionQueue.dequeue();
924 if (mPurgeDaysQueued >= 0)
926 KAlarm::purgeArchive(mPurgeDaysQueued);
927 mPurgeDaysQueued = -1;
933 if (
quitIf(mPendingQuitCode))
937 mProcessingQueue =
false;
951 void KAlarmApp::atLoginEventAdded(
const KAEvent& event)
954 if (!cancelReminderAndDeferral(ev))
958 mActionQueue.enqueue(ActionQEntry(EVENT_HANDLE,
EventId(ev)));
980 static bool creating =
false;
983 if (!mTrayWindow && !creating)
985 if (!KSystemTrayIcon::isSystemTrayAvailable())
996 mTrayWindow =
new TrayWindow(parent ? parent : MainWindow::firstWindow());
1000 if (!checkSystemTray())
1015 bool KAlarmApp::checkSystemTray()
1019 if (KSystemTrayIcon::isSystemTrayAvailable() == mNoSystemTray)
1021 kDebug() <<
"changed ->" << mNoSystemTray;
1022 mNoSystemTray = !mNoSystemTray;
1026 KConfigGroup config(KGlobal::config(),
"General");
1027 config.writeEntry(
"NoSystemTray", mNoSystemTray);
1031 slotShowInSystemTrayChanged();
1033 return !mNoSystemTray;
1048 void KAlarmApp::slotShowInSystemTrayChanged()
1051 if (newShowInSysTray != mOldShowInSystemTray)
1058 mOldShowInSystemTray = newShowInSysTray;
1059 if (newShowInSysTray)
1067 if (win && win->isHidden())
1073 win->setWindowState(win->windowState() | Qt::WindowMinimized);
1086 void KAlarmApp::changeStartOfDay()
1097 void KAlarmApp::slotMessageFontChanged(
const QFont& font)
1099 KAEvent::setDefaultFont(font);
1106 void KAlarmApp::slotWorkTimeChanged(
const QTime& start,
const QTime& end,
const QBitArray& days)
1108 KAEvent::setWorkTime(days, start, end);
1115 void KAlarmApp::slotHolidaysChanged(
const KHolidays::HolidayRegion& holidays)
1117 KAEvent::setHolidays(holidays);
1126 KARecurrence::Feb29Type rtype;
1134 KARecurrence::setDefaultFeb29Type(rtype);
1150 void KAlarmApp::checkWritableCalendar()
1160 static bool done =
false;
1164 kDebug()<<
"checking";
1169 bool active = AlarmResources::instance()->activeCount(CalEvent::ACTIVE,
true);
1173 kWarning() <<
"No writable active calendar";
1175 i18nc(
"@info",
"Alarms cannot be created or updated, because no writable active alarm calendar is enabled.<nl/><nl/>"
1176 "To fix this, use <interface>View | Show Calendars</interface> to check or change calendar statuses."),
1177 QString(), QLatin1String(
"noWritableCal"));
1187 void KAlarmApp::purgeNewArchivedDefault(
const Akonadi::Collection& collection)
1189 Akonadi::Collection col(collection);
1194 kDebug() << collection.id() <<
": standard archived...";
1195 QTimer::singleShot(60000,
this, SLOT(purgeAfterDelay()));
1204 void KAlarmApp::purgeAfterDelay()
1206 if (mArchivedPurgeDays >= 0)
1207 purge(mArchivedPurgeDays);
1209 setArchivePurgeDays();
1219 void KAlarmApp::setArchivePurgeDays()
1222 if (newDays != mArchivedPurgeDays)
1224 int oldDays = mArchivedPurgeDays;
1225 mArchivedPurgeDays = newDays;
1226 if (mArchivedPurgeDays <= 0)
1228 if (mArchivedPurgeDays < 0)
1230 if (oldDays < 0 || mArchivedPurgeDays < oldDays)
1233 purge(mArchivedPurgeDays);
1234 if (!mArchivedPurgeDays)
1247 void KAlarmApp::purge(
int daysToKeep)
1249 if (mPurgeDaysQueued < 0 || daysToKeep < mPurgeDaysQueued)
1250 mPurgeDaysQueued = daysToKeep;
1260 QStringList KAlarmApp::scheduledAlarmList()
1263 QVector<KAEvent> events = KAlarm::getSortedActiveEvents(
this);
1265 KAEvent::List events = KAlarm::getSortedActiveEvents();
1268 for (
int i = 0, count = events.count(); i < count; ++i)
1271 KAEvent*
event = &events[i];
1273 KAEvent*
event = events[i];
1275 KDateTime dateTime =
event->nextTrigger(KAEvent::DISPLAY_TRIGGER).effectiveKDateTime().toLocalZone();
1277 Akonadi::Collection c(event->collectionId());
1279 QString
text(c.resource() + QLatin1String(
":"));
1283 text +=
event->id() + QLatin1Char(
' ')
1284 + dateTime.toString(QLatin1String(
"%Y%m%dT%H%M "))
1285 + AlarmText::summary(*event, 1);
1296 if (enabled != mAlarmsEnabled)
1298 mAlarmsEnabled = enabled;
1301 KAlarm::cancelRtcWake(0);
1302 else if (!mProcessingQueue)
1303 checkNextDueAlarm();
1331 int lateCancel, KAEvent::Flags flags,
const QColor& bg,
const QColor& fg,
1332 const QFont& font,
const QString& audioFile,
float audioVolume,
int reminderMinutes,
1333 const KARecurrence& recurrence,
int repeatInterval,
int repeatCount,
1335 uint mailFromID,
const KCalCore::Person::List& mailAddresses,
1339 const QString& mailSubject,
const QStringList& mailAttachments)
1342 if (!dateTime.isValid())
1344 KDateTime now = KDateTime::currentUtcDateTime();
1345 if (lateCancel && dateTime < now.addSecs(-
maxLateness(lateCancel)))
1347 KDateTime alarmTime = dateTime;
1349 if (!dateTime.isDateOnly())
1350 alarmTime.setTime(QTime(alarmTime.time().hour(), alarmTime.time().minute(), 0));
1352 KAEvent event(alarmTime, text, bg, fg, font, action, lateCancel, flags,
true);
1353 if (reminderMinutes)
1355 bool onceOnly = flags & KAEvent::REMINDER_ONCE;
1356 event.setReminder(reminderMinutes, onceOnly);
1358 if (!audioFile.isEmpty())
1359 event.setAudioFile(audioFile, audioVolume, -1, 0, (flags & KAEvent::REPEAT_SOUND) ? 0 : -1);
1360 if (!mailAddresses.isEmpty())
1361 event.setEmail(mailFromID, mailAddresses, mailSubject, mailAttachments);
1362 event.setRecurrence(recurrence);
1363 event.setFirstRecurrence();
1364 event.setRepetition(Repetition(repeatInterval, repeatCount - 1));
1366 if (alarmTime <= now)
1371 mActionQueue.enqueue(ActionQEntry(event, EVENT_TRIGGER));
1373 execAlarm(event, event.firstAlarm(),
false);
1376 ||
event.setNextOccurrence(now) == KAEvent::NO_OCCURRENCE)
1382 mActionQueue.enqueue(ActionQEntry(event));
1394 bool KAlarmApp::dbusHandleEvent(
const EventId& eventID, EventFunc
function)
1396 bool KAlarmApp::dbusHandleEvent(
const QString& eventID, EventFunc
function)
1399 kDebug() << eventID;
1400 mActionQueue.append(ActionQEntry(
function, eventID));
1402 QTimer::singleShot(0,
this, SLOT(processQueue()));
1412 return scheduledAlarmList().join(QLatin1String(
"\n")) + QLatin1Char(
'\n');
1426 bool KAlarmApp::handleEvent(
const EventId&
id, EventFunc
function,
bool checkDuplicates)
1428 bool KAlarmApp::handleEvent(
const QString& eventID, EventFunc
function)
1432 KAlarm::checkRtcWakeConfig();
1435 const QString eventID(
id.eventId());
1439 if (
id.collectionId() != -1)
1440 kWarning() <<
"Event ID not found, or duplicated:" << eventID;
1442 kWarning() <<
"Event ID not found:" << eventID;
1449 kWarning() <<
"Event ID not found:" << eventID;
1456 kDebug() << eventID <<
", CANCEL";
1457 KAlarm::deleteEvent(*event,
true);
1463 KDateTime now = KDateTime::currentUtcDateTime();
1464 kDebug() << eventID <<
"," << (
function==EVENT_TRIGGER?
"TRIGGER:":
"HANDLE:") << qPrintable(now.dateTime().toString(QLatin1String(
"yyyy-MM-dd hh:mm"))) <<
"UTC";
1465 bool updateCalAndDisplay =
false;
1466 bool alarmToExecuteValid =
false;
1467 KAAlarm alarmToExecute;
1468 bool restart =
false;
1471 for (KAAlarm alarm = event->firstAlarm();
1473 alarm = (restart ?
event->firstAlarm() :
event->nextAlarm(alarm)), restart =
false)
1476 KDateTime nextDT = alarm.dateTime(
true).effectiveKDateTime();
1477 int secs = nextDT.secsTo(now);
1483 if (alarm.dateTime().timeSpec() != KDateTime::ClockTime
1484 || nextDT > now.toTimeSpec(KDateTime::ClockTime))
1487 kDebug() <<
"Alarm" << alarm.type() <<
"at" << nextDT.dateTime() <<
": not due";
1491 bool reschedule =
false;
1492 bool rescheduleWork =
false;
1493 if ((event->workTimeOnly() ||
event->holidaysExcluded()) && !alarm.deferred())
1498 if (alarm.dateTime().isDateOnly())
1500 KDateTime dt(nextDT);
1501 dt.setDateOnly(
true);
1502 reschedule = !
event->isWorkingTime(dt);
1505 reschedule = !
event->isWorkingTime(nextDT);
1506 rescheduleWork = reschedule;
1508 kDebug() <<
"Alarm" << alarm.type() <<
"at" << nextDT.dateTime() <<
": not during working hours";
1510 if (!reschedule && alarm.repeatAtLogin())
1513 kDebug() <<
"REPEAT_AT_LOGIN";
1516 if (alarmToExecute.isValid())
1522 if (!reschedule && event->lateCancel())
1525 kDebug() <<
"LATE_CANCEL";
1526 bool cancel =
false;
1527 if (alarm.dateTime().isDateOnly())
1530 int maxlate =
event->lateCancel() / 1440;
1531 KDateTime limit(DateTime(nextDT.addDays(maxlate + 1)).effectiveKDateTime());
1537 KAEvent::OccurType type =
event->previousOccurrence(now, next,
true);
1538 switch (type & ~KAEvent::OCCURRENCE_REPEAT)
1540 case KAEvent::FIRST_OR_ONLY_OCCURRENCE:
1541 case KAEvent::RECURRENCE_DATE:
1542 case KAEvent::RECURRENCE_DATE_TIME:
1543 case KAEvent::LAST_RECURRENCE:
1544 limit.setDate(next.date().addDays(maxlate + 1));
1547 if (type == KAEvent::LAST_RECURRENCE
1548 || (type == KAEvent::FIRST_OR_ONLY_OCCURRENCE && !event->recurs()))
1554 case KAEvent::NO_OCCURRENCE:
1570 KAEvent::OccurType type =
event->previousOccurrence(now, next,
true);
1571 switch (type & ~KAEvent::OCCURRENCE_REPEAT)
1573 case KAEvent::FIRST_OR_ONLY_OCCURRENCE:
1574 case KAEvent::RECURRENCE_DATE:
1575 case KAEvent::RECURRENCE_DATE_TIME:
1576 case KAEvent::LAST_RECURRENCE:
1577 if (next.effectiveKDateTime().secsTo(now) > maxlate)
1579 if (type == KAEvent::LAST_RECURRENCE
1580 || (type == KAEvent::FIRST_OR_ONLY_OCCURRENCE && !event->recurs()))
1586 case KAEvent::NO_OCCURRENCE:
1597 event->setArchive();
1598 if (cancelAlarm(*event, alarm.type(),
false))
1600 updateCalAndDisplay =
true;
1607 switch (rescheduleAlarm(*event, alarm,
false, (rescheduleWork ? nextDT : KDateTime())))
1613 alarmToExecuteValid =
false;
1621 updateCalAndDisplay =
true;
1624 if (!alarmToExecuteValid)
1626 kDebug() <<
"Alarm" << alarm.type() <<
": execute";
1627 alarmToExecute = alarm;
1628 alarmToExecuteValid =
true;
1631 kDebug() <<
"Alarm" << alarm.type() <<
": skip";
1636 if (alarmToExecute.isValid())
1637 execAlarm(*event, alarmToExecute,
true, !alarmToExecute.repeatAtLogin());
1640 if (
function == EVENT_TRIGGER)
1645 KAAlarm alarm =
event->firstAlarm();
1646 if (alarm.isValid())
1647 execAlarm(*event, alarm,
false);
1649 if (updateCalAndDisplay)
1650 KAlarm::updateEvent(*event);
1651 else if (
function != EVENT_TRIGGER) { kDebug() <<
"No action"; }
1664 if (!event.postAction().isEmpty())
1668 QString command =
event.postAction();
1669 kDebug() <<
event.id() <<
":" << command;
1670 doShellCommand(command, event, 0, ProcData::POST_ACTION);
1687 kDebug() <<
"Alarm type:" << alarm.type();
1689 bool update =
false;
1690 event.startChanges();
1691 if (alarm.repeatAtLogin())
1694 if (!event.reminderActive() &&
event.reminderMinutes() < 0)
1698 event.activateReminderAfter(KDateTime::currentUtcDateTime());
1702 else if (alarm.isReminder() || alarm.deferred())
1705 event.removeExpiredAlarm(alarm.type());
1711 bool cancelled =
false;
1712 DateTime last =
event.mainDateTime(
false);
1713 if (last != event.mainDateTime(
true))
1715 bool next = nextDt.isValid();
1716 KDateTime next_dt = nextDt;
1717 KDateTime now = KDateTime::currentUtcDateTime();
1720 KAEvent::OccurType type =
event.setNextOccurrence(next ? next_dt : now);
1723 case KAEvent::NO_OCCURRENCE:
1725 kDebug() <<
"No occurrence";
1726 if (event.reminderMinutes() < 0 && last.isValid()
1727 && alarm.type() != KAAlarm::AT_LOGIN_ALARM && !
event.mainExpired())
1731 event.activateReminderAfter(last);
1732 updateCalAndDisplay =
true;
1734 if (cancelAlarm(event, alarm.type(), updateCalAndDisplay))
1738 if (!(type & KAEvent::OCCURRENCE_REPEAT))
1741 case KAEvent::RECURRENCE_DATE:
1742 case KAEvent::RECURRENCE_DATE_TIME:
1743 case KAEvent::LAST_RECURRENCE:
1745 if (updateCalAndDisplay)
1748 case KAEvent::FIRST_OR_ONLY_OCCURRENCE:
1754 if (event.deferred())
1757 event.removeExpiredAlarm(KAAlarm::DEFERRED_ALARM);
1764 next_dt =
event.mainDateTime(
true).effectiveKDateTime();
1765 if (event.mainDateTime(
false).isDateOnly())
1767 KDateTime dt(next_dt);
1768 dt.setDateOnly(
true);
1769 next = !
event.isWorkingTime(dt);
1772 next = !
event.isWorkingTime(next_dt);
1774 }
while (next && next_dt <= now);
1775 reply = (!cancelled && next_dt.isValid() && (next_dt <= now)) ? 1 : 0;
1777 if (event.reminderMinutes() < 0 && last.isValid()
1778 && alarm.type() != KAAlarm::AT_LOGIN_ALARM)
1782 event.activateReminderAfter(last);
1787 KAlarm::updateEvent(event);
1796 bool KAlarmApp::cancelAlarm(KAEvent& event, KAAlarm::Type alarmType,
bool updateCalAndDisplay)
1799 if (alarmType == KAAlarm::MAIN_ALARM && !event.displaying() &&
event.toBeArchived())
1803 KAlarm::addArchivedEvent(ev);
1805 event.removeExpiredAlarm(alarmType);
1806 if (!event.alarmCount())
1808 KAlarm::deleteEvent(event,
false);
1811 if (updateCalAndDisplay)
1812 KAlarm::updateEvent(event);
1823 bool KAlarmApp::cancelReminderAndDeferral(KAEvent& event)
1825 return cancelAlarm(event, KAAlarm::REMINDER_ALARM,
false)
1826 || cancelAlarm(event, KAAlarm::DEFERRED_REMINDER_ALARM,
false)
1827 || cancelAlarm(event, KAAlarm::DEFERRED_ALARM,
true);
1838 void*
KAlarmApp::execAlarm(KAEvent& event,
const KAAlarm& alarm,
bool reschedule,
bool allowDefer,
bool noPreAction)
1840 if (!mAlarmsEnabled || !event.enabled())
1843 kDebug() <<
event.id() <<
": disabled";
1849 void* result = (
void*)1;
1852 switch (alarm.action())
1854 case KAAlarm::COMMAND:
1855 if (!event.commandDisplay())
1865 case KAAlarm::MESSAGE:
1876 bool reminder = (alarm.type() & KAAlarm::REMINDER_ALARM);
1877 bool replaceReminder = !reminder && win && (win->
alarmType() & KAAlarm::REMINDER_ALARM);
1879 && (!event.deferred() || (
event.extraActionOptions() & KAEvent::ExecPreActOnDeferral))
1880 && (replaceReminder || !win) && !noPreAction
1881 && !event.preAction().isEmpty())
1891 for (
int i = 0, end = mCommandProcesses.count(); i < end; ++i)
1893 ProcData* pd = mCommandProcesses[i];
1894 if (pd->event->id() ==
event.id() && (pd->flags & ProcData::PRE_ACTION))
1896 kDebug() <<
"Already executing pre-DISPLAY command";
1903 QString command =
event.preAction();
1904 kDebug() <<
"Pre-DISPLAY command:" << command;
1905 int flags = (reschedule ? ProcData::RESCHEDULE : 0) | (allowDefer ? ProcData::ALLOW_DEFER : 0);
1906 if (doShellCommand(command, event, &alarm, (flags | ProcData::PRE_ACTION)))
1912 if (event.cancelOnPreActionError())
1915 kDebug() <<
event.id() <<
": pre-action failed: cancelled";
1927 (
new MessageWin(&event, alarm, flags))->show();
1929 else if (replaceReminder)
1934 else if (!win->
hasDefer() && !alarm.repeatAtLogin())
1953 case KAAlarm::EMAIL:
1955 kDebug() <<
"EMAIL to:" <<
event.emailAddresses(QLatin1String(
","));
1956 QStringList errmsgs;
1957 KAMail::JobData data(event, alarm, reschedule, (reschedule || allowDefer));
1976 case KAAlarm::AUDIO:
2009 if (!errmsgs.isEmpty())
2012 if (errmsgs.count() > 1)
2013 kDebug() << (copyerr ?
"Copy error:" :
"Failed:") << errmsgs[1];
2029 int flags = (
event.commandXterm() ? ProcData::EXEC_IN_XTERM : 0)
2030 | (event.commandDisplay() ? ProcData::DISP_OUTPUT : 0);
2031 QString command =
event.cleanText();
2032 if (event.commandScript())
2035 kDebug() <<
"Script";
2036 QString tmpfile = createTempScriptFile(command,
false, event, alarm);
2037 if (tmpfile.isEmpty())
2042 return doShellCommand(tmpfile, event, &alarm, (flags | ProcData::TEMP_FILE), receiver, slot);
2046 kDebug() << command;
2047 return doShellCommand(command, event, &alarm, flags, receiver, slot);
2064 ShellProcess* KAlarmApp::doShellCommand(
const QString& command,
const KAEvent& event,
const KAAlarm* alarm,
int flags,
const QObject* receiver,
const char* slot)
2066 kDebug() << command <<
"," <<
event.id();
2067 QIODevice::OpenMode mode = QIODevice::WriteOnly;
2069 QString tmpXtermFile;
2070 if (flags & ProcData::EXEC_IN_XTERM)
2073 cmd = composeXTermCommand(command, event, alarm, flags, tmpXtermFile);
2078 mode = QIODevice::ReadWrite;
2088 proc->setEnv(QLatin1String(
"KALARM_UID"), event.id(),
true);
2089 proc->setOutputChannelMode(KProcess::MergedChannels);
2091 if ((flags & ProcData::DISP_OUTPUT) && receiver && slot)
2093 connect(proc, SIGNAL(receivedStdout(
ShellProcess*)), receiver, slot);
2094 connect(proc, SIGNAL(receivedStderr(
ShellProcess*)), receiver, slot);
2096 if (mode == QIODevice::ReadWrite && !event.logFile().isEmpty())
2101 if (alarm && alarm->dateTime().isValid())
2103 QString dateTime = alarm->dateTime().formatLocale();
2104 heading.sprintf(
"\n******* KAlarm %s *******\n", dateTime.toLatin1().data());
2107 heading = QLatin1String(
"\n******* KAlarm *******\n");
2108 QFile logfile(event.logFile());
2109 if (logfile.open(QIODevice::Append | QIODevice::Text))
2111 QTextStream out(&logfile);
2115 proc->setStandardOutputFile(event.logFile(), QIODevice::Append);
2117 pd =
new ProcData(proc,
new KAEvent(event), (alarm ?
new KAAlarm(*alarm) : 0), flags);
2118 if (flags & ProcData::TEMP_FILE)
2119 pd->tempFiles += command;
2120 if (!tmpXtermFile.isEmpty())
2121 pd->tempFiles += tmpXtermFile;
2122 mCommandProcesses.append(pd);
2123 if (proc->
start(mode))
2128 kWarning() <<
"Command failed to start";
2129 commandErrorMsg(proc, event, alarm, flags);
2132 mCommandProcesses.removeAt(mCommandProcesses.indexOf(pd));
2144 QString KAlarmApp::composeXTermCommand(
const QString& command,
const KAEvent& event,
const KAAlarm* alarm,
int flags, QString& tempScriptFile)
const
2146 kDebug() << command <<
"," <<
event.id();
2147 tempScriptFile.clear();
2149 cmd.replace(QLatin1String(
"%t"), KGlobal::mainComponent().aboutData()->programName());
2150 if (cmd.indexOf(QLatin1String(
"%C")) >= 0)
2153 if (flags & ProcData::TEMP_FILE)
2154 cmd.replace(QLatin1String(
"%C"), command);
2157 tempScriptFile = createTempScriptFile(command,
true, event, *alarm);
2158 if (tempScriptFile.isEmpty())
2160 cmd.replace(QLatin1String(
"%C"), tempScriptFile);
2163 else if (cmd.indexOf(QLatin1String(
"%W")) >= 0)
2167 tempScriptFile = createTempScriptFile(command + QLatin1String(
"\nsleep 86400\n"),
true, event, *alarm);
2168 if (tempScriptFile.isEmpty())
2170 cmd.replace(QLatin1String(
"%W"), tempScriptFile);
2172 else if (cmd.indexOf(QLatin1String(
"%w")) >= 0)
2176 QString exec = KShell::quoteArg(command + QLatin1String(
"; sleep 86400"));
2177 cmd.replace(QLatin1String(
"%w"), exec);
2183 QString exec = KShell::quoteArg(command);
2184 if (cmd.indexOf(QLatin1String(
"%c")) >= 0)
2185 cmd.replace(QLatin1String(
"%c"), exec);
2196 QString KAlarmApp::createTempScriptFile(
const QString& command,
bool insertShell,
const KAEvent& event,
const KAAlarm& alarm)
const
2198 KTemporaryFile tmpFile;
2199 tmpFile.setAutoRemove(
false);
2200 if (!tmpFile.open())
2201 kError() <<
"Unable to create a temporary script file";
2204 tmpFile.setPermissions(QFile::ReadUser | QFile::WriteUser | QFile::ExeUser);
2205 QTextStream stream(&tmpFile);
2210 if (tmpFile.error() != QFile::NoError)
2211 kError() <<
"Error" << tmpFile.errorString() <<
" writing to temporary script file";
2213 return tmpFile.fileName();
2216 QStringList errmsgs(i18nc(
"@info",
"Error creating temporary script file"));
2228 for (
int i = 0, end = mCommandProcesses.count(); i < end; ++i)
2230 ProcData* pd = mCommandProcesses[i];
2231 if (pd->process == proc)
2234 bool executeAlarm = pd->preAction();
2238 kDebug() << pd->event->id() <<
": SUCCESS";
2240 : pd->postAction() ? KAEvent::CMD_ERROR_POST
2241 : KAEvent::CMD_ERROR);
2247 kWarning() << pd->event->id() <<
":" << errmsg <<
"exit status =" << status <<
", code =" << proc->
exitCode();
2249 kWarning() << pd->event->id() <<
":" << errmsg <<
"exit status =" << status;
2250 if (pd->messageBoxParent)
2254 if (!dialogs.isEmpty())
2257 : pd->postAction() ? KAEvent::CMD_ERROR_POST
2258 : KAEvent::CMD_ERROR);
2259 if (!pd->tempFile())
2261 errmsg += QLatin1Char(
'\n');
2267 commandErrorMsg(proc, *pd->event, pd->alarm, pd->flags);
2269 if (executeAlarm && pd->event->cancelOnPreActionError())
2271 kDebug() << pd->event->id() <<
": pre-action failed: cancelled";
2272 if (pd->reschedule())
2274 executeAlarm =
false;
2277 if (pd->preAction())
2280 execAlarm(*pd->event, *pd->alarm, pd->reschedule(), pd->allowDefer(),
true);
2281 mCommandProcesses.removeAt(i);
2288 if (mPendingQuit && mCommandProcesses.isEmpty())
2289 quitIf(mPendingQuitCode);
2295 void KAlarmApp::commandErrorMsg(
const ShellProcess* proc,
const KAEvent& event,
const KAAlarm* alarm,
int flags)
2297 KAEvent::CmdErrType cmderr;
2298 QStringList errmsgs;
2299 QString dontShowAgain;
2300 if (flags & ProcData::PRE_ACTION)
2302 if (event.dontShowPreActionError())
2304 errmsgs += i18nc(
"@info",
"Pre-alarm action:");
2305 dontShowAgain = QLatin1String(
"Pre");
2306 cmderr = KAEvent::CMD_ERROR_PRE;
2308 else if (flags & ProcData::POST_ACTION)
2310 errmsgs += i18nc(
"@info",
"Post-alarm action:");
2311 dontShowAgain = QLatin1String(
"Post");
2312 cmderr = (
event.commandError() == KAEvent::CMD_ERROR_PRE)
2313 ? KAEvent::CMD_ERROR_PRE_POST : KAEvent::CMD_ERROR_POST;
2317 dontShowAgain = QLatin1String(
"Exec");
2318 cmderr = KAEvent::CMD_ERROR;
2327 if (!(flags & ProcData::TEMP_FILE))
2329 dontShowAgain += QString::number(proc->
status());
2340 for (
int i = 0, end = mCommandProcesses.count(); i < end; ++i)
2342 ProcData* pd = mCommandProcesses[i];
2343 if (pd->process == proc)
2345 pd->messageBoxParent = parent;
2359 QDBusConnection client = QDBusConnection::sessionBus();
2365 if (KToolInvocation::startServiceByDesktopName(QLatin1String(
"kttsd"), QStringList(), &error))
2367 kDebug() <<
"Failed to start kttsd:" << error;
2374 mKSpeech->setParent(
theApp());
2375 mKSpeech->setApplicationName(KGlobal::mainComponent().aboutData()->programName());
2376 mKSpeech->setDefaultPriority(KSpeech::jpMessage);
2385 void KAlarmApp::slotDBusServiceUnregistered(
const QString& serviceName)
2399 bool KAlarmApp::initCheck(
bool calendarOnly,
bool waitForCollection, Akonadi::Collection::Id collectionId)
2401 bool KAlarmApp::initCheck(
bool calendarOnly)
2404 static bool firstTime =
true;
2406 kDebug() <<
"first time";
2408 if (initialise() || firstTime)
2422 setArchivePurgeDays();
2425 checkWritableCalendar();
2431 startProcessQueue();
2434 if (waitForCollection)
2436 #if KDE_IS_VERSION(4,9,80)
2465 if (err == KAEvent::CMD_ERROR_POST && event.commandError() == KAEvent::CMD_ERROR_PRE)
2466 err = KAEvent::CMD_ERROR_PRE_POST;
2467 event.setCommandError(err);
2473 if (ev && ev->commandError() != err)
2474 ev->setCommandError(err);
2484 KAEvent::CmdErrType newerr =
static_cast<KAEvent::CmdErrType
>(
event.commandError() & ~err);
2485 event.setCommandError(newerr);
2493 newerr =
static_cast<KAEvent::CmdErrType
>(ev->commandError() & ~err);
2494 ev->setCommandError(newerr);
2504 KAlarmApp::ProcData::ProcData(
ShellProcess* p, KAEvent* e, KAAlarm* a,
int f)
2508 messageBoxParent(0),
2512 KAlarmApp::ProcData::~ProcData()
2514 while (!tempFiles.isEmpty())
2517 QFile f(tempFiles.first());
2519 tempFiles.removeFirst();
QStringList attachments() const
KARecurrence * recurrence() const
static int questionYesNoCancel(QWidget *parent, const QString &text, const QString &caption=QString(), const KGuiItem &buttonYes=KStandardGuiItem::yes(), const KGuiItem &buttonNo=KStandardGuiItem::no(), const KGuiItem &buttonCancel=KStandardGuiItem::cancel(), const QString &dontAskAgainName=QString(), Options options=Options(Notify|WindowModal))
KDateTime alarmTime() const
QList< KCal::Person > addressees() const
void rescheduleAlarm(KAEvent &e, const KAAlarm &a)
void setAlarmsEnabled(bool)
static int maxLateness(int lateCancel)
static EventListModel * alarms()
void setAudio(Preferences::SoundType, const QString &file=QString(), float volume=-1, int repeatPause=-1)
static void printError(const QString &errmsg)
void emailSent(KAMail::JobData &, const QStringList &errmsgs, bool copyerr=false)
KAEvent::List atLoginAlarms() const
virtual QByteArray text(quint32 serialNumber) const =0
static bool spread(bool scatter)
bool wantShowInSystemTray() const
static AlarmCalendar * resources()
void updateCommandError(const QString &eventId)
static void error(QWidget *parent, const QString &text, const QString &caption=QString(), Options options=Options(Notify|WindowModal))
static bool isStandard(Akonadi::Collection &, CalEvent::Type)
Return whether a collection is the standard collection for a specified mime type. ...
void spreadWindowsToggled(bool)
bool refresh(Akonadi::Collection &) const
Refresh the specified collection instance with up to date data.
static void terminateCalendars()
static Feb29Type defaultFeb29Type()
Get In non-leap years, repeat yearly February 29th alarms on:
static bool noAutoStart()
Get Suppress autostart at login.
MainWindow * assocMainWindow() const
void commandMessage(ShellProcess *, QWidget *parent)
static const QLatin1String KTTSD_DBUS_SERVICE("org.kde.kttsd")
static void setEventCommandError(const KAEvent &, KAEvent::CmdErrType)
static MainWindow * firstWindow()
static void setAskAutoStart(bool yes)
static void setAutoStart(bool v)
Set Start at login.
static void clearEventCommandError(const KAEvent &, KAEvent::CmdErrType)
static QFont messageFont()
Get Message font.
static void connect(QObject *receiver, const char *member)
Connect to the timer signal.
static int archivedKeepDays()
Get Days to keep expired alarms.
static const QByteArray & shellPath()
bool isTrayParent() const
bool scheduleEvent(KAEvent::SubAction, const QString &text, const KDateTime &, int lateCancel, KAEvent::Flags flags, const QColor &bg, const QColor &fg, const QFont &, const QString &audioFile, float audioVolume, int reminderMinutes, const KARecurrence &recurrence, int repeatInterval, int repeatCount, uint mailFromID=0, const QList< KCal::Person > &mailAddresses=QList< KCal::Person >(), const QString &mailSubject=QString(), const QStringList &mailAttachments=QStringList())
KAEvent * earliestAlarm() const
MessageWin: A window to display an alarm or error message.
QString commandName() const
static QTime startOfDay()
int reminderMinutes() const
static bool autoStart()
Get Start at login.
static CollectionControlModel * instance()
static QString cmdXTermCommand()
MainWindow * trayMainWindow() const
void setReminder(int minutes, bool onceOnly)
void setBgColour(const QColor &)
void removeWindow(TrayWindow *)
void alarmEnabledToggled(bool)
ShellProcess * execCommandAlarm(const KAEvent &, const KAAlarm &, const QObject *receiver=0, const char *slot=0)
static KTimeZone timeZone(bool reload=false)
void notifyAudioPlaying(bool playing)
static bool autoStartChangedByUser()
static void disconnect(QObject *receiver, const char *member=0)
Disconnect from the timer signal.
static const QLatin1String QUIT_WARN
static AkonadiModel * instance()
QString audioFile() const
QString templateName() const
static const QLatin1String ASK_AUTO_START
static void stopAudio(bool wait=false)
displays an alarm message
static KAlarmApp * getInstance()
virtual void commitData(QSessionManager &)
void setFgColour(const QColor &)
void setEmailFields(uint fromID, const QList< KCal::Person > &, const QString &subject, const QStringList &attachments)
static EditAlarmDlg * create(bool Template, Type, QWidget *parent=0, GetResourceType=RES_PROMPT)
QString errorMessage() const
bool isHiddenTrayParent() const
static MainWindow * create(bool restored=false)
float audioVolume() const
KAAlarm::Type alarmType() const
static int instanceCount(bool excludeAlwaysHidden=false)
static void redisplayAlarms()
KAEvent::Flags flags() const
static QTime workDayEnd()
static MessageWin * findEvent(const QString &eventId)
static void connect(const char *signal, const QObject *receiver, const char *member)
static const KHolidays::HolidayRegion & holidays()
static Akonadi::Collection::List enabledCollections(CalEvent::Type, bool writable)
Return the enabled collections which contain a specified mime type.
static QColor archivedColour()
Get Archived alarm color.
static QBitArray workDays()
void showDateTime(const KAEvent &, const KAAlarm &)
Unique event identifier for Akonadi.
static int warningContinueCancel(QWidget *parent, ButtonCode defaultButton, const QString &text, const QString &caption=QString(), const KGuiItem &buttonContinue=KStandardGuiItem::cont(), const QString &dontAskAgainName=QString())
void repeat(const KAAlarm &)
int subRepeatCount() const
EditAlarmDlg::Type editType() const
static void showError(const KAEvent &, const DateTime &alarmDateTime, const QStringList &errmsgs, const QString &dontShowAgain=QString())
void cancelReminder(const KAEvent &, const KAAlarm &)
void setAlarmPending(KAEvent *, bool pending=true)
void setAudio(const QString &file, float volume=-1)
bool displayTrayIcon(bool show, MainWindow *=0)
static bool initialiseCalendars()
static Preferences * self()
void * execAlarm(KAEvent &, const KAAlarm &, bool reschedule, bool allowDefer=true, bool noPreAction=false)
static bool showInSystemTray()
Get Show in system tray.
OrgKdeKSpeechInterface * kspeechInterface(QString &error) const
int subRepeatInterval() const
static int send(JobData &, QStringList &errmsgs)
KAEvent::SubAction editAction() const
KAEvent * event(const QString &uniqueId)
static MainWindow * mainMainWindow()
const QString & command() const
static void displayFatalError(const QString &message)
static void setNoAutoStart(bool v)
Set Suppress autostart at login.
static AlarmCalendar * displayCalendar()
void doQuit(QWidget *parent)
KDateTime simulationTime() const
static QTime workDayStart()
void setSpreadWindowsState(bool spread)
static const QLatin1String KTTDS_DBUS_PATH("/KSpeech")
virtual int newInstance()
bool start(OpenMode=ReadWrite)
void alarmCompleted(const KAEvent &)
void updateCommandError(const KAEvent &)
To be called when the command error status of an alarm has changed, to set in the Akonadi database an...
static void information(QWidget *parent, const QString &text, const QString &caption=QString(), const QString &dontShowAgainName=QString(), Options options=Options(Notify|WindowModal))