diff options
author | Eike Ziller <[email protected]> | 2024-04-03 15:58:07 +0200 |
---|---|---|
committer | Eike Ziller <[email protected]> | 2024-04-09 07:36:26 +0000 |
commit | e8d6e4fc3412bd4bd3c4ae30421240eadbbb24c2 (patch) | |
tree | f403acc7748d82f712d9f1f515280a197bc2c23d | |
parent | 0be8e6ed0183285daf1781bcdd536a933ff82a2f (diff) |
iOS: Remove simulator management from settings page
Simulators can be managed via Xcode, which must be installed anyway. Re-
implementing this functionality is not useful, error-prone, and a
maintenance burden. Point users to the corresponding Xcode documentation
instead.
Add a button for updating the list of simulators in the run configuration
settings (which didn't update when simulators were changed in Xcode).
Change-Id: I5a861f21851bb866d45a703f46bb20ed5df960e8
Reviewed-by: Leena Miettinen <[email protected]>
Reviewed-by: Qt CI Bot <[email protected]>
Reviewed-by: Marcus Tillmanns <[email protected]>
-rw-r--r-- | src/plugins/ios/CMakeLists.txt | 3 | ||||
-rw-r--r-- | src/plugins/ios/createsimulatordialog.cpp | 172 | ||||
-rw-r--r-- | src/plugins/ios/createsimulatordialog.h | 46 | ||||
-rw-r--r-- | src/plugins/ios/iosconfigurations.cpp | 28 | ||||
-rw-r--r-- | src/plugins/ios/iosconfigurations.h | 3 | ||||
-rw-r--r-- | src/plugins/ios/iosrunconfiguration.cpp | 20 | ||||
-rw-r--r-- | src/plugins/ios/iosrunconfiguration.h | 9 | ||||
-rw-r--r-- | src/plugins/ios/iossettingspage.cpp | 343 | ||||
-rw-r--r-- | src/plugins/ios/simulatorinfomodel.cpp | 142 | ||||
-rw-r--r-- | src/plugins/ios/simulatorinfomodel.h | 37 | ||||
-rw-r--r-- | src/plugins/ios/simulatoroperationdialog.cpp | 125 | ||||
-rw-r--r-- | src/plugins/ios/simulatoroperationdialog.h | 47 |
12 files changed, 35 insertions, 940 deletions
diff --git a/src/plugins/ios/CMakeLists.txt b/src/plugins/ios/CMakeLists.txt index e6ec1665b2c..1b7256e43e5 100644 --- a/src/plugins/ios/CMakeLists.txt +++ b/src/plugins/ios/CMakeLists.txt @@ -2,7 +2,6 @@ add_qtc_plugin(Ios DEPENDS QmlDebug Qt::Xml PLUGIN_DEPENDS Core Debugger ProjectExplorer QmakeProjectManager CMakeProjectManager SOURCES - createsimulatordialog.cpp createsimulatordialog.h devicectlutils.cpp devicectlutils.h ios.qrc @@ -23,8 +22,6 @@ add_qtc_plugin(Ios iostoolhandler.cpp iostoolhandler.h iostr.h simulatorcontrol.cpp simulatorcontrol.h - simulatorinfomodel.cpp simulatorinfomodel.h - simulatoroperationdialog.cpp simulatoroperationdialog.h ) extend_qtc_plugin(Ios diff --git a/src/plugins/ios/createsimulatordialog.cpp b/src/plugins/ios/createsimulatordialog.cpp deleted file mode 100644 index bacba246f27..00000000000 --- a/src/plugins/ios/createsimulatordialog.cpp +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright (C) 2017 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "createsimulatordialog.h" - -#include "iostr.h" -#include "simulatorcontrol.h" - -#include <utils/algorithm.h> -#include <utils/async.h> -#include <utils/layoutbuilder.h> - -#include <QApplication> -#include <QComboBox> -#include <QDialogButtonBox> -#include <QLabel> -#include <QLineEdit> -#include <QPushButton> - -namespace Ios::Internal { - -CreateSimulatorDialog::CreateSimulatorDialog(QWidget *parent) - : QDialog(parent) -{ - resize(320, 160); - setWindowTitle(Tr::tr("Create Simulator")); - - m_nameEdit = new QLineEdit(this); - m_deviceTypeCombo = new QComboBox(this); - m_runtimeCombo = new QComboBox(this); - - auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Cancel|QDialogButtonBox::Ok); - buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); - - using namespace Layouting; - - Column { - Form { - Tr::tr("Simulator name:"), m_nameEdit, br, - Tr::tr("Device type:"), m_deviceTypeCombo, br, - Tr::tr("OS version:"), m_runtimeCombo, br, - }, - buttonBox - }.attachTo(this); - - connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); - connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); - - const auto enableOk = [this, buttonBox] { - buttonBox->button(QDialogButtonBox::Ok)->setEnabled( - !m_nameEdit->text().isEmpty() && - m_deviceTypeCombo->currentIndex() > 0 && - m_runtimeCombo->currentIndex() > 0); - }; - - connect(m_nameEdit, &QLineEdit::textChanged, this, enableOk); - connect(m_runtimeCombo, &QComboBox::currentIndexChanged, this, enableOk); - connect(m_deviceTypeCombo, &QComboBox::currentIndexChanged, this, [this, enableOk] { - populateRuntimes(m_deviceTypeCombo->currentData().value<DeviceTypeInfo>()); - enableOk(); - }); - - m_futureSync.addFuture(Utils::onResultReady(SimulatorControl::updateDeviceTypes(), this, - &CreateSimulatorDialog::populateDeviceTypes)); - - QFuture<QList<RuntimeInfo>> runtimesfuture = SimulatorControl::updateRuntimes(); - Utils::onResultReady(runtimesfuture, this, [this](const QList<RuntimeInfo> &runtimes) { - m_runtimes = runtimes; - }); - m_futureSync.addFuture(runtimesfuture); - populateRuntimes(DeviceTypeInfo()); -} - -CreateSimulatorDialog::~CreateSimulatorDialog() = default; - -/*! - Returns the simulator name entered by user. - */ -QString CreateSimulatorDialog::name() const -{ - return m_nameEdit->text(); -} - -/*! - Returns the simulator runtime (OS version) selected by user. - Though the runtimes are filtered by the selected device type but the runtime camppatibility is - not checked. i.e. User can select the Runtime iOS 10.2 for iPhone 4 but the combination is not - possible as iOS 10.2 is not compatible with iPhone 4. In this case the command to create - simulator shall fail with an error message describing the compatibility. - */ -RuntimeInfo CreateSimulatorDialog::runtime() const -{ - return m_runtimeCombo->currentData().value<RuntimeInfo>(); -} - -/*! - Returns the selected device type. - */ -DeviceTypeInfo CreateSimulatorDialog::deviceType() const -{ - return m_deviceTypeCombo->currentData().value<DeviceTypeInfo>(); -} - -/*! - Populates the devices types. Similar device types are grouped together. - */ -void CreateSimulatorDialog::populateDeviceTypes(const QList<DeviceTypeInfo> &deviceTypes) -{ - m_deviceTypeCombo->clear(); - m_deviceTypeCombo->addItem(Tr::tr("None")); - - if (deviceTypes.isEmpty()) - return; - - m_deviceTypeCombo->insertSeparator(1); - - auto addItems = [this, deviceTypes](const QString &filter) { - const auto filteredTypes = Utils::filtered(deviceTypes, [filter](const DeviceTypeInfo &type){ - return type.name.contains(filter, Qt::CaseInsensitive); - }); - for (auto type : filteredTypes) { - m_deviceTypeCombo->addItem(type.name, QVariant::fromValue<DeviceTypeInfo>(type)); - } - return filteredTypes.count(); - }; - - if (addItems(QStringLiteral("iPhone")) > 0) - m_deviceTypeCombo->insertSeparator(m_deviceTypeCombo->count()); - if (addItems(QStringLiteral("iPad")) > 0) - m_deviceTypeCombo->insertSeparator(m_deviceTypeCombo->count()); - if (addItems(QStringLiteral("TV")) > 0) - m_deviceTypeCombo->insertSeparator(m_deviceTypeCombo->count()); - addItems(QStringLiteral("Watch")); -} - -/*! - Populates the available runtimes. Though the runtimes are filtered by the selected device type - but the runtime camppatibility is not checked. i.e. User can select the Runtime iOS 10.2 for - iPhone 4 but the combination is not possible as iOS 10.2 is not compatible with iPhone 4. In - this case the command to create simulator shall fail with an error message describing the - compatibility issue. - */ -void CreateSimulatorDialog::populateRuntimes(const DeviceTypeInfo &deviceType) -{ - m_runtimeCombo->clear(); - m_runtimeCombo->addItem(Tr::tr("None")); - - if (deviceType.name.isEmpty()) - return; - - m_runtimeCombo->insertSeparator(1); - - auto addItems = [this](const QString &filter) { - const auto filteredTypes = Utils::filtered(m_runtimes, [filter](const RuntimeInfo &runtime){ - return runtime.name.contains(filter, Qt::CaseInsensitive); - }); - for (auto runtime : filteredTypes) { - m_runtimeCombo->addItem(runtime.name, QVariant::fromValue<RuntimeInfo>(runtime)); - } - }; - - if (deviceType.name.contains(QStringLiteral("iPhone"))) - addItems(QStringLiteral("iOS")); - else if (deviceType.name.contains(QStringLiteral("iPad"))) - addItems(QStringLiteral("iOS")); - else if (deviceType.name.contains(QStringLiteral("TV"))) - addItems(QStringLiteral("tvOS")); - else if (deviceType.name.contains(QStringLiteral("Watch"))) - addItems(QStringLiteral("watchOS")); -} - -} // Ios::Internal diff --git a/src/plugins/ios/createsimulatordialog.h b/src/plugins/ios/createsimulatordialog.h deleted file mode 100644 index 9f269cc636e..00000000000 --- a/src/plugins/ios/createsimulatordialog.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (C) 2017 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include <utils/futuresynchronizer.h> - -#include <QDialog> - -QT_BEGIN_NAMESPACE -class QComboBox; -class QLineEdit; -QT_END_NAMESPACE - -namespace Ios::Internal { - -class DeviceTypeInfo; -class RuntimeInfo; - -/*! - A dialog to select the iOS Device type and the runtime for a new - iOS simulator device. - */ -class CreateSimulatorDialog : public QDialog -{ -public: - explicit CreateSimulatorDialog(QWidget *parent = nullptr); - ~CreateSimulatorDialog() override; - - QString name() const; - RuntimeInfo runtime() const; - DeviceTypeInfo deviceType() const; - -private: - void populateDeviceTypes(const QList<DeviceTypeInfo> &deviceTypes); - void populateRuntimes(const DeviceTypeInfo &deviceType); - - QList<RuntimeInfo> m_runtimes; - - QLineEdit *m_nameEdit; - QComboBox *m_deviceTypeCombo; - QComboBox *m_runtimeCombo; - Utils::FutureSynchronizer m_futureSync; // Keep me last -}; - -} // Ios::Internal diff --git a/src/plugins/ios/iosconfigurations.cpp b/src/plugins/ios/iosconfigurations.cpp index ff995c6c2c7..d7ad6bf3bee 100644 --- a/src/plugins/ios/iosconfigurations.cpp +++ b/src/plugins/ios/iosconfigurations.cpp @@ -69,7 +69,6 @@ const bool IgnoreAllDevicesDefault = false; const char SettingsGroup[] = "IosConfigurations"; const char ignoreAllDevicesKey[] = "IgnoreAllDevices"; -const char screenshotDirPathKey[] = "ScreeshotDirPath"; const char provisioningTeamsTag[] = "IDEProvisioningTeams"; const char freeTeamTag[] = "isFreeProvisioningTeam"; @@ -343,19 +342,6 @@ void IosConfigurations::setIgnoreAllDevices(bool ignoreDevices) } } -void IosConfigurations::setScreenshotDir(const FilePath &path) -{ - if (m_instance->m_screenshotDir != path) { - m_instance->m_screenshotDir = path; - m_instance->save(); - } -} - -FilePath IosConfigurations::screenshotDir() -{ - return m_instance->m_screenshotDir; -} - FilePath IosConfigurations::developerPath() { return m_instance->m_developerPath; @@ -366,20 +352,11 @@ QVersionNumber IosConfigurations::xcodeVersion() return m_instance->m_xcodeVersion; } -static FilePath defaultScreenshotDirPath() -{ - return FilePath::fromUserInput( - QStandardPaths::standardLocations(QStandardPaths::PicturesLocation).constFirst()); -} - void IosConfigurations::save() { QtcSettings *settings = Core::ICore::settings(); settings->beginGroup(SettingsGroup); settings->setValueWithDefault(ignoreAllDevicesKey, m_ignoreAllDevices, IgnoreAllDevicesDefault); - settings->setValueWithDefault(screenshotDirPathKey, - m_screenshotDir.toSettings(), - defaultScreenshotDirPath().toSettings()); settings->endGroup(); } @@ -396,11 +373,6 @@ void IosConfigurations::load() QtcSettings *settings = Core::ICore::settings(); settings->beginGroup(SettingsGroup); m_ignoreAllDevices = settings->value(ignoreAllDevicesKey, IgnoreAllDevicesDefault).toBool(); - m_screenshotDir = FilePath::fromSettings(settings->value(screenshotDirPathKey)); - - if (!m_screenshotDir.isWritableDir()) - m_screenshotDir = defaultScreenshotDirPath(); - settings->endGroup(); } diff --git a/src/plugins/ios/iosconfigurations.h b/src/plugins/ios/iosconfigurations.h index 7b65f2f8e6b..953b872cd07 100644 --- a/src/plugins/ios/iosconfigurations.h +++ b/src/plugins/ios/iosconfigurations.h @@ -78,8 +78,6 @@ public: static void initialize(); static bool ignoreAllDevices(); static void setIgnoreAllDevices(bool ignoreDevices); - static void setScreenshotDir(const Utils::FilePath &path); - static Utils::FilePath screenshotDir(); static Utils::FilePath developerPath(); static QVersionNumber xcodeVersion(); static Utils::FilePath lldbPath(); @@ -103,7 +101,6 @@ private: void loadProvisioningData(bool notify = true); Utils::FilePath m_developerPath; - Utils::FilePath m_screenshotDir; QVersionNumber m_xcodeVersion; bool m_ignoreAllDevices; QFileSystemWatcher *m_provisioningDataWatcher = nullptr; diff --git a/src/plugins/ios/iosrunconfiguration.cpp b/src/plugins/ios/iosrunconfiguration.cpp index 676fb68724a..23a27e85f6a 100644 --- a/src/plugins/ios/iosrunconfiguration.cpp +++ b/src/plugins/ios/iosrunconfiguration.cpp @@ -21,10 +21,11 @@ #include <projectexplorer/target.h> #include <utils/algorithm.h> +#include <utils/async.h> #include <utils/filepath.h> #include <utils/layoutbuilder.h> -#include <utils/qtcprocess.h> #include <utils/qtcassert.h> +#include <utils/qtcprocess.h> #include <QAction> #include <QApplication> @@ -33,6 +34,7 @@ #include <QLabel> #include <QLineEdit> #include <QList> +#include <QPushButton> #include <QVariant> #include <QWidget> @@ -342,12 +344,25 @@ void IosDeviceTypeAspect::addToLayout(Layouting::LayoutItem &parent) m_deviceTypeLabel = new QLabel(Tr::tr("Device type:")); - parent.addItems({m_deviceTypeLabel, m_deviceTypeComboBox}); + m_updateButton = new QPushButton(Tr::tr("Update")); + + parent.addItems({m_deviceTypeLabel, m_deviceTypeComboBox, m_updateButton, Layouting::st}); updateValues(); connect(m_deviceTypeComboBox, &QComboBox::currentIndexChanged, this, &IosDeviceTypeAspect::setDeviceTypeIndex); + connect(m_updateButton, &QPushButton::clicked, this, [this] { + m_updateButton->setEnabled(false); + Utils::onFinished( + QFuture<void>(SimulatorControl::updateAvailableSimulators(this)), + this, + [this](QFuture<void>) { + m_updateButton->setEnabled(true); + m_deviceTypeModel.clear(); + updateValues(); + }); + }); } void IosDeviceTypeAspect::setDeviceTypeIndex(int devIndex) @@ -363,6 +378,7 @@ void IosDeviceTypeAspect::updateValues() bool showDeviceSelector = deviceType().type != IosDeviceType::IosDevice; m_deviceTypeLabel->setVisible(showDeviceSelector); m_deviceTypeComboBox->setVisible(showDeviceSelector); + m_updateButton->setVisible(showDeviceSelector); if (showDeviceSelector && m_deviceTypeModel.rowCount() == 0) { const QList<SimulatorInfo> devices = SimulatorControl::availableSimulators(); for (const SimulatorInfo &device : devices) { diff --git a/src/plugins/ios/iosrunconfiguration.h b/src/plugins/ios/iosrunconfiguration.h index baef05cd1d2..524369605c6 100644 --- a/src/plugins/ios/iosrunconfiguration.h +++ b/src/plugins/ios/iosrunconfiguration.h @@ -3,8 +3,6 @@ #pragma once -#include "iosconstants.h" -#include "iosconfigurations.h" #include "iossimulator.h" #include <projectexplorer/runconfiguration.h> @@ -12,9 +10,13 @@ #include <utils/fileutils.h> -#include <QComboBox> #include <QStandardItemModel> +QT_BEGIN_NAMESPACE +class QComboBox; +class QPushButton; +QT_END_NAMESPACE + namespace Ios::Internal { class IosRunConfiguration; @@ -58,6 +60,7 @@ private: QStandardItemModel m_deviceTypeModel; QLabel *m_deviceTypeLabel = nullptr; QComboBox *m_deviceTypeComboBox = nullptr; + QPushButton *m_updateButton = nullptr; }; class IosRunConfiguration : public ProjectExplorer::RunConfiguration diff --git a/src/plugins/ios/iossettingspage.cpp b/src/plugins/ios/iossettingspage.cpp index 042dfca9af6..8c699ebc033 100644 --- a/src/plugins/ios/iossettingspage.cpp +++ b/src/plugins/ios/iossettingspage.cpp @@ -3,34 +3,17 @@ #include "iossettingspage.h" -#include "createsimulatordialog.h" #include "iosconfigurations.h" #include "iosconstants.h" #include "iostr.h" -#include "simulatorcontrol.h" -#include "simulatorinfomodel.h" -#include "simulatoroperationdialog.h" #include <coreplugin/dialogs/ioptionspage.h> #include <projectexplorer/projectexplorerconstants.h> -#include <utils/algorithm.h> -#include <utils/async.h> #include <utils/layoutbuilder.h> -#include <utils/pathchooser.h> #include <QCheckBox> -#include <QDateTime> -#include <QGroupBox> -#include <QHeaderView> -#include <QInputDialog> -#include <QLabel> -#include <QMessageBox> -#include <QPointer> -#include <QPushButton> -#include <QSortFilterProxyModel> -#include <QTreeView> using namespace std::placeholders; @@ -47,43 +30,10 @@ private: void saveSettings(); - void onStart(); - void onCreate(); - void onReset(); - void onRename(); - void onDelete(); - void onScreenshot(); - void onSelectionChanged(); - private: - Utils::PathChooser *m_pathWidget; - QPushButton *m_startButton; - QPushButton *m_renameButton; - QPushButton *m_deleteButton; - QPushButton *m_resetButton; - QTreeView *m_deviceView; QCheckBox *m_deviceAskCheckBox; }; -const int simStartWarnCount = 4; - -static SimulatorInfoList selectedSimulators(const QTreeView *deviceTreeView) -{ - SimulatorInfoList list; - QItemSelectionModel *selectionModel = deviceTreeView->selectionModel(); - for (QModelIndex index: selectionModel->selectedRows()) - list << deviceTreeView->model()->data(index, Qt::UserRole).value<SimulatorInfo>(); - return list; -} - -static void onSimOperation(const SimulatorInfo &simInfo, - SimulatorOperationDialog *dlg, - const QString &contextStr, - const SimulatorControl::Response &response) -{ - dlg->addMessage(simInfo, response, contextStr); -} - IosSettingsWidget::IosSettingsWidget() { setWindowTitle(Tr::tr("iOS Configuration")); @@ -91,43 +41,14 @@ IosSettingsWidget::IosSettingsWidget() m_deviceAskCheckBox = new QCheckBox(Tr::tr("Ask about devices not in developer mode")); m_deviceAskCheckBox->setChecked(!IosConfigurations::ignoreAllDevices()); - m_renameButton = new QPushButton(Tr::tr("Rename")); - m_renameButton->setEnabled(false); - m_renameButton->setToolTip(Tr::tr("Rename a simulator device.")); - - m_deleteButton = new QPushButton(Tr::tr("Delete")); - m_deleteButton->setEnabled(false); - m_deleteButton->setToolTip(Tr::tr("Delete simulator devices.")); - - m_resetButton = new QPushButton(Tr::tr("Reset")); - m_resetButton->setEnabled(false); - m_resetButton->setToolTip(Tr::tr("Reset contents and settings of simulator devices.")); - - auto createButton = new QPushButton(Tr::tr("Create")); - createButton->setToolTip(Tr::tr("Create a new simulator device.")); - - m_startButton = new QPushButton(Tr::tr("Start")); - m_startButton->setEnabled(false); - m_startButton->setToolTip(Tr::tr("Start simulator devices.")); - - auto proxyModel = new QSortFilterProxyModel(this); - proxyModel->setSourceModel(new SimulatorInfoModel(this)); - - m_deviceView = new QTreeView; - m_deviceView->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Expanding); - m_deviceView->setSelectionMode(QAbstractItemView::ExtendedSelection); - m_deviceView->setSelectionBehavior(QAbstractItemView::SelectRows); - m_deviceView->setSortingEnabled(true); - m_deviceView->setModel(proxyModel); - m_deviceView->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents); - - m_pathWidget = new Utils::PathChooser; - m_pathWidget->setExpectedKind(Utils::PathChooser::ExistingDirectory); - m_pathWidget->lineEdit()->setReadOnly(true); - m_pathWidget->setFilePath(IosConfigurations::screenshotDir()); - m_pathWidget->addButton(Tr::tr("Screenshot"), this, - std::bind(&IosSettingsWidget::onScreenshot, this)); + auto xcodeLabel = new QLabel( + Tr::tr("Configure available simulator devices in <a href=\"%1\">Xcode</a>.") + .arg("https://developer.apple.com/documentation/xcode/" + "running-your-app-in-simulator-or-on-a-device/" + "#Configure-the-list-of-simulated-devices")); + xcodeLabel->setOpenExternalLinks(true); + // clang-format off using namespace Layouting; Column { Group { @@ -136,33 +57,11 @@ IosSettingsWidget::IosSettingsWidget() }, Group { title(Tr::tr("Simulator")), - Column { - Row { - m_deviceView, - Column { - createButton, - st, // FIXME: Better some fixed space? - m_startButton, - m_renameButton, - m_resetButton, - m_deleteButton, - st - }, - }, - hr, - Row { Tr::tr("Screenshot directory:"), m_pathWidget } - } - } + Row { xcodeLabel } + }, + st }.attachTo(this); - - connect(m_startButton, &QPushButton::clicked, this, &IosSettingsWidget::onStart); - connect(createButton, &QPushButton::clicked, this, &IosSettingsWidget::onCreate); - connect(m_renameButton, &QPushButton::clicked, this, &IosSettingsWidget::onRename); - connect(m_resetButton, &QPushButton::clicked, this, &IosSettingsWidget::onReset); - connect(m_deleteButton, &QPushButton::clicked, this, &IosSettingsWidget::onDelete); - - connect(m_deviceView->selectionModel(), &QItemSelectionModel::selectionChanged, - this, &IosSettingsWidget::onSelectionChanged); + // clang-format on } IosSettingsWidget::~IosSettingsWidget() = default; @@ -173,229 +72,9 @@ void IosSettingsWidget::apply() IosConfigurations::updateAutomaticKitList(); } -/*! - Called on start button click. Selected simulator devices are started. Multiple devices can be - started simultaneously provided they in shutdown state. - */ -void IosSettingsWidget::onStart() -{ - const SimulatorInfoList simulatorInfoList = selectedSimulators(m_deviceView); - if (simulatorInfoList.isEmpty()) - return; - - if (simulatorInfoList.count() > simStartWarnCount) { - const QString message = - Tr::tr("You are trying to launch %n simulators simultaneously. This " - "will take significant system resources. Do you really want to " - "continue?", "", simulatorInfoList.count()); - const int buttonCode = QMessageBox::warning(this, Tr::tr("Simulator Start"), message, - QMessageBox::Ok | QMessageBox::Abort, - QMessageBox::Abort); - - if (buttonCode == QMessageBox::Abort) - return; - } - - QPointer<SimulatorOperationDialog> statusDialog = new SimulatorOperationDialog(this); - statusDialog->setAttribute(Qt::WA_DeleteOnClose); - statusDialog->addMessage(Tr::tr("Starting %n simulator device(s)...", "", simulatorInfoList.count()), - Utils::NormalMessageFormat); - - QList<QFuture<void>> futureList; - for (const SimulatorInfo &info : simulatorInfoList) { - if (!info.isShutdown()) { - statusDialog->addMessage(Tr::tr("Cannot start simulator (%1, %2) in current state: %3.") - .arg(info.name) - .arg(info.runtimeName) - .arg(info.state), - Utils::StdErrFormat); - } else { - futureList << QFuture<void>(Utils::onResultReady( - SimulatorControl::startSimulator(info.identifier), this, - std::bind(onSimOperation, info, statusDialog, Tr::tr("simulator start"), _1))); - } - } - - statusDialog->addFutures(futureList); - statusDialog->exec(); // Modal dialog returns only when all the operations are done or cancelled. -} - -/*! - Called on create button click. User is presented with the create simulator dialog and with the - selected options a new device is created. - */ -void IosSettingsWidget::onCreate() -{ - QPointer<SimulatorOperationDialog> statusDialog = new SimulatorOperationDialog(this); - statusDialog->setAttribute(Qt::WA_DeleteOnClose); - statusDialog->addMessage(Tr::tr("Creating simulator device..."), Utils::NormalMessageFormat); - const auto onSimulatorCreate = [statusDialog](const QString &name, - const SimulatorControl::Response &response) { - if (response) { - statusDialog->addMessage(Tr::tr("Simulator device (%1) created.\nUDID: %2") - .arg(name) - .arg(response->simUdid), - Utils::StdOutFormat); - } else { - statusDialog->addMessage(Tr::tr("Simulator device (%1) creation failed.\nError: %2") - .arg(name) - .arg(response.error()), - Utils::StdErrFormat); - } - }; - - CreateSimulatorDialog createDialog(this); - if (createDialog.exec() == QDialog::Accepted) { - QFuture<void> f = QFuture<void>(Utils::onResultReady(SimulatorControl::createSimulator( - createDialog.name(), createDialog.deviceType(), createDialog.runtime()), - this, std::bind(onSimulatorCreate, createDialog.name(), _1))); - statusDialog->addFutures({ f }); - statusDialog->exec(); // Modal dialog returns only when all the operations are done or cancelled. - } -} - -/*! - Called on reset button click. Contents and settings of the selected devices are erased. Multiple - devices can be erased simultaneously provided they in shutdown state. - */ -void IosSettingsWidget::onReset() -{ - const SimulatorInfoList simulatorInfoList = selectedSimulators(m_deviceView); - if (simulatorInfoList.isEmpty()) - return; - - const int userInput = QMessageBox::question(this, Tr::tr("Reset"), - Tr::tr("Do you really want to reset the contents and settings" - " of the %n selected device(s)?", "", - simulatorInfoList.count())); - if (userInput == QMessageBox::No) - return; - - QPointer<SimulatorOperationDialog> statusDialog = new SimulatorOperationDialog(this); - statusDialog->setAttribute(Qt::WA_DeleteOnClose); - statusDialog->addMessage(Tr::tr("Resetting contents and settings..."), - Utils::NormalMessageFormat); - - QList<QFuture<void>> futureList; - for (const SimulatorInfo &info : simulatorInfoList) { - futureList << QFuture<void>(Utils::onResultReady( - SimulatorControl::resetSimulator(info.identifier), this, - std::bind(onSimOperation, info, statusDialog, Tr::tr("simulator reset"), _1))); - } - - statusDialog->addFutures(futureList); - statusDialog->exec(); // Modal dialog returns only when all the operations are done or cancelled. -} - -/*! - Called on rename button click. Selected device is renamed. Only one device can be renamed at a - time. Rename button is disabled on multi-selection. - */ -void IosSettingsWidget::onRename() -{ - const SimulatorInfoList simulatorInfoList = selectedSimulators(m_deviceView); - if (simulatorInfoList.isEmpty() || simulatorInfoList.count() > 1) - return; - - const SimulatorInfo &simInfo = simulatorInfoList.at(0); - const QString newName = QInputDialog::getText(this, Tr::tr("Rename %1").arg(simInfo.name), - Tr::tr("Enter new name:")); - if (newName.isEmpty()) - return; - - QPointer<SimulatorOperationDialog> statusDialog = new SimulatorOperationDialog(this); - statusDialog->setAttribute(Qt::WA_DeleteOnClose); - statusDialog->addMessage(Tr::tr("Renaming simulator device..."), Utils::NormalMessageFormat); - QFuture<void> f = QFuture<void>(Utils::onResultReady( - SimulatorControl::renameSimulator(simInfo.identifier, newName), this, - std::bind(onSimOperation, simInfo, statusDialog, Tr::tr("simulator rename"), _1))); - statusDialog->addFutures({f}); - statusDialog->exec(); // Modal dialog returns only when all the operations are done or cancelled. -} - -/*! - Called on delete button click. Selected devices are deleted. Multiple devices can be deleted - simultaneously provided they in shutdown state. - */ -void IosSettingsWidget::onDelete() -{ - const SimulatorInfoList simulatorInfoList = selectedSimulators(m_deviceView); - if (simulatorInfoList.isEmpty()) - return; - - const int userInput = - QMessageBox::question(this, Tr::tr("Delete Device"), - Tr::tr("Do you really want to delete the %n selected " - "device(s)?", "", simulatorInfoList.count())); - if (userInput == QMessageBox::No) - return; - - QPointer<SimulatorOperationDialog> statusDialog = new SimulatorOperationDialog(this); - statusDialog->setAttribute(Qt::WA_DeleteOnClose); - statusDialog->addMessage(Tr::tr("Deleting %n simulator device(s)...", "", simulatorInfoList.count()), - Utils::NormalMessageFormat); - QList<QFuture<void>> futureList; - for (const SimulatorInfo &info : simulatorInfoList) { - futureList << QFuture<void>(Utils::onResultReady( - SimulatorControl::deleteSimulator(info.identifier), this, - std::bind(onSimOperation, info, statusDialog, Tr::tr("simulator delete"), _1))); - } - - statusDialog->addFutures(futureList); - statusDialog->exec(); // Modal dialog returns only when all the operations are done or cancelled. -} - -/*! - Called on screenshot button click. Screenshot of the selected devices are saved to the selected - path. Screenshot from multiple devices can be taken simultaneously provided they in booted state. - */ -void IosSettingsWidget::onScreenshot() -{ - const SimulatorInfoList simulatorInfoList = selectedSimulators(m_deviceView); - if (simulatorInfoList.isEmpty()) - return; - - const auto generatePath = [this](const SimulatorInfo &info) { - const QString fileName = QString("%1_%2_%3.png").arg(info.name).arg(info.runtimeName) - .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd_HH-mm-ss-z")).replace(' ', '_'); - return m_pathWidget->filePath().pathAppended(fileName).toString(); - }; - - QPointer<SimulatorOperationDialog> statusDialog = new SimulatorOperationDialog(this); - statusDialog->setAttribute(Qt::WA_DeleteOnClose); - statusDialog->addMessage(Tr::tr("Capturing screenshots from %n device(s)...", "", - simulatorInfoList.count()), Utils::NormalMessageFormat); - QList<QFuture<void>> futureList; - for (const SimulatorInfo &info : simulatorInfoList) { - futureList << QFuture<void>(Utils::onResultReady( - SimulatorControl::takeSceenshot(info.identifier, generatePath(info)), this, - std::bind(onSimOperation, info, statusDialog, Tr::tr("simulator screenshot"), _1))); - } - - statusDialog->addFutures(futureList); - statusDialog->exec(); // Modal dialog returns only when all the operations are done or cancelled. -} - -void IosSettingsWidget::onSelectionChanged() -{ - const SimulatorInfoList infoList = selectedSimulators(m_deviceView); - const bool hasRunning = Utils::anyOf(infoList, [](const SimulatorInfo &info) { - return info.isBooted(); - }); - const bool hasShutdown = Utils::anyOf(infoList, [](const SimulatorInfo &info) { - return info.isShutdown(); - }); - m_startButton->setEnabled(hasShutdown); - m_deleteButton->setEnabled(hasShutdown); - m_resetButton->setEnabled(hasShutdown); - m_renameButton->setEnabled(infoList.count() == 1 && hasShutdown); - m_pathWidget->buttonAtIndex(1)->setEnabled(hasRunning); // Screenshot button -} - void IosSettingsWidget::saveSettings() { IosConfigurations::setIgnoreAllDevices(!m_deviceAskCheckBox->isChecked()); - IosConfigurations::setScreenshotDir(m_pathWidget->filePath()); } // IosSettingsPage diff --git a/src/plugins/ios/simulatorinfomodel.cpp b/src/plugins/ios/simulatorinfomodel.cpp deleted file mode 100644 index dce56467134..00000000000 --- a/src/plugins/ios/simulatorinfomodel.cpp +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright (C) 2017 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "simulatorinfomodel.h" - -#include "iostr.h" - -#include <utils/algorithm.h> -#include <utils/async.h> - -#include <QTimer> - -namespace Ios::Internal { - -using namespace std::placeholders; - -const int colCount = 3; -const int nameCol = 0; -const int runtimeCol = 1; -const int stateCol = 2; -const int deviceUpdateInterval = 1000; // Update simulator state every 1 sec. - -SimulatorInfoModel::SimulatorInfoModel(QObject *parent) : - QAbstractItemModel(parent) -{ - requestSimulatorInfo(); - - auto updateTimer = new QTimer(this); - connect(updateTimer, &QTimer::timeout, this, &SimulatorInfoModel::requestSimulatorInfo); - updateTimer->setInterval(deviceUpdateInterval); - updateTimer->start(); -} - -QVariant SimulatorInfoModel::data(const QModelIndex &index, int role) const -{ - if (!index.isValid()) - return {}; - - const SimulatorInfo &simInfo = m_simList[index.row()]; - if (role == Qt::EditRole || role == Qt::DisplayRole) { - switch (index.column()) { - case nameCol: - return simInfo.name; - case runtimeCol: - return simInfo.runtimeName; - case stateCol: - return simInfo.state; - default: - return ""; - } - } else if (role == Qt::ToolTipRole) { - return Tr::tr("UDID: %1").arg(simInfo.identifier); - } else if (role == Qt::UserRole) { - return QVariant::fromValue<SimulatorInfo>(simInfo); - } - - return {}; -} - -int SimulatorInfoModel::rowCount(const QModelIndex &parent) const -{ - if (!parent.isValid()) - return m_simList.count(); - return 0; -} - -int SimulatorInfoModel::columnCount(const QModelIndex &parent) const -{ - Q_UNUSED(parent) - return colCount; -} - -QVariant SimulatorInfoModel::headerData(int section, Qt::Orientation orientation, int role) const -{ - if (orientation == Qt::Vertical || section > colCount) - return {}; - - if (role == Qt::DisplayRole) { - switch (section) { - case nameCol: - return Tr::tr("Simulator Name"); - case runtimeCol: - return Tr::tr("Runtime"); - case stateCol: - return Tr::tr("Current State"); - default: - return {}; - } - } - - return {}; -} - -QModelIndex SimulatorInfoModel::index(int row, int column, const QModelIndex &parent) const -{ - return hasIndex(row, column, parent) ? createIndex(row, column) : QModelIndex(); -} - -QModelIndex SimulatorInfoModel::parent(const QModelIndex &) const -{ - return {}; -} - -void SimulatorInfoModel::requestSimulatorInfo() -{ - m_fetchFuture.flushFinishedFutures(); - if (!m_fetchFuture.isEmpty()) - return; // Ignore the request if the last request is still pending. - - m_fetchFuture.addFuture(Utils::onResultReady(SimulatorControl::updateAvailableSimulators(this), - this, &SimulatorInfoModel::populateSimulators)); -} - -void SimulatorInfoModel::populateSimulators(const SimulatorInfoList &simulatorList) -{ - if (m_simList.isEmpty() || m_simList.count() != simulatorList.count()) { - // Reset the model in case of addition or deletion. - beginResetModel(); - m_simList = simulatorList; - endResetModel(); - } else { - // update the rows with data chagne. e.g. state changes. - auto newItr = simulatorList.cbegin(); - int start = -1, end = -1; - std::list<std::pair<int, int>> updatedIndexes; - for (auto itr = m_simList.cbegin(); itr < m_simList.cend(); ++itr, ++newItr) { - if (*itr == *newItr) { - if (end != -1) - updatedIndexes.emplace_back(start, end - 1); - start = std::distance(m_simList.cbegin(), itr); - end = -1; - } else { - end = std::distance(m_simList.cbegin(), itr); - } - } - m_simList = simulatorList; - for (auto pair: updatedIndexes) - emit dataChanged(index(pair.first,0), index(pair.second, colCount - 1)); - } -} - -} // Ios::Internal diff --git a/src/plugins/ios/simulatorinfomodel.h b/src/plugins/ios/simulatorinfomodel.h deleted file mode 100644 index c5769000d32..00000000000 --- a/src/plugins/ios/simulatorinfomodel.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (C) 2017 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include "simulatorcontrol.h" - -#include <utils/futuresynchronizer.h> - -#include <QAbstractListModel> - -namespace Ios::Internal { - -using SimulatorInfoList = QList<SimulatorInfo>; - -class SimulatorInfoModel : public QAbstractItemModel -{ -public: - SimulatorInfoModel(QObject *parent = nullptr); - - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; - int rowCount(const QModelIndex &parent = QModelIndex()) const override; - int columnCount(const QModelIndex &parent) const override; - QVariant headerData(int section, Qt::Orientation orientation, - int role = Qt::DisplayRole) const override; - QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; - QModelIndex parent(const QModelIndex &) const override; - -private: - void requestSimulatorInfo(); - void populateSimulators(const SimulatorInfoList &simulatorList); - - Utils::FutureSynchronizer m_fetchFuture; - SimulatorInfoList m_simList; -}; - -} // Ios::Internal diff --git a/src/plugins/ios/simulatoroperationdialog.cpp b/src/plugins/ios/simulatoroperationdialog.cpp deleted file mode 100644 index b260f503101..00000000000 --- a/src/plugins/ios/simulatoroperationdialog.cpp +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright (C) 2017 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "simulatoroperationdialog.h" - -#include "iostr.h" - -#include <utils/layoutbuilder.h> -#include <utils/outputformatter.h> -#include <utils/qtcassert.h> - -#include <QDialogButtonBox> -#include <QFutureWatcher> -#include <QLoggingCategory> -#include <QPlainTextEdit> -#include <QProgressBar> -#include <QPushButton> - -namespace Ios::Internal { - -static Q_LOGGING_CATEGORY(iosCommon, "qtc.ios.common", QtWarningMsg) - -SimulatorOperationDialog::SimulatorOperationDialog(QWidget *parent) : - // TODO: Maximize buttong only because of QTBUG-41932 - QDialog(parent,Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowMaximizeButtonHint) -{ - resize(580, 320); - setModal(true); - setWindowTitle(Tr::tr("Simulator Operation Status")); - - auto messageEdit = new QPlainTextEdit; - messageEdit->setReadOnly(true); - - m_progressBar = new QProgressBar; - m_progressBar->setMaximum(0); - m_progressBar->setValue(-1); - - m_buttonBox = new QDialogButtonBox(QDialogButtonBox::Cancel|QDialogButtonBox::Ok); - - m_formatter = new Utils::OutputFormatter; - m_formatter->setPlainTextEdit(messageEdit); - - using namespace Layouting; - - Column { - messageEdit, - m_progressBar, - m_buttonBox - }.attachTo(this); - - connect(m_buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); - connect(m_buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); -} - -SimulatorOperationDialog::~SimulatorOperationDialog() -{ - // Cancel all pending futures. - const auto futureWatchList = m_futureWatchList; - for (auto watcher : futureWatchList) { - if (!watcher->isFinished()) - watcher->cancel(); - } - - // wait for futures to finish - for (auto watcher : futureWatchList) { - if (!watcher->isFinished()) - watcher->waitForFinished(); - delete watcher; - } - - delete m_formatter; -} - -void SimulatorOperationDialog::addFutures(const QList<QFuture<void> > &futureList) -{ - for (auto future : futureList) { - if (!future.isFinished() || !future.isCanceled()) { - auto watcher = new QFutureWatcher<void>; - connect(watcher, &QFutureWatcherBase::finished, this, [this, watcher] { - m_futureWatchList.removeAll(watcher); - watcher->deleteLater(); - updateInputs(); - }); - watcher->setFuture(future); - m_futureWatchList << watcher; - } - } - updateInputs(); -} - -void SimulatorOperationDialog::addMessage(const QString &message, Utils::OutputFormat format) -{ - m_formatter->appendMessage(message + "\n\n", format); -} - -void SimulatorOperationDialog::addMessage(const SimulatorInfo &siminfo, - const SimulatorControl::Response &response, - const QString &context) -{ - if (response) { - QTC_CHECK(siminfo.identifier == response->simUdid); - addMessage(Tr::tr("%1, %2\nOperation %3 completed successfully.").arg(siminfo.name) - .arg(siminfo.runtimeName).arg(context), Utils::StdOutFormat); - } else { - QString erroMsg = response.error(); - QString message = Tr::tr("%1, %2\nOperation %3 failed.\nUDID: %4\nError: %5").arg(siminfo.name) - .arg(siminfo.runtimeName).arg(context).arg(siminfo.identifier) - .arg(erroMsg.isEmpty() ? Tr::tr("Unknown") : erroMsg); - addMessage(message, Utils::StdErrFormat); - qCDebug(iosCommon) << message; - } -} - -void SimulatorOperationDialog::updateInputs() -{ - bool enableOk = m_futureWatchList.isEmpty(); - m_buttonBox->button(QDialogButtonBox::Cancel)->setEnabled(!enableOk); - m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(enableOk); - if (enableOk) { - addMessage(Tr::tr("Done."), Utils::NormalMessageFormat); - m_progressBar->setMaximum(1); // Stop progress bar. - } -} - -} // Ios::Internal diff --git a/src/plugins/ios/simulatoroperationdialog.h b/src/plugins/ios/simulatoroperationdialog.h deleted file mode 100644 index 46cbb3f787e..00000000000 --- a/src/plugins/ios/simulatoroperationdialog.h +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (C) 2017 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include "simulatorcontrol.h" - -#include <utils/outputformat.h> - -#include <QDialog> -#include <QFuture> -#include <QList> - -QT_BEGIN_NAMESPACE -class QDialogButtonBox; -class QProgressBar; -QT_END_NAMESPACE - -namespace Utils { class OutputFormatter; } - -namespace Ios::Internal { - -class SimulatorOperationDialog : public QDialog -{ - -public: - explicit SimulatorOperationDialog(QWidget *parent = nullptr); - ~SimulatorOperationDialog() override; - -public: - void addFutures(const QList<QFuture<void> > &futureList); - void addMessage(const QString &message, Utils::OutputFormat format); - void addMessage(const SimulatorInfo &siminfo, - const SimulatorControl::Response &response, - const QString &context); - -private: - void updateInputs(); - - Utils::OutputFormatter *m_formatter = nullptr; - - QList<QFutureWatcher<void> *> m_futureWatchList; - QProgressBar *m_progressBar; - QDialogButtonBox *m_buttonBox; -}; - -} // Ios::Internal |