* 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:
/// 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
~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
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