+///
+/// FileMonitor, a file monitor based on QFileSystemWatcher
+///
+
+class FileMonitor;
+class FileMonitorGuard;
+using FileMonitorPtr = std::unique_ptr<FileMonitor>;
+
+///
+/// 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)
+///
+/// Block notifications for the duration of a scope:
+/// {
+/// FileMonitorBlocker block = monitor.block();
+/// ...
+/// }
+///
+/// Reset connections:
+/// monitor.disconnect();
+/// or the disconnect method of the connection object for the boost signal.
+///
+class FileSystemWatcher
+{
+public:
+ // as described above
+ static FileMonitorPtr monitor(FileName const & file_with_path);
+ // 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 to monitor
+ static FileSystemWatcher & instance();
+ // Caches the monitor guards but allow them to be destroyed
+ std::map<std::string, std::weak_ptr<FileMonitorGuard>> store_;
+ // This class is a wrapper for QFileSystemWatcher
+ std::unique_ptr<QFileSystemWatcher> 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_; }
+ /// Make sure it is being monitored, after e.g. a deletion. See
+ /// <https://bugreports.qt.io/browse/QTBUG-46483>. This is called
+ /// automatically.
+ /// \param new_file If true, emit fileChanged if the file exists and was
+ /// successfully added.
+ void refresh(bool new_file = false);
+
+Q_SIGNALS:
+ /// Connect to this to be notified when the file changes
+ void fileChanged() const;
+
+private Q_SLOTS:
+ /// Receive notifications from the QFileSystemWatcher
+ void notifyChange(QString const & path);
+
+private:
+ std::string const filename_;
+ QFileSystemWatcher * qwatcher_;
+};
+
+
+class FileMonitorBlockerGuard : public QObject