/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** 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 "cppprojectupdater.h" #include "cppmodelmanager.h" #include "cppprojectinfogenerator.h" #include "generatedcodemodelsupport.h" #include #include #include #include #include #include #include using namespace ProjectExplorer; namespace CppTools { CppProjectUpdater::CppProjectUpdater() { connect(&m_generateFutureWatcher, &QFutureWatcher::finished, this, &CppProjectUpdater::onProjectInfoGenerated); m_futureSynchronizer.setCancelOnWait(true); } CppProjectUpdater::~CppProjectUpdater() { cancel(); } void CppProjectUpdater::update(const ProjectUpdateInfo &projectUpdateInfo) { update(projectUpdateInfo, {}); } void CppProjectUpdater::update(const ProjectUpdateInfo &projectUpdateInfo, const QList &extraCompilers) { // Stop previous update. cancel(); m_extraCompilers = Utils::transform(extraCompilers, [](ExtraCompiler *compiler) { return QPointer(compiler); }); m_projectUpdateInfo = projectUpdateInfo; using namespace ProjectExplorer; // Run the project info generator in a worker thread and continue if that one is finished. auto generateFuture = Utils::runAsync([=](QFutureInterface &futureInterface) { ProjectUpdateInfo fullProjectUpdateInfo = projectUpdateInfo; if (fullProjectUpdateInfo.rppGenerator) fullProjectUpdateInfo.rawProjectParts = fullProjectUpdateInfo.rppGenerator(); Internal::ProjectInfoGenerator generator(futureInterface, fullProjectUpdateInfo); futureInterface.reportResult(generator.generate()); }); m_generateFutureWatcher.setFuture(generateFuture); m_futureSynchronizer.addFuture(generateFuture); // extra compilers for (QPointer compiler : qAsConst(m_extraCompilers)) { if (compiler->isDirty()) { auto watcher = new QFutureWatcher; // queued connection to delay after the extra compiler updated its result contents, // which is also done in the main thread when compiler->run() finished connect(watcher, &QFutureWatcherBase::finished, this, [this, watcher] { m_projectUpdateFutureInterface->setProgressValue( m_projectUpdateFutureInterface->progressValue() + 1); m_extraCompilersFutureWatchers.remove(watcher); watcher->deleteLater(); if (!watcher->isCanceled()) checkForExtraCompilersFinished(); }, Qt::QueuedConnection); m_extraCompilersFutureWatchers += watcher; watcher->setFuture(QFuture(compiler->run())); m_futureSynchronizer.addFuture(watcher->future()); } } m_projectUpdateFutureInterface.reset(new QFutureInterface); m_projectUpdateFutureInterface->setProgressRange(0, m_extraCompilersFutureWatchers.size() + 1 /*generateFuture*/); m_projectUpdateFutureInterface->setProgressValue(0); m_projectUpdateFutureInterface->reportStarted(); Core::ProgressManager::addTask(m_projectUpdateFutureInterface->future(), tr("Preparing C++ Code Model"), "CppProjectUpdater"); } void CppProjectUpdater::cancel() { if (m_projectUpdateFutureInterface && m_projectUpdateFutureInterface->isRunning()) m_projectUpdateFutureInterface->reportFinished(); m_generateFutureWatcher.setFuture({}); m_isProjectInfoGenerated = false; qDeleteAll(m_extraCompilersFutureWatchers); m_extraCompilersFutureWatchers.clear(); m_extraCompilers.clear(); m_futureSynchronizer.cancelAllFutures(); } void CppProjectUpdater::onProjectInfoGenerated() { if (m_generateFutureWatcher.isCanceled() || m_generateFutureWatcher.future().resultCount() < 1) return; m_projectUpdateFutureInterface->setProgressValue(m_projectUpdateFutureInterface->progressValue() + 1); m_isProjectInfoGenerated = true; checkForExtraCompilersFinished(); } void CppProjectUpdater::checkForExtraCompilersFinished() { if (!m_extraCompilersFutureWatchers.isEmpty() || !m_isProjectInfoGenerated) return; // still need to wait m_projectUpdateFutureInterface->reportFinished(); m_projectUpdateFutureInterface.reset(); QList extraCompilers; QSet compilerFiles; for (const QPointer &compiler : qAsConst(m_extraCompilers)) { if (compiler) { extraCompilers += compiler.data(); compilerFiles += Utils::transform(compiler->targets(), &Utils::FilePath::toString); } } GeneratedCodeModelSupport::update(extraCompilers); m_extraCompilers.clear(); auto updateFuture = CppModelManager::instance() ->updateProjectInfo(m_generateFutureWatcher.result(), compilerFiles); m_futureSynchronizer.addFuture(updateFuture); } CppProjectUpdaterFactory::CppProjectUpdaterFactory() { setObjectName("CppProjectUpdaterFactory"); } CppProjectUpdaterInterface *CppProjectUpdaterFactory::create() { return new CppProjectUpdater; } } // namespace CppTools