Ressurect old FileMonitor à la Frankenstein

ActiveFileMonitor combines QFileSystemWatcher with the previous checksum
approach.
This commit is contained in:
Guillaume Munch 2017-03-19 00:06:40 +01:00
parent 6c4b9c97cb
commit 9926927fb1
2 changed files with 125 additions and 15 deletions

View File

@ -3,6 +3,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.
@ -42,17 +43,32 @@ FileSystemWatcher::FileSystemWatcher()
{}
//static
FileMonitorPtr FileSystemWatcher::monitor(FileName const & file_with_path)
shared_ptr<FileMonitorGuard>
FileSystemWatcher::getGuard(FileName const & filename)
{
FileSystemWatcher & f = instance();
string const filename = file_with_path.absFileName();
weak_ptr<FileMonitorGuard> & wptr = f.store_[filename];
string const absfilename = filename.absFileName();
weak_ptr<FileMonitorGuard> & wptr = store_[absfilename];
if (shared_ptr<FileMonitorGuard> mon = wptr.lock())
return make_unique<FileMonitor>(mon);
auto mon = make_shared<FileMonitorGuard>(filename, f.qwatcher_.get());
return mon;
auto mon = make_shared<FileMonitorGuard>(absfilename, qwatcher_.get());
wptr = mon;
return make_unique<FileMonitor>(mon);
return mon;
}
//static
FileMonitorPtr FileSystemWatcher::monitor(FileName const & filename)
{
return make_unique<FileMonitor>(instance().getGuard(filename));
}
//static
ActiveFileMonitorPtr FileSystemWatcher::activeMonitor(FileName const & filename,
int interval)
{
return make_unique<ActiveFileMonitor>(instance().getGuard(filename),
filename, interval);
}
@ -211,6 +227,59 @@ FileMonitorBlockerGuard::~FileMonitorBlockerGuard()
QTimer::singleShot(delay_, monitor_, SLOT(reconnectToFileMonitorGuard()));
}
ActiveFileMonitor::ActiveFileMonitor(std::shared_ptr<FileMonitorGuard> monitor,
FileName const & filename, int interval)
: FileMonitor(monitor), filename_(filename), interval_(interval),
timestamp_(0), checksum_(0), cooldown_(true)
{
QObject::connect(this, SIGNAL(fileChanged()), this, SLOT(setCooldown()));
QTimer::singleShot(interval_, this, SLOT(clearCooldown()));
if (!filename_.exists())
return;
timestamp_ = filename_.lastModified();
checksum_ = filename_.checksum();
}
void ActiveFileMonitor::checkModified()
{
if (cooldown_)
return;
cooldown_ = true;
bool changed = false;
if (!filename_.exists()) {
changed = timestamp_ || checksum_;
timestamp_ = 0;
checksum_ = 0;
} else {
time_t const new_timestamp = filename_.lastModified();
if (new_timestamp != timestamp_) {
timestamp_ = new_timestamp;
unsigned long const new_checksum = filename_.checksum();
if (new_checksum != checksum_) {
checksum_ = new_checksum;
changed = true;
}
}
}
if (changed)
FileMonitor::changed();
QTimer::singleShot(interval_, this, SLOT(clearCooldown()));
}
void ActiveFileMonitor::checkModifiedAsync()
{
if (!cooldown_)
QTimer::singleShot(0, this, SLOT(checkModified()));
}
} // namespace support
} // namespace lyx

View 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.
@ -15,6 +16,8 @@
#ifndef FILEMONITOR_H
#define FILEMONITOR_H
#include "support/FileName.h"
#include <memory>
#include <QFileSystemWatcher>
@ -27,15 +30,15 @@
namespace lyx {
namespace support {
class FileName;
///
/// FileMonitor, a file monitor based on QFileSystemWatcher
///
class FileMonitor;
class ActiveFileMonitor;
class FileMonitorGuard;
typedef std::unique_ptr<FileMonitor> FileMonitorPtr;
typedef std::unique_ptr<ActiveFileMonitor> ActiveFileMonitorPtr;
///
/// Watch a file:
@ -72,14 +75,19 @@ class FileSystemWatcher
{
public:
// as described above
static FileMonitorPtr monitor(FileName const & file_with_path);
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();
///
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
@ -87,8 +95,8 @@ private:
};
// 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
@ -174,7 +182,7 @@ Q_SIGNALS:
/// Connect to this to be notified when the file changes
void fileChanged() const;
private Q_SLOTS:
protected Q_SLOTS:
/// Receive notifications from the FileMonitorGuard
void changed();
///
@ -190,6 +198,39 @@ private:
};
/// 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