1 /* 2 This file is part of the KDE libraries 3 4 SPDX-FileCopyrightText: 2006 Jacob R Rideout <kde@jacobrideout.net> 5 6 SPDX-License-Identifier: LGPL-2.0-or-later 7 */ 8 9 #ifndef KAUTOSAVEFILE_H 10 #define KAUTOSAVEFILE_H 11 12 #include <kcoreaddons_export.h> 13 14 #include <QFile> 15 #include <QList> 16 #include <QUrl> 17 18 #include <memory> 19 20 class KAutoSaveFilePrivate; 21 /** 22 * \class KAutoSaveFile kautosavefile.h <KAutoSaveFile> 23 * 24 * @brief Creates and manages a temporary "auto-save" file. 25 * Autosave files are temporary files that applications use to store 26 * the unsaved data in a file they have open for 27 * editing. KAutoSaveFile allows you to easily create and manage such 28 * files, as well as to recover the unsaved data left over by a 29 * crashed or otherwise gone process. 30 * 31 * Each KAutoSaveFile object is associated with one specific file that 32 * the application holds open. KAutoSaveFile is also a QObject, so it 33 * can be reparented to the actual opened file object, so as to manage 34 * the lifetime of the temporary file. 35 * 36 * Typical use consists of: 37 * - verifying whether stale autosave files exist for the opened file 38 * - deciding whether to recover the old, autosaved data 39 * - if not recovering, creating a KAutoSaveFile object for the opened file 40 * - during normal execution of the program, periodically save unsaved 41 * data into the KAutoSaveFile file. 42 * 43 * KAutoSaveFile holds a lock on the autosave file, so it's safe to 44 * delete the file and recreate it later. Because of that, disposing 45 * of stale autosave files should be done with releaseLock(). No lock is 46 * held on the managed file. 47 * 48 * Examples: 49 * Opening a new file: 50 * @code 51 * void Document::open(const QUrl &url) 52 * { 53 * // check whether autosave files exist: 54 * const QList<KAutoSaveFile *> staleFiles = KAutoSaveFile::staleFiles(url); 55 * if (!staleFiles.isEmpty()) { 56 * if (KMessageBox::questionYesNo(parent, 57 * "Auto-saved files exist. Do you want to recover them now?", 58 * "File Recovery", 59 * "Recover", "Don't recover") == KMessage::Yes) { 60 * recoverFiles(staleFiles); 61 * return; 62 * } else { 63 * // remove the stale files 64 * for (KAutoSaveFile *stale : staleFiles) { 65 * stale->open(QIODevice::ReadWrite); 66 * delete stale; 67 * } 68 * } 69 * } 70 * 71 * // create new autosave object 72 * m_autosave = new KAutoSaveFile(url, this); 73 * 74 * // continue the process of opening file 'url' 75 * ... 76 * } 77 * @endcode 78 * 79 * The function recoverFiles could loop over the list of files and do this: 80 * @code 81 * for (KAutoSaveFile *stale : staleFiles) { 82 * if (!stale->open(QIODevice::ReadWrite)) { 83 * // show an error message; we could not steal the lockfile 84 * // maybe another application got to the file before us? 85 * delete stale; 86 * continue; 87 * } 88 * Document *doc = new Document; 89 * doc->m_autosave = stale; 90 * stale->setParent(doc); // reparent 91 * 92 * doc->setUrl(stale->managedFile()); 93 * doc->setContents(stale->readAll()); 94 * doc->setState(Document::Modified); // mark it as modified and unsaved 95 * 96 * documentManager->addDocument(doc); 97 * } 98 * @endcode 99 * 100 * If the file is unsaved, periodically write the contents to the save file: 101 * @code 102 * if (!m_autosave->isOpen() && !m_autosave->open(QIODevice::ReadWrite)) { 103 * // show error: could not open the autosave file 104 * } 105 * m_autosave->write(contents()); 106 * @endcode 107 * 108 * When the user saves the file, the autosaved file is no longer 109 * necessary and can be removed or emptied. 110 * @code 111 * m_autosave->resize(0); // leaves the file open 112 * @endcode 113 * 114 * @code 115 * m_autosave->remove(); // closes the file 116 * @endcode 117 * 118 * @author Jacob R Rideout <kde@jacobrideout.net> 119 */ 120 class KCOREADDONS_EXPORT KAutoSaveFile : public QFile 121 { 122 Q_OBJECT 123 public: 124 /** 125 * Constructs a KAutoSaveFile for file @p filename. The temporary 126 * file is not opened or created until actually needed. The file 127 * @p filename does not have to exist for KAutoSaveFile to be 128 * constructed (if it exists, it will not be touched). 129 * 130 * @param filename the filename that this KAutoSaveFile refers to 131 * @param parent the parent object 132 */ 133 explicit KAutoSaveFile(const QUrl &filename, QObject *parent = nullptr); 134 135 /** 136 * @overload 137 * Constructs a KAutoSaveFile object. Note that you need to call 138 * setManagedFile() before calling open(). 139 * 140 * @param parent the parent object 141 */ 142 explicit KAutoSaveFile(QObject *parent = nullptr); 143 144 /** 145 * Destroys the KAutoSaveFile object, removes the autosave 146 * file and drops the lock being held (if any). 147 */ 148 ~KAutoSaveFile() override; 149 150 /** 151 * Retrieves the URL of the file managed by KAutoSaveFile. This 152 * is the same URL that was given to setManagedFile() or the 153 * KAutoSaveFile constructor. 154 * 155 * This is the name of the real file being edited by the 156 * application. To get the name of the temporary file where data 157 * can be saved, use fileName() (after you have called open()). 158 */ 159 QUrl managedFile() const; 160 161 /** 162 * Sets the URL of the file managed by KAutoSaveFile. This should 163 * be the name of the real file being edited by the application. 164 * If the file was previously set, this function calls releaseLock(). 165 * 166 * @param filename the filename that this KAutoSaveFile refers to 167 */ 168 void setManagedFile(const QUrl &filename); 169 170 /** 171 * Closes the autosave file resource and removes the lock 172 * file. The file name returned by fileName() will no longer be 173 * protected and can be overwritten by another application at any 174 * time. To obtain a new lock, call open() again. 175 * 176 * This function calls remove(), so the autosave temporary file 177 * will be removed too. 178 */ 179 virtual void releaseLock(); 180 181 /** 182 * Opens the autosave file and locks it if it wasn't already 183 * locked. The name of the temporary file where data can be saved 184 * to will be set by this function and can be retrieved with 185 * fileName(). It will not change unless releaseLock() is called. No 186 * other application will attempt to edit such a file either while 187 * the lock is held. 188 * 189 * @param openmode the mode that should be used to open the file, 190 * probably QIODevice::ReadWrite 191 * @returns true if the file could be opened (= locked and 192 * created), false if the operation failed 193 */ 194 bool open(OpenMode openmode) override; 195 196 /** 197 * Checks for stale autosave files for the file @p url. Returns a list 198 * of autosave files that contain autosaved data left behind by 199 * other instances of the application, due to crashing or 200 * otherwise uncleanly exiting. 201 * 202 * It is the application's job to determine what to do with such 203 * unsaved data. Generally, this is done by asking the user if he 204 * wants to see the recovered data, and then allowing the user to 205 * save if he wants to. 206 * 207 * If not given, the application name is obtained from 208 * QCoreApplication, so be sure to have set it correctly before 209 * calling this function. 210 * 211 * This function returns a list of unopened KAutoSaveFile 212 * objects. By calling open() on them, the application will steal 213 * the lock. Subsequent releaseLock() or deleting of the object will 214 * then erase the stale autosave file. 215 * 216 * The application owns all returned KAutoSaveFile objects and is 217 * responsible for deleting them when no longer needed. Remember that 218 * deleting the KAutoSaveFile will release the file lock and remove the 219 * stale autosave file. 220 */ 221 static QList<KAutoSaveFile *> staleFiles(const QUrl &url, const QString &applicationName = QString()); 222 223 /** 224 * Returns all stale autosave files left behind by crashed or 225 * otherwise gone instances of this application. 226 * 227 * If not given, the application name is obtained from 228 * QCoreApplication, so be sure to have set it correctly before 229 * calling this function. 230 * 231 * See staleFiles() for information on the returned objects. 232 * 233 * The application owns all returned KAutoSaveFile objects and is 234 * responsible for deleting them when no longer needed. Remember that 235 * deleting the KAutoSaveFile will release the file lock and remove the 236 * stale autosave file. 237 */ 238 static QList<KAutoSaveFile *> allStaleFiles(const QString &applicationName = QString()); 239 240 private: 241 Q_DISABLE_COPY(KAutoSaveFile) 242 friend class KAutoSaveFilePrivate; 243 std::unique_ptr<KAutoSaveFilePrivate> const d; 244 }; 245 246 #endif // KAUTOSAVEFILE_H 247