diff --git a/src/plugins/qbsprojectmanager/qbsproject.cpp b/src/plugins/qbsprojectmanager/qbsproject.cpp index eaafb89c818..deb49bdfc7d 100644 --- a/src/plugins/qbsprojectmanager/qbsproject.cpp +++ b/src/plugins/qbsprojectmanager/qbsproject.cpp @@ -102,6 +102,7 @@ QbsProject::QbsProject(QbsManager *manager, const QString &fileName) : m_qbsUpdateFutureInterface(0), m_forceParsing(false), m_parsingScheduled(false), + m_cancelingParsing(false), m_currentBc(0) { m_parsingDelay.setInterval(1000); // delay parsing by 1s. @@ -275,12 +276,23 @@ void QbsProject::handleQbsParsingDone(bool success) { QTC_ASSERT(m_qbsProjectParser, return); + // If this parse operation was canceled, start a new one right away, ignoring the old result. + if (m_cancelingParsing) { + m_cancelingParsing = false; + m_qbsProjectParser->deleteLater(); + m_qbsProjectParser = 0; + parseCurrentBuildConfiguration(m_forceParsing); + return; + } + generateErrors(m_qbsProjectParser->error()); if (success) { m_qbsProject = m_qbsProjectParser->qbsProject(); QTC_CHECK(m_qbsProject.isValid()); readQbsData(); + } else { + m_qbsUpdateFutureInterface->reportCanceled(); } m_qbsProjectParser->deleteLater(); @@ -369,12 +381,27 @@ void QbsProject::parseCurrentBuildConfiguration(bool force) m_parsingScheduled = false; if (!m_forceParsing) m_forceParsing = force; + if (m_cancelingParsing) + return; if (!activeTarget()) return; QbsBuildConfiguration *bc = qobject_cast(activeTarget()->activeBuildConfiguration()); if (!bc) return; + + // New parse requests override old ones. + // NOTE: We need to wait for the current operation to finish, since otherwise there could + // be a conflict. Consider the case where the old qbs::ProjectSetupJob is writing + // to the build graph file when the cancel request comes in. If we don't wait for + // acknowledgment, it might still be doing that when the new one already reads from the + // same file. + if (m_qbsProjectParser) { + m_cancelingParsing = true; + m_qbsProjectParser->cancel(); + return; + } + parse(bc->qbsConfiguration(), bc->environment(), bc->buildDirectory().toString()); } diff --git a/src/plugins/qbsprojectmanager/qbsproject.h b/src/plugins/qbsprojectmanager/qbsproject.h index 97c01787bc1..ab757cc82f4 100644 --- a/src/plugins/qbsprojectmanager/qbsproject.h +++ b/src/plugins/qbsprojectmanager/qbsproject.h @@ -153,6 +153,7 @@ private: QFutureInterface *m_qbsUpdateFutureInterface; bool m_forceParsing; bool m_parsingScheduled; + bool m_cancelingParsing; QFuture m_codeModelFuture; diff --git a/src/plugins/qbsprojectmanager/qbsprojectparser.cpp b/src/plugins/qbsprojectmanager/qbsprojectparser.cpp index e707dc36f8c..171e921b16b 100644 --- a/src/plugins/qbsprojectmanager/qbsprojectparser.cpp +++ b/src/plugins/qbsprojectmanager/qbsprojectparser.cpp @@ -136,6 +136,12 @@ bool QbsProjectParser::parse(const QVariantMap &config, const Environment &env, return true; } +void QbsProjectParser::cancel() +{ + QTC_ASSERT(m_qbsSetupProjectJob, return); + m_qbsSetupProjectJob->cancel(); +} + qbs::Project QbsProjectParser::qbsProject() const { return m_project; @@ -153,8 +159,8 @@ void QbsProjectParser::handleQbsParsingDone(bool success) m_project = m_qbsSetupProjectJob->project(); m_error = m_qbsSetupProjectJob->error(); - if (!success) - m_fi->reportCanceled(); + // Do not report the operation as canceled here, as we might want to make overlapping + // parses appear atomic to the user. emit done(success); } diff --git a/src/plugins/qbsprojectmanager/qbsprojectparser.h b/src/plugins/qbsprojectmanager/qbsprojectparser.h index 36ddd7ea8fe..9d0d1496aec 100644 --- a/src/plugins/qbsprojectmanager/qbsprojectparser.h +++ b/src/plugins/qbsprojectmanager/qbsprojectparser.h @@ -54,6 +54,7 @@ public: void setForced(bool); bool parse(const QVariantMap &config, const Utils::Environment &env, const QString &dir); + void cancel(); qbs::Project qbsProject() const; qbs::ErrorInfo error();