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: