forked from qt-creator/qt-creator
ProjectExplorer: Further orthogonalize Target/Tools
This introduces a 'TargetRunner' base that it meant as a base
class for classes like the current AndroidRunner, IosRunner,
WinRTRunnerHelper, similar to the existing 'ToolRunner' class
taking care of the tool bits.
This makes a RunControl only responsible for state management
(start/stop control), application output and general user
visible display tasks, delegation most of the real work either
to the the target or the tool.
The usage pattern for creating a run control is now
RunControl *RunControlFactory::create(...)
{
if (barToolOnFooTargetIsSupported()) {
auto runControl = new RunControl(runConfig, runMode);
(void) new FooTargetRunner(runControl);
(void) new BarToolRunner(runControl);
return runControl;
}
...
}
The pattern can possibly be simplified later, for now the goal
is to make it uniformly used.
As first use, "split" SimpleRunControl into a SimpleToolRunner
(which happens to be all its previous non-(Base)RunControl bits)
and the run control bits (its RunControl base).
This will make the SimpleRun*Control* class as such vanish again,
keep it for now to give downstream uses (Qnx/Boot2Qt) some time
window to adapt.
Change-Id: Ifafed4d0577466186280ac5014f4ad9eec78c56c
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Reviewed-by: Tobias Hunger <tobias.hunger@qt.io>
This commit is contained in:
@@ -519,6 +519,7 @@ public:
|
|||||||
|
|
||||||
~RunControlPrivate()
|
~RunControlPrivate()
|
||||||
{
|
{
|
||||||
|
delete targetRunner;
|
||||||
delete toolRunner;
|
delete toolRunner;
|
||||||
delete outputFormatter;
|
delete outputFormatter;
|
||||||
}
|
}
|
||||||
@@ -531,6 +532,7 @@ public:
|
|||||||
Utils::Icon icon;
|
Utils::Icon icon;
|
||||||
const QPointer<RunConfiguration> runConfiguration; // Not owned.
|
const QPointer<RunConfiguration> runConfiguration; // Not owned.
|
||||||
QPointer<Project> project; // Not owned.
|
QPointer<Project> project; // Not owned.
|
||||||
|
QPointer<TargetRunner> targetRunner; // Owned. QPointer as "extra safety" for now.
|
||||||
QPointer<ToolRunner> toolRunner; // Owned. QPointer as "extra safety" for now.
|
QPointer<ToolRunner> toolRunner; // Owned. QPointer as "extra safety" for now.
|
||||||
Utils::OutputFormatter *outputFormatter = nullptr;
|
Utils::OutputFormatter *outputFormatter = nullptr;
|
||||||
|
|
||||||
@@ -629,6 +631,16 @@ void RunControl::setToolRunner(ToolRunner *tool)
|
|||||||
d->toolRunner = tool;
|
d->toolRunner = tool;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TargetRunner *RunControl::targetRunner() const
|
||||||
|
{
|
||||||
|
return d->targetRunner;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RunControl::setTargetRunner(TargetRunner *runner)
|
||||||
|
{
|
||||||
|
d->targetRunner = runner;
|
||||||
|
}
|
||||||
|
|
||||||
QString RunControl::displayName() const
|
QString RunControl::displayName() const
|
||||||
{
|
{
|
||||||
return d->displayName;
|
return d->displayName;
|
||||||
@@ -801,6 +813,18 @@ void RunControl::bringApplicationToForeground()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RunControl::start()
|
||||||
|
{
|
||||||
|
QTC_ASSERT(d->targetRunner, return);
|
||||||
|
d->targetRunner->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RunControl::stop()
|
||||||
|
{
|
||||||
|
QTC_ASSERT(d->targetRunner, return);
|
||||||
|
d->targetRunner->stop();
|
||||||
|
}
|
||||||
|
|
||||||
void RunControl::reportApplicationStart()
|
void RunControl::reportApplicationStart()
|
||||||
{
|
{
|
||||||
setState(State::Running);
|
setState(State::Running);
|
||||||
@@ -846,18 +870,6 @@ bool Runnable::canReUseOutputPane(const Runnable &other) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// SimpleRunControlPrivate
|
|
||||||
|
|
||||||
namespace Internal {
|
|
||||||
|
|
||||||
class SimpleRunControlPrivate
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ApplicationLauncher m_launcher;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // Internal
|
|
||||||
|
|
||||||
// FIXME: Remove once ApplicationLauncher signalling does not depend on device.
|
// FIXME: Remove once ApplicationLauncher signalling does not depend on device.
|
||||||
static bool isSynchronousLauncher(RunControl *runControl)
|
static bool isSynchronousLauncher(RunControl *runControl)
|
||||||
{
|
{
|
||||||
@@ -868,112 +880,117 @@ static bool isSynchronousLauncher(RunControl *runControl)
|
|||||||
return !deviceId.isValid() || deviceId == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE;
|
return !deviceId.isValid() || deviceId == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
SimpleRunControl::SimpleRunControl(RunConfiguration *runConfiguration, Core::Id mode)
|
SimpleTargetRunner::SimpleTargetRunner(RunControl *runControl)
|
||||||
: RunControl(runConfiguration, mode), d(new Internal::SimpleRunControlPrivate)
|
: TargetRunner(runControl)
|
||||||
{
|
{
|
||||||
setRunnable(runConfiguration->runnable());
|
|
||||||
setIcon(Utils::Icons::RUN_SMALL_TOOLBAR);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SimpleRunControl::~SimpleRunControl()
|
void SimpleTargetRunner::start()
|
||||||
{
|
{
|
||||||
delete d;
|
runControl()->reportApplicationStart();
|
||||||
}
|
m_launcher.disconnect(this);
|
||||||
|
|
||||||
ApplicationLauncher &SimpleRunControl::applicationLauncher()
|
Runnable r = runControl()->runnable();
|
||||||
{
|
|
||||||
return d->m_launcher;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SimpleRunControl::start()
|
if (isSynchronousLauncher(runControl())) {
|
||||||
{
|
|
||||||
reportApplicationStart();
|
|
||||||
d->m_launcher.disconnect(this);
|
|
||||||
|
|
||||||
Runnable r = runnable();
|
connect(&m_launcher, &ApplicationLauncher::appendMessage,
|
||||||
|
this, &TargetRunner::appendMessage);
|
||||||
if (isSynchronousLauncher(this)) {
|
connect(&m_launcher, &ApplicationLauncher::processStarted,
|
||||||
|
this, &SimpleTargetRunner::onProcessStarted);
|
||||||
connect(&d->m_launcher, &ApplicationLauncher::appendMessage,
|
connect(&m_launcher, &ApplicationLauncher::processExited,
|
||||||
this, static_cast<void(RunControl::*)(const QString &, OutputFormat)>(&RunControl::appendMessage));
|
this, &SimpleTargetRunner::onProcessFinished);
|
||||||
connect(&d->m_launcher, &ApplicationLauncher::processStarted,
|
|
||||||
this, &SimpleRunControl::onProcessStarted);
|
|
||||||
connect(&d->m_launcher, &ApplicationLauncher::processExited,
|
|
||||||
this, &SimpleRunControl::onProcessFinished);
|
|
||||||
|
|
||||||
QTC_ASSERT(r.is<StandardRunnable>(), return);
|
QTC_ASSERT(r.is<StandardRunnable>(), return);
|
||||||
const QString executable = r.as<StandardRunnable>().executable;
|
const QString executable = r.as<StandardRunnable>().executable;
|
||||||
if (executable.isEmpty()) {
|
if (executable.isEmpty()) {
|
||||||
appendMessage(RunControl::tr("No executable specified.") + '\n',
|
appendMessage(RunControl::tr("No executable specified.") + '\n',
|
||||||
Utils::ErrorMessageFormat);
|
Utils::ErrorMessageFormat);
|
||||||
reportApplicationStop();
|
runControl()->reportApplicationStop();
|
||||||
} else if (!QFileInfo::exists(executable)) {
|
} else if (!QFileInfo::exists(executable)) {
|
||||||
appendMessage(RunControl::tr("Executable %1 does not exist.")
|
appendMessage(RunControl::tr("Executable %1 does not exist.")
|
||||||
.arg(QDir::toNativeSeparators(executable)) + '\n',
|
.arg(QDir::toNativeSeparators(executable)) + '\n',
|
||||||
Utils::ErrorMessageFormat);
|
Utils::ErrorMessageFormat);
|
||||||
reportApplicationStop();
|
runControl()->reportApplicationStop();
|
||||||
} else {
|
} else {
|
||||||
QString msg = RunControl::tr("Starting %1...").arg(QDir::toNativeSeparators(executable)) + '\n';
|
QString msg = RunControl::tr("Starting %1...").arg(QDir::toNativeSeparators(executable)) + '\n';
|
||||||
appendMessage(msg, Utils::NormalMessageFormat);
|
appendMessage(msg, Utils::NormalMessageFormat);
|
||||||
d->m_launcher.start(r);
|
m_launcher.start(r);
|
||||||
setApplicationProcessHandle(d->m_launcher.applicationPID());
|
runControl()->setApplicationProcessHandle(m_launcher.applicationPID());
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
connect(&d->m_launcher, &ApplicationLauncher::reportError,
|
connect(&m_launcher, &ApplicationLauncher::reportError,
|
||||||
this, [this](const QString &error) {
|
this, [this](const QString &error) {
|
||||||
appendMessage(error, Utils::ErrorMessageFormat);
|
appendMessage(error, Utils::ErrorMessageFormat);
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(&d->m_launcher, &ApplicationLauncher::remoteStderr,
|
connect(&m_launcher, &ApplicationLauncher::remoteStderr,
|
||||||
this, [this](const QByteArray &output) {
|
this, [this](const QByteArray &output) {
|
||||||
appendMessage(QString::fromUtf8(output), Utils::StdErrFormatSameLine);
|
appendMessage(QString::fromUtf8(output), Utils::StdErrFormatSameLine);
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(&d->m_launcher, &ApplicationLauncher::remoteStdout,
|
connect(&m_launcher, &ApplicationLauncher::remoteStdout,
|
||||||
this, [this](const QByteArray &output) {
|
this, [this](const QByteArray &output) {
|
||||||
appendMessage(QString::fromUtf8(output), Utils::StdOutFormatSameLine);
|
appendMessage(QString::fromUtf8(output), Utils::StdOutFormatSameLine);
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(&d->m_launcher, &ApplicationLauncher::finished,
|
connect(&m_launcher, &ApplicationLauncher::finished,
|
||||||
this, [this] {
|
this, [this] {
|
||||||
d->m_launcher.disconnect(this);
|
m_launcher.disconnect(this);
|
||||||
reportApplicationStop();
|
runControl()->reportApplicationStop();
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(&d->m_launcher, &ApplicationLauncher::reportProgress,
|
connect(&m_launcher, &ApplicationLauncher::reportProgress,
|
||||||
this, [this](const QString &progressString) {
|
this, [this](const QString &progressString) {
|
||||||
appendMessage(progressString + '\n', Utils::NormalMessageFormat);
|
appendMessage(progressString + '\n', Utils::NormalMessageFormat);
|
||||||
});
|
});
|
||||||
|
|
||||||
d->m_launcher.start(r, device());
|
m_launcher.start(r, runControl()->device());
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimpleRunControl::stop()
|
void SimpleTargetRunner::stop()
|
||||||
{
|
{
|
||||||
d->m_launcher.stop();
|
m_launcher.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimpleRunControl::onProcessStarted()
|
void SimpleTargetRunner::onProcessStarted()
|
||||||
{
|
{
|
||||||
// Console processes only know their pid after being started
|
// Console processes only know their pid after being started
|
||||||
setApplicationProcessHandle(d->m_launcher.applicationPID());
|
runControl()->setApplicationProcessHandle(m_launcher.applicationPID());
|
||||||
bringApplicationToForeground();
|
runControl()->bringApplicationToForeground();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimpleRunControl::onProcessFinished(int exitCode, QProcess::ExitStatus status)
|
void SimpleTargetRunner::onProcessFinished(int exitCode, QProcess::ExitStatus status)
|
||||||
{
|
{
|
||||||
QString msg;
|
QString msg;
|
||||||
QString exe = runnable().as<StandardRunnable>().executable;
|
QString exe = runControl()->runnable().as<StandardRunnable>().executable;
|
||||||
if (status == QProcess::CrashExit)
|
if (status == QProcess::CrashExit)
|
||||||
msg = tr("%1 crashed.").arg(QDir::toNativeSeparators(exe));
|
msg = tr("%1 crashed.").arg(QDir::toNativeSeparators(exe));
|
||||||
else
|
else
|
||||||
msg = tr("%1 exited with code %2").arg(QDir::toNativeSeparators(exe)).arg(exitCode);
|
msg = tr("%1 exited with code %2").arg(QDir::toNativeSeparators(exe)).arg(exitCode);
|
||||||
appendMessage(msg + QLatin1Char('\n'), Utils::NormalMessageFormat);
|
appendMessage(msg + '\n', Utils::NormalMessageFormat);
|
||||||
reportApplicationStop();
|
runControl()->reportApplicationStop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TargetRunner
|
||||||
|
|
||||||
|
TargetRunner::TargetRunner(RunControl *runControl)
|
||||||
|
: m_runControl(runControl)
|
||||||
|
{
|
||||||
|
runControl->setTargetRunner(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
RunControl *TargetRunner::runControl() const
|
||||||
|
{
|
||||||
|
return m_runControl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TargetRunner::appendMessage(const QString &msg, OutputFormat format)
|
||||||
|
{
|
||||||
|
m_runControl->appendMessage(msg, format);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToolRunner
|
// ToolRunner
|
||||||
@@ -994,4 +1011,14 @@ void ToolRunner::appendMessage(const QString &msg, OutputFormat format)
|
|||||||
m_runControl->appendMessage(msg, format);
|
m_runControl->appendMessage(msg, format);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SimpleRunControl
|
||||||
|
|
||||||
|
SimpleRunControl::SimpleRunControl(RunConfiguration *runConfiguration, Core::Id mode)
|
||||||
|
: RunControl(runConfiguration, mode)
|
||||||
|
{
|
||||||
|
setRunnable(runConfiguration->runnable());
|
||||||
|
setIcon(Utils::Icons::RUN_SMALL_TOOLBAR);
|
||||||
|
(void) new SimpleTargetRunner(this);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ProjectExplorer
|
} // namespace ProjectExplorer
|
||||||
|
|||||||
@@ -49,8 +49,9 @@ class IRunConfigurationAspect;
|
|||||||
class RunConfiguration;
|
class RunConfiguration;
|
||||||
class RunConfigWidget;
|
class RunConfigWidget;
|
||||||
class RunControl;
|
class RunControl;
|
||||||
class ToolRunner;
|
|
||||||
class Target;
|
class Target;
|
||||||
|
class TargetRunner;
|
||||||
|
class ToolRunner;
|
||||||
|
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
class RunControlPrivate;
|
class RunControlPrivate;
|
||||||
@@ -349,6 +350,14 @@ signals:
|
|||||||
void displayNameChanged(const QString &);
|
void displayNameChanged(const QString &);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A RunControl controls the running of an application or tool
|
||||||
|
* on a target device. It controls start and stop, and handles
|
||||||
|
* application output.
|
||||||
|
*
|
||||||
|
* RunControls are created by RunControlFactories.
|
||||||
|
*/
|
||||||
|
|
||||||
class PROJECTEXPLORER_EXPORT RunControl : public QObject
|
class PROJECTEXPLORER_EXPORT RunControl : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@@ -401,9 +410,15 @@ public:
|
|||||||
ToolRunner *toolRunner() const;
|
ToolRunner *toolRunner() const;
|
||||||
void setToolRunner(ToolRunner *tool);
|
void setToolRunner(ToolRunner *tool);
|
||||||
|
|
||||||
|
TargetRunner *targetRunner() const;
|
||||||
|
void setTargetRunner(TargetRunner *tool);
|
||||||
|
|
||||||
virtual void appendMessage(const QString &msg, Utils::OutputFormat format);
|
virtual void appendMessage(const QString &msg, Utils::OutputFormat format);
|
||||||
virtual void bringApplicationToForeground();
|
virtual void bringApplicationToForeground();
|
||||||
|
|
||||||
|
void reportApplicationStart(); // Call this when the application starts to run
|
||||||
|
void reportApplicationStop(); // Call this when the application has stopped for any reason
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void appendMessageRequested(ProjectExplorer::RunControl *runControl,
|
void appendMessageRequested(ProjectExplorer::RunControl *runControl,
|
||||||
const QString &msg, Utils::OutputFormat format);
|
const QString &msg, Utils::OutputFormat format);
|
||||||
@@ -413,11 +428,8 @@ signals:
|
|||||||
void applicationProcessHandleChanged(QPrivateSignal); // Use setApplicationProcessHandle
|
void applicationProcessHandleChanged(QPrivateSignal); // Use setApplicationProcessHandle
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void start() = 0;
|
virtual void start();
|
||||||
virtual void stop() = 0;
|
virtual void stop();
|
||||||
|
|
||||||
void reportApplicationStart(); // Call this when the application starts to run
|
|
||||||
void reportApplicationStop(); // Call this when the application has stopped for any reason
|
|
||||||
|
|
||||||
bool showPromptToStopDialog(const QString &title, const QString &text,
|
bool showPromptToStopDialog(const QString &title, const QString &text,
|
||||||
const QString &stopButtonText = QString(),
|
const QString &stopButtonText = QString(),
|
||||||
@@ -430,27 +442,27 @@ private:
|
|||||||
Internal::RunControlPrivate *d;
|
Internal::RunControlPrivate *d;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PROJECTEXPLORER_EXPORT SimpleRunControl : public RunControl
|
/**
|
||||||
|
* A base for target-specific additions to the RunControl.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class PROJECTEXPLORER_EXPORT TargetRunner : public QObject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SimpleRunControl(RunConfiguration *runConfiguration, Core::Id mode);
|
explicit TargetRunner(RunControl *runControl);
|
||||||
~SimpleRunControl();
|
|
||||||
|
|
||||||
ApplicationLauncher &applicationLauncher();
|
RunControl *runControl() const;
|
||||||
void start() override;
|
void appendMessage(const QString &msg, Utils::OutputFormat format);
|
||||||
void stop() override;
|
|
||||||
|
|
||||||
virtual void onProcessStarted();
|
virtual void start() {}
|
||||||
virtual void onProcessFinished(int exitCode, QProcess::ExitStatus status);
|
virtual void stop() {}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setFinished();
|
QPointer<RunControl> m_runControl;
|
||||||
|
|
||||||
Internal::SimpleRunControlPrivate * const d;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A base for tool-specific additions to target-specific RunControl.
|
* A base for tool-specific additions to RunControl.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class PROJECTEXPLORER_EXPORT ToolRunner : public QObject
|
class PROJECTEXPLORER_EXPORT ToolRunner : public QObject
|
||||||
@@ -465,4 +477,34 @@ private:
|
|||||||
QPointer<RunControl> m_runControl;
|
QPointer<RunControl> m_runControl;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple TargetRunner for cases where a plain ApplicationLauncher is
|
||||||
|
* sufficient for running purposes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class PROJECTEXPLORER_EXPORT SimpleTargetRunner : public TargetRunner
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit SimpleTargetRunner(RunControl *runControl);
|
||||||
|
|
||||||
|
void start() override;
|
||||||
|
void stop() override;
|
||||||
|
|
||||||
|
virtual void onProcessStarted();
|
||||||
|
virtual void onProcessFinished(int exitCode, QProcess::ExitStatus status);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setFinished();
|
||||||
|
|
||||||
|
ApplicationLauncher m_launcher;
|
||||||
|
};
|
||||||
|
|
||||||
|
// A RunControl with a SimpleTargetRunner and no Tool.
|
||||||
|
// FIXME: Do not use. Will be dissolved.
|
||||||
|
class PROJECTEXPLORER_EXPORT SimpleRunControl : public RunControl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SimpleRunControl(RunConfiguration *runConfiguration, Core::Id mode);
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace ProjectExplorer
|
} // namespace ProjectExplorer
|
||||||
|
|||||||
Reference in New Issue
Block a user