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:
hjk
2017-03-29 11:01:16 +02:00
parent 06250531db
commit 15867a9518
2 changed files with 146 additions and 77 deletions

View File

@@ -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

View File

@@ -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