File indexing completed on 2024-05-12 05:14:48
0001 /* 0002 * kalarmapp.h - the KAlarm application object 0003 * Program: kalarm 0004 * SPDX-FileCopyrightText: 2001-2023 David Jarvie <djarvie@kde.org> 0005 * 0006 * SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #pragma once 0010 0011 /** @file kalarmapp.h - the KAlarm application object */ 0012 0013 #include "eventid.h" 0014 #include "preferences.h" 0015 #include "kalarmcalendar/kaevent.h" 0016 0017 #include <QApplication> 0018 #include <QPointer> 0019 #include <QQueue> 0020 0021 namespace KCal { class Event; } 0022 namespace MailSend { struct JobData; } 0023 class Resource; 0024 class DBusHandler; 0025 class MainWindow; 0026 class MessageWindow; 0027 class TrayWindow; 0028 class ShellProcess; 0029 0030 using namespace KAlarmCal; 0031 0032 0033 class KAlarmApp : public QApplication 0034 { 0035 Q_OBJECT 0036 public: 0037 /** Flags for execAlarm(). */ 0038 enum ExecAlarmFlag 0039 { 0040 NoExecFlag = 0, 0041 Reschedule = 0x01, // reschedule the alarm after executing it 0042 AllowDefer = 0x02, // allow the alarm to be deferred 0043 NoRecordCmdError = 0x04, // don't record command errors 0044 NoPreAction = 0x08, // it isn't a pre-alarm action 0045 NoNotifyInhibit = 0x10 // ignore notification inhibit 0046 }; 0047 Q_DECLARE_FLAGS(ExecAlarmFlags, ExecAlarmFlag) 0048 0049 ~KAlarmApp() override; 0050 0051 /** Create the unique instance. */ 0052 static KAlarmApp* create(int& argc, char** argv); 0053 0054 /** Must be called to complete initialisation after KAboutData is set, 0055 * but before the application is activated or restored. 0056 */ 0057 void initialise(); 0058 0059 /** Return the unique instance. */ 0060 static KAlarmApp* instance() { return mInstance; } 0061 0062 bool checkCalendar() { return initCheck(); } 0063 bool wantShowInSystemTray() const; 0064 bool alarmsEnabled() const { return mAlarmsEnabled; } 0065 bool korganizerEnabled() const { return mKOrganizerEnabled; } 0066 int activateInstance(const QStringList& args, const QString& workingDirectory, QString* outputText = nullptr); 0067 bool restoreSession(); 0068 bool quitIf() { return quitIf(0); } 0069 void doQuit(QWidget* parent); 0070 static void displayFatalError(const QString& message); 0071 void addWindow(TrayWindow* w) { mTrayWindow = w; } 0072 void removeWindow(TrayWindow*); 0073 TrayWindow* trayWindow() const { return mTrayWindow; } 0074 MainWindow* trayMainWindow() const; 0075 bool displayTrayIcon(bool show, MainWindow* = nullptr); 0076 bool trayIconDisplayed() const { return mTrayWindow; } 0077 bool editNewAlarm(MainWindow* = nullptr); 0078 0079 void* execAlarm(KAEvent&, const KAAlarm&, ExecAlarmFlags flags = NoExecFlag); 0080 ShellProcess* execCommandAlarm(const KAEvent&, const KAAlarm&, bool noRecordError = false, 0081 QObject* receiver = nullptr, 0082 const char* slotOutput = nullptr, 0083 const char* methodExited = nullptr); 0084 void alarmCompleted(const KAEvent&); 0085 void rescheduleAlarm(KAEvent& e, const KAAlarm& a) { rescheduleAlarm(e, a, true); } 0086 void purgeAll() { purge(0); } 0087 void commandMessage(ShellProcess*, QWidget* parent); 0088 void notifyAudioPlaying(bool playing); 0089 void setSpreadWindowsState(bool spread); 0090 bool windowFocusBroken() const; 0091 bool needWindowFocusFix() const; 0092 // Methods called indirectly by the D-Bus interface 0093 bool scheduleEvent(KAEvent::SubAction subAction, const QString& name, const QString& text, 0094 const KADateTime& dt, int lateCancel, KAEvent::Flags flags, 0095 const QColor& bg, const QColor& fg, const QFont& font, 0096 const QString& audioFile, float audioVolume, 0097 int reminderMinutes, const KARecurrence& recurrence, 0098 const KCalendarCore::Duration& repeatInterval, int repeatCount, 0099 uint mailFromID = 0, const KCalendarCore::Person::List& mailAddresses = KCalendarCore::Person::List(), 0100 const QString& mailSubject = QString(), 0101 const QStringList& mailAttachments = QStringList()) 0102 { return scheduleEvent(QueuedAction::NoAction, 0103 subAction, name, text, dt, lateCancel, flags, 0104 bg, fg, font, audioFile, audioVolume, 0105 reminderMinutes, recurrence, repeatInterval, repeatCount, 0106 mailFromID, mailAddresses, mailSubject, mailAttachments); 0107 } 0108 bool dbusTriggerEvent(const EventId& eventID) { return dbusHandleEvent(eventID, QueuedAction::Trigger); } 0109 bool dbusDeleteEvent(const EventId& eventID) { return dbusHandleEvent(eventID, QueuedAction::Cancel); } 0110 QString dbusList(); 0111 0112 public Q_SLOTS: 0113 void activateByDBus(const QStringList& args, const QString& workingDirectory) 0114 { activateInstance(args, workingDirectory); } 0115 void processQueue(); 0116 void setAlarmsEnabled(bool); 0117 void purgeNewArchivedDefault(const Resource&); 0118 void atLoginEventAdded(const KAlarmCal::KAEvent&); 0119 void notifyAudioStopped() { notifyAudioPlaying(false); } 0120 void stopAudio(); 0121 void spreadWindows(bool); 0122 void emailSent(const MailSend::JobData&, const QStringList& errmsgs, bool copyerr = false); 0123 0124 Q_SIGNALS: 0125 void setExitValue(int); // set exit code for duplicate application instances 0126 void trayIconToggled(); 0127 void alarmEnabledToggled(bool); 0128 void audioPlaying(bool); 0129 void spreadWindowsToggled(bool); 0130 void execAlarmSuccess(); 0131 0132 private: 0133 using Feb29Type = Preferences::Feb29Type; // allow it to be used in SIGNAL mechanism 0134 0135 private Q_SLOTS: 0136 void quitFatal(); 0137 void checkNextDueAlarm(); 0138 void slotShowInSystemTrayChanged(); 0139 void changeStartOfDay(); 0140 void slotWorkTimeChanged(const QTime& start, const QTime& end, const QBitArray& days); 0141 void slotHolidaysChanged(const KAlarmCal::Holidays&); 0142 void slotFeb29TypeChanged(KAlarmApp::Feb29Type); 0143 void slotResourcesTimeout(); 0144 void slotResourcesCreated(); 0145 void slotEditAlarmById(); 0146 void promptArchivedCalendar(); 0147 void slotMessageFontChanged(const QFont&); 0148 void setArchivePurgeDays(); 0149 void slotResourceAdded(const Resource&); 0150 void slotResourcePopulated(const Resource&); 0151 void slotPurge() { purge(mArchivedPurgeDays); } 0152 void slotCommandExited(ShellProcess*); 0153 void slotFDOPropertiesChanged(const QString& interface, 0154 const QVariantMap& changedProperties, 0155 const QStringList& invalidatedProperties); 0156 0157 private: 0158 // Actions to execute in processQueue(). May be OR'ed together. 0159 enum class QueuedAction 0160 { 0161 // Action to execute 0162 NoAction = 0, 0163 ActionMask = 0x07, // bit mask to extract action to execute 0164 Handle = 0x01, // if the alarm is due, execute it and then reschedule it 0165 Trigger = 0x02, // execute the alarm regardless, and then reschedule it if it's already due 0166 Cancel = 0x03, // delete the alarm 0167 Edit = 0x04, // edit an alarm (command line option) 0168 List = 0x05, // list all alarms (command line option) 0169 // Modifier flags 0170 FindId = 0x10, // search all resources for unique event ID 0171 Exit = 0x20, // exit application after executing action 0172 ErrorExit = 0x40, // exit application after executing action if it fails 0173 CmdLine = 0x80 // the action is from the command line, so output error messages 0174 }; 0175 struct ProcData 0176 { 0177 ProcData(ShellProcess*, KAEvent*, KAAlarm*, int flags = 0); 0178 ~ProcData(); 0179 enum 0180 { 0181 PRE_ACTION = 0x01, 0182 POST_ACTION = 0x02, 0183 RESCHEDULE = 0x04, 0184 ALLOW_DEFER = 0x08, 0185 TEMP_FILE = 0x10, 0186 EXEC_IN_XTERM = 0x20, 0187 DISP_OUTPUT = 0x40, 0188 NO_RECORD_ERROR = 0x80 // don't record command error 0189 }; 0190 bool preAction() const { return flags & PRE_ACTION; } 0191 bool postAction() const { return flags & POST_ACTION; } 0192 bool reschedule() const { return flags & RESCHEDULE; } 0193 bool allowDefer() const { return flags & ALLOW_DEFER; } 0194 bool tempFile() const { return flags & TEMP_FILE; } 0195 bool execInXterm() const { return flags & EXEC_IN_XTERM; } 0196 bool dispOutput() const { return flags & DISP_OUTPUT; } 0197 bool noRecordCmdErr() const { return flags & NO_RECORD_ERROR; } 0198 ShellProcess* process; 0199 KAEvent* event; 0200 KAAlarm* alarm; 0201 QPointer<QObject> exitReceiver; 0202 QByteArray exitMethod; 0203 QPointer<QWidget> messageBoxParent; 0204 QStringList tempFiles; 0205 int flags; 0206 bool eventDeleted {false}; 0207 }; 0208 struct ActionQEntry 0209 { 0210 ActionQEntry(QueuedAction a, const EventId& id) : action(a), eventId(id) { } 0211 ActionQEntry(QueuedAction a, const EventId& id, const QString& resId) : action(a), eventId(id), resourceId(resId) { } 0212 explicit ActionQEntry(const KAEvent& e, QueuedAction a = QueuedAction::Handle) : action(a), event(e) { } 0213 ActionQEntry() = default; 0214 QueuedAction action; 0215 EventId eventId; 0216 KAEvent event; 0217 QString resourceId; // resource ID or name, if resources not created yet 0218 }; 0219 0220 KAlarmApp(int& argc, char** argv); 0221 bool initialiseTimerResources(); 0222 bool initCheck(bool calendarOnly = false); 0223 bool quitIf(int exitCode, bool force = false); 0224 void showRestoredWindows(); 0225 void createOnlyMainWindow(); 0226 bool checkSystemTray(); 0227 void startProcessQueue(bool evenIfStarted = false); 0228 void setResourcesTimeout(); 0229 void checkWritableCalendar(); 0230 void checkArchivedCalendar(); 0231 void queueAlarmId(const KAEvent&); 0232 bool dbusHandleEvent(const EventId&, QueuedAction); 0233 bool scheduleEvent(QueuedAction queuedActionFlags, 0234 KAEvent::SubAction, const QString& name, const QString& text, 0235 const KADateTime&, int lateCancel, KAEvent::Flags flags, 0236 const QColor& bg, const QColor& fg, const QFont&, 0237 const QString& audioFile, float audioVolume, 0238 int reminderMinutes, const KARecurrence& recurrence, 0239 const KCalendarCore::Duration& repeatInterval, int repeatCount, 0240 uint mailFromID = 0, const KCalendarCore::Person::List& mailAddresses = KCalendarCore::Person::List(), 0241 const QString& mailSubject = QString(), 0242 const QStringList& mailAttachments = QStringList()); 0243 int handleEvent(const EventId&, QueuedAction, bool findUniqueId = false); 0244 int rescheduleAlarm(KAEvent&, const KAAlarm&, bool updateCalAndDisplay, 0245 const KADateTime& nextDt = KADateTime()); 0246 bool cancelAlarm(KAEvent&, KAAlarm::Type, bool updateCalAndDisplay); 0247 bool cancelReminderAndDeferral(KAEvent&); 0248 ShellProcess* doShellCommand(const QString& command, const KAEvent&, const KAAlarm*, 0249 int flags = 0, QObject* receiver = nullptr, 0250 const char* slotOutput = nullptr, 0251 const char* methodExited = nullptr); 0252 QString composeXTermCommand(const QString& command, const KAEvent&, const KAAlarm*, 0253 int flags, QString& tempScriptFile) const; 0254 QString createTempScriptFile(const QString& command, bool insertShell, const KAEvent&, const KAAlarm&) const; 0255 void commandErrorMsg(const ShellProcess*, const KAEvent&, const KAAlarm*, int flags = 0, const QStringList& errmsgs = QStringList()); 0256 void purge(int daysToKeep); 0257 QStringList scheduledAlarmList(); 0258 void setEventCommandError(const KAEvent&, KAEvent::CmdErr) const; 0259 void clearEventCommandError(const KAEvent&, KAEvent::CmdErr) const; 0260 ProcData* findCommandProcess(const QString& eventId) const; 0261 0262 static KAlarmApp* mInstance; // the one and only KAlarmApp instance 0263 static int mActiveCount; // number of active instances without main windows 0264 static int mFatalError; // a fatal error has occurred - just wait to exit 0265 static QString mFatalMessage; // fatal error message to output 0266 QString mCommandOption; // command option used on command line 0267 bool mInitialised {false}; // initialisation complete: ready to process execution queue 0268 bool mRedisplayAlarms {false}; // need to redisplay alarms when collection tree fetched 0269 bool mQuitting {false}; // a forced quit is in progress 0270 bool mReadOnly {false}; // only read-only access to calendars is needed 0271 QString mActivateArg0; // activate()'s first arg the first time it was called 0272 DBusHandler* mDBusHandler; // the parent of the main D-Bus receiver object 0273 TrayWindow* mTrayWindow {nullptr}; // active system tray icon 0274 QTimer* mAlarmTimer {nullptr}; // activates KAlarm when next alarm is due 0275 QColor mPrefsArchivedColour; // archived alarms text colour 0276 int mArchivedPurgeDays {-1}; // how long to keep archived alarms, 0 = don't keep, -1 = keep indefinitely 0277 int mPurgeDaysQueued {-1}; // >= 0 to purge the archive calendar from KAlarmApp::processLoop() 0278 QList<ResourceId> mPendingPurges; // new resources which may need to be purged when populated 0279 QList<ProcData*> mCommandProcesses; // currently active command alarm processes 0280 QQueue<ActionQEntry> mActionQueue; // queued commands and actions 0281 QList<MessageWindow*> mRestoredWindows; // message windows restored at startup, waiting to be displayed 0282 int mEditingCmdLineAlarm {0}; // whether currently editing alarm specified on command line 0283 int mPendingQuitCode; // exit code for a pending quit 0284 bool mPendingQuit {false}; // quit once the D-Bus command and shell command queues have been processed 0285 bool mCancelRtcWake {false}; // cancel RTC wake on quitting 0286 bool mProcessingQueue {false}; // a mActionQueue entry is currently being processed 0287 bool mNoSystemTray; // no system tray exists 0288 bool mOldShowInSystemTray; // showing in system tray was selected 0289 bool mAlarmsEnabled {true}; // alarms are enabled 0290 bool mKOrganizerEnabled; // KOrganizer options are enabled (korganizer exists) 0291 bool mWindowFocusBroken; // keyboard focus transfer between windows doesn't work 0292 bool mResourcesTimedOut {false}; // timeout has expired for populating resources 0293 bool mNotificationsInhibited {false}; // Freedesktop notifications are inhibited 0294 }; 0295 0296 inline KAlarmApp* theApp() { return KAlarmApp::instance(); } 0297 0298 Q_DECLARE_OPERATORS_FOR_FLAGS(KAlarmApp::ExecAlarmFlags) 0299 0300 // vim: et sw=4: