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

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