1 | /* |
2 | This file is part of the KDE libraries |
3 | |
4 | SPDX-FileCopyrightText: 1998 Sven Radej <sven@lisa.exp.univie.ac.at> |
5 | |
6 | SPDX-License-Identifier: LGPL-2.0-only |
7 | */ |
8 | #ifndef _KDIRWATCH_H |
9 | #define _KDIRWATCH_H |
10 | |
11 | #include <QDateTime> |
12 | #include <QObject> |
13 | #include <QString> |
14 | |
15 | #include <kcoreaddons_export.h> |
16 | |
17 | class KDirWatchPrivate; |
18 | |
19 | /*! |
20 | * \class KDirWatch |
21 | * \inmodule KCoreAddons |
22 | * |
23 | * \brief Class for watching directory and file changes. |
24 | * |
25 | * Watch directories and files for changes. |
26 | * The watched directories or files don't have to exist yet. |
27 | * |
28 | * When a watched directory is changed, i.e. when files therein are |
29 | * created or deleted, KDirWatch will emit the signal dirty(). |
30 | * |
31 | * When a watched, but previously not existing directory gets created, |
32 | * KDirWatch will emit the signal created(). |
33 | * |
34 | * When a watched directory gets deleted, KDirWatch will emit the |
35 | * signal deleted(). The directory is still watched for new |
36 | * creation. |
37 | * |
38 | * When a watched file is changed, i.e. attributes changed or written |
39 | * to, KDirWatch will emit the signal dirty(). |
40 | * |
41 | * Scanning of particular directories or files can be stopped temporarily |
42 | * and restarted. The whole class can be stopped and restarted. |
43 | * Directories and files can be added/removed from the list in any state. |
44 | * |
45 | * The implementation uses the INOTIFY functionality on LINUX. |
46 | * As a last resort, a regular polling for change of modification times |
47 | * is done; the polling interval is a global config option: |
48 | * DirWatch/PollInterval and DirWatch/NFSPollInterval for NFS mounted |
49 | * directories. |
50 | * The choice of implementation can be adjusted by the user, with the key |
51 | * [DirWatch] PreferredMethod={Stat|QFSWatch|inotify} |
52 | * |
53 | */ |
54 | class KCOREADDONS_EXPORT KDirWatch : public QObject |
55 | { |
56 | Q_OBJECT |
57 | |
58 | public: |
59 | /*! |
60 | * Available watch modes for directory monitoring |
61 | * |
62 | * \value WatchDirOnly Watch just the specified directory |
63 | * \value WatchFiles Watch also all files contained by the directory |
64 | * \value WatchSubDirs Watch also all the subdirs contained by the directory |
65 | * |
66 | **/ |
67 | enum WatchMode { |
68 | WatchDirOnly = 0, |
69 | WatchFiles = 0x01, |
70 | WatchSubDirs = 0x02, |
71 | }; |
72 | Q_DECLARE_FLAGS(WatchModes, WatchMode) |
73 | |
74 | /*! |
75 | * Constructor. |
76 | * |
77 | * Scanning begins immediately when a dir/file watch |
78 | * is added. |
79 | * |
80 | * \a parent the parent of the QObject (or \c nullptr for parent-less KDataTools) |
81 | */ |
82 | explicit KDirWatch(QObject *parent = nullptr); |
83 | |
84 | /*! |
85 | * Destructor. |
86 | * |
87 | * Stops scanning and cleans up. |
88 | */ |
89 | ~KDirWatch() override; |
90 | |
91 | /*! |
92 | * Adds a directory to be watched. |
93 | * |
94 | * The directory does not have to exist. When \a watchModes is set to |
95 | * WatchDirOnly (the default), the signals dirty(), created(), deleted() |
96 | * can be emitted, all for the watched directory. |
97 | * When \a watchModes is set to WatchFiles, all files in the watched |
98 | * directory are watched for changes, too. Thus, the signals dirty(), |
99 | * created(), deleted() can be emitted. |
100 | * When \a watchModes is set to WatchSubDirs, all subdirs are watched using |
101 | * the same flags specified in \a watchModes (symlinks aren't followed). |
102 | * If the \a path points to a symlink to a directory, the target directory |
103 | * is watched instead. If you want to watch the link, use \a addFile(). |
104 | * |
105 | * \a path the path to watch |
106 | * |
107 | * \a watchModes watch modes |
108 | * |
109 | * \sa KDirWatch::WatchMode |
110 | */ |
111 | void addDir(const QString &path, WatchModes watchModes = WatchDirOnly); |
112 | |
113 | /*! |
114 | * Adds a file to be watched. |
115 | * If it's a symlink to a directory, it watches the symlink itself. |
116 | * |
117 | * \a file the file to watch |
118 | */ |
119 | void addFile(const QString &file); |
120 | |
121 | /*! |
122 | * Returns the time the directory/file was last changed. |
123 | * |
124 | * \a path the file to check |
125 | * |
126 | * Returns the date of the last modification |
127 | */ |
128 | QDateTime ctime(const QString &path) const; |
129 | |
130 | /*! |
131 | * Removes a directory from the list of scanned directories. |
132 | * |
133 | * If specified path is not in the list this does nothing. |
134 | * |
135 | * \a path the path of the dir to be removed from the list |
136 | */ |
137 | void removeDir(const QString &path); |
138 | |
139 | /*! |
140 | * Removes a file from the list of watched files. |
141 | * |
142 | * If specified path is not in the list this does nothing. |
143 | * |
144 | * \a file the file to be removed from the list |
145 | */ |
146 | void removeFile(const QString &file); |
147 | |
148 | /*! |
149 | * Stops scanning the specified path. |
150 | * |
151 | * The \a path is not deleted from the internal list, it is just skipped. |
152 | * Call this function when you perform an huge operation |
153 | * on this directory (copy/move big files or many files). When finished, |
154 | * call restartDirScan(path). |
155 | * |
156 | * \a path the path to skip |
157 | * |
158 | * Returns true if the \a path is being watched, otherwise false |
159 | * \sa restartDirScan() |
160 | */ |
161 | bool stopDirScan(const QString &path); |
162 | |
163 | /*! |
164 | * Restarts scanning for specified path. |
165 | * |
166 | * It doesn't notify about the changes (by emitting a signal). |
167 | * The ctime value is reset. |
168 | * |
169 | * Call it when you are finished with big operations on that path, |
170 | * \e and when \e you have refreshed that path. |
171 | * |
172 | * \a path the path to restart scanning |
173 | * |
174 | * Returns \c true if the \a path is being watched, otherwise false |
175 | * \sa stopDirScan() |
176 | */ |
177 | bool restartDirScan(const QString &path); |
178 | |
179 | /*! |
180 | * Starts scanning of all dirs in list. |
181 | * |
182 | * \a notify If true, all changed directories (since |
183 | * stopScan() call) will be notified for refresh. If notify is |
184 | * false, all ctimes will be reset (except those who are stopped, |
185 | * but only if \a skippedToo is false) and changed dirs won't be |
186 | * notified. You can start scanning even if the list is |
187 | * empty. First call should be called with \a false or else all |
188 | * directories |
189 | * in list will be notified. |
190 | * |
191 | * \a skippedToo if true, the skipped directories (scanning of which was |
192 | * stopped with stopDirScan() ) will be reset and notified |
193 | * for change. Otherwise, stopped directories will continue to be |
194 | * unnotified. |
195 | */ |
196 | void startScan(bool notify = false, bool skippedToo = false); |
197 | |
198 | /*! |
199 | * Stops scanning of all directories in internal list. |
200 | * |
201 | * The timer is stopped, but the list is not cleared. |
202 | */ |
203 | void stopScan(); |
204 | |
205 | /*! |
206 | * Is scanning stopped? |
207 | * After creation of a KDirWatch instance, this is false. |
208 | * Returns true when scanning stopped |
209 | */ |
210 | bool isStopped(); |
211 | |
212 | /*! |
213 | * Check if a directory is being watched by this KDirWatch instance |
214 | * \a path the directory to check |
215 | * Returns true if the directory is being watched |
216 | */ |
217 | bool contains(const QString &path) const; |
218 | |
219 | /*! |
220 | \enum KDirWatch::Method |
221 | |
222 | \value INotify INotify |
223 | \value Stat Stat |
224 | \value QFSWatch QFileSystemWatcher |
225 | */ |
226 | enum Method { |
227 | INotify, |
228 | Stat, |
229 | QFSWatch, |
230 | }; |
231 | /*! |
232 | * Returns the preferred internal method to |
233 | * watch for changes. |
234 | */ |
235 | Method internalMethod() const; |
236 | |
237 | /*! |
238 | * The KDirWatch instance usually globally used in an application. |
239 | * It is automatically deleted when the application exits. |
240 | * |
241 | * However, you can create an arbitrary number of KDirWatch instances |
242 | * aside from this one - for those you have to take care of memory management. |
243 | * |
244 | * This function returns an instance of KDirWatch. If there is none, it |
245 | * will be created. |
246 | * |
247 | * Returns a KDirWatch instance |
248 | */ |
249 | static KDirWatch *self(); |
250 | /*! |
251 | * Returns true if there is an instance of KDirWatch. |
252 | * \sa KDirWatch::self() |
253 | */ |
254 | static bool exists(); |
255 | |
256 | bool event(QEvent *event) override; |
257 | |
258 | public Q_SLOTS: |
259 | |
260 | /*! |
261 | * Emits created(). |
262 | * |
263 | * \a path the path of the file or directory |
264 | */ |
265 | void setCreated(const QString &path); |
266 | |
267 | /*! |
268 | * Emits dirty(). |
269 | * |
270 | * \a path the path of the file or directory |
271 | */ |
272 | void setDirty(const QString &path); |
273 | |
274 | /*! |
275 | * Emits deleted(). |
276 | * |
277 | * \a path the path of the file or directory |
278 | */ |
279 | void setDeleted(const QString &path); |
280 | |
281 | Q_SIGNALS: |
282 | |
283 | /*! |
284 | * Emitted when a watched object is changed. |
285 | * For a directory this signal is emitted when files |
286 | * therein are created or deleted. |
287 | * For a file this signal is emitted when its size or attributes change. |
288 | * |
289 | * When you watch a directory, changes in the size or attributes of |
290 | * contained files may or may not trigger this signal to be emitted |
291 | * depending on which backend is used by KDirWatch. |
292 | * |
293 | * The new ctime is set before the signal is emitted. |
294 | * |
295 | * \a path the path of the file or directory |
296 | */ |
297 | void dirty(const QString &path); |
298 | |
299 | /*! |
300 | * Emitted when a file or directory (being watched explicitly) is created. |
301 | * This is not emitted when creating a file is created in a watched directory. |
302 | * |
303 | * \a path the path of the file or directory |
304 | */ |
305 | void created(const QString &path); |
306 | |
307 | /*! |
308 | * Emitted when a file or directory is deleted. |
309 | * |
310 | * The object is still watched for new creation. |
311 | * |
312 | * \a path the path of the file or directory |
313 | */ |
314 | void deleted(const QString &path); |
315 | |
316 | private: |
317 | KDirWatchPrivate *d; |
318 | friend class KDirWatchPrivate; |
319 | friend class KDirWatch_UnitTest; |
320 | }; |
321 | |
322 | /*! |
323 | * Dump debug information about the KDirWatch::self() instance. |
324 | * This checks for consistency, too. |
325 | * \relates KDirWatch |
326 | */ |
327 | KCOREADDONS_EXPORT QDebug operator<<(QDebug debug, const KDirWatch &watch); |
328 | |
329 | Q_DECLARE_OPERATORS_FOR_FLAGS(KDirWatch::WatchModes) |
330 | |
331 | #endif |
332 | |