Utils: Introduce GlobalFileChangeBlocker

Tracks application state, and signals when it is changed.

Supports forcing blocked state with reference counting.

Change-Id: Ic173d42446b1b08bd4a1e7c1acf38c68644d30b3
Reviewed-by: Nikolai Kosjar <nikolai.kosjar@qt.io>
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
Orgad Shaneh
2018-12-16 00:32:14 +02:00
committed by Orgad Shaneh
parent 81ce096719
commit c225216b93
15 changed files with 152 additions and 71 deletions

View File

@@ -0,0 +1,70 @@
/****************************************************************************
**
** Copyright (C) 2019 Orgad Shaneh <orgads@gmail.com>
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "globalfilechangeblocker.h"
#include "qtcassert.h"
#include <QApplication>
namespace Utils {
GlobalFileChangeBlocker::GlobalFileChangeBlocker()
{
m_blockedState = QApplication::applicationState() != Qt::ApplicationActive;
qApp->installEventFilter(this);
}
GlobalFileChangeBlocker *GlobalFileChangeBlocker::instance()
{
static GlobalFileChangeBlocker blocker;
return &blocker;
}
void GlobalFileChangeBlocker::forceBlocked(bool blocked)
{
if (blocked)
++m_forceBlocked;
else if (QTC_GUARD(m_forceBlocked > 0))
--m_forceBlocked;
emitIfChanged();
}
bool GlobalFileChangeBlocker::eventFilter(QObject *obj, QEvent *e)
{
if (obj == qApp && e->type() == QEvent::ApplicationStateChange)
emitIfChanged();
return false;
}
void GlobalFileChangeBlocker::emitIfChanged()
{
const bool blocked = m_forceBlocked || (QApplication::applicationState() != Qt::ApplicationActive);
if (blocked != m_blockedState) {
emit stateChanged(blocked);
m_blockedState = blocked;
}
}
} // namespace Utils

View File

@@ -0,0 +1,55 @@
/****************************************************************************
**
** Copyright (C) 2019 Orgad Shaneh <orgads@gmail.com>
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "utils_global.h"
#include <QObject>
namespace Utils {
class QTCREATOR_UTILS_EXPORT GlobalFileChangeBlocker : public QObject
{
Q_OBJECT
public:
static GlobalFileChangeBlocker *instance();
void forceBlocked(bool blocked);
bool isBlocked() const { return m_blockedState; }
signals:
void stateChanged(bool blocked);
private:
GlobalFileChangeBlocker();
bool eventFilter(QObject *obj, QEvent *e) override;
void emitIfChanged();
int m_forceBlocked = 0;
bool m_blockedState = false;
};
} // namespace Utils

View File

@@ -22,6 +22,7 @@ win32: LIBS += -luser32 -lshell32
win32: LIBS += -liphlpapi -lws2_32 win32: LIBS += -liphlpapi -lws2_32
SOURCES += \ SOURCES += \
$$PWD/globalfilechangeblocker.cpp \
$$PWD/benchmarker.cpp \ $$PWD/benchmarker.cpp \
$$PWD/environment.cpp \ $$PWD/environment.cpp \
$$PWD/environmentmodel.cpp \ $$PWD/environmentmodel.cpp \
@@ -128,6 +129,7 @@ win32:SOURCES += $$PWD/consoleprocess_win.cpp
else:SOURCES += $$PWD/consoleprocess_unix.cpp else:SOURCES += $$PWD/consoleprocess_unix.cpp
HEADERS += \ HEADERS += \
$$PWD/globalfilechangeblocker.h \
$$PWD/benchmarker.h \ $$PWD/benchmarker.h \
$$PWD/environment.h \ $$PWD/environment.h \
$$PWD/environmentmodel.h \ $$PWD/environmentmodel.h \

View File

@@ -122,6 +122,8 @@ Project {
"functiontraits.h", "functiontraits.h",
"fuzzymatcher.cpp", "fuzzymatcher.cpp",
"fuzzymatcher.h", "fuzzymatcher.h",
"globalfilechangeblocker.cpp",
"globalfilechangeblocker.h",
"guard.cpp", "guard.cpp",
"guard.h", "guard.h",
"highlightingitemdelegate.cpp", "highlightingitemdelegate.cpp",

View File

@@ -48,6 +48,7 @@
#include <clangsupport/filecontainer.h> #include <clangsupport/filecontainer.h>
#include <clangsupport/clangcodemodelservermessages.h> #include <clangsupport/clangcodemodelservermessages.h>
#include <utils/globalfilechangeblocker.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <QDateTime> #include <QDateTime>
@@ -104,6 +105,10 @@ BackendCommunicator::BackendCommunicator()
this, &BackendCommunicator::onEditorAboutToClose); this, &BackendCommunicator::onEditorAboutToClose);
connect(Core::ICore::instance(), &Core::ICore::coreAboutToClose, connect(Core::ICore::instance(), &Core::ICore::coreAboutToClose,
this, &BackendCommunicator::setupDummySender); this, &BackendCommunicator::setupDummySender);
auto globalFCB = ::Utils::GlobalFileChangeBlocker::instance();
m_postponeBackendJobs = globalFCB->isBlocked();
connect(globalFCB, &::Utils::GlobalFileChangeBlocker::stateChanged,
this, &BackendCommunicator::setBackendJobsPostponed);
initializeBackend(); initializeBackend();
} }
@@ -210,14 +215,11 @@ bool BackendCommunicator::isNotWaitingForCompletion() const
void BackendCommunicator::setBackendJobsPostponed(bool postponed) void BackendCommunicator::setBackendJobsPostponed(bool postponed)
{ {
if (postponed) { if (postponed) {
if (!m_postponeBackendJobs) documentVisibilityChanged(Utf8String(), {});
documentVisibilityChanged(Utf8String(), {}); m_postponeBackendJobs = postponed;
++m_postponeBackendJobs;
} else { } else {
if (QTC_GUARD(m_postponeBackendJobs > 0)) m_postponeBackendJobs = postponed;
--m_postponeBackendJobs; documentVisibilityChanged();
if (!m_postponeBackendJobs)
documentVisibilityChanged();
} }
} }

View File

@@ -136,7 +136,7 @@ private:
QTimer m_backendStartTimeOut; QTimer m_backendStartTimeOut;
QScopedPointer<ClangBackEnd::ClangCodeModelServerInterface> m_sender; QScopedPointer<ClangBackEnd::ClangCodeModelServerInterface> m_sender;
int m_connectedCount = 0; int m_connectedCount = 0;
int m_postponeBackendJobs = 1; // Initial application state is inactive, so no jobs should be run. bool m_postponeBackendJobs = false;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -76,8 +76,6 @@ ClangModelManagerSupport::ClangModelManagerSupport()
QTC_CHECK(!m_instance); QTC_CHECK(!m_instance);
m_instance = this; m_instance = this;
QApplication::instance()->installEventFilter(this);
CppTools::CppModelManager::instance()->setCurrentDocumentFilter( CppTools::CppModelManager::instance()->setCurrentDocumentFilter(
std::make_unique<ClangCurrentDocumentFilter>()); std::make_unique<ClangCurrentDocumentFilter>());
@@ -141,11 +139,6 @@ std::unique_ptr<CppTools::AbstractOverviewModel> ClangModelManagerSupport::creat
return std::make_unique<OverviewModel>(); return std::make_unique<OverviewModel>();
} }
void ClangModelManagerSupport::setBackendJobsPostponed(bool postponed)
{
m_communicator.setBackendJobsPostponed(postponed);
}
CppTools::BaseEditorDocumentProcessor *ClangModelManagerSupport::createEditorDocumentProcessor( CppTools::BaseEditorDocumentProcessor *ClangModelManagerSupport::createEditorDocumentProcessor(
TextEditor::TextDocument *baseTextDocument) TextEditor::TextDocument *baseTextDocument)
{ {
@@ -219,20 +212,6 @@ void ClangModelManagerSupport::connectToWidgetsMarkContextMenuRequested(QWidget
} }
} }
bool ClangModelManagerSupport::eventFilter(QObject *obj, QEvent *e)
{
if (obj == QApplication::instance() && e->type() == QEvent::ApplicationStateChange) {
switch (QApplication::applicationState()) {
case Qt::ApplicationInactive: setBackendJobsPostponed(true); break;
case Qt::ApplicationActive: setBackendJobsPostponed(false); break;
default:
QTC_CHECK(false && "Unexpected Qt::ApplicationState");
}
}
return false;
}
void ClangModelManagerSupport::onEditorOpened(Core::IEditor *editor) void ClangModelManagerSupport::onEditorOpened(Core::IEditor *editor)
{ {
QTC_ASSERT(editor, return); QTC_ASSERT(editor, return);

View File

@@ -72,7 +72,6 @@ public:
CppTools::FollowSymbolInterface &followSymbolInterface() override; CppTools::FollowSymbolInterface &followSymbolInterface() override;
CppTools::RefactoringEngineInterface &refactoringEngineInterface() override; CppTools::RefactoringEngineInterface &refactoringEngineInterface() override;
std::unique_ptr<CppTools::AbstractOverviewModel> createOverviewModel() override; std::unique_ptr<CppTools::AbstractOverviewModel> createOverviewModel() override;
void setBackendJobsPostponed(bool postponed) override;
BackendCommunicator &communicator(); BackendCommunicator &communicator();
QString dummyUiHeaderOnDiskDirPath() const; QString dummyUiHeaderOnDiskDirPath() const;
@@ -83,8 +82,6 @@ public:
static ClangModelManagerSupport *instance(); static ClangModelManagerSupport *instance();
private: private:
bool eventFilter(QObject *obj, QEvent *e) override;
void onEditorOpened(Core::IEditor *editor); void onEditorOpened(Core::IEditor *editor);
void onEditorClosed(const QList<Core::IEditor *> &editors); void onEditorClosed(const QList<Core::IEditor *> &editors);
void onCurrentEditorChanged(Core::IEditor *newCurrent); void onCurrentEditorChanged(Core::IEditor *newCurrent);

View File

@@ -44,6 +44,7 @@
#include <extensionsystem/pluginmanager.h> #include <extensionsystem/pluginmanager.h>
#include <utils/fileutils.h> #include <utils/fileutils.h>
#include <utils/globalfilechangeblocker.h>
#include <utils/hostosinfo.h> #include <utils/hostosinfo.h>
#include <utils/mimetypes/mimedatabase.h> #include <utils/mimetypes/mimedatabase.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
@@ -229,7 +230,13 @@ DocumentManager::DocumentManager(QObject *parent)
{ {
d = new DocumentManagerPrivate; d = new DocumentManagerPrivate;
m_instance = this; m_instance = this;
qApp->installEventFilter(this);
connect(Utils::GlobalFileChangeBlocker::instance(), &Utils::GlobalFileChangeBlocker::stateChanged,
this, [this](bool blocked) {
d->m_postponeAutoReload = blocked;
if (!blocked)
QTimer::singleShot(500, m_instance, &DocumentManager::checkForReload);
});
readSettings(); readSettings();
@@ -597,13 +604,6 @@ void DocumentManager::unexpectFileChange(const QString &fileName)
updateExpectedState(filePathKey(fileName, ResolveLinks)); updateExpectedState(filePathKey(fileName, ResolveLinks));
} }
void DocumentManager::setAutoReloadPostponed(bool postponed)
{
d->m_postponeAutoReload = postponed;
if (!postponed)
QTimer::singleShot(500, m_instance, &DocumentManager::checkForReload);
}
static bool saveModifiedFilesHelper(const QList<IDocument *> &documents, static bool saveModifiedFilesHelper(const QList<IDocument *> &documents,
const QString &message, bool *cancelled, bool silently, const QString &message, bool *cancelled, bool silently,
const QString &alwaysSaveMessage, bool *alwaysSave, const QString &alwaysSaveMessage, bool *alwaysSave,
@@ -1470,14 +1470,6 @@ void DocumentManager::notifyFilesChangedInternally(const QStringList &files)
emit m_instance->filesChangedInternally(files); emit m_instance->filesChangedInternally(files);
} }
bool DocumentManager::eventFilter(QObject *obj, QEvent *e)
{
if (obj == qApp && e->type() == QEvent::ApplicationStateChange) {
QTimer::singleShot(0, this, &DocumentManager::checkForReload);
}
return false;
}
// -------------- FileChangeBlocker // -------------- FileChangeBlocker
FileChangeBlocker::FileChangeBlocker(const QString &fileName) FileChangeBlocker::FileChangeBlocker(const QString &fileName)

View File

@@ -69,8 +69,6 @@ public:
static void expectFileChange(const QString &fileName); static void expectFileChange(const QString &fileName);
static void unexpectFileChange(const QString &fileName); static void unexpectFileChange(const QString &fileName);
static void setAutoReloadPostponed(bool enabled);
// recent files // recent files
static void addToRecentFiles(const QString &fileName, Id editorId = Id()); static void addToRecentFiles(const QString &fileName, Id editorId = Id());
Q_SLOT void clearRecentFiles(); Q_SLOT void clearRecentFiles();
@@ -155,9 +153,6 @@ signals:
void documentRenamed(Core::IDocument *document, const QString &from, const QString &to); void documentRenamed(Core::IDocument *document, const QString &from, const QString &to);
void projectsDirectoryChanged(const Utils::FileName &directory); void projectsDirectoryChanged(const Utils::FileName &directory);
protected:
bool eventFilter(QObject *obj, QEvent *e) override;
private: private:
explicit DocumentManager(QObject *parent); explicit DocumentManager(QObject *parent);
~DocumentManager() override; ~DocumentManager() override;

View File

@@ -47,7 +47,6 @@ public:
FollowSymbolInterface &followSymbolInterface() final; FollowSymbolInterface &followSymbolInterface() final;
RefactoringEngineInterface &refactoringEngineInterface() final; RefactoringEngineInterface &refactoringEngineInterface() final;
std::unique_ptr<AbstractOverviewModel> createOverviewModel() final; std::unique_ptr<AbstractOverviewModel> createOverviewModel() final;
void setBackendJobsPostponed(bool) final {}
private: private:
QScopedPointer<CppCompletionAssistProvider> m_completionAssistProvider; QScopedPointer<CppCompletionAssistProvider> m_completionAssistProvider;

View File

@@ -1318,11 +1318,6 @@ void CppModelManager::renameIncludes(const QString &oldFileName, const QString &
} }
} }
void CppModelManager::setBackendJobsPostponed(bool postponed)
{
d->m_activeModelManagerSupport->setBackendJobsPostponed(postponed);
}
void CppModelManager::onCoreAboutToClose() void CppModelManager::onCoreAboutToClose()
{ {
Core::ProgressManager::cancelTasks(CppTools::Constants::TASK_INDEX); Core::ProgressManager::cancelTasks(CppTools::Constants::TASK_INDEX);

View File

@@ -230,8 +230,6 @@ public:
void renameIncludes(const QString &oldFileName, const QString &newFileName); void renameIncludes(const QString &oldFileName, const QString &newFileName);
void setBackendJobsPostponed(bool postponed);
signals: signals:
/// Project data might be locked while this is emitted. /// Project data might be locked while this is emitted.
void aboutToRemoveFiles(const QStringList &files); void aboutToRemoveFiles(const QStringList &files);

View File

@@ -60,7 +60,6 @@ public:
virtual FollowSymbolInterface &followSymbolInterface() = 0; virtual FollowSymbolInterface &followSymbolInterface() = 0;
virtual RefactoringEngineInterface &refactoringEngineInterface() = 0; virtual RefactoringEngineInterface &refactoringEngineInterface() = 0;
virtual std::unique_ptr<AbstractOverviewModel> createOverviewModel() = 0; virtual std::unique_ptr<AbstractOverviewModel> createOverviewModel() = 0;
virtual void setBackendJobsPostponed(bool yesno) = 0;
}; };
class CPPTOOLS_EXPORT ModelManagerSupportProvider class CPPTOOLS_EXPORT ModelManagerSupportProvider

View File

@@ -29,7 +29,7 @@
#include <coreplugin/documentmanager.h> #include <coreplugin/documentmanager.h>
#include <coreplugin/vcsmanager.h> #include <coreplugin/vcsmanager.h>
#include <cpptools/cppmodelmanager.h> #include <utils/globalfilechangeblocker.h>
#include <utils/synchronousprocess.h> #include <utils/synchronousprocess.h>
#include <QProcessEnvironment> #include <QProcessEnvironment>
@@ -61,16 +61,12 @@ VcsCommand::VcsCommand(const QString &workingDirectory,
return proxy; return proxy;
}); });
connect(this, &VcsCommand::started, this, [this] { connect(this, &VcsCommand::started, this, [this] {
if (flags() & ExpectRepoChanges) { if (flags() & ExpectRepoChanges)
Core::DocumentManager::setAutoReloadPostponed(true); Utils::GlobalFileChangeBlocker::instance()->forceBlocked(true);
CppTools::CppModelManager::instance()->setBackendJobsPostponed(true);
}
}); });
connect(this, &VcsCommand::finished, this, [this] { connect(this, &VcsCommand::finished, this, [this] {
if (flags() & ExpectRepoChanges) { if (flags() & ExpectRepoChanges)
Core::DocumentManager::setAutoReloadPostponed(false); Utils::GlobalFileChangeBlocker::instance()->forceBlocked(false);
CppTools::CppModelManager::instance()->setBackendJobsPostponed(false);
}
}); });
} }