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