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
17class 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 */
54class KCOREADDONS_EXPORT KDirWatch : public QObject
55{
56 Q_OBJECT
57
58public:
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
258public 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
281Q_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
316private:
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 */
327KCOREADDONS_EXPORT QDebug operator<<(QDebug debug, const KDirWatch &watch);
328
329Q_DECLARE_OPERATORS_FOR_FLAGS(KDirWatch::WatchModes)
330
331#endif
332

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