diff --git a/src/plugins/autotoolsprojectmanager/autotoolsproject.cpp b/src/plugins/autotoolsprojectmanager/autotoolsproject.cpp index 38257ad7542..3d88515768e 100644 --- a/src/plugins/autotoolsprojectmanager/autotoolsproject.cpp +++ b/src/plugins/autotoolsprojectmanager/autotoolsproject.cpp @@ -119,6 +119,7 @@ Project::RestoreResult AutotoolsProject::fromMap(const QVariantMap &map, QString void AutotoolsProject::loadProjectTree() { + emitParsingStarted(); if (m_makefileParserThread) { // The thread is still busy parsing a previus configuration. // Wait until the thread has been finished and delete it. @@ -218,7 +219,7 @@ void AutotoolsProject::makefileParsingFinished() m_makefileParserThread->deleteLater(); m_makefileParserThread = nullptr; - emit parsingFinished(); + emitParsingFinished(true); } void AutotoolsProject::onFileChanged(const QString &file) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index ef828919faa..a0358988eb8 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -144,12 +144,15 @@ void CMakeBuildConfiguration::ctor() connect(m_buildDirManager.get(), &BuildDirManager::dataAvailable, this, [this, project]() { - project->updateProjectData(this); clearError(); + project->updateProjectData(this); emit dataAvailable(); }); connect(m_buildDirManager.get(), &BuildDirManager::errorOccured, - this, &CMakeBuildConfiguration::setError); + this, [this, project](const QString &msg) { + setError(msg); + project->handleParsingError(this); + }); connect(m_buildDirManager.get(), &BuildDirManager::configurationStarted, this, [this, project]() { project->handleParsingStarted(); diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.cpp index fe85283ad2a..881c8d984c7 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.cpp @@ -204,7 +204,7 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc) setError(bc->error()); setWarning(bc->warning()); - connect(project, &CMakeProject::parsingStarted, this, [this]() { + connect(project, &ProjectExplorer::Project::parsingStarted, this, [this]() { updateButtonState(); m_showProgressTimer.start(); }); diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.cpp b/src/plugins/cmakeprojectmanager/cmakeproject.cpp index 91aa189e64c..4d37f661be5 100644 --- a/src/plugins/cmakeprojectmanager/cmakeproject.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeproject.cpp @@ -188,7 +188,18 @@ void CMakeProject::updateProjectData(CMakeBuildConfiguration *bc) emit bc->emitBuildTypeChanged(); - emit parsingFinished(); + emitParsingFinished(true); +} + +void CMakeProject::handleParsingError(CMakeBuildConfiguration *bc) +{ + QTC_ASSERT(bc, return); + + Target *t = activeTarget(); + if (!t || t->activeBuildConfiguration() != bc) + return; + + emitParsingFinished(false); } void CMakeProject::updateQmlJSCodeModel() @@ -369,7 +380,7 @@ void CMakeProject::handleActiveBuildConfigurationChanged() void CMakeProject::handleParsingStarted() { if (activeTarget() && activeTarget()->activeBuildConfiguration() == sender()) - emit parsingStarted(); + emitParsingStarted(); } void CMakeProject::handleTreeScanningFinished() diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.h b/src/plugins/cmakeprojectmanager/cmakeproject.h index 2b20a7479cc..92bf4f3b404 100644 --- a/src/plugins/cmakeprojectmanager/cmakeproject.h +++ b/src/plugins/cmakeprojectmanager/cmakeproject.h @@ -105,10 +105,6 @@ public: ProjectExplorer::ProjectImporter *projectImporter() const final; -signals: - /// emitted when cmake is running: - void parsingStarted(); - protected: RestoreResult fromMap(const QVariantMap &map, QString *errorMessage) final; bool setupTarget(ProjectExplorer::Target *t) final; @@ -121,6 +117,7 @@ private: void handleParsingStarted(); void handleTreeScanningFinished(); void updateProjectData(Internal::CMakeBuildConfiguration *cmakeBc); + void handleParsingError(Internal::CMakeBuildConfiguration *bc); void updateQmlJSCodeModel(); void createGeneratedCodeModelSupport(); diff --git a/src/plugins/genericprojectmanager/genericproject.cpp b/src/plugins/genericprojectmanager/genericproject.cpp index 97d884c8713..1018f99b9d9 100644 --- a/src/plugins/genericprojectmanager/genericproject.cpp +++ b/src/plugins/genericprojectmanager/genericproject.cpp @@ -336,6 +336,7 @@ void GenericProject::parseProject(RefreshOptions options) void GenericProject::refresh(RefreshOptions options) { + emitParsingStarted(); parseProject(options); if (options & Files) { @@ -362,7 +363,7 @@ void GenericProject::refresh(RefreshOptions options) } refreshCppCodeModel(); - emit parsingFinished(); + emitParsingFinished(true); } /** diff --git a/src/plugins/nim/project/nimproject.cpp b/src/plugins/nim/project/nimproject.cpp index 8910bd42af6..c6d28a3974a 100644 --- a/src/plugins/nim/project/nimproject.cpp +++ b/src/plugins/nim/project/nimproject.cpp @@ -127,6 +127,7 @@ void NimProject::collectProjectFiles() void NimProject::updateProject() { + emitParsingStarted(); const QStringList oldFiles = m_files; m_files.clear(); @@ -152,7 +153,7 @@ void NimProject::updateProject() newRoot->setDisplayName(displayName()); newRoot->addNestedNodes(fileNodes); setRootProjectNode(newRoot); - emit parsingFinished(); + emitParsingFinished(true); } bool NimProject::supportsKit(Kit *k, QString *errorMessage) const diff --git a/src/plugins/projectexplorer/project.cpp b/src/plugins/projectexplorer/project.cpp index 32cbcdc218d..9c7f5ee2a59 100644 --- a/src/plugins/projectexplorer/project.cpp +++ b/src/plugins/projectexplorer/project.cpp @@ -136,6 +136,8 @@ public: ~ProjectPrivate(); Core::Id m_id; + bool m_isParsing = false; + bool m_hasParsingData = false; std::unique_ptr m_document; ProjectNode *m_rootProjectNode = nullptr; std::unique_ptr m_containerNode; @@ -464,6 +466,24 @@ bool Project::setupTarget(Target *t) return true; } +void Project::emitParsingStarted() +{ + QTC_ASSERT(!d->m_isParsing, return); + + d->m_isParsing = true; + d->m_hasParsingData = false; + emit parsingStarted(); +} + +void Project::emitParsingFinished(bool success) +{ + QTC_ASSERT(d->m_isParsing, return); + + d->m_isParsing = false; + d->m_hasParsingData = success; + emit parsingFinished(success); +} + void Project::setDisplayName(const QString &name) { if (name == d->m_displayName) @@ -813,6 +833,16 @@ Utils::MacroExpander *Project::macroExpander() const return &d->m_macroExpander; } +bool Project::isParsing() const +{ + return d->m_isParsing; +} + +bool Project::hasParsingData() const +{ + return d->m_hasParsingData; +} + ProjectImporter *Project::projectImporter() const { return nullptr; diff --git a/src/plugins/projectexplorer/project.h b/src/plugins/projectexplorer/project.h index f76a1513dea..d3582241b5b 100644 --- a/src/plugins/projectexplorer/project.h +++ b/src/plugins/projectexplorer/project.h @@ -163,6 +163,9 @@ public: void setup(QList infoList); Utils::MacroExpander *macroExpander() const; + bool isParsing() const; + bool hasParsingData() const; + signals: void displayNameChanged(); void fileListChanged(); @@ -185,12 +188,19 @@ signals: void projectContextUpdated(); void projectLanguagesUpdated(); - void parsingFinished(); + void parsingStarted(); + void parsingFinished(bool success); protected: virtual RestoreResult fromMap(const QVariantMap &map, QString *errorMessage); virtual bool setupTarget(Target *t); + // Helper methods to manage parsing state and signalling + // Call in GUI thread before the actual parsing starts + void emitParsingStarted(); + // Call in GUI thread right after the actual parsing is done + void emitParsingFinished(bool success); + void setDisplayName(const QString &name); void setRequiredKitPredicate(const Kit::Predicate &predicate); void setPreferredKitPredicate(const Kit::Predicate &predicate); diff --git a/src/plugins/pythoneditor/pythoneditorplugin.cpp b/src/plugins/pythoneditor/pythoneditorplugin.cpp index bb907067844..6dad6d29fa8 100644 --- a/src/plugins/pythoneditor/pythoneditorplugin.cpp +++ b/src/plugins/pythoneditor/pythoneditorplugin.cpp @@ -507,6 +507,7 @@ private: void PythonProject::refresh() { + emitParsingStarted(); parseProject(); QDir baseDir(projectDirectory().toString()); @@ -517,7 +518,7 @@ void PythonProject::refresh() } setRootProjectNode(newRoot); - emit parsingFinished(); + emitParsingFinished(true); } /** diff --git a/src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp b/src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp index 208ca398fe4..98af06c996f 100644 --- a/src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp +++ b/src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp @@ -69,8 +69,8 @@ QbsBuildConfiguration::QbsBuildConfiguration(Target *target) : m_isParsing(true), m_parsingError(false) { - connect(project(), &QbsProject::projectParsingStarted, this, &BuildConfiguration::enabledChanged); - connect(project(), &QbsProject::projectParsingDone, this, &BuildConfiguration::enabledChanged); + connect(project(), &Project::parsingStarted, this, &BuildConfiguration::enabledChanged); + connect(project(), &Project::parsingFinished, this, &BuildConfiguration::enabledChanged); BuildStepList *bsl = stepList(ProjectExplorer::Constants::BUILDSTEPS_BUILD); connect(bsl, &BuildStepList::stepInserted, this, &QbsBuildConfiguration::buildStepInserted); diff --git a/src/plugins/qbsprojectmanager/qbsbuildstep.cpp b/src/plugins/qbsprojectmanager/qbsbuildstep.cpp index 87978b78280..8f57fd3c719 100644 --- a/src/plugins/qbsprojectmanager/qbsbuildstep.cpp +++ b/src/plugins/qbsprojectmanager/qbsbuildstep.cpp @@ -346,7 +346,8 @@ void QbsBuildStep::buildingDone(bool success) void QbsBuildStep::reparsingDone(bool success) { - disconnect(qbsProject(), &QbsProject::projectParsingDone, this, &QbsBuildStep::reparsingDone); + disconnect(qbsProject(), &ProjectExplorer::Project::parsingFinished, + this, &QbsBuildStep::reparsingDone); m_parsingProject = false; if (m_job) { // This was a scheduled reparsing after building. finish(); @@ -485,7 +486,8 @@ void QbsBuildStep::setCleanInstallRoot(bool clean) void QbsBuildStep::parseProject() { m_parsingProject = true; - connect(qbsProject(), &QbsProject::projectParsingDone, this, &QbsBuildStep::reparsingDone); + connect(qbsProject(), &ProjectExplorer::Project::parsingFinished, + this, &QbsBuildStep::reparsingDone); qbsProject()->parseCurrentBuildConfiguration(); } diff --git a/src/plugins/qbsprojectmanager/qbsinstallstep.cpp b/src/plugins/qbsprojectmanager/qbsinstallstep.cpp index 840cf4eefd5..8a4e9ad7b9d 100644 --- a/src/plugins/qbsprojectmanager/qbsinstallstep.cpp +++ b/src/plugins/qbsprojectmanager/qbsinstallstep.cpp @@ -286,7 +286,7 @@ QbsInstallStepConfigWidget::QbsInstallStepConfigWidget(QbsInstallStep *step) : connect(m_ui->keepGoingCheckBox, &QAbstractButton::toggled, this, &QbsInstallStepConfigWidget::changeKeepGoing); - connect(project, &QbsProject::projectParsingDone, + connect(project, &ProjectExplorer::Project::parsingFinished, this, &QbsInstallStepConfigWidget::updateState); updateState(); diff --git a/src/plugins/qbsprojectmanager/qbsproject.cpp b/src/plugins/qbsprojectmanager/qbsproject.cpp index 295a70690f5..da88f9ab4a5 100644 --- a/src/plugins/qbsprojectmanager/qbsproject.cpp +++ b/src/plugins/qbsprojectmanager/qbsproject.cpp @@ -502,8 +502,7 @@ void QbsProject::handleQbsParsingDone(bool success) if (dataChanged) updateAfterParse(); - emit projectParsingDone(success); - emit parsingFinished(); + emitParsingFinished(success); } void QbsProject::rebuildProjectTree() @@ -529,7 +528,7 @@ void QbsProject::handleRuleExecutionDone() QTC_ASSERT(m_qbsProject.isValid(), return); m_projectData = m_qbsProject.projectData(); updateAfterParse(); - emit projectParsingDone(true); + // finishParsing(true); } void QbsProject::targetWasAdded(Target *t) @@ -699,7 +698,7 @@ void QbsProject::parse(const QVariantMap &config, const Environment &env, const QbsManager::instance()->updateProfileIfNecessary(activeTarget()->kit()); m_qbsProjectParser->parse(config, env, dir, configName); - emit projectParsingStarted(); + emitParsingStarted(); } void QbsProject::prepareForParsing() diff --git a/src/plugins/qbsprojectmanager/qbsproject.h b/src/plugins/qbsprojectmanager/qbsproject.h index 500761380bd..8ff26640743 100644 --- a/src/plugins/qbsprojectmanager/qbsproject.h +++ b/src/plugins/qbsprojectmanager/qbsproject.h @@ -108,14 +108,9 @@ public: const qbs::ProductData &product); static QString uniqueProductName(const qbs::ProductData &product); -public: void invalidate(); void delayParsing(); -signals: - void projectParsingStarted(); - void projectParsingDone(bool); - private: void handleQbsParsingDone(bool success); diff --git a/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp b/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp index a15c2ca2cc7..43f6e49050a 100644 --- a/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp +++ b/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp @@ -295,9 +295,9 @@ void QbsProjectManagerPlugin::projectWasAdded(Project *project) if (!qbsProject) return; - connect(qbsProject, &QbsProject::projectParsingStarted, + connect(qbsProject, &Project::parsingStarted, this, &QbsProjectManagerPlugin::projectChanged); - connect(qbsProject, &QbsProject::projectParsingDone, + connect(qbsProject, &Project::parsingFinished, this, &QbsProjectManagerPlugin::projectChanged); } diff --git a/src/plugins/qbsprojectmanager/qbsrunconfiguration.cpp b/src/plugins/qbsprojectmanager/qbsrunconfiguration.cpp index e8b90d4377a..44f464702a5 100644 --- a/src/plugins/qbsprojectmanager/qbsrunconfiguration.cpp +++ b/src/plugins/qbsprojectmanager/qbsrunconfiguration.cpp @@ -119,7 +119,7 @@ QbsRunConfiguration::QbsRunConfiguration(Target *parent, Core::Id id) : } ); addExtraAspect(envAspect); - connect(static_cast(parent->project()), &QbsProject::parsingFinished, this, + connect(static_cast(parent->project()), &Project::parsingFinished, this, [envAspect]() { envAspect->buildEnvironmentHasChanged(); }); addExtraAspect(new ArgumentsAspect(this, QStringLiteral("Qbs.RunConfiguration.CommandLineArguments"))); addExtraAspect(new WorkingDirectoryAspect(this, QStringLiteral("Qbs.RunConfiguration.WorkingDirectory"))); @@ -162,8 +162,8 @@ void QbsRunConfiguration::ctor() setDefaultDisplayName(defaultDisplayName()); QbsProject *project = static_cast(target()->project()); - connect(project, &QbsProject::projectParsingStarted, this, &RunConfiguration::enabledChanged); - connect(project, &QbsProject::projectParsingDone, this, [this](bool success) { + connect(project, &Project::parsingStarted, this, &RunConfiguration::enabledChanged); + connect(project, &Project::parsingFinished, this, [this](bool success) { auto terminalAspect = extraAspect(); if (success && !terminalAspect->isUserSet()) terminalAspect->setUseTerminal(isConsoleApplication()); diff --git a/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp b/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp index e0d80e766ca..38e25554cfb 100644 --- a/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp @@ -1473,7 +1473,7 @@ void QmakeProFile::asyncEvaluate(QFutureInterface &fi, QmakeE void QmakeProFile::applyAsyncEvaluate() { applyEvaluate(m_parseFutureWatcher.result()); - m_project->decrementPendingEvaluateFutures(); + m_project->decrementPendingEvaluateFutures(validParse()); } bool sortByParserNodes(Node *a, Node *b) diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.cpp b/src/plugins/qmakeprojectmanager/qmakeproject.cpp index 0b0c2673b63..ed9bbccd3c1 100644 --- a/src/plugins/qmakeprojectmanager/qmakeproject.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeproject.cpp @@ -408,6 +408,7 @@ void QmakeProject::scheduleAsyncUpdate(QmakeProFile *file, QmakeProFile::AsyncUp return; } + emitParsingStarted(); file->setParseInProgressRecursive(true); setAllBuildConfigurationsEnabled(false); @@ -464,6 +465,7 @@ void QmakeProject::scheduleAsyncUpdate(QmakeProFile::AsyncUpdateDelay delay) return; } + emitParsingStarted(); rootProFile()->setParseInProgressRecursive(true); setAllBuildConfigurationsEnabled(false); @@ -492,19 +494,26 @@ void QmakeProject::startAsyncTimer(QmakeProFile::AsyncUpdateDelay delay) void QmakeProject::incrementPendingEvaluateFutures() { ++m_pendingEvaluateFuturesCount; + if (m_pendingEvaluateFuturesCount == 1) + m_totalEvaluationSuccess = true; m_asyncUpdateFutureInterface->setProgressRange(m_asyncUpdateFutureInterface->progressMinimum(), m_asyncUpdateFutureInterface->progressMaximum() + 1); } -void QmakeProject::decrementPendingEvaluateFutures() +void QmakeProject::decrementPendingEvaluateFutures(bool success) { --m_pendingEvaluateFuturesCount; + m_totalEvaluationSuccess = m_totalEvaluationSuccess && success; + m_asyncUpdateFutureInterface->setProgressValue(m_asyncUpdateFutureInterface->progressValue() + 1); if (m_pendingEvaluateFuturesCount == 0) { // We are done! setRootProjectNode(QmakeNodeTreeBuilder::buildTree(this)); + if (!m_totalEvaluationSuccess) + m_asyncUpdateFutureInterface->reportCanceled(); + m_asyncUpdateFutureInterface->reportFinished(); delete m_asyncUpdateFutureInterface; m_asyncUpdateFutureInterface = nullptr; @@ -512,6 +521,7 @@ void QmakeProject::decrementPendingEvaluateFutures() // TODO clear the profile cache ? if (m_asyncUpdateState == AsyncFullUpdatePending || m_asyncUpdateState == AsyncPartialUpdatePending) { + // Already parsing! rootProFile()->setParseInProgressRecursive(true); setAllBuildConfigurationsEnabled(false); startAsyncTimer(QmakeProFile::ParseLater); @@ -526,7 +536,7 @@ void QmakeProject::decrementPendingEvaluateFutures() activeTarget()->updateDefaultDeployConfigurations(); updateRunConfigurations(); emit proFilesEvaluated(); - emit parsingFinished(); + emitParsingFinished(true); // Qmake always returns (some) data, even when it failed:-) } } } @@ -542,6 +552,8 @@ void QmakeProject::asyncUpdate() m_qmakeVfs->invalidateCache(); + emitParsingStarted(); + Q_ASSERT(!m_asyncUpdateFutureInterface); m_asyncUpdateFutureInterface = new QFutureInterface(); diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.h b/src/plugins/qmakeprojectmanager/qmakeproject.h index 590fe4f46ee..ac816463177 100644 --- a/src/plugins/qmakeprojectmanager/qmakeproject.h +++ b/src/plugins/qmakeprojectmanager/qmakeproject.h @@ -102,7 +102,7 @@ public: /// \internal void incrementPendingEvaluateFutures(); /// \internal - void decrementPendingEvaluateFutures(); + void decrementPendingEvaluateFutures(bool success); /// \internal bool wasEvaluateCanceled(); @@ -188,6 +188,7 @@ private: // cached data during project rescan QMakeGlobals *m_qmakeGlobals = nullptr; int m_qmakeGlobalsRefCnt = 0; + bool m_totalEvaluationSuccess = false; QString m_qmakeSysroot; diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp b/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp index 817676bfeea..5c18900931c 100644 --- a/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp @@ -279,8 +279,8 @@ void QmakeProjectManagerPlugin::projectChanged() if (m_previousStartupProject) { connect(m_previousStartupProject, &Project::activeTargetChanged, - this, &QmakeProjectManagerPlugin::activeTargetChanged); - connect(m_previousStartupProject, &QmakeProject::parsingFinished, + this, &QmakeProjectManagerPlugin::activeTargetChanged); + connect(m_previousStartupProject, &Project::parsingFinished, this, &QmakeProjectManagerPlugin::updateActions); } diff --git a/src/plugins/qmlprojectmanager/qmlproject.cpp b/src/plugins/qmlprojectmanager/qmlproject.cpp index 49de48f7621..76c3e6fa2bd 100644 --- a/src/plugins/qmlprojectmanager/qmlproject.cpp +++ b/src/plugins/qmlprojectmanager/qmlproject.cpp @@ -170,6 +170,7 @@ void QmlProject::parseProject(RefreshOptions options) void QmlProject::refresh(RefreshOptions options) { + emitParsingStarted(); parseProject(options); if (options & Files) @@ -187,7 +188,7 @@ void QmlProject::refresh(RefreshOptions options) modelManager->updateProjectInfo(projectInfo, this); - emit parsingFinished(); + emitParsingFinished(true); } QString QmlProject::mainFile() const