X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fsupport%2FFileMonitor.h;h=14aa834c80c6a556a09fb2a73ae96f92999f5154;hb=28be7d552f62cc02fa86d7f79201d089bfb2d7b5;hp=2c2131025195e1b819346ac49e1e7c0cbc729b1c;hpb=fad47c0fe0a45da4ac4a395817a0ad73425ef275;p=lyx.git diff --git a/src/support/FileMonitor.h b/src/support/FileMonitor.h index 2c21310251..14aa834c80 100644 --- a/src/support/FileMonitor.h +++ b/src/support/FileMonitor.h @@ -5,6 +5,7 @@ * Licence details can be found in the file COPYING. * * \author Angus Leeming + * \author Guillaume Munch * * Full author contact details are available in file CREDITS. * @@ -15,58 +16,189 @@ #ifndef FILEMONITOR_H #define FILEMONITOR_H -#include -#include -#include +#include "support/FileName.h" +#include "support/signals.h" + +#include + +#include +#include +#include + namespace lyx { namespace support { -class FileName; +/// +/// FileMonitor, a file monitor based on QFileSystemWatcher +/// -class FileMonitor : boost::noncopyable { +class FileMonitor; +class ActiveFileMonitor; +class FileMonitorGuard; +typedef std::unique_ptr FileMonitorPtr; +typedef std::unique_ptr ActiveFileMonitorPtr; + +/// +/// Watch a file: +/// FileMonitorPtr monitor = FileSystemWatcher::monitor(file_with_path); +/// monitor.connect(...); //(using boost::signals2), or: +/// connect(monitor, SIGNAL(fileChanged()),...); // (using Qt) +/// +/// Remember that a unique_ptr is automatically deleted at the end of a scope if +/// it has not been moved, or when assigned. When that happens, the signal +/// object is deleted and therefore all the connections are closed. The file +/// ceases being tracked when all the monitors for a file have been deleted. +/// +/// Stop watching: +/// * as determined statically by the scope, or +/// * dynamically, using: +/// monitor = nullptr; +/// +/// Watch a different file: +/// monitor = FileSystemWatcher::monitor(file_with_path2); +/// monitor.connect(...); +/// (stops watching the first) +/// +/// Reset connections: +/// monitor.disconnect(); +/// or the disconnect method of the connection object for the boost signal. +/// +class FileSystemWatcher +{ public: - /** Once monitoring begins, the file will be monitored every - * interval ms. - */ - FileMonitor(FileName const & file_with_path, int interval); + /// as described above + static FileMonitorPtr monitor(FileName const & filename); + /// same but with an ActiveFileMonitor + static ActiveFileMonitorPtr activeMonitor(FileName const & filename, + int interval = 10000); + /// Output whether the paths tracked by qwatcher_ and the active + /// FileMonitorGuards are in correspondence. + static void debug(); +private: + FileSystemWatcher(); + /// A global instance is created automatically on first call + static FileSystemWatcher & instance(); + /// + std::shared_ptr getGuard(FileName const & filename); + /// Caches the monitor guards but allow them to be destroyed + std::map> store_; + /// This class is a wrapper for QFileSystemWatcher + std::unique_ptr const qwatcher_; +}; - /// Define an empty d-tor out-of-line to keep boost::scoped_ptr happy. - ~FileMonitor(); - /// - void reset(FileName const & file_with_path) const; +/// Must be unique per path +/// Ends the watch when deleted +class FileMonitorGuard : public QObject +{ + Q_OBJECT - /// - FileName const & filename() const; +public: + /// Start the watch + FileMonitorGuard(std::string const & filename, + QFileSystemWatcher * qwatcher); + /// End the watch + ~FileMonitorGuard(); + /// absolute path being tracked + std::string const & filename() { return filename_; } - /// Begin monitoring the file - void start() const; - /// - void stop() const; - /// - bool monitoring() const; +public Q_SLOTS: + /// Make sure it is being monitored, after e.g. a deletion. See + /// . This is called + /// automatically. + void refresh(bool emit = true); + +Q_SIGNALS: + /// Connect to this to be notified when the file changes + void fileChanged(bool exists) const; + +private Q_SLOTS: + /// Receive notifications from the QFileSystemWatcher + void notifyChange(QString const & path); + +private: + std::string const filename_; + QFileSystemWatcher * qwatcher_; + /// for emitting fileChanged() when the file is created or deleted + bool exists_; +}; - /** The checksum is recomputed whenever the file is modified. - * If the file is not being monitored, then the checksum will be - * recomputed each time this function is called. - */ - unsigned long checksum() const; +/// Main class +class FileMonitor : public QObject +{ + Q_OBJECT + +public: + FileMonitor(std::shared_ptr monitor); + + typedef signals2::signal sig; + typedef sig::slot_type slot; /// Connect and you'll be informed when the file has changed. - typedef boost::signal FileChangedSig; - typedef FileChangedSig::slot_type slot_type; + signals2::connection connect(slot const &); + /// disconnect all slots connected to the boost signal fileChanged_ or to + /// the qt signal fileChanged() + void disconnect(); + /// absolute path being tracked + std::string const & filename() { return monitor_->filename(); } + /// Make sure the good file is being monitored, after e.g. a move or a + /// deletion. See . This is + /// called automatically. + void refresh() { monitor_->refresh(); } + +Q_SIGNALS: + /// Connect to this to be notified when the file changes + void fileChanged(bool exists) const; + +protected Q_SLOTS: + /// Receive notifications from the FileMonitorGuard + void changed(bool exists); /// - boost::signals::connection connect(slot_type const &) const; + void connectToFileMonitorGuard(); private: - /// Use the Pimpl idiom to hide the internals. - class Impl; + /// boost signal + sig fileChanged_; + /// the unique watch for our file + std::shared_ptr const monitor_; +}; + + +/// When a more active monitoring style is needed. +/// For instance because QFileSystemWatcher does not work for remote file +/// systems. +class ActiveFileMonitor : public FileMonitor +{ + Q_OBJECT +public: + ActiveFileMonitor(std::shared_ptr monitor, + FileName const & filename, int interval); + /// call checkModified asynchronously + void checkModifiedAsync(); - /// The pointer never changes although *pimpl_'s contents may. - boost::scoped_ptr const pimpl_; +public Q_SLOTS: + /// Check explicitly for a modification, but not more than once every + /// interval ms. + void checkModified(); + +private Q_SLOTS: + void setCooldown() { cooldown_ = true; } + void clearCooldown() { cooldown_ = false; } + +private: + FileName const filename_; + /// + int const interval_; + /// + time_t timestamp_; + /// + unsigned long checksum_; + /// + bool cooldown_; }; + } // namespace support } // namespace lyx