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 |
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 | */ |
123 | class KCOREADDONS_EXPORT KAutoSaveFile : public QFile |
124 | { |
125 | Q_OBJECT |
126 | public: |
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 | |
245 | private: |
246 | Q_DISABLE_COPY(KAutoSaveFile) |
247 | friend class KAutoSaveFilePrivate; |
248 | std::unique_ptr<KAutoSaveFilePrivate> const d; |
249 | }; |
250 | |
251 | #endif // KAUTOSAVEFILE_H |
252 | |