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>
24 #include <boost/signals2.hpp>
33 /// FileMonitor, a file monitor based on QFileSystemWatcher
37 class FileMonitorGuard;
38 typedef std::unique_ptr<FileMonitor> FileMonitorPtr;
42 /// FileMonitorPtr monitor = FileSystemWatcher::monitor(file_with_path);
43 /// monitor.connect(...); //(using boost::signals2), or:
44 /// connect(monitor, SIGNAL(fileChanged()),...); // (using Qt)
46 /// Remember that a unique_ptr is automatically deleted at the end of a scope if
47 /// it has not been moved, or when assigned. When that happens, the signal
48 /// object is deleted and therefore all the connections are closed. The file
49 /// ceases being tracked when all the monitors for a file have been deleted.
52 /// * as determined statically by the scope, or
53 /// * dynamically, using:
54 /// monitor = nullptr;
56 /// Watch a different file:
57 /// monitor = FileSystemWatcher::monitor(file_with_path2);
58 /// monitor.connect(...);
59 /// (stops watching the first)
61 /// Block notifications for the duration of a scope:
63 /// FileMonitorBlocker block = monitor.block();
67 /// Reset connections:
68 /// monitor.disconnect();
69 /// or the disconnect method of the connection object for the boost signal.
71 class FileSystemWatcher
75 static FileMonitorPtr monitor(FileName const & file_with_path);
76 // Output whether the paths tracked by qwatcher_ and the active
77 // FileMonitorGuards are in correspondence.
81 // A global instance is created automatically on first call to monitor
82 static FileSystemWatcher & instance();
83 // Caches the monitor guards but allow them to be destroyed
84 std::map<std::string, std::weak_ptr<FileMonitorGuard>> store_;
85 // This class is a wrapper for QFileSystemWatcher
86 std::unique_ptr<QFileSystemWatcher> const qwatcher_;
90 // Must be unique per path
91 // Ends the watch when deleted
92 class FileMonitorGuard : public QObject
98 FileMonitorGuard(std::string const & filename,
99 QFileSystemWatcher * qwatcher);
102 /// absolute path being tracked
103 std::string const & filename() { return filename_; }
104 /// if false, emit fileChanged() when we notice the existence of the file
105 void setExists(bool exists) { exists_ = exists; }
108 /// Make sure it is being monitored, after e.g. a deletion. See
109 /// <https://bugreports.qt.io/browse/QTBUG-46483>. This is called
114 /// Connect to this to be notified when the file changes
115 void fileChanged() const;
118 /// Receive notifications from the QFileSystemWatcher
119 void notifyChange(QString const & path);
122 std::string const filename_;
123 QFileSystemWatcher * qwatcher_;
128 class FileMonitorBlockerGuard : public QObject
131 QPointer<FileMonitor> monitor_;
135 FileMonitorBlockerGuard(FileMonitor * monitor);
136 ~FileMonitorBlockerGuard();
137 void setDelay(int delay);
141 typedef std::shared_ptr<FileMonitorBlockerGuard> FileMonitorBlocker;
145 class FileMonitor : public QObject
148 friend class FileMonitorBlockerGuard;
151 FileMonitor(std::shared_ptr<FileMonitorGuard> monitor);
153 typedef boost::signals2::signal<void()> sig;
154 /// Connect and you'll be informed when the file has changed.
155 boost::signals2::connection connect(sig::slot_type const &);
156 /// disconnect all slots connected to the boost signal fileChanged_ or to
157 /// the qt signal fileChanged()
159 /// absolute path being tracked
160 std::string const & filename() { return monitor_->filename(); }
161 /// Creates a guard that blocks notifications. Copyable. Notifications from
162 /// this monitor are blocked as long as there are copies around.
163 /// \param delay is the amount waited in ms after expiration of the guard
164 /// before reconnecting. This delay thing is to deal with asynchronous
165 /// notifications in a not so elegant fashion. But it can also be used to
166 /// slow down incoming events.
167 FileMonitorBlocker block(int delay = 0);
168 /// Make sure the good file is being monitored, after e.g. a move or a
169 /// deletion. See <https://bugreports.qt.io/browse/QTBUG-46483>. This is
170 /// called automatically.
171 void refresh() { return monitor_->refresh(); }
174 /// Connect to this to be notified when the file changes
175 void fileChanged() const;
178 /// Receive notifications from the FileMonitorGuard
181 void reconnectToFileMonitorGuard();
186 // the unique watch for our file
187 std::shared_ptr<FileMonitorGuard> const monitor_;
189 std::weak_ptr<FileMonitorBlockerGuard> blocker_;
194 } // namespace support
197 #endif // FILEMONITOR_H