1 | /* kate: tab-indents off; replace-tabs on; tab-width 4; remove-trailing-space on; encoding utf-8;*/ |
2 | /* |
3 | This file is part of the KDE libraries |
4 | Copyright 1999 Waldo Bastian <bastian@kde.org> |
5 | Copyright 2006 Jaison Lee <lee.jaison@gmail.com> |
6 | |
7 | This library is free software; you can redistribute it and/or |
8 | modify it under the terms of the GNU Library General Public |
9 | License version 2 as published by the Free Software Foundation. |
10 | |
11 | This library is distributed in the hope that it will be useful, |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | Library General Public License for more details. |
15 | |
16 | You should have received a copy of the GNU Library General Public License |
17 | along with this library; see the file COPYING.LIB. If not, write to |
18 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
19 | Boston, MA 02110-1301, USA. |
20 | */ |
21 | |
22 | #ifndef KSAVEFILE_H |
23 | #define KSAVEFILE_H |
24 | |
25 | #include <kdecore_export.h> |
26 | |
27 | #include <QtCore/QFile> |
28 | #include <QtCore/QString> |
29 | #include <kglobal.h> |
30 | |
31 | /** |
32 | * \class KSaveFile ksavefile.h <KSaveFile> |
33 | * |
34 | * @brief Class to allow for atomic file I/O, as well as utility functions. |
35 | * |
36 | * The KSaveFile class has been made to write out changes to an existing |
37 | * file atomically. This means that either <b>ALL</b> changes will be written |
38 | * to the file, or <b>NO</b> changes have been written, and the original file |
39 | * (if any) has been unchanged. This is useful if you have lots of |
40 | * time-consuming processing to perform during which an interruption could |
41 | * occur, or if any error in the file structure will cause the entire file |
42 | * to be corrupt. |
43 | * |
44 | * When you create a KSaveFile for a given file, a temporary file is instead |
45 | * created and all your I/O occurs in the save file. Once you call finalize() |
46 | * the temporary file is renamed to the target file, so that all your changes |
47 | * happen at once. If abort() is called then the temporary file is removed and |
48 | * the target file is untouched. KSaveFile derives from QFile so you can use |
49 | * it just as you would a normal QFile. |
50 | * |
51 | * This class also includes several static utility functions available that |
52 | * can help ensure data integrity. See the individual functions for details. |
53 | * |
54 | * Here is a quick example of how to use KSaveFile: |
55 | * |
56 | * First we create the KSaveFile and open it. |
57 | * |
58 | * @code |
59 | * KSaveFile saveFile; |
60 | * saveFile.setFileName("/lib/foo/bar.dat"); |
61 | * if ( !saveFile.open() ) { |
62 | * //Handle error |
63 | * } |
64 | * @endcode |
65 | * |
66 | * At this point the file "/lib/foo/bar.dat" has not been altered in any way. |
67 | * Now, let's write out some data to the file. |
68 | * |
69 | * @code |
70 | * QTextStream stream ( &saveFile ); |
71 | * stream << "Add some data."; |
72 | * // Perform long processing |
73 | * stream << "Add some more data."; |
74 | * stream.flush(); |
75 | * @endcode |
76 | * |
77 | * Even after writing this data, the target file "/lib/foo/bar.dat" still has |
78 | * not been altered in any way. Now that we are done writing our data, we can |
79 | * write out all the changes that we have made by calling finalize(). |
80 | * |
81 | * @code |
82 | * if ( !saveFile.finalize() ) { |
83 | * //Handle error |
84 | * } |
85 | * @endcode |
86 | * |
87 | * If a user interruption or error occurred while we were writing out our |
88 | * changes, we would instead call abort() to cancel all the I/O without |
89 | * affecting the target file. |
90 | * |
91 | * @see QFile |
92 | * |
93 | * @author Jaison Lee <lee.jaison@gmail.com> |
94 | * @author Waldo Bastian <bastian@kde.org> |
95 | */ |
96 | class KDECORE_EXPORT KSaveFile : public QFile |
97 | { |
98 | public: |
99 | /** |
100 | * Default constructor. |
101 | */ |
102 | KSaveFile(); |
103 | |
104 | /** |
105 | * Creates a new KSaveFile and sets the target file to @p filename. |
106 | * |
107 | * @param filename the path of the file |
108 | * @param componentData unused |
109 | */ |
110 | explicit KSaveFile(const QString &filename, const KComponentData &componentData = KGlobal::mainComponent()); // KDE5 TODO: remove KComponentData |
111 | |
112 | /** |
113 | * Destructor. |
114 | * @note If the file has been opened but not yet finalized, the |
115 | * destructor will call finalize(). If you do not want the target file |
116 | * to be affected you need to call abort() before destroying the object. |
117 | **/ |
118 | virtual ~KSaveFile(); |
119 | |
120 | /** |
121 | * @brief Set the target filename for the save file. |
122 | * You must use this to set the filename of the target file if you do |
123 | * not use the contructor that does so. |
124 | * @param filename Name of the target file. |
125 | */ |
126 | void setFileName(const QString &filename); |
127 | |
128 | /** |
129 | * @brief Returns the name of the target file. |
130 | * This function returns the name of the target file, or an empty |
131 | * QString if it has not yet been set. |
132 | * @returns The name of the target file. |
133 | */ |
134 | QString fileName() const; |
135 | |
136 | /** |
137 | * @brief Returns the last error that occurred. |
138 | * Use this function to check for errors. |
139 | * @returns The last error that occurred, or QFile::NoError. |
140 | */ |
141 | QFile::FileError error() const; |
142 | |
143 | /** |
144 | * @brief Returns a human-readable description of the last error. |
145 | * Use this function to get a human-readable description of the |
146 | * last error that occurred. |
147 | * @return A string describing the last error that occurred. |
148 | */ |
149 | QString errorString() const; |
150 | |
151 | /** |
152 | * @brief Open the save file. |
153 | * This function will open the save file by creating a temporary file to write |
154 | * to. It will also check to ensure that there are sufficient permissions to |
155 | * write to the target file. |
156 | * |
157 | * @param flags Sets the QIODevice::OpenMode. It should contain the write flag, otherwise you |
158 | * have a save file you cannot save to. |
159 | * |
160 | * @return true if successful, or false if an error has occurred. |
161 | */ |
162 | virtual bool open(OpenMode flags = QIODevice::ReadWrite); |
163 | |
164 | /** |
165 | * @brief Discard changes without affecting the target file. |
166 | * This will discard all changes that have been made to this file. |
167 | * The target file will not be altered in any way. |
168 | **/ |
169 | void abort(); |
170 | |
171 | /** |
172 | * @brief Finalize changes to the file. |
173 | * This will commit all the changes that have been made to the file. |
174 | * @return true if successful, or false if an error has occurred. |
175 | **/ |
176 | bool finalize(); |
177 | |
178 | /** |
179 | * Allows writing over the existing file if necessary. |
180 | * |
181 | * QSaveFile creates a temporary file in the same directory as the final |
182 | * file and atomically renames it. However this is not possible if the |
183 | * directory permissions do not allow creating new files. |
184 | * In order to preserve atomicity guarantees, open() fails when it |
185 | * cannot create the temporary file. |
186 | * |
187 | * In order to allow users to edit files with write permissions in a |
188 | * directory with restricted permissions, call setDirectWriteFallback() with |
189 | * \a enabled set to true, and the following calls to open() will fallback to |
190 | * opening the existing file directly and writing into it, without the use of |
191 | * a temporary file. |
192 | * This does not have atomicity guarantees, i.e. an application crash or |
193 | * for instance a power failure could lead to a partially-written file on disk. |
194 | * It also means cancelWriting() has no effect, in such a case. |
195 | * |
196 | * Typically, to save documents edited by the user, call setDirectWriteFallback(true), |
197 | * and to save application internal files (configuration files, data files, ...), keep |
198 | * the default setting which ensures atomicity. |
199 | * |
200 | * @since 4.10.3 |
201 | */ |
202 | void setDirectWriteFallback(bool enabled); |
203 | |
204 | /** |
205 | * Returns true if the fallback solution for saving files in read-only |
206 | * directories is enabled. |
207 | * |
208 | * @since 4.10.3 |
209 | */ |
210 | bool directWriteFallback() const; |
211 | |
212 | /** |
213 | * @brief Static method to create a backup file before saving. |
214 | * |
215 | * If empty (the default), the backup will be in the same directory as @p filename. |
216 | * The backup type (simple, rcs, or numbered), extension string, and maximum |
217 | * number of backup files are read from the user's global configuration. |
218 | * Use simpleBackupFile() or numberedBackupFile() to force one of these |
219 | * specific backup styles. |
220 | * You can use this method even if you don't use KSaveFile. |
221 | * @param filename the file to backup |
222 | * @param backupDir optional directory where to save the backup file in. |
223 | * @return true if successful, or false if an error has occurred. |
224 | */ |
225 | static bool backupFile( const QString& filename, |
226 | const QString& backupDir = QString() ); |
227 | |
228 | /** |
229 | * @brief Static method to create a backup file for a given filename. |
230 | * |
231 | * This function creates a backup file from the given filename. |
232 | * You can use this method even if you don't use KSaveFile. |
233 | * @param filename the file to backup |
234 | * @param backupDir optional directory where to save the backup file in. |
235 | * If empty (the default), the backup will be in the same directory as @p filename. |
236 | * @param backupExtension the extension to append to @p filename, "~" by default. |
237 | * @return true if successful, or false if an error has occurred. |
238 | */ |
239 | static bool simpleBackupFile( const QString& filename, |
240 | const QString& backupDir = QString(), |
241 | const QString& backupExtension = QLatin1String( "~" ) ); |
242 | |
243 | /** |
244 | * @brief Static method to create a backup file for a given filename. |
245 | * |
246 | * This function creates a series of numbered backup files from the |
247 | * given filename. |
248 | * |
249 | * The backup file names will be of the form: |
250 | * \<name\>.\<number\>\<extension\> |
251 | * for instance |
252 | * \verbatim chat.3.log \endverbatim |
253 | * |
254 | * The new backup file will be have the backup number 1. |
255 | * Each existing backup file will have its number incremented by 1. |
256 | * Any backup files with numbers greater than the maximum number |
257 | * permitted (@p maxBackups) will be removed. |
258 | * You can use this method even if you don't use KSaveFile. |
259 | * |
260 | * @param filename the file to backup |
261 | * @param backupDir optional directory where to save the backup file in. |
262 | * If empty (the default), the backup will be in the same directory as |
263 | * @p filename. |
264 | * @param backupExtension the extension to append to @p filename, |
265 | * which is "~" by default. Do not use an extension containing digits. |
266 | * @param maxBackups the maximum number of backup files permitted. |
267 | * For best performance a small number (10) is recommended. |
268 | * @return true if successful, or false if an error has occurred. |
269 | */ |
270 | static bool numberedBackupFile( const QString& filename, |
271 | const QString& backupDir = QString(), |
272 | const QString& backupExtension = QString::fromLatin1( "~" ), |
273 | const uint maxBackups = 10 |
274 | ); |
275 | |
276 | |
277 | /** |
278 | * @brief Static method to create an rcs backup file for a given filename. |
279 | * |
280 | * This function creates a rcs-formatted backup file from the |
281 | * given filename. |
282 | * |
283 | * The backup file names will be of the form: |
284 | * \<name\>,v |
285 | * for instance |
286 | * \verbatim photo.jpg,v \endverbatim |
287 | * |
288 | * The new backup file will be in RCS format. |
289 | * Each existing backup file will be committed as a new revision. |
290 | * You can use this method even if you don't use KSaveFile. |
291 | * |
292 | * @param filename the file to backup |
293 | * @param backupDir optional directory where to save the backup file in. |
294 | * If empty (the default), the backup will be in the same directory as |
295 | * @p filename. |
296 | * @param backupMessage is the RCS commit message for this revision. |
297 | * @return true if successful, or false if an error has occurred. |
298 | */ |
299 | static bool rcsBackupFile( const QString& filename, |
300 | const QString& backupDir = QString(), |
301 | const QString& backupMessage = QString() |
302 | ); |
303 | |
304 | private: |
305 | Q_DISABLE_COPY(KSaveFile) |
306 | |
307 | class Private; |
308 | Private *const d; |
309 | }; |
310 | |
311 | #endif |
312 | |