From bc8e87016cfeb4a63151425bcd0f69f21a5fc1c1 Mon Sep 17 00:00:00 2001 From: ck Date: Wed, 9 Dec 2009 15:47:26 +0100 Subject: Assistant: Make doc file watching work for the intended use case. The QFileSystemWatcher signals the changing of a file several times, with the first one coming too early. As a result, we are likely checking a file that is not yet fully constructed. The workaround/solution is to delay reacting to the change until after the (hopefully) last signal from the QFileSystemWatcher. Reviewed-by: kh1 --- .../tools/assistant/helpenginewrapper.cpp | 53 +++++++++++++++++++++- .../assistant/tools/assistant/helpenginewrapper.h | 23 ++++++++++ 2 files changed, 75 insertions(+), 1 deletion(-) diff --git a/tools/assistant/tools/assistant/helpenginewrapper.cpp b/tools/assistant/tools/assistant/helpenginewrapper.cpp index 899954c..79a25ec 100644 --- a/tools/assistant/tools/assistant/helpenginewrapper.cpp +++ b/tools/assistant/tools/assistant/helpenginewrapper.cpp @@ -45,6 +45,7 @@ #include #include +#include #include #include #include @@ -646,9 +647,28 @@ void HelpEngineWrapper::assertDocFilesWatched() == m_helpEngine->registeredDocumentations().count()); } +TimeoutForwarder::TimeoutForwarder(const QString &fileName) + : m_fileName(fileName) +{ + TRACE_OBJ +} + +void TimeoutForwarder::forward() +{ + TRACE_OBJ + HelpEngineWrapper::instance().qchFileChanged(m_fileName, true); +} + void HelpEngineWrapper::qchFileChanged(const QString &fileName) { TRACE_OBJ + qchFileChanged(fileName, false); +} + +void HelpEngineWrapper::qchFileChanged(const QString &fileName, bool fromTimeout) +{ + TRACE_OBJ + /* * We don't use QHelpEngineCore::namespaceName(fileName), because the file * may not exist anymore or contain a different namespace. @@ -665,9 +685,39 @@ void HelpEngineWrapper::qchFileChanged(const QString &fileName) * We can't do an assertion here, because QFileSystemWatcher may send the * signal more than once. */ - if (ns.isEmpty()) + if (ns.isEmpty()) { + m_recentQchUpdates.remove(fileName); + return; + } + + /* + * Since the QFileSystemWatcher typically sends the signal more than once, + * we repeatedly delay our reaction a bit until we think the last signal + * was sent. + */ + + QMap::Iterator it = m_recentQchUpdates.find(fileName); + const QDateTime &now = QDateTime::currentDateTime(); + + // Case 1: This is the first recent signal for the file. + if (it == m_recentQchUpdates.end()) { + QSharedPointer forwarder(new TimeoutForwarder(fileName)); + m_recentQchUpdates.insert(fileName, RecentSignal(now, forwarder)); + QTimer::singleShot(UpdateGracePeriod, forwarder.data(), SLOT(forward())); + return; + } + + // Case 2: The last signal for this file has not expired yet. + if (it.value().first > now.addMSecs(-UpdateGracePeriod)) { + if (!fromTimeout) + it.value().first = now; + else + QTimer::singleShot(UpdateGracePeriod, it.value().second.data(), + SLOT(forward())); return; + } + // Case 3: The last signal for this file has expired. if (m_helpEngine->unregisterDocumentation(ns)) { if (!QFileInfo(fileName).exists() || !m_helpEngine->registerDocumentation(fileName)) { @@ -678,6 +728,7 @@ void HelpEngineWrapper::qchFileChanged(const QString &fileName) } m_helpEngine->setupData(); } + m_recentQchUpdates.erase(it); } QT_END_NAMESPACE diff --git a/tools/assistant/tools/assistant/helpenginewrapper.h b/tools/assistant/tools/assistant/helpenginewrapper.h index f827d95..348479e 100644 --- a/tools/assistant/tools/assistant/helpenginewrapper.h +++ b/tools/assistant/tools/assistant/helpenginewrapper.h @@ -42,8 +42,11 @@ #ifndef HELPENGINEWRAPPER_H #define HELPENGINEWRAPPER_H +#include #include #include +#include +#include #include #include #include @@ -67,6 +70,20 @@ enum { ShowLastPages = 2 }; + +class TimeoutForwarder : public QObject +{ + Q_OBJECT +public: + TimeoutForwarder(const QString &fileName); +private slots: + void forward(); +private: + friend class HelpEngineWrapper; + + const QString m_fileName; +}; + class HelpEngineWrapper : public QObject { Q_OBJECT @@ -197,13 +214,19 @@ private slots: void qchFileChanged(const QString &fileName); private: + friend class TimeoutForwarder; + HelpEngineWrapper(const QString &collectionFile); void initFileSystemWatchers(); void assertDocFilesWatched(); + void qchFileChanged(const QString &fileName, bool fromTimeout); + static const int UpdateGracePeriod = 2000; static HelpEngineWrapper *helpEngineWrapper; QHelpEngine * const m_helpEngine; QFileSystemWatcher * const m_qchWatcher; + typedef QPair > RecentSignal; + QMap m_recentQchUpdates; }; QT_END_NAMESPACE -- cgit v0.12