From c225216b93300f7ddbfe13919c72f90b18f36b7b Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Sun, 16 Dec 2018 00:32:14 +0200 Subject: [PATCH] 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 Reviewed-by: Eike Ziller --- src/libs/utils/globalfilechangeblocker.cpp | 70 +++++++++++++++++++ src/libs/utils/globalfilechangeblocker.h | 55 +++++++++++++++ src/libs/utils/utils-lib.pri | 2 + src/libs/utils/utils.qbs | 2 + .../clangbackendcommunicator.cpp | 16 +++-- .../clangcodemodel/clangbackendcommunicator.h | 2 +- .../clangmodelmanagersupport.cpp | 21 ------ .../clangcodemodel/clangmodelmanagersupport.h | 3 - src/plugins/coreplugin/documentmanager.cpp | 24 +++---- src/plugins/coreplugin/documentmanager.h | 5 -- .../cpptools/cppbuiltinmodelmanagersupport.h | 1 - src/plugins/cpptools/cppmodelmanager.cpp | 5 -- src/plugins/cpptools/cppmodelmanager.h | 2 - src/plugins/cpptools/cppmodelmanagersupport.h | 1 - src/plugins/vcsbase/vcscommand.cpp | 14 ++-- 15 files changed, 152 insertions(+), 71 deletions(-) create mode 100644 src/libs/utils/globalfilechangeblocker.cpp create mode 100644 src/libs/utils/globalfilechangeblocker.h diff --git a/src/libs/utils/globalfilechangeblocker.cpp b/src/libs/utils/globalfilechangeblocker.cpp new file mode 100644 index 00000000000..060e0f210d5 --- /dev/null +++ b/src/libs/utils/globalfilechangeblocker.cpp @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Orgad Shaneh +** 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 + +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 diff --git a/src/libs/utils/globalfilechangeblocker.h b/src/libs/utils/globalfilechangeblocker.h new file mode 100644 index 00000000000..0f36dfce92f --- /dev/null +++ b/src/libs/utils/globalfilechangeblocker.h @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Orgad Shaneh +** 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 + +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 diff --git a/src/libs/utils/utils-lib.pri b/src/libs/utils/utils-lib.pri index 3369e0e1618..90194cfb32f 100644 --- a/src/libs/utils/utils-lib.pri +++ b/src/libs/utils/utils-lib.pri @@ -22,6 +22,7 @@ win32: LIBS += -luser32 -lshell32 win32: LIBS += -liphlpapi -lws2_32 SOURCES += \ + $$PWD/globalfilechangeblocker.cpp \ $$PWD/benchmarker.cpp \ $$PWD/environment.cpp \ $$PWD/environmentmodel.cpp \ @@ -128,6 +129,7 @@ win32:SOURCES += $$PWD/consoleprocess_win.cpp else:SOURCES += $$PWD/consoleprocess_unix.cpp HEADERS += \ + $$PWD/globalfilechangeblocker.h \ $$PWD/benchmarker.h \ $$PWD/environment.h \ $$PWD/environmentmodel.h \ diff --git a/src/libs/utils/utils.qbs b/src/libs/utils/utils.qbs index 40f7a21ca42..36153bbbbd6 100644 --- a/src/libs/utils/utils.qbs +++ b/src/libs/utils/utils.qbs @@ -122,6 +122,8 @@ Project { "functiontraits.h", "fuzzymatcher.cpp", "fuzzymatcher.h", + "globalfilechangeblocker.cpp", + "globalfilechangeblocker.h", "guard.cpp", "guard.h", "highlightingitemdelegate.cpp", diff --git a/src/plugins/clangcodemodel/clangbackendcommunicator.cpp b/src/plugins/clangcodemodel/clangbackendcommunicator.cpp index c777281897d..33b253a3b34 100644 --- a/src/plugins/clangcodemodel/clangbackendcommunicator.cpp +++ b/src/plugins/clangcodemodel/clangbackendcommunicator.cpp @@ -48,6 +48,7 @@ #include #include +#include #include #include @@ -104,6 +105,10 @@ BackendCommunicator::BackendCommunicator() this, &BackendCommunicator::onEditorAboutToClose); connect(Core::ICore::instance(), &Core::ICore::coreAboutToClose, this, &BackendCommunicator::setupDummySender); + auto globalFCB = ::Utils::GlobalFileChangeBlocker::instance(); + m_postponeBackendJobs = globalFCB->isBlocked(); + connect(globalFCB, &::Utils::GlobalFileChangeBlocker::stateChanged, + this, &BackendCommunicator::setBackendJobsPostponed); initializeBackend(); } @@ -210,14 +215,11 @@ bool BackendCommunicator::isNotWaitingForCompletion() const void BackendCommunicator::setBackendJobsPostponed(bool postponed) { if (postponed) { - if (!m_postponeBackendJobs) - documentVisibilityChanged(Utf8String(), {}); - ++m_postponeBackendJobs; + documentVisibilityChanged(Utf8String(), {}); + m_postponeBackendJobs = postponed; } else { - if (QTC_GUARD(m_postponeBackendJobs > 0)) - --m_postponeBackendJobs; - if (!m_postponeBackendJobs) - documentVisibilityChanged(); + m_postponeBackendJobs = postponed; + documentVisibilityChanged(); } } diff --git a/src/plugins/clangcodemodel/clangbackendcommunicator.h b/src/plugins/clangcodemodel/clangbackendcommunicator.h index 8bf988b5080..58435d48a67 100644 --- a/src/plugins/clangcodemodel/clangbackendcommunicator.h +++ b/src/plugins/clangcodemodel/clangbackendcommunicator.h @@ -136,7 +136,7 @@ private: QTimer m_backendStartTimeOut; QScopedPointer m_sender; 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 diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp index 004129c813c..3de0f99755e 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp @@ -76,8 +76,6 @@ ClangModelManagerSupport::ClangModelManagerSupport() QTC_CHECK(!m_instance); m_instance = this; - QApplication::instance()->installEventFilter(this); - CppTools::CppModelManager::instance()->setCurrentDocumentFilter( std::make_unique()); @@ -141,11 +139,6 @@ std::unique_ptr ClangModelManagerSupport::creat return std::make_unique(); } -void ClangModelManagerSupport::setBackendJobsPostponed(bool postponed) -{ - m_communicator.setBackendJobsPostponed(postponed); -} - CppTools::BaseEditorDocumentProcessor *ClangModelManagerSupport::createEditorDocumentProcessor( 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) { QTC_ASSERT(editor, return); diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.h b/src/plugins/clangcodemodel/clangmodelmanagersupport.h index 90570402cc7..d4082c7bedb 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.h +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.h @@ -72,7 +72,6 @@ public: CppTools::FollowSymbolInterface &followSymbolInterface() override; CppTools::RefactoringEngineInterface &refactoringEngineInterface() override; std::unique_ptr createOverviewModel() override; - void setBackendJobsPostponed(bool postponed) override; BackendCommunicator &communicator(); QString dummyUiHeaderOnDiskDirPath() const; @@ -83,8 +82,6 @@ public: static ClangModelManagerSupport *instance(); private: - bool eventFilter(QObject *obj, QEvent *e) override; - void onEditorOpened(Core::IEditor *editor); void onEditorClosed(const QList &editors); void onCurrentEditorChanged(Core::IEditor *newCurrent); diff --git a/src/plugins/coreplugin/documentmanager.cpp b/src/plugins/coreplugin/documentmanager.cpp index 053af7d8ae7..9faf6b13639 100644 --- a/src/plugins/coreplugin/documentmanager.cpp +++ b/src/plugins/coreplugin/documentmanager.cpp @@ -44,6 +44,7 @@ #include #include +#include #include #include #include @@ -229,7 +230,13 @@ DocumentManager::DocumentManager(QObject *parent) { d = new DocumentManagerPrivate; 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(); @@ -597,13 +604,6 @@ void DocumentManager::unexpectFileChange(const QString &fileName) 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 &documents, const QString &message, bool *cancelled, bool silently, const QString &alwaysSaveMessage, bool *alwaysSave, @@ -1470,14 +1470,6 @@ void DocumentManager::notifyFilesChangedInternally(const QStringList &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(const QString &fileName) diff --git a/src/plugins/coreplugin/documentmanager.h b/src/plugins/coreplugin/documentmanager.h index 7ddafef3f1a..911e46615a8 100644 --- a/src/plugins/coreplugin/documentmanager.h +++ b/src/plugins/coreplugin/documentmanager.h @@ -69,8 +69,6 @@ public: static void expectFileChange(const QString &fileName); static void unexpectFileChange(const QString &fileName); - static void setAutoReloadPostponed(bool enabled); - // recent files static void addToRecentFiles(const QString &fileName, Id editorId = Id()); Q_SLOT void clearRecentFiles(); @@ -155,9 +153,6 @@ signals: void documentRenamed(Core::IDocument *document, const QString &from, const QString &to); void projectsDirectoryChanged(const Utils::FileName &directory); -protected: - bool eventFilter(QObject *obj, QEvent *e) override; - private: explicit DocumentManager(QObject *parent); ~DocumentManager() override; diff --git a/src/plugins/cpptools/cppbuiltinmodelmanagersupport.h b/src/plugins/cpptools/cppbuiltinmodelmanagersupport.h index 93707d465a1..49b07566905 100644 --- a/src/plugins/cpptools/cppbuiltinmodelmanagersupport.h +++ b/src/plugins/cpptools/cppbuiltinmodelmanagersupport.h @@ -47,7 +47,6 @@ public: FollowSymbolInterface &followSymbolInterface() final; RefactoringEngineInterface &refactoringEngineInterface() final; std::unique_ptr createOverviewModel() final; - void setBackendJobsPostponed(bool) final {} private: QScopedPointer m_completionAssistProvider; diff --git a/src/plugins/cpptools/cppmodelmanager.cpp b/src/plugins/cpptools/cppmodelmanager.cpp index e5185174b10..60fc5a872f0 100644 --- a/src/plugins/cpptools/cppmodelmanager.cpp +++ b/src/plugins/cpptools/cppmodelmanager.cpp @@ -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() { Core::ProgressManager::cancelTasks(CppTools::Constants::TASK_INDEX); diff --git a/src/plugins/cpptools/cppmodelmanager.h b/src/plugins/cpptools/cppmodelmanager.h index e273a128c6f..9726c8086f1 100644 --- a/src/plugins/cpptools/cppmodelmanager.h +++ b/src/plugins/cpptools/cppmodelmanager.h @@ -230,8 +230,6 @@ public: void renameIncludes(const QString &oldFileName, const QString &newFileName); - void setBackendJobsPostponed(bool postponed); - signals: /// Project data might be locked while this is emitted. void aboutToRemoveFiles(const QStringList &files); diff --git a/src/plugins/cpptools/cppmodelmanagersupport.h b/src/plugins/cpptools/cppmodelmanagersupport.h index f7ff56ca3bc..c5457cd51f3 100644 --- a/src/plugins/cpptools/cppmodelmanagersupport.h +++ b/src/plugins/cpptools/cppmodelmanagersupport.h @@ -60,7 +60,6 @@ public: virtual FollowSymbolInterface &followSymbolInterface() = 0; virtual RefactoringEngineInterface &refactoringEngineInterface() = 0; virtual std::unique_ptr createOverviewModel() = 0; - virtual void setBackendJobsPostponed(bool yesno) = 0; }; class CPPTOOLS_EXPORT ModelManagerSupportProvider diff --git a/src/plugins/vcsbase/vcscommand.cpp b/src/plugins/vcsbase/vcscommand.cpp index 54334559816..6422eb2997d 100644 --- a/src/plugins/vcsbase/vcscommand.cpp +++ b/src/plugins/vcsbase/vcscommand.cpp @@ -29,7 +29,7 @@ #include #include -#include +#include #include #include @@ -61,16 +61,12 @@ VcsCommand::VcsCommand(const QString &workingDirectory, return proxy; }); connect(this, &VcsCommand::started, this, [this] { - if (flags() & ExpectRepoChanges) { - Core::DocumentManager::setAutoReloadPostponed(true); - CppTools::CppModelManager::instance()->setBackendJobsPostponed(true); - } + if (flags() & ExpectRepoChanges) + Utils::GlobalFileChangeBlocker::instance()->forceBlocked(true); }); connect(this, &VcsCommand::finished, this, [this] { - if (flags() & ExpectRepoChanges) { - Core::DocumentManager::setAutoReloadPostponed(false); - CppTools::CppModelManager::instance()->setBackendJobsPostponed(false); - } + if (flags() & ExpectRepoChanges) + Utils::GlobalFileChangeBlocker::instance()->forceBlocked(false); }); }