File indexing completed on 2024-05-19 03:56:20
0001 /* 0002 This file is part of the KDE libraries 0003 0004 SPDX-FileCopyrightText: 1998 Sven Radej <sven@lisa.exp.univie.ac.at> 0005 0006 SPDX-License-Identifier: LGPL-2.0-only 0007 */ 0008 #ifndef _KDIRWATCH_H 0009 #define _KDIRWATCH_H 0010 0011 #include <QDateTime> 0012 #include <QObject> 0013 #include <QString> 0014 0015 #include <kcoreaddons_export.h> 0016 0017 class KDirWatchPrivate; 0018 0019 /** 0020 * @class KDirWatch kdirwatch.h KDirWatch 0021 * 0022 * @short Class for watching directory and file changes. 0023 * 0024 * Watch directories and files for changes. 0025 * The watched directories or files don't have to exist yet. 0026 * 0027 * When a watched directory is changed, i.e. when files therein are 0028 * created or deleted, KDirWatch will emit the signal dirty(). 0029 * 0030 * When a watched, but previously not existing directory gets created, 0031 * KDirWatch will emit the signal created(). 0032 * 0033 * When a watched directory gets deleted, KDirWatch will emit the 0034 * signal deleted(). The directory is still watched for new 0035 * creation. 0036 * 0037 * When a watched file is changed, i.e. attributes changed or written 0038 * to, KDirWatch will emit the signal dirty(). 0039 * 0040 * Scanning of particular directories or files can be stopped temporarily 0041 * and restarted. The whole class can be stopped and restarted. 0042 * Directories and files can be added/removed from the list in any state. 0043 * 0044 * The implementation uses the INOTIFY functionality on LINUX. 0045 * As a last resort, a regular polling for change of modification times 0046 * is done; the polling interval is a global config option: 0047 * DirWatch/PollInterval and DirWatch/NFSPollInterval for NFS mounted 0048 * directories. 0049 * The choice of implementation can be adjusted by the user, with the key 0050 * [DirWatch] PreferredMethod={Stat|QFSWatch|inotify} 0051 * 0052 * @see self() 0053 * @author Sven Radej (in 1998) 0054 */ 0055 class KCOREADDONS_EXPORT KDirWatch : public QObject 0056 { 0057 Q_OBJECT 0058 0059 public: 0060 /** 0061 * Available watch modes for directory monitoring 0062 * @see WatchModes 0063 **/ 0064 enum WatchMode { 0065 WatchDirOnly = 0, ///< Watch just the specified directory 0066 WatchFiles = 0x01, ///< Watch also all files contained by the directory 0067 WatchSubDirs = 0x02, ///< Watch also all the subdirs contained by the directory 0068 }; 0069 /** 0070 * Stores a combination of #WatchMode values. 0071 */ 0072 Q_DECLARE_FLAGS(WatchModes, WatchMode) 0073 0074 /** 0075 * Constructor. 0076 * 0077 * Scanning begins immediately when a dir/file watch 0078 * is added. 0079 * @param parent the parent of the QObject (or @c nullptr for parent-less KDataTools) 0080 */ 0081 explicit KDirWatch(QObject *parent = nullptr); 0082 0083 /** 0084 * Destructor. 0085 * 0086 * Stops scanning and cleans up. 0087 */ 0088 ~KDirWatch() override; 0089 0090 /** 0091 * Adds a directory to be watched. 0092 * 0093 * The directory does not have to exist. When @p watchModes is set to 0094 * WatchDirOnly (the default), the signals dirty(), created(), deleted() 0095 * can be emitted, all for the watched directory. 0096 * When @p watchModes is set to WatchFiles, all files in the watched 0097 * directory are watched for changes, too. Thus, the signals dirty(), 0098 * created(), deleted() can be emitted. 0099 * When @p watchModes is set to WatchSubDirs, all subdirs are watched using 0100 * the same flags specified in @p watchModes (symlinks aren't followed). 0101 * If the @p path points to a symlink to a directory, the target directory 0102 * is watched instead. If you want to watch the link, use @p addFile(). 0103 * 0104 * @param path the path to watch 0105 * @param watchModes watch modes 0106 * 0107 * @sa KDirWatch::WatchMode 0108 */ 0109 void addDir(const QString &path, WatchModes watchModes = WatchDirOnly); 0110 0111 /** 0112 * Adds a file to be watched. 0113 * If it's a symlink to a directory, it watches the symlink itself. 0114 * @param file the file to watch 0115 */ 0116 void addFile(const QString &file); 0117 0118 /** 0119 * Returns the time the directory/file was last changed. 0120 * @param path the file to check 0121 * @return the date of the last modification 0122 */ 0123 QDateTime ctime(const QString &path) const; 0124 0125 /** 0126 * Removes a directory from the list of scanned directories. 0127 * 0128 * If specified path is not in the list this does nothing. 0129 * @param path the path of the dir to be removed from the list 0130 */ 0131 void removeDir(const QString &path); 0132 0133 /** 0134 * Removes a file from the list of watched files. 0135 * 0136 * If specified path is not in the list this does nothing. 0137 * @param file the file to be removed from the list 0138 */ 0139 void removeFile(const QString &file); 0140 0141 /** 0142 * Stops scanning the specified path. 0143 * 0144 * The @p path is not deleted from the internal list, it is just skipped. 0145 * Call this function when you perform an huge operation 0146 * on this directory (copy/move big files or many files). When finished, 0147 * call restartDirScan(path). 0148 * 0149 * @param path the path to skip 0150 * @return true if the @p path is being watched, otherwise false 0151 * @see restartDirScan() 0152 */ 0153 bool stopDirScan(const QString &path); 0154 0155 /** 0156 * Restarts scanning for specified path. 0157 * 0158 * It doesn't notify about the changes (by emitting a signal). 0159 * The ctime value is reset. 0160 * 0161 * Call it when you are finished with big operations on that path, 0162 * @em and when @em you have refreshed that path. 0163 * 0164 * @param path the path to restart scanning 0165 * @return true if the @p path is being watched, otherwise false 0166 * @see stopDirScan() 0167 */ 0168 bool restartDirScan(const QString &path); 0169 0170 /** 0171 * Starts scanning of all dirs in list. 0172 * 0173 * @param notify If true, all changed directories (since 0174 * stopScan() call) will be notified for refresh. If notify is 0175 * false, all ctimes will be reset (except those who are stopped, 0176 * but only if @p skippedToo is false) and changed dirs won't be 0177 * notified. You can start scanning even if the list is 0178 * empty. First call should be called with @p false or else all 0179 * directories 0180 * in list will be notified. 0181 * @param skippedToo if true, the skipped directories (scanning of which was 0182 * stopped with stopDirScan() ) will be reset and notified 0183 * for change. Otherwise, stopped directories will continue to be 0184 * unnotified. 0185 */ 0186 void startScan(bool notify = false, bool skippedToo = false); 0187 0188 /** 0189 * Stops scanning of all directories in internal list. 0190 * 0191 * The timer is stopped, but the list is not cleared. 0192 */ 0193 void stopScan(); 0194 0195 /** 0196 * Is scanning stopped? 0197 * After creation of a KDirWatch instance, this is false. 0198 * @return true when scanning stopped 0199 */ 0200 bool isStopped(); 0201 0202 /** 0203 * Check if a directory is being watched by this KDirWatch instance 0204 * @param path the directory to check 0205 * @return true if the directory is being watched 0206 */ 0207 bool contains(const QString &path) const; 0208 0209 enum Method { 0210 INotify, 0211 Stat, 0212 QFSWatch, 0213 }; 0214 /** 0215 * Returns the preferred internal method to 0216 * watch for changes. 0217 */ 0218 Method internalMethod() const; 0219 0220 /** 0221 * The KDirWatch instance usually globally used in an application. 0222 * It is automatically deleted when the application exits. 0223 * 0224 * However, you can create an arbitrary number of KDirWatch instances 0225 * aside from this one - for those you have to take care of memory management. 0226 * 0227 * This function returns an instance of KDirWatch. If there is none, it 0228 * will be created. 0229 * 0230 * @return a KDirWatch instance 0231 */ 0232 static KDirWatch *self(); 0233 /** 0234 * Returns true if there is an instance of KDirWatch. 0235 * @return true if there is an instance of KDirWatch. 0236 * @see KDirWatch::self() 0237 */ 0238 static bool exists(); 0239 0240 /** 0241 * @brief Trivial override. See QObject::event. 0242 */ 0243 bool event(QEvent *event) override; 0244 0245 public Q_SLOTS: 0246 0247 /** 0248 * Emits created(). 0249 * @param path the path of the file or directory 0250 */ 0251 void setCreated(const QString &path); 0252 0253 /** 0254 * Emits dirty(). 0255 * @param path the path of the file or directory 0256 */ 0257 void setDirty(const QString &path); 0258 0259 /** 0260 * Emits deleted(). 0261 * @param path the path of the file or directory 0262 */ 0263 void setDeleted(const QString &path); 0264 0265 Q_SIGNALS: 0266 0267 /** 0268 * Emitted when a watched object is changed. 0269 * For a directory this signal is emitted when files 0270 * therein are created or deleted. 0271 * For a file this signal is emitted when its size or attributes change. 0272 * 0273 * When you watch a directory, changes in the size or attributes of 0274 * contained files may or may not trigger this signal to be emitted 0275 * depending on which backend is used by KDirWatch. 0276 * 0277 * The new ctime is set before the signal is emitted. 0278 * @param path the path of the file or directory 0279 */ 0280 void dirty(const QString &path); 0281 0282 /** 0283 * Emitted when a file or directory (being watched explicitly) is created. 0284 * This is not emitted when creating a file is created in a watched directory. 0285 * @param path the path of the file or directory 0286 */ 0287 void created(const QString &path); 0288 0289 /** 0290 * Emitted when a file or directory is deleted. 0291 * 0292 * The object is still watched for new creation. 0293 * @param path the path of the file or directory 0294 */ 0295 void deleted(const QString &path); 0296 0297 private: 0298 KDirWatchPrivate *d; 0299 friend class KDirWatchPrivate; 0300 friend class KDirWatch_UnitTest; 0301 }; 0302 0303 /** 0304 * Dump debug information about the KDirWatch::self() instance. 0305 * This checks for consistency, too. 0306 */ 0307 KCOREADDONS_EXPORT QDebug operator<<(QDebug debug, const KDirWatch &watch); 0308 0309 Q_DECLARE_OPERATORS_FOR_FLAGS(KDirWatch::WatchModes) 0310 0311 #endif