4 * This file is part of LyX, the document processor.
5 * Licence details can be found in the file COPYING.
7 * \author Guillaume Munch
9 * Full author contact details are available in file CREDITS.
11 * FileMonitor monitors a file and informs a listener when that file has
20 #include <QFileSystemWatcher>
23 #include <boost/signals2.hpp>
32 /// FileMonitor, a file monitor based on QFileSystemWatcher
36 class FileMonitorGuard;
37 using FileMonitorPtr = std::unique_ptr<FileMonitor>;
41 /// FileMonitorPtr monitor = FileSystemWatcher::monitor(file_with_path);
42 /// monitor.connect(...); //(using boost::signals2), or:
43 /// connect(monitor, SIGNAL(fileChanged()),...); // (using Qt)
45 /// Remember that a unique_ptr is automatically deleted at the end of a scope if
46 /// it has not been moved, or when assigned. When that happens, the signal
47 /// object is deleted and therefore all the connections are closed. The file
48 /// ceases being tracked when all the monitors for a file have been deleted.
51 /// * as determined statically by the scope, or
52 /// * dynamically, using:
53 /// monitor = nullptr;
55 /// Watch a different file:
56 /// monitor = FileSystemWatcher::monitor(file_with_path2);
57 /// monitor.connect(...);
58 /// (stops watching the first)
60 /// Block notifications for the duration of a scope:
62 /// FileMonitorBlocker block = monitor.block();
66 /// Reset connections:
67 /// monitor.disconnect();
68 /// or the disconnect method of the connection object for the boost signal.
70 class FileSystemWatcher
74 static FileMonitorPtr monitor(FileName const & file_with_path);
75 // Output whether the paths tracked by qwatcher_ and the active
76 // FileMonitorGuards are in correspondence.
80 // A global instance is created automatically on first call to monitor
81 static FileSystemWatcher & instance();
82 // Caches the monitor guards but allow them to be destroyed
83 std::map<std::string, std::weak_ptr<FileMonitorGuard>> store_;
84 // This class is a wrapper for QFileSystemWatcher
85 std::unique_ptr<QFileSystemWatcher> const qwatcher_;
89 // Must be unique per path
90 // Ends the watch when deleted
91 class FileMonitorGuard : public QObject
97 FileMonitorGuard(std::string const & filename,
98 QFileSystemWatcher * qwatcher);
101 /// absolute path being tracked
102 std::string const & filename() { return filename_; }
103 /// Make sure it is being monitored, after e.g. a deletion. See
104 /// <https://bugreports.qt.io/browse/QTBUG-46483>. This is called
106 /// \param new_file If true, emit fileChanged if the file exists and was
107 /// successfully added.
108 void refresh(bool new_file = false);
111 /// Connect to this to be notified when the file changes
112 void fileChanged() const;
115 /// Receive notifications from the QFileSystemWatcher
116 void notifyChange(QString const & path);
119 std::string const filename_;
120 QFileSystemWatcher * qwatcher_;
124 class FileMonitorBlockerGuard : public QObject
127 FileMonitor * parent_;
131 FileMonitorBlockerGuard(FileMonitor * parent);
132 ~FileMonitorBlockerGuard();
133 void setDelay(int delay);
137 using FileMonitorBlocker = std::shared_ptr<FileMonitorBlockerGuard>;
141 class FileMonitor : public QObject
144 friend class FileMonitorBlockerGuard;
147 FileMonitor(std::shared_ptr<FileMonitorGuard> monitor);
149 using sig = boost::signals2::signal<void()>;
150 /// Connect and you'll be informed when the file has changed.
151 boost::signals2::connection connect(sig::slot_type const &);
152 /// disconnect all slots connected to the boost signal fileChanged_ or to
153 /// the qt signal fileChanged()
155 /// absolute path being tracked
156 std::string const & filename() { return monitor_->filename(); }
157 /// Creates a guard that blocks notifications. Copyable. Notifications from
158 /// this monitor are blocked as long as there are copies around.
159 /// \param delay is the amount waited in ms after expiration of the guard
160 /// before reconnecting. This delay thing is to deal with asynchronous
161 /// notifications in a not so elegant fashion. But it can also be used to
162 /// slow down incoming events.
163 FileMonitorBlocker block(int delay = 0);
164 /// Make sure the good file is being monitored, after e.g. a move or a
165 /// deletion. See <https://bugreports.qt.io/browse/QTBUG-46483>. This is
166 /// called automatically.
167 void refresh() { return monitor_->refresh(); }
170 /// Connect to this to be notified when the file changes
171 void fileChanged() const;
174 /// Receive notifications from the FileMonitorGuard
178 void connectToFileMonitorGuard();
181 // the unique watch for our file
182 std::shared_ptr<FileMonitorGuard> const monitor_;
184 std::weak_ptr<FileMonitorBlockerGuard> blocker_;
189 } // namespace support
192 #endif // FILEMONITOR_H