1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of Qt Creator.
7**
8** Commercial License Usage
9** Licensees holding valid commercial Qt licenses may use this file in
10** accordance with the commercial license agreement provided with the
11** Software or, alternatively, in accordance with the terms contained in
12** a written agreement between you and The Qt Company. For licensing terms
13** and conditions see https://www.qt.io/terms-conditions. For further
14** information use the contact form at https://www.qt.io/contact-us.
15**
16** GNU General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU
18** General Public License version 3 as published by the Free Software
19** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20** included in the packaging of this file. Please review the following
21** information to ensure the GNU General Public License requirements will
22** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23**
24****************************************************************************/
25
26#pragma once
27
28#include "projectconfiguration.h"
29#include "projectexplorerconstants.h"
30#include "applicationlauncher.h"
31#include "devicesupport/idevice.h"
32
33#include <utils/port.h>
34#include <utils/processhandle.h>
35#include <utils/qtcassert.h>
36#include <utils/icon.h>
37
38#include <QPointer>
39#include <QWidget>
40
41#include <functional>
42#include <memory>
43
44namespace Utils { class OutputFormatter; }
45
46namespace ProjectExplorer {
47class Abi;
48class BuildConfiguration;
49class IRunConfigurationAspect;
50class RunConfiguration;
51class RunConfigWidget;
52class RunControl;
53class Target;
54
55namespace Internal {
56class RunControlPrivate;
57class RunWorkerPrivate;
58class SimpleRunControlPrivate;
59} // Internal
60
61/**
62 * An interface for a hunk of global or per-project
63 * configuration data.
64 *
65 */
66
67class PROJECTEXPLORER_EXPORT ISettingsAspect : public QObject
68{
69 Q_OBJECT
70
71public:
72 ISettingsAspect() { }
73
74 /// Create a configuration widget for this settings aspect.
75 virtual QWidget *createConfigWidget(QWidget *parent) = 0;
76 /// "Virtual default constructor"
77 virtual ISettingsAspect *create() const = 0;
78 /// "Virtual copy constructor"
79 ISettingsAspect *clone() const;
80
81protected:
82 ///
83 friend class IRunConfigurationAspect;
84 /// Converts current object into map for storage.
85 virtual void toMap(QVariantMap &map) const = 0;
86 /// Read object state from @p map.
87 virtual void fromMap(const QVariantMap &map) = 0;
88};
89
90
91/**
92 * An interface to facilitate switching between hunks of
93 * global and per-project configuration data.
94 *
95 */
96
97class PROJECTEXPLORER_EXPORT IRunConfigurationAspect : public QObject
98{
99 Q_OBJECT
100
101public:
102 explicit IRunConfigurationAspect(RunConfiguration *runConfig);
103 ~IRunConfigurationAspect() override;
104
105 using RunConfigWidgetCreator = std::function<RunConfigWidget *()>;
106 void setRunConfigWidgetCreator(const RunConfigWidgetCreator &runConfigWidgetCreator);
107 RunConfigWidget *createConfigurationWidget() const;
108 void copyFrom(IRunConfigurationAspect *other);
109
110 void setId(Core::Id id) { m_id = id; }
111 void setDisplayName(const QString &displayName) { m_displayName = displayName; }
112 void setSettingsKey(const QString &settingsKey) { m_settingsKey = settingsKey; }
113 void setProjectSettings(ISettingsAspect *settings);
114 void setGlobalSettings(ISettingsAspect *settings);
115
116 Core::Id id() const { return m_id; }
117 QString displayName() const { return m_displayName; }
118 QString settingsKey() const { return m_settingsKey; }
119 bool isUsingGlobalSettings() const { return m_useGlobalSettings; }
120 void setUsingGlobalSettings(bool value);
121 void resetProjectToGlobalSettings();
122
123 ISettingsAspect *projectSettings() const { return m_projectSettings; }
124 ISettingsAspect *globalSettings() const { return m_globalSettings; }
125 ISettingsAspect *currentSettings() const;
126 RunConfiguration *runConfiguration() const { return m_runConfiguration; }
127
128protected:
129 friend class RunConfiguration;
130 virtual void fromMap(const QVariantMap &map);
131 virtual void toMap(QVariantMap &data) const;
132
133private:
134 Core::Id m_id;
135 QString m_displayName;
136 QString m_settingsKey; // Name of data in settings.
137 bool m_useGlobalSettings = false;
138 RunConfiguration *m_runConfiguration = nullptr;
139 ISettingsAspect *m_projectSettings = nullptr; // Owned if present.
140 ISettingsAspect *m_globalSettings = nullptr; // Not owned.
141 RunConfigWidgetCreator m_runConfigWidgetCreator;
142};
143
144class PROJECTEXPLORER_EXPORT Runnable
145{
146 struct Concept
147 {
148 virtual ~Concept() {}
149 virtual Concept *clone() const = 0;
150 virtual bool canReUseOutputPane(const std::unique_ptr<Concept> &other) const = 0;
151 virtual QString displayName() const = 0;
152 virtual void *typeId() const = 0;
153 };
154
155 template <class T>
156 struct Model : public Concept
157 {
158 Model(const T &data) : m_data(data) {}
159
160 Concept *clone() const override { return new Model(*this); }
161
162 bool canReUseOutputPane(const std::unique_ptr<Concept> &other) const override
163 {
164 if (!other.get())
165 return false;
166 if (other->typeId() != typeId())
167 return false;
168 auto that = static_cast<const Model<T> *>(other.get());
169 return m_data == that->m_data;
170 }
171
172 QString displayName() const override { return m_data.displayName(); }
173
174 void *typeId() const override { return T::staticTypeId; }
175
176 T m_data;
177 };
178
179public:
180 Runnable() = default;
181 Runnable(const Runnable &other) : d(other.d ? other.d->clone() : nullptr) { }
182 Runnable(Runnable &&other) : d(std::move(other.d)) {}
183 template <class T> Runnable(const T &data) : d(new Model<T>(data)) {}
184
185 void operator=(Runnable other) { d = std::move(other.d); }
186
187 template <class T> bool is() const {
188 return d.get() && (d.get()->typeId() == T::staticTypeId);
189 }
190
191 template <class T> const T &as() const {
192 return static_cast<Model<T> *>(d.get())->m_data;
193 }
194
195 bool canReUseOutputPane(const Runnable &other) const;
196 QString displayName() const { return d ? d->displayName() : QString(); }
197
198private:
199 std::unique_ptr<Concept> d;
200};
201
202// Documentation inside.
203class PROJECTEXPLORER_EXPORT RunConfiguration : public StatefulProjectConfiguration
204{
205 Q_OBJECT
206
207public:
208 ~RunConfiguration() override;
209
210 bool isActive() const override;
211
212 QString disabledReason() const override;
213
214 virtual QWidget *createConfigurationWidget() = 0;
215
216 virtual bool isConfigured() const;
217 // Pop up configuration dialog in case for example the executable is missing.
218 enum ConfigurationState { Configured, UnConfigured, Waiting };
219 // TODO rename function
220 virtual ConfigurationState ensureConfigured(QString *errorMessage = nullptr);
221
222 Target *target() const;
223 Project *project() const override;
224
225 virtual Utils::OutputFormatter *createOutputFormatter() const;
226
227 bool fromMap(const QVariantMap &map) override;
228 QVariantMap toMap() const override;
229
230 QList<IRunConfigurationAspect *> extraAspects() const;
231 IRunConfigurationAspect *extraAspect(Core::Id id) const;
232
233 template <typename T> T *extraAspect() const
234 {
235 foreach (IRunConfigurationAspect *aspect, m_aspects)
236 if (T *result = qobject_cast<T *>(aspect))
237 return result;
238 return nullptr;
239 }
240
241 virtual Runnable runnable() const;
242 virtual Abi abi() const;
243
244 // Return the name of the build system target that created this run configuration.
245 // May return an empty string if no target built the executable!
246 virtual QString buildSystemTarget() const { return QString(); }
247
248 void addExtraAspect(IRunConfigurationAspect *aspect);
249
250 static RunConfiguration *startupRunConfiguration();
251
252 using AspectFactory = std::function<IRunConfigurationAspect *(RunConfiguration *)>;
253 template <class T> static void registerAspect()
254 {
255 addAspectFactory([](RunConfiguration *rc) { return new T(rc); });
256 }
257
258signals:
259 void requestRunActionsUpdate();
260 void configurationFinished();
261
262protected:
263 friend class IRunConfigurationFactory;
264
265 RunConfiguration(Target *target);
266 virtual void initialize(Core::Id id);
267 void copyFrom(const RunConfiguration *source);
268
269 /// convenience function to get current build configuration.
270 BuildConfiguration *activeBuildConfiguration() const;
271
272 virtual void updateEnabledState();
273
274private:
275 static void addAspectFactory(const AspectFactory &aspectFactory);
276
277 QList<IRunConfigurationAspect *> m_aspects;
278};
279
280class PROJECTEXPLORER_EXPORT IRunConfigurationFactory : public QObject
281{
282 Q_OBJECT
283
284public:
285 explicit IRunConfigurationFactory(QObject *parent = nullptr);
286
287 enum CreationMode {UserCreate, AutoCreate};
288 virtual QList<Core::Id> availableCreationIds(Target *parent, CreationMode mode = UserCreate) const = 0;
289 virtual QString displayNameForId(Core::Id id) const = 0;
290
291 virtual bool canHandle(Target *target) const;
292 virtual bool canCreate(Target *parent, Core::Id id) const = 0;
293 RunConfiguration *create(Target *parent, Core::Id id);
294 virtual bool canRestore(Target *parent, const QVariantMap &map) const = 0;
295 RunConfiguration *restore(Target *parent, const QVariantMap &map);
296 virtual bool canClone(Target *parent, RunConfiguration *product) const = 0;
297 RunConfiguration *clone(Target *parent, RunConfiguration *product);
298
299 static IRunConfigurationFactory *find(Target *parent, const QVariantMap &map);
300 static IRunConfigurationFactory *find(Target *parent, RunConfiguration *rc);
301 static QList<IRunConfigurationFactory *> find(Target *parent);
302
303signals:
304 void availableCreationIdsChanged();
305
306protected:
307 using RunConfigurationCreator = std::function<RunConfiguration *(Target *)>;
308
309 template <class RunConfig>
310 void registerRunConfiguration()
311 {
312 m_creator = [](Target *t) -> RunConfiguration * { return new RunConfig(t); };
313 }
314
315 using ProjectTypeChecker = std::function<bool(Project *)>;
316
317 template <class ProjectType>
318 void setSupportedProjectType()
319 {
320 m_projectTypeChecker = [](Project *p) { return qobject_cast<ProjectType *>(p) != nullptr; };
321 }
322
323 void setSupportedTargetDeviceTypes(const QList<Core::Id> &ids);
324
325private:
326 RunConfigurationCreator m_creator;
327 ProjectTypeChecker m_projectTypeChecker;
328 QList<Core::Id> m_supportedTargetDeviceTypes;
329};
330
331class PROJECTEXPLORER_EXPORT RunConfigWidget : public QWidget
332{
333 Q_OBJECT
334
335public:
336 virtual QString displayName() const = 0;
337
338signals:
339 void displayNameChanged(const QString &);
340};
341
342class PROJECTEXPLORER_EXPORT RunWorker : public QObject
343{
344 Q_OBJECT
345
346public:
347 explicit RunWorker(RunControl *runControl);
348 ~RunWorker() override;
349
350 RunControl *runControl() const;
351
352 void addStartDependency(RunWorker *dependency);
353 void addStopDependency(RunWorker *dependency);
354
355 void setDisplayName(const QString &id) { setId(id); } // FIXME: Obsoleted by setId.
356 void setId(const QString &id);
357
358 void setStartTimeout(int ms, const std::function<void()> &callback = {});
359 void setStopTimeout(int ms, const std::function<void()> &callback = {});
360
361 void recordData(const QString &channel, const QVariant &data);
362 QVariant recordedData(const QString &channel) const;
363
364 // Part of read-only interface of RunControl for convenience.
365 void appendMessage(const QString &msg, Utils::OutputFormat format);
366 IDevice::ConstPtr device() const;
367 const Runnable &runnable() const;
368 Core::Id runMode() const;
369
370 // States
371 void initiateStart();
372 void reportStarted();
373
374 void initiateStop();
375 void reportStopped();
376
377 void reportDone();
378
379 void reportFailure(const QString &msg = QString());
380 void setSupportsReRunning(bool reRunningSupported);
381 bool supportsReRunning() const;
382
383 static QString userMessageForProcessError(QProcess::ProcessError, const QString &programName);
384
385 bool isEssential() const;
386 void setEssential(bool essential);
387
388signals:
389 void started();
390 void stopped();
391
392protected:
393 void virtual start();
394 void virtual stop();
395 void virtual onFinished() {}
396
397private:
398 friend class Internal::RunControlPrivate;
399 friend class Internal::RunWorkerPrivate;
400 Internal::RunWorkerPrivate *d;
401};
402
403/**
404 * A RunControl controls the running of an application or tool
405 * on a target device. It controls start and stop, and handles
406 * application output.
407 *
408 * RunControls are created by RunControlFactories.
409 */
410
411class PROJECTEXPLORER_EXPORT RunControl : public QObject
412{
413 Q_OBJECT
414
415public:
416 RunControl(RunConfiguration *runConfiguration, Core::Id mode);
417 ~RunControl() override;
418
419 void initiateStart();
420 void initiateReStart();
421 void initiateStop();
422 void forceStop();
423 void initiateFinish();
424
425 bool promptToStop(bool *optionalPrompt = nullptr) const;
426 void setPromptToStop(const std::function<bool(bool *)> &promptToStop);
427
428 bool supportsReRunning() const;
429
430 virtual QString displayName() const;
431 void setDisplayName(const QString &displayName);
432
433 bool isRunning() const;
434 bool isStarting() const;
435 bool isStopping() const;
436 bool isStopped() const;
437
438 void setIcon(const Utils::Icon &icon);
439 Utils::Icon icon() const;
440
441 Utils::ProcessHandle applicationProcessHandle() const;
442 void setApplicationProcessHandle(const Utils::ProcessHandle &handle);
443 Abi abi() const;
444 IDevice::ConstPtr device() const;
445
446 RunConfiguration *runConfiguration() const;
447 Project *project() const;
448 bool canReUseOutputPane(const RunControl *other) const;
449
450 Utils::OutputFormatter *outputFormatter() const;
451 Core::Id runMode() const;
452
453 const Runnable &runnable() const;
454 void setRunnable(const Runnable &runnable);
455
456 virtual void appendMessage(const QString &msg, Utils::OutputFormat format);
457
458 static bool showPromptToStopDialog(const QString &title, const QString &text,
459 const QString &stopButtonText = QString(),
460 const QString &cancelButtonText = QString(),
461 bool *prompt = nullptr);
462
463 RunWorker *createWorker(Core::Id id);
464
465 using WorkerCreator = std::function<RunWorker *(RunControl *)>;
466 using Constraint = std::function<bool(RunConfiguration *)>;
467
468 static void registerWorkerCreator(Core::Id id, const WorkerCreator &workerCreator);
469
470 static void registerWorker(Core::Id runMode, const WorkerCreator &producer,
471 const Constraint &constraint = {})
472 {
473 addWorkerFactory({runMode, constraint, producer});
474 }
475 template <class Worker>
476 static void registerWorker(Core::Id runMode, const Constraint &constraint, int priority = 0)
477 {
478 auto producer = [](RunControl *rc) { return new Worker(rc); };
479 addWorkerFactory({runMode, constraint, producer, priority});
480 }
481 template <class Config, class Worker>
482 static void registerWorker(Core::Id runMode, int priority = 0)
483 {
484 auto constraint = [](RunConfiguration *runConfig) { return qobject_cast<Config *>(runConfig) != nullptr; };
485 auto producer = [](RunControl *rc) { return new Worker(rc); };
486 addWorkerFactory({runMode, constraint, producer, priority});
487 }
488
489 struct WorkerFactory {
490 Core::Id runMode;
491 Constraint constraint;
492 WorkerCreator producer;
493 int priority = 0;
494
495 WorkerFactory(const Core::Id &mode, Constraint constr, const WorkerCreator &prod,
496 int prio = 0)
497 : runMode(mode), constraint(constr), producer(prod), priority(prio) {}
498 bool canRun(RunConfiguration *runConfiguration, Core::Id runMode) const;
499 };
500
501 static WorkerCreator producer(RunConfiguration *runConfiguration, Core::Id runMode);
502
503signals:
504 void appendMessageRequested(ProjectExplorer::RunControl *runControl,
505 const QString &msg, Utils::OutputFormat format);
506 void aboutToStart();
507 void started();
508 void stopped();
509 void finished();
510 void applicationProcessHandleChanged(QPrivateSignal); // Use setApplicationProcessHandle
511
512private:
513 friend class RunWorker;
514 friend class Internal::RunWorkerPrivate;
515
516 static void addWorkerFactory(const WorkerFactory &workerFactory);
517 Internal::RunControlPrivate *d;
518};
519
520
521/**
522 * A simple TargetRunner for cases where a plain ApplicationLauncher is
523 * sufficient for running purposes.
524 */
525
526class PROJECTEXPLORER_EXPORT SimpleTargetRunner : public RunWorker
527{
528 Q_OBJECT
529
530public:
531 explicit SimpleTargetRunner(RunControl *runControl);
532
533 void setRunnable(const Runnable &runnable);
534
535 void setDevice(const IDevice::ConstPtr &device);
536 IDevice::ConstPtr device() const;
537
538protected:
539 void start() override;
540 void stop() override;
541
542private:
543 void onProcessStarted();
544 void onProcessFinished(int exitCode, QProcess::ExitStatus status);
545 void onProcessError(QProcess::ProcessError error);
546
547 ApplicationLauncher m_launcher;
548 Runnable m_runnable;
549 IDevice::ConstPtr m_device;
550 bool m_stopReported = false;
551};
552
553} // namespace ProjectExplorer
554