File indexing completed on 2024-11-24 04:42:33
0001 /* 0002 * singlefileresource.h - calendar resource held in a single file 0003 * Program: kalarm 0004 * SPDX-FileCopyrightText: 2020-2023 David Jarvie <djarvie@kde.org> 0005 * 0006 * SPDX-License-Identifier: LGPL-2.0-or-later 0007 */ 0008 0009 #pragma once 0010 0011 #include "fileresource.h" 0012 #include "fileresourceconfigmanager.h" 0013 0014 #include <KCalendarCore/MemoryCalendar> 0015 #include <KCalendarCore/FileStorage> 0016 0017 #include <QUrl> 0018 0019 namespace KIO { 0020 class FileCopyJob; 0021 } 0022 class KJob; 0023 class QTimer; 0024 0025 using namespace KAlarmCal; 0026 0027 /** 0028 * Calendar resource stored in a single file, either local or remote. 0029 */ 0030 class SingleFileResource : public FileResource 0031 { 0032 Q_OBJECT 0033 public: 0034 /** Construct a new SingleFileResource. 0035 * Initialises the resource and initiates loading its events. 0036 */ 0037 static Resource create(FileResourceSettings::Ptr settings); 0038 0039 protected: 0040 /** Constructor. 0041 * Initialises the resource and initiates loading its events. 0042 */ 0043 explicit SingleFileResource(FileResourceSettings::Ptr settings); 0044 0045 public: 0046 ~SingleFileResource() override; 0047 0048 /** Return the type of storage used by the resource. */ 0049 Storage storageType() const override { return Storage::File; } 0050 0051 /** Return whether the resource is configured as read-only or is 0052 * read-only on disc. 0053 */ 0054 bool readOnly() const override; 0055 0056 /** Return whether the resource is both enabled and fully writable for a 0057 * given alarm type, i.e. not read-only, and compatible with the current 0058 * KAlarm calendar format. 0059 * 0060 * @param type alarm type to check for, or EMPTY to check for any type. 0061 * @return 1 = fully enabled and writable, 0062 * 0 = enabled and writable except that backend calendar is in an 0063 * old KAlarm format, 0064 * -1 = read-only, disabled or incompatible format. 0065 */ 0066 int writableStatus(CalEvent::Type type = CalEvent::EMPTY) const override; 0067 0068 /** Reload the resource. Any cached data is first discarded. 0069 * @param discardMods Discard any modifications since the last save. 0070 * @return true if loading succeeded or has been initiated. 0071 * false if it failed. 0072 */ 0073 bool reload(bool discardMods = false) override; 0074 0075 /** Return whether the resource is waiting for a save() to complete. */ 0076 bool isSaving() const override; 0077 0078 /** Close the resource. This saves any unsaved data. 0079 * Saving is not performed if the resource is disabled. 0080 */ 0081 void close() override; 0082 0083 /** Called when the resource's FileResourceSettings object is about to be destroyed. */ 0084 void removeSettings() override; 0085 0086 protected: 0087 /** Update the resource to the current KAlarm storage format. */ 0088 bool updateStorageFmt() override; 0089 0090 /** This method is called by load() to allow derived classes to implement 0091 * loading the resource from its backend, and fetch all events into 0092 * @p newEvents. 0093 * If the resource is cached, it should be loaded from the cache file (which 0094 * if @p readThroughCache is true, should first be downloaded from the 0095 * resource file). 0096 * If the resource initiates but does not complete loading, loaded() must be 0097 * called when loading completes or fails. 0098 * @see loaded() 0099 * 0100 * @param newEvents To be updated to contain the events fetched. 0101 * @param readThroughCache If the resource is cached, refresh the cache first. 0102 * @return 1 = loading succeeded 0103 * 0 = loading has been initiated, but has not yet completed 0104 * -1 = loading failed. 0105 */ 0106 int doLoad(QHash<QString, KAEvent>& newEvents, bool readThroughCache, QString& errorMessage) override; 0107 0108 /** This method is called by save() to allow derived classes to implement 0109 * saving the resource to its backend. 0110 * If the resource is cached, it should be saved to the cache file (which 0111 * if @p writeThroughCache is true, should then be uploaded from the 0112 * resource file). 0113 * If the resource initiates but does not complete saving, saved() must be 0114 * called when saving completes or fails. 0115 * @see saved() 0116 * 0117 * @param writeThroughCache If the resource is cached, update the file 0118 * after writing to the cache. 0119 * @param force Save even if no changes have been made since last 0120 * loaded or saved. 0121 * @return 1 = saving succeeded 0122 * 0 = saving has been initiated, but has not yet completed 0123 * -1 = saving failed. 0124 */ 0125 int doSave(bool writeThroughCache, bool force, QString& errorMessage) override; 0126 0127 /** Schedule the resource for saving. 0128 * This delays calling save(), so as to enable multiple event changes to 0129 * be saved together. 0130 * 0131 * @return true if saving succeeded or has been initiated/scheduled. 0132 * false if it failed. 0133 */ 0134 bool scheduleSave(bool writeThroughCache = true) override; 0135 0136 /** 0137 * Handles everything needed when the hash of a file has changed between the 0138 * last write and the first read. This stores the new hash in a config file 0139 * and notifies implementing resources to handle a hash change if the 0140 * previous known hash was not empty. 0141 * Returns true on success, false otherwise. 0142 */ 0143 bool readLocalFile(const QString& fileName, QString& errorMessage); 0144 0145 /** Read the data from the given local file. */ 0146 bool readFromFile(const QString& fileName, QString& errorMessage); 0147 0148 /** 0149 * Reimplement to write your data to the given file. 0150 * The file is always local, storing back to the network url is done 0151 * automatically when needed. 0152 */ 0153 bool writeToFile(const QString& fileName, QString& errorMessage); 0154 0155 /** This method is called by addEvent() to allow derived classes to add 0156 * an event to the resource. 0157 */ 0158 bool doAddEvent(const KAEvent&) override; 0159 0160 /** This method is called by updateEvent() to allow derived classes to update 0161 * an event in the resource. The event's UID must be unchanged. 0162 */ 0163 bool doUpdateEvent(const KAEvent&) override; 0164 0165 /** This method is called by deleteEvent() to allow derived classes to delete 0166 * an event from the resource. 0167 */ 0168 bool doDeleteEvent(const KAEvent&) override; 0169 0170 /** Called when settings have changed, to allow derived classes to process 0171 * the changes. 0172 * @note Resources::notifySettingsChanged() is called after this, to 0173 * notify clients. 0174 */ 0175 void handleSettingsChange(Changes&) override; 0176 0177 /** 0178 * Generates the full path for the cache file in the case that a remote file 0179 * is used. 0180 */ 0181 QString cacheFilePath() const; 0182 0183 /** 0184 * Calculates an MD5 hash for given file. If the file does not exists 0185 * or the path is empty, this will return an empty QByteArray. 0186 */ 0187 QByteArray calculateHash(const QString& fileName) const; 0188 0189 /** 0190 * Stores the given hash into the config file. 0191 */ 0192 void saveHash(const QByteArray& hash) const; 0193 0194 private Q_SLOTS: 0195 void slotSave() { save(nullptr, mSavePendingCache); } 0196 // void handleProgress(KJob*, unsigned long); 0197 void localFileChanged(const QString& fileName); 0198 void slotDownloadJobResult(KJob*); 0199 void slotUploadJobResult(KJob*); 0200 void updateFormat() { updateStorageFmt(); } 0201 bool addLoadedEvent(const KCalendarCore::Event::Ptr&); 0202 0203 private: 0204 void setLoadFailure(bool exists, Status); 0205 0206 QUrl mSaveUrl; // current local file for save() to use (may be temporary) 0207 KIO::FileCopyJob* mDownloadJob {nullptr}; 0208 KIO::FileCopyJob* mUploadJob {nullptr}; 0209 QByteArray mCurrentHash; 0210 KCalendarCore::MemoryCalendar::Ptr mCalendar; 0211 KCalendarCore::FileStorage::Ptr mFileStorage; 0212 QHash<QString, KAEvent> mLoadedEvents; // events loaded from calendar last time file was read 0213 QTimer* mSaveTimer {nullptr}; // timer to enable multiple saves to be grouped 0214 bool mSavePendingCache; // writeThroughCache parameter for delayed save() 0215 bool mFileReadOnly {false}; // the calendar file is a read-only local file 0216 }; 0217 0218 // vim: et sw=4: