WingHexExplorer2/3rdparty/qcodeedit2/lib/qreliablefilewatch.cpp

161 lines
4.3 KiB
C++

/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#include "qreliablefilewatch.h"
/*!
\file qreliablefilewatch.cpp
\brief Implementation of the QReliableFileWatch class.
*/
#include <QFile>
#include <QTimerEvent>
/*!
\class QReliableFileWatch
\brief A specialized file monitor that works around some issues in
QFileSystemWatcher
*/
QReliableFileWatch::QReliableFileWatch(QObject *p) : QFileSystemWatcher(p) {
connect(this, SIGNAL(fileChanged(QString)), this,
SLOT(sourceChanged(QString)));
}
QReliableFileWatch::~QReliableFileWatch() {}
void QReliableFileWatch::addWatch(const QString &file, QObject *recipient) {
QHash<QString, Watch>::iterator it = m_targets.find(file);
if (it != m_targets.end()) {
it->recipients << recipient;
} else {
QFile f(file);
Watch w;
w.state = Clean;
w.size = f.size();
w.recipients << recipient;
m_targets[file] = w;
addPath(file);
}
}
void QReliableFileWatch::removeWatch(QObject *recipient) {
removeWatch(QString(), recipient);
}
void QReliableFileWatch::removeWatch(const QString &file, QObject *recipient) {
QHash<QString, Watch>::iterator it = m_targets.find(file);
if (it == m_targets.end()) {
if (!recipient)
return;
// given recipient stop watching any file
it = m_targets.begin();
while (it != m_targets.end()) {
int n = it->recipients.removeAll(recipient);
if (n && it->recipients.isEmpty()) {
// no more recipients watching this file
removePath(it.key());
it = m_targets.erase(it);
} else {
++it;
}
}
} else {
if (recipient) {
// given recipient stops watching given file
it->recipients.removeAll(recipient);
if (it->recipients.isEmpty()) {
// no more recipients watching this file
removePath(it.key());
m_targets.erase(it);
}
} else {
// stop watching given file at all
m_targets.erase(it);
}
}
}
void QReliableFileWatch::timerEvent(QTimerEvent *e) {
if (e->timerId() != m_timer.timerId())
return QFileSystemWatcher::timerEvent(e);
int postponedEmissions = 0;
QHash<QString, Watch>::iterator it = m_targets.begin();
while (it != m_targets.end()) {
if (it->state & Duplicate) {
// postpone signal emission...
++postponedEmissions;
it->state = Recent;
} else if (it->state & Recent) {
// send signal
it->state = Clean;
QFile f(it.key());
if (f.size() == it->size) {
// TODO : avoid signal emission if checksum match
// DO this in editor or here?
}
// qDebug("%s emission.", qPrintable(it.key()));
it->recipients.removeAll(nullptr);
foreach (QObject *r, it->recipients)
QMetaObject::invokeMethod(r, "fileChanged",
Q_ARG(QString, it.key()));
// it = m_state.erase(it);
}
++it;
}
if (postponedEmissions) {
// qDebug("%i postponed emissions", postponedEmissions);
m_timer.start(20, this);
}
}
void QReliableFileWatch::sourceChanged(const QString &filepath) {
m_timer.stop();
QHash<QString, Watch>::iterator it = m_targets.find(filepath);
if (it == m_targets.end())
return;
// qDebug("%s modified.", qPrintable(filepath));
if (it->state) {
it->state = Recent | Duplicate;
} else {
it->state = Recent;
}
m_timer.start(20, this);
}