ProjectExplorer: Allow to schedule a build/run during a project parse

Once we parsed the project initially, subsequent parses typically do not
change things in a major way, so we can expect e.g. run configurations to
stay intact.
It therefore makes sense to allow users to schedule an
application run not only during a build (see 4b92b7ac60), but also
during a parse. Arguably, this is even more relevant, as parsing is
usually not triggered directly by the user, but happens as a side effect
of editing a document or switching a branch. It is then annoying for
users to have to wait until the respective buttons get enabled again.

Fixes: QTCREATORBUG-24986
Change-Id: I1081ccde668eee794c39b96cd0bad5c3aaa580bc
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Christian Kandeler
2020-12-03 15:17:23 +01:00
parent 2839d9fa92
commit 29ddb3bcdb
7 changed files with 55 additions and 23 deletions

View File

@@ -531,13 +531,11 @@ void BuildConfiguration::setUserEnvironmentChanges(const EnvironmentItems &diff)
bool BuildConfiguration::isEnabled() const bool BuildConfiguration::isEnabled() const
{ {
return !buildSystem()->isParsing() && buildSystem()->hasParsingData(); return buildSystem()->hasParsingData();
} }
QString BuildConfiguration::disabledReason() const QString BuildConfiguration::disabledReason() const
{ {
if (buildSystem()->isParsing())
return (tr("The project is currently being parsed."));
if (!buildSystem()->hasParsingData()) if (!buildSystem()->hasParsingData())
return (tr("The project was not parsed successfully.")); return (tr("The project was not parsed successfully."));
return QString(); return QString();

View File

@@ -91,8 +91,8 @@ public:
bool fromMap(const QVariantMap &map) override; bool fromMap(const QVariantMap &map) override;
QVariantMap toMap() const override; QVariantMap toMap() const override;
virtual bool isEnabled() const; bool isEnabled() const;
virtual QString disabledReason() const; QString disabledReason() const;
virtual bool regenerateBuildFiles(Node *node); virtual bool regenerateBuildFiles(Node *node);

View File

@@ -27,6 +27,7 @@
#include "buildprogress.h" #include "buildprogress.h"
#include "buildsteplist.h" #include "buildsteplist.h"
#include "buildsystem.h"
#include "compileoutputwindow.h" #include "compileoutputwindow.h"
#include "deployconfiguration.h" #include "deployconfiguration.h"
#include "kit.h" #include "kit.h"
@@ -46,6 +47,7 @@
#include <coreplugin/progressmanager/futureprogress.h> #include <coreplugin/progressmanager/futureprogress.h>
#include <coreplugin/progressmanager/progressmanager.h> #include <coreplugin/progressmanager/progressmanager.h>
#include <extensionsystem/pluginmanager.h> #include <extensionsystem/pluginmanager.h>
#include <utils/algorithm.h>
#include <utils/outputformatter.h> #include <utils/outputformatter.h>
#include <utils/runextensions.h> #include <utils/runextensions.h>
#include <utils/stringutils.h> #include <utils/stringutils.h>
@@ -57,6 +59,7 @@
#include <QList> #include <QList>
#include <QMessageBox> #include <QMessageBox>
#include <QPointer> #include <QPointer>
#include <QSet>
#include <QTime> #include <QTime>
#include <QTimer> #include <QTimer>
@@ -215,6 +218,7 @@ public:
Internal::CompileOutputWindow *m_outputWindow = nullptr; Internal::CompileOutputWindow *m_outputWindow = nullptr;
Internal::TaskWindow *m_taskWindow = nullptr; Internal::TaskWindow *m_taskWindow = nullptr;
QMetaObject::Connection m_scheduledBuild;
QList<BuildStep *> m_buildQueue; QList<BuildStep *> m_buildQueue;
QList<bool> m_enabledState; QList<bool> m_enabledState;
QStringList m_stepNames; QStringList m_stepNames;
@@ -459,6 +463,12 @@ QString BuildManager::displayNameForStepId(Id stepId)
void BuildManager::cancel() void BuildManager::cancel()
{ {
if (d->m_scheduledBuild) {
disconnect(d->m_scheduledBuild);
d->m_scheduledBuild = {};
clearBuildQueue();
return;
}
if (d->m_running) { if (d->m_running) {
if (d->m_canceling) if (d->m_canceling)
return; return;
@@ -502,11 +512,13 @@ void BuildManager::clearBuildQueue()
d->m_previousBuildStepProject = nullptr; d->m_previousBuildStepProject = nullptr;
d->m_currentBuildStep = nullptr; d->m_currentBuildStep = nullptr;
d->m_progressFutureInterface->reportCanceled(); if (d->m_progressFutureInterface) {
d->m_progressFutureInterface->reportFinished(); d->m_progressFutureInterface->reportCanceled();
d->m_progressWatcher.setFuture(QFuture<void>()); d->m_progressFutureInterface->reportFinished();
delete d->m_progressFutureInterface; d->m_progressWatcher.setFuture(QFuture<void>());
d->m_progressFutureInterface = nullptr; delete d->m_progressFutureInterface;
d->m_progressFutureInterface = nullptr;
}
d->m_futureProgress = nullptr; d->m_futureProgress = nullptr;
d->m_maxProgress = 0; d->m_maxProgress = 0;
@@ -544,6 +556,28 @@ void BuildManager::startBuildQueue()
emit m_instance->buildQueueFinished(true); emit m_instance->buildQueueFinished(true);
return; return;
} }
// Delay if any of the involved build systems are currently parsing.
const auto buildSystems = transform<QSet<BuildSystem *>>(d->m_buildQueue,
[](const BuildStep *bs) { return bs->buildSystem(); });
for (const BuildSystem * const bs : buildSystems) {
if (!bs || !bs->isParsing())
continue;
d->m_scheduledBuild = QObject::connect(bs, &BuildSystem::parsingFinished,
BuildManager::instance(),
[](bool parsingSuccess) {
if (!d->m_scheduledBuild)
return;
QObject::disconnect(d->m_scheduledBuild);
d->m_scheduledBuild = {};
if (parsingSuccess)
startBuildQueue();
else
clearBuildQueue();
}, Qt::QueuedConnection);
return;
}
if (!d->m_running) { if (!d->m_running) {
d->m_elapsed.start(); d->m_elapsed.start();
// Progress Reporting // Progress Reporting

View File

@@ -107,7 +107,6 @@ void BuildSystem::emitParsingStarted()
QTC_ASSERT(!d->m_isParsing, return); QTC_ASSERT(!d->m_isParsing, return);
d->m_isParsing = true; d->m_isParsing = true;
d->m_hasParsingData = false;
emit parsingStarted(); emit parsingStarted();
emit d->m_target->parsingStarted(); emit d->m_target->parsingStarted();
} }

View File

@@ -2870,6 +2870,11 @@ void ProjectExplorerPlugin::runRunConfiguration(RunConfiguration *rc,
{ {
if (!rc->isEnabled()) if (!rc->isEnabled())
return; return;
const auto delay = [rc, runMode] {
dd->m_runMode = runMode;
dd->m_delayedRunConfiguration = rc;
dd->m_shouldHaveRunConfiguration = true;
};
const BuildForRunConfigStatus buildStatus = forceSkipDeploy const BuildForRunConfigStatus buildStatus = forceSkipDeploy
? BuildManager::isBuilding(rc->project()) ? BuildManager::isBuilding(rc->project())
? BuildForRunConfigStatus::Building : BuildForRunConfigStatus::NotBuilding ? BuildForRunConfigStatus::Building : BuildForRunConfigStatus::NotBuilding
@@ -2879,14 +2884,13 @@ void ProjectExplorerPlugin::runRunConfiguration(RunConfiguration *rc,
return; return;
case BuildForRunConfigStatus::Building: case BuildForRunConfigStatus::Building:
QTC_ASSERT(dd->m_runMode == Constants::NO_RUN_MODE, return); QTC_ASSERT(dd->m_runMode == Constants::NO_RUN_MODE, return);
delay();
// delay running till after our queued steps were processed
dd->m_runMode = runMode;
dd->m_delayedRunConfiguration = rc;
dd->m_shouldHaveRunConfiguration = true;
break; break;
case BuildForRunConfigStatus::NotBuilding: case BuildForRunConfigStatus::NotBuilding:
dd->executeRunConfiguration(rc, runMode); if (rc->isEnabled())
dd->executeRunConfiguration(rc, runMode);
else
delay();
break; break;
} }

View File

@@ -199,7 +199,7 @@ QbsBuildStep::~QbsBuildStep()
bool QbsBuildStep::init() bool QbsBuildStep::init()
{ {
if (qbsBuildSystem()->isParsing() || m_session) if (m_session)
return false; return false;
auto bc = static_cast<QbsBuildConfiguration *>(buildConfiguration()); auto bc = static_cast<QbsBuildConfiguration *>(buildConfiguration());

View File

@@ -231,11 +231,8 @@ QString QmlProjectRunConfiguration::commandLineArguments() const
bool QmlProjectRunConfiguration::isEnabled() const bool QmlProjectRunConfiguration::isEnabled() const
{ {
if (m_qmlMainFileAspect->isQmlFilePresent() && !commandLine().executable().isEmpty()) { return m_qmlMainFileAspect->isQmlFilePresent() && !commandLine().executable().isEmpty()
BuildSystem *bs = activeBuildSystem(); && activeBuildSystem()->hasParsingData();
return !bs->isParsing() && bs->hasParsingData();
}
return false;
} }
QString QmlProjectRunConfiguration::mainScript() const QString QmlProjectRunConfiguration::mainScript() const