| 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 | |
| 44 | namespace Utils { class OutputFormatter; } |
| 45 | |
| 46 | namespace ProjectExplorer { |
| 47 | class Abi; |
| 48 | class BuildConfiguration; |
| 49 | class IRunConfigurationAspect; |
| 50 | class RunConfiguration; |
| 51 | class RunConfigWidget; |
| 52 | class RunControl; |
| 53 | class Target; |
| 54 | |
| 55 | namespace Internal { |
| 56 | class RunControlPrivate; |
| 57 | class RunWorkerPrivate; |
| 58 | class SimpleRunControlPrivate; |
| 59 | } // Internal |
| 60 | |
| 61 | /** |
| 62 | * An interface for a hunk of global or per-project |
| 63 | * configuration data. |
| 64 | * |
| 65 | */ |
| 66 | |
| 67 | class PROJECTEXPLORER_EXPORT ISettingsAspect : public QObject |
| 68 | { |
| 69 | Q_OBJECT |
| 70 | |
| 71 | public: |
| 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 | |
| 81 | protected: |
| 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 | |
| 97 | class PROJECTEXPLORER_EXPORT IRunConfigurationAspect : public QObject |
| 98 | { |
| 99 | Q_OBJECT |
| 100 | |
| 101 | public: |
| 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 | |
| 128 | protected: |
| 129 | friend class RunConfiguration; |
| 130 | virtual void fromMap(const QVariantMap &map); |
| 131 | virtual void toMap(QVariantMap &data) const; |
| 132 | |
| 133 | private: |
| 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 | |
| 144 | class 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 | |
| 179 | public: |
| 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 | |
| 198 | private: |
| 199 | std::unique_ptr<Concept> d; |
| 200 | }; |
| 201 | |
| 202 | // Documentation inside. |
| 203 | class PROJECTEXPLORER_EXPORT RunConfiguration : public StatefulProjectConfiguration |
| 204 | { |
| 205 | Q_OBJECT |
| 206 | |
| 207 | public: |
| 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 *> () const; |
| 231 | IRunConfigurationAspect *(Core::Id id) const; |
| 232 | |
| 233 | template <typename T> T *() 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 (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 | |
| 258 | signals: |
| 259 | void requestRunActionsUpdate(); |
| 260 | void configurationFinished(); |
| 261 | |
| 262 | protected: |
| 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 | |
| 274 | private: |
| 275 | static void addAspectFactory(const AspectFactory &aspectFactory); |
| 276 | |
| 277 | QList<IRunConfigurationAspect *> m_aspects; |
| 278 | }; |
| 279 | |
| 280 | class PROJECTEXPLORER_EXPORT IRunConfigurationFactory : public QObject |
| 281 | { |
| 282 | Q_OBJECT |
| 283 | |
| 284 | public: |
| 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 | |
| 303 | signals: |
| 304 | void availableCreationIdsChanged(); |
| 305 | |
| 306 | protected: |
| 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 | |
| 325 | private: |
| 326 | RunConfigurationCreator m_creator; |
| 327 | ProjectTypeChecker m_projectTypeChecker; |
| 328 | QList<Core::Id> m_supportedTargetDeviceTypes; |
| 329 | }; |
| 330 | |
| 331 | class PROJECTEXPLORER_EXPORT RunConfigWidget : public QWidget |
| 332 | { |
| 333 | Q_OBJECT |
| 334 | |
| 335 | public: |
| 336 | virtual QString displayName() const = 0; |
| 337 | |
| 338 | signals: |
| 339 | void displayNameChanged(const QString &); |
| 340 | }; |
| 341 | |
| 342 | class PROJECTEXPLORER_EXPORT RunWorker : public QObject |
| 343 | { |
| 344 | Q_OBJECT |
| 345 | |
| 346 | public: |
| 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 | |
| 388 | signals: |
| 389 | void started(); |
| 390 | void stopped(); |
| 391 | |
| 392 | protected: |
| 393 | void virtual start(); |
| 394 | void virtual stop(); |
| 395 | void virtual onFinished() {} |
| 396 | |
| 397 | private: |
| 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 | |
| 411 | class PROJECTEXPLORER_EXPORT RunControl : public QObject |
| 412 | { |
| 413 | Q_OBJECT |
| 414 | |
| 415 | public: |
| 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 | |
| 503 | signals: |
| 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 | |
| 512 | private: |
| 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 | |
| 526 | class PROJECTEXPLORER_EXPORT SimpleTargetRunner : public RunWorker |
| 527 | { |
| 528 | Q_OBJECT |
| 529 | |
| 530 | public: |
| 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 | |
| 538 | protected: |
| 539 | void start() override; |
| 540 | void stop() override; |
| 541 | |
| 542 | private: |
| 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 | |