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