forked from qt-creator/qt-creator
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 <riitta-leena.miettinen@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Marcus Tillmanns <marcus.tillmanns@qt.io>
This commit is contained in:
@@ -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
|
||||
|
@@ -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
|
@@ -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
|
@@ -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();
|
||||
}
|
||||
|
||||
|
@@ -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;
|
||||
|
@@ -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) {
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
Reference in New Issue
Block a user