X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fsupport%2FFileMonitor.h;h=07a8dc532c93335007ab4f9b79e5b24afa445dd6;hb=82b3a26a320f1056b09d4061bfbe704e838b7487;hp=3ddf4417a9b540b86d19c633bc67a4e32de9e205;hpb=25d9537fbd059f30f8fdabcb47484ec6b7e3ef6c;p=lyx.git diff --git a/src/support/FileMonitor.h b/src/support/FileMonitor.h index 3ddf4417a9..07a8dc532c 100644 --- a/src/support/FileMonitor.h +++ b/src/support/FileMonitor.h @@ -5,8 +5,9 @@ * Licence details can be found in the file COPYING. * * \author Angus Leeming + * \author Guillaume Munch * - * Full author contact details are available in file CREDITS + * Full author contact details are available in file CREDITS. * * FileMonitor monitors a file and informs a listener when that file has * changed. @@ -15,56 +16,183 @@ #ifndef FILEMONITOR_H #define FILEMONITOR_H -#ifdef __GNUG__ -#pragma interface -#endif +#include "support/FileName.h" +#include "support/signals.h" -#include "LString.h" +#include -#include -#include -#include +#include +#include +#include -class FileMonitor : boost::noncopyable { -public: - /** Once monitoring begins, the file will be monitored every - * interval ms. - */ - FileMonitor(string const & file_with_path, int interval); - /// Define an empty d-tor out-of-line to keep boost::scoped_ptr happy. - ~FileMonitor(); +namespace lyx { +namespace support { - /// - void reset(string const & file_with_path) const; +/// +/// FileMonitor, a file monitor based on QFileSystemWatcher +/// - /// - string const & filename() const; +class FileMonitor; +class ActiveFileMonitor; +class FileMonitorGuard; +typedef std::unique_ptr FileMonitorPtr; +typedef std::unique_ptr ActiveFileMonitorPtr; - /// Begin monitoring the file - void start() const; - /// - void stop() const; +/// +/// 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) +/// +class FileSystemWatcher +{ +public: + /// 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(); /// - bool monitoring() const; + 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_; +}; + + +/// Must be unique per path +/// Ends the watch when deleted +class FileMonitorGuard : public QObject +{ + Q_OBJECT + +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_; } + +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::signal0::slot_type slot_type; + signals2::connection connect(slot const &); + /// 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(); + +public Q_SLOTS: + /// Check explicitly for a modification, but not more than once every + /// interval ms. + void checkModified(); - /// The pointer never changes although *pimpl_'s contents may. - boost::scoped_ptr const pimpl_; +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 + #endif // FILEMONITOR_H