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 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 | */ |
55 | class KCOREADDONS_EXPORT KDirWatch : public QObject |
56 | { |
57 | Q_OBJECT |
58 | |
59 | public: |
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 | |
245 | public 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 | |
265 | Q_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 | |
297 | private: |
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 | */ |
307 | KCOREADDONS_EXPORT QDebug operator<<(QDebug debug, const KDirWatch &watch); |
308 | |
309 | Q_DECLARE_OPERATORS_FOR_FLAGS(KDirWatch::WatchModes) |
310 | |
311 | #endif |
312 | |