//static
FileMonitorPtr FileSystemWatcher::monitor(FileName const & filename)
{
- return make_unique<FileMonitor>(instance().getGuard(filename));
+ return lyx::make_unique<FileMonitor>(instance().getGuard(filename));
}
ActiveFileMonitorPtr FileSystemWatcher::activeMonitor(FileName const & filename,
int interval)
{
- return make_unique<ActiveFileMonitor>(instance().getGuard(filename),
+ return lyx::make_unique<ActiveFileMonitor>(instance().getGuard(filename),
filename, interval);
}
QFileSystemWatcher * qwatcher)
: filename_(filename), qwatcher_(qwatcher), exists_(true)
{
+ if (filename.empty())
+ return;
QObject::connect(qwatcher, SIGNAL(fileChanged(QString const &)),
this, SLOT(notifyChange(QString const &)));
if (qwatcher_->files().contains(toqstr(filename)))
FileMonitorGuard::~FileMonitorGuard()
{
- qwatcher_->removePath(toqstr(filename_));
+ if (!filename_.empty())
+ qwatcher_->removePath(toqstr(filename_));
}
-void FileMonitorGuard::refresh()
+void FileMonitorGuard::refresh(bool const emit)
{
+ if (filename_.empty())
+ return;
QString const qfilename = toqstr(filename_);
- if(!qwatcher_->files().contains(qfilename)) {
- bool exists = QFile(qfilename).exists();
+ if (!qwatcher_->files().contains(qfilename)) {
+ bool const existed = exists_;
+ exists_ = QFile(qfilename).exists();
#if (QT_VERSION >= 0x050000)
- if (!exists || !qwatcher_->addPath(qfilename))
+ if (exists_ && !qwatcher_->addPath(qfilename))
#else
auto add_path = [&]() {
qwatcher_->addPath(qfilename);
return qwatcher_->files().contains(qfilename);
};
- if (!exists || !add_path())
+ if (exists_ && !add_path())
#endif
{
- if (exists)
- LYXERR(Debug::FILES,
- "Could not add path to QFileSystemWatcher: "
- << filename_);
- QTimer::singleShot(2000, this, SLOT(refresh()));
- } else if (exists && !exists_)
- Q_EMIT fileChanged();
- setExists(exists);
+ LYXERR(Debug::FILES,
+ "Could not add path to QFileSystemWatcher: " << filename_);
+ QTimer::singleShot(5000, this, SLOT(refresh()));
+ } else {
+ if (!exists_)
+ // The standard way to overwrite a file is to delete it and
+ // create a new file with the same name. Therefore if the file
+ // has just been deleted, it is smart to check not too long
+ // after whether it has been recreated.
+ QTimer::singleShot(existed ? 100 : 2000, this, SLOT(refresh()));
+ if (existed != exists_ && emit)
+ Q_EMIT fileChanged(exists_);
+ }
}
}
void FileMonitorGuard::notifyChange(QString const & path)
{
if (path == toqstr(filename_)) {
- Q_EMIT fileChanged();
// If the file has been modified by delete-move, we are notified of the
// deletion but we no longer track the file. See
// <https://bugreports.qt.io/browse/QTBUG-46483> (not a bug).
- refresh();
+ // Therefore we must refresh.
+ refresh(false);
+ Q_EMIT fileChanged(exists_);
}
}
FileMonitor::FileMonitor(std::shared_ptr<FileMonitorGuard> monitor)
: monitor_(monitor)
{
- QObject::connect(monitor_.get(), SIGNAL(fileChanged()),
- this, SLOT(changed()));
+ connectToFileMonitorGuard();
refresh();
}
-void FileMonitor::reconnectToFileMonitorGuard()
+void FileMonitor::connectToFileMonitorGuard()
{
- monitor_->setExists(true);
- QObject::connect(monitor_.get(), SIGNAL(fileChanged()),
- this, SLOT(changed()));
+ // Connections need to be asynchronous because the receiver can own this
+ // object and therefore is allowed to delete it.
+ // Qt signal:
+ QObject::connect(monitor_.get(), SIGNAL(fileChanged(bool)),
+ this, SIGNAL(fileChanged(bool)),
+ Qt::QueuedConnection);
+ // Boost signal:
+ QObject::connect(this, SIGNAL(fileChanged(bool)),
+ this, SLOT(changed(bool)));
}
-boost::signals2::connection
-FileMonitor::connect(sig::slot_type const & slot)
+connection FileMonitor::connect(slot const & slot)
{
return fileChanged_.connect(slot);
}
-void FileMonitor::disconnect()
-{
- fileChanged_.disconnect_all_slots();
- QObject::disconnect(this, SIGNAL(fileChanged()));
-}
-
-
-void FileMonitor::changed()
+void FileMonitor::changed(bool const exists)
{
// emit boost signal
- fileChanged_();
- Q_EMIT fileChanged();
-}
-
-
-FileMonitorBlocker FileMonitor::block(int delay)
-{
- FileMonitorBlocker blocker = blocker_.lock();
- if (!blocker)
- blocker_ = blocker = make_shared<FileMonitorBlockerGuard>(this);
- blocker->setDelay(delay);
- return blocker;
-}
-
-
-FileMonitorBlockerGuard::FileMonitorBlockerGuard(FileMonitor * monitor)
- : monitor_(monitor), delay_(0)
-{
- QObject::disconnect(monitor->monitor_.get(), SIGNAL(fileChanged()),
- monitor, SLOT(changed()));
-}
-
-
-void FileMonitorBlockerGuard::setDelay(int delay)
-{
- delay_ = max(delay_, delay);
-}
-
-
-FileMonitorBlockerGuard::~FileMonitorBlockerGuard()
-{
- if (!monitor_)
- return;
- // Even if delay_ is 0, the QTimer is necessary. Indeed, the notifications
- // from QFileSystemWatcher that we meant to ignore are not going to be
- // treated immediately, so we must yield to give us the opportunity to
- // ignore them.
- QTimer::singleShot(delay_, monitor_, SLOT(reconnectToFileMonitorGuard()));
+ fileChanged_(exists);
}
: FileMonitor(monitor), filename_(filename), interval_(interval),
timestamp_(0), checksum_(0), cooldown_(true)
{
- QObject::connect(this, SIGNAL(fileChanged()), this, SLOT(setCooldown()));
+ QObject::connect(this, SIGNAL(fileChanged(bool)), this, SLOT(setCooldown()));
QTimer::singleShot(interval_, this, SLOT(clearCooldown()));
+ filename_.refresh();
if (!filename_.exists())
return;
timestamp_ = filename_.lastModified();
cooldown_ = true;
bool changed = false;
- if (!filename_.exists()) {
+ filename_.refresh();
+ bool exists = filename_.exists();
+ if (!exists) {
changed = timestamp_ || checksum_;
timestamp_ = 0;
checksum_ = 0;
}
}
if (changed)
- FileMonitor::changed();
+ Q_EMIT FileMonitor::fileChanged(exists);
QTimer::singleShot(interval_, this, SLOT(clearCooldown()));
}