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

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