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
20class 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::questionTwoActions(parent,
57 * "Auto-saved files exist. Do you want to recover them now?",
58 * "File Recovery",
59 * KGuiItem("Recover"), KGuiItem("Do Not recover")) == KMessageBox::PrimaryAction) {
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 */
120class KCOREADDONS_EXPORT KAutoSaveFile : public QFile
121{
122 Q_OBJECT
123public:
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
240private:
241 Q_DISABLE_COPY(KAutoSaveFile)
242 friend class KAutoSaveFilePrivate;
243 std::unique_ptr<KAutoSaveFilePrivate> const d;
244};
245
246#endif // KAUTOSAVEFILE_H
247

source code of kcoreaddons/src/lib/io/kautosavefile.h