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
{
return !buildSystem()->isParsing() && buildSystem()->hasParsingData();
return buildSystem()->hasParsingData();
}
QString BuildConfiguration::disabledReason() const
{
if (buildSystem()->isParsing())
return (tr("The project is currently being parsed."));
if (!buildSystem()->hasParsingData())
return (tr("The project was not parsed successfully."));
return QString();

View File

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

View File

@@ -27,6 +27,7 @@
#include "buildprogress.h"
#include "buildsteplist.h"
#include "buildsystem.h"
#include "compileoutputwindow.h"
#include "deployconfiguration.h"
#include "kit.h"
@@ -46,6 +47,7 @@
#include <coreplugin/progressmanager/futureprogress.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <extensionsystem/pluginmanager.h>
#include <utils/algorithm.h>
#include <utils/outputformatter.h>
#include <utils/runextensions.h>
#include <utils/stringutils.h>
@@ -57,6 +59,7 @@
#include <QList>
#include <QMessageBox>
#include <QPointer>
#include <QSet>
#include <QTime>
#include <QTimer>
@@ -215,6 +218,7 @@ public:
Internal::CompileOutputWindow *m_outputWindow = nullptr;
Internal::TaskWindow *m_taskWindow = nullptr;
QMetaObject::Connection m_scheduledBuild;
QList<BuildStep *> m_buildQueue;
QList<bool> m_enabledState;
QStringList m_stepNames;
@@ -459,6 +463,12 @@ QString BuildManager::displayNameForStepId(Id stepId)
void BuildManager::cancel()
{
if (d->m_scheduledBuild) {
disconnect(d->m_scheduledBuild);
d->m_scheduledBuild = {};
clearBuildQueue();
return;
}
if (d->m_running) {
if (d->m_canceling)
return;
@@ -502,11 +512,13 @@ void BuildManager::clearBuildQueue()
d->m_previousBuildStepProject = nullptr;
d->m_currentBuildStep = nullptr;
d->m_progressFutureInterface->reportCanceled();
d->m_progressFutureInterface->reportFinished();
d->m_progressWatcher.setFuture(QFuture<void>());
delete d->m_progressFutureInterface;
d->m_progressFutureInterface = nullptr;
if (d->m_progressFutureInterface) {
d->m_progressFutureInterface->reportCanceled();
d->m_progressFutureInterface->reportFinished();
d->m_progressWatcher.setFuture(QFuture<void>());
delete d->m_progressFutureInterface;
d->m_progressFutureInterface = nullptr;
}
d->m_futureProgress = nullptr;
d->m_maxProgress = 0;
@@ -544,6 +556,28 @@ void BuildManager::startBuildQueue()
emit m_instance->buildQueueFinished(true);
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) {
d->m_elapsed.start();
// Progress Reporting

View File

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

View File

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

View File

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

View File

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