]> git.lyx.org Git - lyx.git/blobdiff - src/support/FileMonitor.cpp
Cosmetic
[lyx.git] / src / support / FileMonitor.cpp
index 051bbbbe0fac5f61e0ab7b236d7f7bbe3f9c62ca..f1446a3aba6bde7175e769f1b80cef960b1cfadc 100644 (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.
@@ -31,7 +32,7 @@ namespace support {
 
 FileSystemWatcher & FileSystemWatcher::instance()
 {
-       // This thread-safe because QFileSystemWatcher is thread-safe.
+       // This is thread-safe because QFileSystemWatcher is thread-safe.
        static FileSystemWatcher f;
        return f;
 }
@@ -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);
 }
 
 
@@ -82,7 +98,7 @@ void FileSystemWatcher::debug()
 
 FileMonitorGuard::FileMonitorGuard(string const & filename,
                                    QFileSystemWatcher * qwatcher)
-       : filename_(filename), qwatcher_(qwatcher)
+       : filename_(filename), qwatcher_(qwatcher), exists_(true)
 {
        QObject::connect(qwatcher, SIGNAL(fileChanged(QString const &)),
                         this, SLOT(notifyChange(QString const &)));
@@ -99,37 +115,29 @@ FileMonitorGuard::~FileMonitorGuard()
 }
 
 
-void FileMonitorGuard::refresh(bool new_file)
+void FileMonitorGuard::refresh()
 {
        QString const qfilename = toqstr(filename_);
        if(!qwatcher_->files().contains(qfilename)) {
                bool exists = QFile(qfilename).exists();
 #if (QT_VERSION >= 0x050000)
-               if (!exists || !qwatcher_->addPath(qfilename)) {
-                       if (exists)
-                               LYXERR(Debug::FILES,
-                                      "Could not add path to QFileSystemWatcher: "
-                                      << filename_);
-                       QTimer::singleShot(1000, this, [=](){
-                                       refresh(new_file || !exists);
-                               });
+               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_);
-                       if (new_file || !exists)
-                               QTimer::singleShot(1000, this, SLOT(refreshTrue()));
-                       else
-                               QTimer::singleShot(1000, this, SLOT(refreshFalse()));
-#endif
-               } else if (exists && new_file)
+                       QTimer::singleShot(2000, this, SLOT(refresh()));
+               } else if (exists && !exists_)
                        Q_EMIT fileChanged();
+               setExists(exists);
        }
 }
 
@@ -149,13 +157,15 @@ void FileMonitorGuard::notifyChange(QString const & path)
 FileMonitor::FileMonitor(std::shared_ptr<FileMonitorGuard> monitor)
        : monitor_(monitor)
 {
-       connectToFileMonitorGuard();
+       QObject::connect(monitor_.get(), SIGNAL(fileChanged()),
+                        this, SLOT(changed()));
        refresh();
 }
 
 
-void FileMonitor::connectToFileMonitorGuard()
+void FileMonitor::reconnectToFileMonitorGuard()
 {
+       monitor_->setExists(true);
        QObject::connect(monitor_.get(), SIGNAL(fileChanged()),
                         this, SLOT(changed()));
 }
@@ -193,11 +203,11 @@ FileMonitorBlocker FileMonitor::block(int delay)
 }
 
 
-FileMonitorBlockerGuard::FileMonitorBlockerGuard(FileMonitor * parent)
-       : QObject(parent), parent_(parent), delay_(0)
+FileMonitorBlockerGuard::FileMonitorBlockerGuard(FileMonitor * monitor)
+       : monitor_(monitor), delay_(0)
 {
-       QObject::disconnect(parent_->monitor_.get(), SIGNAL(fileChanged()),
-                           parent_, SLOT(changed()));
+       QObject::disconnect(monitor->monitor_.get(), SIGNAL(fileChanged()),
+                           monitor, SLOT(changed()));
 }
 
 
@@ -209,16 +219,68 @@ void FileMonitorBlockerGuard::setDelay(int delay)
 
 FileMonitorBlockerGuard::~FileMonitorBlockerGuard()
 {
-       // closures can only copy local copies
-       FileMonitor * parent = parent_;
-       // parent is also our QObject::parent() so we are deleted before parent.
+       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_, parent, SLOT(connectToFileMonitorGuard()));
+       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