]> git.lyx.org Git - lyx.git/blobdiff - src/support/FileMonitor.h
Keep permissions of the saved files intact. (Backporting 04fe818b2239).
[lyx.git] / src / support / FileMonitor.h
index 09d85e81a11eb2ac3b2ab279c8ec550f340f791f..07a8dc532c93335007ab4f9b79e5b24afa445dd6 100644 (file)
@@ -4,6 +4,7 @@
  * This file is part of LyX, the document processor.
  * Licence details can be found in the file COPYING.
  *
+ * \author Angus Leeming
  * \author Guillaume Munch
  *
  * Full author contact details are available in file CREDITS.
 #ifndef FILEMONITOR_H
 #define FILEMONITOR_H
 
+#include "support/FileName.h"
+#include "support/signals.h"
+
 #include <memory>
 
 #include <QFileSystemWatcher>
 #include <QObject>
-
-#include <boost/signals2.hpp>
+#include <QPointer>
 
 
 namespace lyx {
 namespace support {
 
-class FileName;
-
 ///
 ///  FileMonitor, a file monitor based on QFileSystemWatcher
 ///
 
 class FileMonitor;
+class ActiveFileMonitor;
 class FileMonitorGuard;
-using FileMonitorPtr = std::unique_ptr<FileMonitor>;
+typedef std::unique_ptr<FileMonitor> FileMonitorPtr;
+typedef std::unique_ptr<ActiveFileMonitor> ActiveFileMonitorPtr;
 
 ///
 /// Watch a file:
@@ -57,37 +60,32 @@ using FileMonitorPtr = std::unique_ptr<FileMonitor>;
 ///   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.
+       /// 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 to monitor
+       /// A global instance is created automatically on first call
        static FileSystemWatcher & instance();
-       // Caches the monitor guards but allow them to be destroyed
+       ///
+       std::shared_ptr<FileMonitorGuard> getGuard(FileName const & filename);
+       /// 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
+       /// This class is a wrapper for QFileSystemWatcher
        std::unique_ptr<QFileSystemWatcher> const qwatcher_;
 };
 
 
-// Must be unique per path
-// Ends the watch when deleted
+/// Must be unique per path
+/// Ends the watch when deleted
 class FileMonitorGuard : public QObject
 {
        Q_OBJECT
@@ -100,16 +98,16 @@ public:
        ~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
        /// <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);
+       void refresh(bool emit = true);
 
 Q_SIGNALS:
        /// Connect to this to be notified when the file changes
-       void fileChanged() const;
+       void fileChanged(bool exists) const;
 
 private Q_SLOTS:
        /// Receive notifications from the QFileSystemWatcher
@@ -118,73 +116,81 @@ private Q_SLOTS:
 private:
        std::string const filename_;
        QFileSystemWatcher * qwatcher_;
+       /// for emitting fileChanged() when the file is created or deleted
+       bool exists_;
 };
 
 
-class FileMonitorBlockerGuard : public QObject
-{
-       Q_OBJECT
-       FileMonitor * parent_;
-       int delay_;
-
-public:
-       FileMonitorBlockerGuard(FileMonitor * parent);
-       ~FileMonitorBlockerGuard();
-       void setDelay(int delay);
-};
-
-
-using FileMonitorBlocker = std::shared_ptr<FileMonitorBlockerGuard>;
-
-
 /// Main class
 class FileMonitor : public QObject
 {
        Q_OBJECT
-       friend class FileMonitorBlockerGuard;
 
 public:
        FileMonitor(std::shared_ptr<FileMonitorGuard> monitor);
 
-       using sig = boost::signals2::signal<void()>;
+       typedef signals2::signal<void(bool)> sig;
+       typedef sig::slot_type slot;
        /// Connect and you'll be informed when the file has changed.
-       boost::signals2::connection connect(sig::slot_type const &);
-       /// disconnect all slots connected to the boost signal fileChanged_ or to
-       /// the qt signal fileChanged()
-       void disconnect();
+       signals2::connection connect(slot const &);
        /// absolute path being tracked
        std::string const & filename() { return monitor_->filename(); }
-       /// Creates a guard that blocks notifications. Copyable. Notifications from
-       /// this monitor are blocked as long as there are copies around.
-       /// \param delay is the amount waited in ms after expiration of the guard
-       /// before reconnecting. This delay thing is to deal with asynchronous
-       /// notifications in a not so elegant fashion. But it can also be used to
-       /// slow down incoming events.
-       FileMonitorBlocker block(int delay = 0);
        /// Make sure the good file is being monitored, after e.g. a move or a
        /// deletion. See <https://bugreports.qt.io/browse/QTBUG-46483>. This is
        /// called automatically.
-       void refresh() { return monitor_->refresh(); }
+       void refresh() { monitor_->refresh(); }
 
 Q_SIGNALS:
        /// Connect to this to be notified when the file changes
-       void fileChanged() const;
+       void fileChanged(bool exists) const;
 
-private Q_SLOTS:
+protected Q_SLOTS:
        /// Receive notifications from the FileMonitorGuard
-       void changed();
+       void changed(bool exists);
+       ///
+       void connectToFileMonitorGuard();
 
 private:
-       void connectToFileMonitorGuard();
-       // boost signal
+       /// boost signal
        sig fileChanged_;
-       // the unique watch for our file
+       /// the unique watch for our file
        std::shared_ptr<FileMonitorGuard> const monitor_;
-       //
-       std::weak_ptr<FileMonitorBlockerGuard> blocker_;
 };
 
 
+/// 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<FileMonitorGuard> 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();
+
+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