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::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 | */ |
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 | |