Project: Base IDevice on AspectContainer

This is effectively the same approach as taken with ProjectConfiguration.

Having the settings separate leads to quite some boilerplate and in the
end to parallel IDevice and DeviceSettings hierarchies.

The unusual registration of the docker aspects are due to the multiple
inheritance, we need to "dynamic" downcast.

Change-Id: I50864e2009f4e525d635decf1c9beaad5e6a5f1f
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
hjk
2024-08-01 12:30:23 +02:00
parent e78da3dfee
commit 2a7bf0fdaf
21 changed files with 229 additions and 296 deletions

View File

@@ -177,7 +177,7 @@ static IDevice::Ptr createDeviceFromInfo(const CreateAvdInfo &info)
const Id deviceId = AndroidDevice::idFromAvdInfo(info); const Id deviceId = AndroidDevice::idFromAvdInfo(info);
dev->setupId(IDevice::AutoDetected, deviceId); dev->setupId(IDevice::AutoDetected, deviceId);
dev->setMachineType(IDevice::Emulator); dev->setMachineType(IDevice::Emulator);
dev->settings()->displayName.setValue(info.name); dev->displayName.setValue(info.name);
dev->setDeviceState(IDevice::DeviceConnected); dev->setDeviceState(IDevice::DeviceConnected);
dev->setAvdPath(avdFilePath() / (info.name + ".avd")); dev->setAvdPath(avdFilePath() / (info.name + ".avd"));
dev->setExtraData(Constants::AndroidAvdName, info.name); dev->setExtraData(Constants::AndroidAvdName, info.name);
@@ -349,7 +349,7 @@ AndroidDevice::AndroidDevice()
{ {
setupId(IDevice::AutoDetected, Constants::ANDROID_DEVICE_ID); setupId(IDevice::AutoDetected, Constants::ANDROID_DEVICE_ID);
setType(Constants::ANDROID_DEVICE_TYPE); setType(Constants::ANDROID_DEVICE_TYPE);
settings()->displayName.setDefaultValue(Tr::tr("Run on Android")); displayName.setDefaultValue(Tr::tr("Run on Android"));
setDisplayType(Tr::tr("Android")); setDisplayType(Tr::tr("Android"));
setMachineType(IDevice::Hardware); setMachineType(IDevice::Hardware);
setOsType(OsType::OsTypeOtherUnix); setOsType(OsType::OsTypeOtherUnix);
@@ -672,7 +672,7 @@ static void handleDevicesListChange(const QString &serialNumber)
} else { } else {
AndroidDevice *newDev = new AndroidDevice(); AndroidDevice *newDev = new AndroidDevice();
newDev->setupId(IDevice::AutoDetected, id); newDev->setupId(IDevice::AutoDetected, id);
newDev->settings()->displayName.setValue(displayName); newDev->displayName.setValue(displayName);
newDev->setMachineType(IDevice::Hardware); newDev->setMachineType(IDevice::Hardware);
newDev->setDeviceState(state); newDev->setDeviceState(state);
@@ -758,7 +758,7 @@ static void handleAvdListChange(const AndroidDeviceInfoList &avdList)
AndroidDevice *newDev = new AndroidDevice; AndroidDevice *newDev = new AndroidDevice;
newDev->setupId(IDevice::AutoDetected, deviceId); newDev->setupId(IDevice::AutoDetected, deviceId);
newDev->settings()->displayName.setValue(displayName); newDev->displayName.setValue(displayName);
newDev->setMachineType(item.type); newDev->setMachineType(item.type);
newDev->setDeviceState(item.state); newDev->setDeviceState(item.state);

View File

@@ -26,7 +26,7 @@ ProjectExplorer::IDevice::Ptr BareMetalDeviceConfigurationWizard::device() const
{ {
const auto dev = BareMetalDevice::create(); const auto dev = BareMetalDevice::create();
dev->setupId(ProjectExplorer::IDevice::ManuallyAdded, Utils::Id()); dev->setupId(ProjectExplorer::IDevice::ManuallyAdded, Utils::Id());
dev->settings()->displayName.setDefaultValue(m_setupPage->configurationName()); dev->displayName.setDefaultValue(m_setupPage->configurationName());
dev->setType(Constants::BareMetalOsType); dev->setType(Constants::BareMetalOsType);
dev->setMachineType(ProjectExplorer::IDevice::Hardware); dev->setMachineType(ProjectExplorer::IDevice::Hardware);
dev->setDebugServerProviderId(m_setupPage->debugServerProviderId()); dev->setDebugServerProviderId(m_setupPage->debugServerProviderId());

View File

@@ -84,7 +84,7 @@ void DeviceDetector::handleDeviceEvent(QdbDeviceTracker::DeviceEventType eventTy
const QString name = Tr::tr("Boot to Qt device %1").arg(serial); const QString name = Tr::tr("Boot to Qt device %1").arg(serial);
QdbDevice::Ptr device = QdbDevice::create(); QdbDevice::Ptr device = QdbDevice::create();
device->setupId(IDevice::AutoDetected, deviceId); device->setupId(IDevice::AutoDetected, deviceId);
device->settings()->displayName.setValue(name); device->displayName.setValue(name);
device->setType(Qdb::Constants::QdbLinuxOsType); device->setType(Qdb::Constants::QdbLinuxOsType);
device->setMachineType(IDevice::Hardware); device->setMachineType(IDevice::Hardware);
device->setExtraData(ProjectExplorer::Constants::SUPPORTS_RSYNC, true); device->setExtraData(ProjectExplorer::Constants::SUPPORTS_RSYNC, true);

View File

@@ -207,7 +207,7 @@ public:
{ {
QdbDevice::Ptr device = QdbDevice::create(); QdbDevice::Ptr device = QdbDevice::create();
device->settings()->displayName.setValue(settingsPage.deviceName()); device->displayName.setValue(settingsPage.deviceName());
device->setupId(ProjectExplorer::IDevice::ManuallyAdded, Utils::Id()); device->setupId(ProjectExplorer::IDevice::ManuallyAdded, Utils::Id());
device->setType(Constants::QdbLinuxOsType); device->setType(Constants::QdbLinuxOsType);
device->setMachineType(ProjectExplorer::IDevice::Hardware); device->setMachineType(ProjectExplorer::IDevice::Hardware);

View File

@@ -142,128 +142,8 @@ public:
} }
}; };
void DockerDeviceSettings::fromMap(const Store &map)
{
DeviceSettings::fromMap(map);
// This is the only place where we can correctly set the default name.
// Only here do we know the image id and the repo reliably, no matter
// where or how we were created.
if (displayName.value() == displayName.defaultValue()) {
displayName.setDefaultValue(
Tr::tr("Docker Image \"%1\" (%2)").arg(repoAndTag()).arg(imageId.value()));
}
}
DockerDeviceSettings::DockerDeviceSettings()
{
imageId.setSettingsKey(DockerDeviceDataImageIdKey);
imageId.setLabelText(Tr::tr("Image ID:"));
imageId.setReadOnly(true);
repo.setSettingsKey(DockerDeviceDataRepoKey);
repo.setLabelText(Tr::tr("Repository:"));
repo.setReadOnly(true);
tag.setSettingsKey(DockerDeviceDataTagKey);
tag.setLabelText(Tr::tr("Tag:"));
tag.setReadOnly(true);
useLocalUidGid.setSettingsKey(DockerDeviceUseOutsideUser);
useLocalUidGid.setLabelText(Tr::tr("Run as outside user:"));
useLocalUidGid.setDefaultValue(true);
useLocalUidGid.setLabelPlacement(BoolAspect::LabelPlacement::InExtraLabel);
keepEntryPoint.setSettingsKey(DockerDeviceKeepEntryPoint);
keepEntryPoint.setLabelText(Tr::tr("Do not modify entry point:"));
keepEntryPoint.setDefaultValue(false);
keepEntryPoint.setLabelPlacement(BoolAspect::LabelPlacement::InExtraLabel);
enableLldbFlags.setSettingsKey(DockerDeviceEnableLldbFlags);
enableLldbFlags.setLabelText(Tr::tr("Enable flags needed for LLDB:"));
enableLldbFlags.setDefaultValue(false);
enableLldbFlags.setLabelPlacement(BoolAspect::LabelPlacement::InExtraLabel);
mounts.setSettingsKey(DockerDeviceMappedPaths);
mounts.setLabelText(Tr::tr("Paths to mount:"));
mounts.setDefaultValue({Core::DocumentManager::projectsDirectory().toString()});
mounts.setToolTip(Tr::tr("Maps paths in this list one-to-one to the docker container."));
mounts.setPlaceHolderText(Tr::tr("Host directories to mount into the container."));
extraArgs.setSettingsKey(DockerDeviceExtraArgs);
extraArgs.setLabelText(Tr::tr("Extra arguments:"));
extraArgs.setToolTip(Tr::tr("Extra arguments to pass to docker create."));
extraArgs.setDisplayStyle(StringAspect::LineEditDisplay);
clangdExecutable.setSettingsKey(DockerDeviceClangDExecutable);
clangdExecutable.setLabelText(Tr::tr("Clangd Executable:"));
clangdExecutable.setAllowPathFromDevice(true);
network.setSettingsKey("Network");
network.setLabelText(Tr::tr("Network:"));
network.setDefaultValue("bridge");
network.setFillCallback([this](const StringSelectionAspect::ResultCallback &cb) {
auto future = DockerApi::instance()->networks();
auto watcher = new QFutureWatcher<expected_str<QList<Network>>>(this);
watcher->setFuture(future);
QObject::connect(watcher,
&QFutureWatcher<expected_str<QList<Network>>>::finished,
this,
[watcher, cb]() {
expected_str<QList<Network>> result = watcher->result();
if (result) {
auto items = transform(*result, [](const Network &network) {
QStandardItem *item = new QStandardItem(network.name);
item->setData(network.name);
item->setToolTip(network.toString());
return item;
});
cb(items);
} else {
QStandardItem *errorItem = new QStandardItem(Tr::tr("Error"));
errorItem->setToolTip(result.error());
cb({errorItem});
}
});
});
connect(DockerApi::instance(),
&DockerApi::dockerDaemonAvailableChanged,
&network,
&StringSelectionAspect::refill);
clangdExecutable.setValidationFunction(
[this](const QString &newValue) -> FancyLineEdit::AsyncValidationFuture {
const FilePath rootPath = FilePath::fromParts(Constants::DOCKER_DEVICE_SCHEME,
repoAndTagEncoded(),
u"/");
return asyncRun([rootPath, newValue]() -> expected_str<QString> {
QString changedValue = newValue;
FilePath path = FilePath::fromUserInput(newValue);
if (!path.needsDevice()) {
const FilePath onDevicePath = rootPath.withNewMappedPath(path);
if (onDevicePath.exists()) {
changedValue = onDevicePath.toUserOutput();
path = onDevicePath;
} else {
return make_unexpected(
Tr::tr("The path \"%1\" does not exist.").arg(onDevicePath.toUserOutput()));
}
}
QString error;
bool result = checkClangdVersion(path, &error);
if (!result)
return make_unexpected(error);
return changedValue;
});
});
containerStatus.setText(Tr::tr("stopped"));
}
// Used for "docker run" // Used for "docker run"
QString DockerDeviceSettings::repoAndTag() const QString DockerDevice::repoAndTag() const
{ {
if (repo() == "<none>") if (repo() == "<none>")
return imageId(); return imageId();
@@ -274,12 +154,12 @@ QString DockerDeviceSettings::repoAndTag() const
return repo() + ':' + tag(); return repo() + ':' + tag();
} }
QString DockerDeviceSettings::repoAndTagEncoded() const QString DockerDevice::repoAndTagEncoded() const
{ {
return repoAndTag().replace(':', '.'); return repoAndTag().replace(':', '.');
} }
FilePath DockerDeviceSettings::rootPath() const FilePath DockerDevice::rootPath() const
{ {
return FilePath::fromParts(Constants::DOCKER_DEVICE_SCHEME, repoAndTagEncoded(), u"/"); return FilePath::fromParts(Constants::DOCKER_DEVICE_SCHEME, repoAndTagEncoded(), u"/");
} }
@@ -289,9 +169,8 @@ class DockerDevicePrivate : public QObject
public: public:
DockerDevicePrivate(DockerDevice *parent) DockerDevicePrivate(DockerDevice *parent)
: q(parent) : q(parent)
, deviceSettings(static_cast<DockerDeviceSettings *>(q->settings()))
{ {
QObject::connect(deviceSettings, &DockerDeviceSettings::applied, this, [this] { QObject::connect(q, &DockerDevice::applied, this, [this] {
if (!m_container.isEmpty()) { if (!m_container.isEmpty()) {
stopCurrentContainer(); stopCurrentContainer();
} }
@@ -310,10 +189,6 @@ public:
QString containerId() { return m_container; } QString containerId() { return m_container; }
QString repoAndTag() const { return deviceSettings->repoAndTag(); }
QString repoAndTagEncoded() const { return deviceSettings->repoAndTagEncoded(); }
QString dockerImageId() const { return deviceSettings->imageId(); }
expected_str<QPair<Utils::OsType, Utils::OsArch>> osTypeAndArch() const; expected_str<QPair<Utils::OsType, Utils::OsArch>> osTypeAndArch() const;
expected_str<Environment> environment(); expected_str<Environment> environment();
@@ -337,11 +212,11 @@ public:
std::optional<FilePath> clangdExecutable() const std::optional<FilePath> clangdExecutable() const
{ {
if (deviceSettings->clangdExecutable().isEmpty()) if (q->clangdExecutableAspect().isEmpty())
return std::nullopt; return std::nullopt;
if (!deviceSettings->clangdExecutable().needsDevice()) if (!q->clangdExecutableAspect().needsDevice())
return deviceSettings->rootPath().withNewMappedPath(deviceSettings->clangdExecutable()); return q->rootPath().withNewMappedPath(q->clangdExecutableAspect());
return deviceSettings->clangdExecutable(); return q->clangdExecutableAspect();
} }
QStringList createMountArgs() const; QStringList createMountArgs() const;
@@ -349,7 +224,6 @@ public:
bool isImageAvailable() const; bool isImageAvailable() const;
DockerDevice *const q; DockerDevice *const q;
DockerDeviceSettings *deviceSettings;
struct MountPair struct MountPair
{ {
@@ -569,7 +443,7 @@ Tasks DockerDevicePrivate::validateMounts() const
{ {
Tasks result; Tasks result;
for (const FilePath &mount : deviceSettings->mounts()) { for (const FilePath &mount : q->mounts()) {
if (!mount.isDir()) { if (!mount.isDir()) {
const QString message = Tr::tr("Path \"%1\" is not a directory or does not exist.") const QString message = Tr::tr("Path \"%1\" is not a directory or does not exist.")
.arg(mount.toUserOutput()); .arg(mount.toUserOutput());
@@ -593,10 +467,114 @@ QString DockerDeviceFileAccess::mapToDevicePath(const QString &hostPath) const
return newPath; return newPath;
} }
DockerDevice::DockerDevice(std::unique_ptr<DockerDeviceSettings> deviceSettings) DockerDevice::DockerDevice()
: ProjectExplorer::IDevice(std::move(deviceSettings)) : d(new DockerDevicePrivate(this))
, d(new DockerDevicePrivate(this))
{ {
imageId.setSettingsKey(DockerDeviceDataImageIdKey);
imageId.setLabelText(Tr::tr("Image ID:"));
imageId.setReadOnly(true);
repo.setSettingsKey(DockerDeviceDataRepoKey);
repo.setLabelText(Tr::tr("Repository:"));
repo.setReadOnly(true);
tag.setSettingsKey(DockerDeviceDataTagKey);
tag.setLabelText(Tr::tr("Tag:"));
tag.setReadOnly(true);
useLocalUidGid.setSettingsKey(DockerDeviceUseOutsideUser);
useLocalUidGid.setLabelText(Tr::tr("Run as outside user:"));
useLocalUidGid.setDefaultValue(true);
useLocalUidGid.setLabelPlacement(BoolAspect::LabelPlacement::InExtraLabel);
keepEntryPoint.setSettingsKey(DockerDeviceKeepEntryPoint);
keepEntryPoint.setLabelText(Tr::tr("Do not modify entry point:"));
keepEntryPoint.setDefaultValue(false);
keepEntryPoint.setLabelPlacement(BoolAspect::LabelPlacement::InExtraLabel);
enableLldbFlags.setSettingsKey(DockerDeviceEnableLldbFlags);
enableLldbFlags.setLabelText(Tr::tr("Enable flags needed for LLDB:"));
enableLldbFlags.setDefaultValue(false);
enableLldbFlags.setLabelPlacement(BoolAspect::LabelPlacement::InExtraLabel);
mounts.setSettingsKey(DockerDeviceMappedPaths);
mounts.setLabelText(Tr::tr("Paths to mount:"));
mounts.setDefaultValue({Core::DocumentManager::projectsDirectory().toString()});
mounts.setToolTip(Tr::tr("Maps paths in this list one-to-one to the docker container."));
mounts.setPlaceHolderText(Tr::tr("Host directories to mount into the container."));
extraArgs.setSettingsKey(DockerDeviceExtraArgs);
extraArgs.setLabelText(Tr::tr("Extra arguments:"));
extraArgs.setToolTip(Tr::tr("Extra arguments to pass to docker create."));
extraArgs.setDisplayStyle(StringAspect::LineEditDisplay);
clangdExecutableAspect.setSettingsKey(DockerDeviceClangDExecutable);
clangdExecutableAspect.setLabelText(Tr::tr("Clangd Executable:"));
clangdExecutableAspect.setAllowPathFromDevice(true);
network.setSettingsKey("Network");
network.setLabelText(Tr::tr("Network:"));
network.setDefaultValue("bridge");
network.setFillCallback([this](const StringSelectionAspect::ResultCallback &cb) {
auto future = DockerApi::instance()->networks();
auto watcher = new QFutureWatcher<expected_str<QList<Network>>>(this);
watcher->setFuture(future);
QObject::connect(watcher,
&QFutureWatcher<expected_str<QList<Network>>>::finished,
this,
[watcher, cb]() {
expected_str<QList<Network>> result = watcher->result();
if (result) {
auto items = transform(*result, [](const Network &network) {
QStandardItem *item = new QStandardItem(network.name);
item->setData(network.name);
item->setToolTip(network.toString());
return item;
});
cb(items);
} else {
QStandardItem *errorItem = new QStandardItem(Tr::tr("Error"));
errorItem->setToolTip(result.error());
cb({errorItem});
}
});
});
connect(DockerApi::instance(),
&DockerApi::dockerDaemonAvailableChanged,
&network,
&StringSelectionAspect::refill);
clangdExecutableAspect.setValidationFunction(
[this](const QString &newValue) -> FancyLineEdit::AsyncValidationFuture {
const FilePath rootPath = FilePath::fromParts(Constants::DOCKER_DEVICE_SCHEME,
repoAndTagEncoded(),
u"/");
return asyncRun([rootPath, newValue]() -> expected_str<QString> {
QString changedValue = newValue;
FilePath path = FilePath::fromUserInput(newValue);
if (!path.needsDevice()) {
const FilePath onDevicePath = rootPath.withNewMappedPath(path);
if (onDevicePath.exists()) {
changedValue = onDevicePath.toUserOutput();
path = onDevicePath;
} else {
return make_unexpected(
Tr::tr("The path \"%1\" does not exist.").arg(onDevicePath.toUserOutput()));
}
}
QString error;
bool result = checkClangdVersion(path, &error);
if (!result)
return make_unexpected(error);
return changedValue;
});
});
containerStatus.setText(Tr::tr("stopped"));
auto createBridgeFileAccess = [this]() -> expected_str<std::unique_ptr<DeviceFileAccess>> { auto createBridgeFileAccess = [this]() -> expected_str<std::unique_ptr<DeviceFileAccess>> {
expected_str<FilePath> cmdBridgePath = d->getCmdBridgePath(); expected_str<FilePath> cmdBridgePath = d->getCmdBridgePath();
@@ -874,7 +852,7 @@ QStringList DockerDevicePrivate::createMountArgs() const
QStringList cmds; QStringList cmds;
QList<MountPair> mounts; QList<MountPair> mounts;
for (const FilePath &m : deviceSettings->mounts()) for (const FilePath &m : q->mounts())
mounts.append({m, m}); mounts.append({m, m});
if (cmdBridgePath && cmdBridgePath->isSameDevice(settings().dockerBinaryPath())) if (cmdBridgePath && cmdBridgePath->isSameDevice(settings().dockerBinaryPath()))
@@ -893,12 +871,12 @@ bool DockerDevicePrivate::isImageAvailable() const
Process proc; Process proc;
proc.setCommand( proc.setCommand(
{settings().dockerBinaryPath(), {settings().dockerBinaryPath(),
{"image", "list", deviceSettings->repoAndTag(), "--format", "{{.Repository}}:{{.Tag}}"}}); {"image", "list", q->repoAndTag(), "--format", "{{.Repository}}:{{.Tag}}"}});
proc.runBlocking(); proc.runBlocking();
if (proc.result() != ProcessResult::FinishedWithSuccess) if (proc.result() != ProcessResult::FinishedWithSuccess)
return false; return false;
if (proc.stdOut().trimmed() == deviceSettings->repoAndTag()) if (proc.stdOut().trimmed() == q->repoAndTag())
return true; return true;
return false; return false;
@@ -919,26 +897,26 @@ CommandLine DockerDevicePrivate::createCommandLine()
#ifdef Q_OS_UNIX #ifdef Q_OS_UNIX
// no getuid() and getgid() on Windows. // no getuid() and getgid() on Windows.
if (deviceSettings->useLocalUidGid()) if (q->useLocalUidGid())
dockerCreate.addArgs({"-u", QString("%1:%2").arg(getuid()).arg(getgid())}); dockerCreate.addArgs({"-u", QString("%1:%2").arg(getuid()).arg(getgid())});
#endif #endif
if (!deviceSettings->network().isEmpty()) { if (!q->network().isEmpty()) {
dockerCreate.addArg("--network"); dockerCreate.addArg("--network");
dockerCreate.addArg(deviceSettings->network()); dockerCreate.addArg(q->network());
} }
dockerCreate.addArgs(createMountArgs()); dockerCreate.addArgs(createMountArgs());
if (!deviceSettings->keepEntryPoint()) if (!q->keepEntryPoint())
dockerCreate.addArgs({"--entrypoint", "/bin/sh"}); dockerCreate.addArgs({"--entrypoint", "/bin/sh"});
if (deviceSettings->enableLldbFlags()) if (q->enableLldbFlags())
dockerCreate.addArgs({"--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined"}); dockerCreate.addArgs({"--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined"});
dockerCreate.addArgs(deviceSettings->extraArgs(), CommandLine::Raw); dockerCreate.addArgs(q->extraArgs(), CommandLine::Raw);
dockerCreate.addArg(deviceSettings->repoAndTag()); dockerCreate.addArg(q->repoAndTag());
return dockerCreate; return dockerCreate;
} }
@@ -946,7 +924,7 @@ CommandLine DockerDevicePrivate::createCommandLine()
expected_str<QString> DockerDevicePrivate::createContainer() expected_str<QString> DockerDevicePrivate::createContainer()
{ {
if (!isImageAvailable()) if (!isImageAvailable())
return make_unexpected(Tr::tr("Image \"%1\" is not available.").arg(repoAndTag())); return make_unexpected(Tr::tr("Image \"%1\" is not available.").arg(q->repoAndTag()));
const CommandLine cmdLine = createCommandLine(); const CommandLine cmdLine = createCommandLine();
@@ -1005,7 +983,7 @@ expected_str<void> DockerDevicePrivate::updateContainerAccess()
result = make_unexpected(QString("Failed to start container: %1").arg(result.error())); result = make_unexpected(QString("Failed to start container: %1").arg(result.error()));
QTimer::singleShot(0, this, [this, containerStatus] { QTimer::singleShot(0, this, [this, containerStatus] {
deviceSettings->containerStatus.setText(containerStatus); q->containerStatus.setText(containerStatus);
}); });
return result; return result;
@@ -1019,13 +997,19 @@ void DockerDevice::setMounts(const QStringList &mounts) const
void DockerDevice::fromMap(const Store &map) void DockerDevice::fromMap(const Store &map)
{ {
ProjectExplorer::IDevice::fromMap(map); ProjectExplorer::IDevice::fromMap(map);
d->deviceSettings->fromMap(map);
// This is the only place where we can correctly set the default name.
// Only here do we know the image id and the repo reliably, no matter
// where or how we were created.
if (displayName.value() == displayName.defaultValue()) {
displayName.setDefaultValue(
Tr::tr("Docker Image \"%1\" (%2)").arg(repoAndTag()).arg(imageId.value()));
}
} }
void DockerDevice::toMap(Store &map) const void DockerDevice::toMap(Store &map) const
{ {
IDevice::toMap(map); IDevice::toMap(map);
d->deviceSettings->toMap(map);
} }
ProcessInterface *DockerDevice::createProcessInterface() const ProcessInterface *DockerDevice::createProcessInterface() const
@@ -1046,15 +1030,10 @@ bool DockerDevice::usableAsBuildDevice() const
FilePath DockerDevice::filePath(const QString &pathOnDevice) const FilePath DockerDevice::filePath(const QString &pathOnDevice) const
{ {
return FilePath::fromParts(Constants::DOCKER_DEVICE_SCHEME, return FilePath::fromParts(Constants::DOCKER_DEVICE_SCHEME,
d->repoAndTagEncoded(), repoAndTagEncoded(),
pathOnDevice); pathOnDevice);
} }
FilePath DockerDevice::rootPath() const
{
return d->deviceSettings->rootPath();
}
bool DockerDevice::handlesFile(const FilePath &filePath) const bool DockerDevice::handlesFile(const FilePath &filePath) const
{ {
if (filePath.scheme() == u"device" && filePath.host() == id().toString()) if (filePath.scheme() == u"device" && filePath.host() == id().toString())
@@ -1062,13 +1041,13 @@ bool DockerDevice::handlesFile(const FilePath &filePath) const
const bool isDockerScheme = filePath.scheme() == Constants::DOCKER_DEVICE_SCHEME; const bool isDockerScheme = filePath.scheme() == Constants::DOCKER_DEVICE_SCHEME;
if (isDockerScheme && filePath.host() == d->dockerImageId()) if (isDockerScheme && filePath.host() == imageId())
return true; return true;
if (isDockerScheme && filePath.host() == d->repoAndTagEncoded()) if (isDockerScheme && filePath.host() == repoAndTagEncoded())
return true; return true;
if (isDockerScheme && filePath.host() == d->repoAndTag()) if (isDockerScheme && filePath.host() == repoAndTag())
return true; return true;
return false; return false;
@@ -1301,12 +1280,10 @@ public:
m_proxyModel->mapToSource(selectedRows.front())); m_proxyModel->mapToSource(selectedRows.front()));
QTC_ASSERT(item, return {}); QTC_ASSERT(item, return {});
auto deviceSettings = std::make_unique<DockerDeviceSettings>(); auto device = DockerDevice::create();
deviceSettings->repo.setValue(item->repo); device->repo.setValue(item->repo);
deviceSettings->tag.setValue(item->tag); device->tag.setValue(item->tag);
deviceSettings->imageId.setValue(item->imageId); device->imageId.setValue(item->imageId);
auto device = DockerDevice::create(std::move(deviceSettings));
return device; return device;
} }
@@ -1336,7 +1313,7 @@ DockerDeviceFactory::DockerDeviceFactory()
return wizard.device(); return wizard.device();
}); });
setConstructionFunction([this] { setConstructionFunction([this] {
auto device = DockerDevice::create(std::make_unique<DockerDeviceSettings>()); auto device = DockerDevice::create();
QMutexLocker lk(&m_deviceListMutex); QMutexLocker lk(&m_deviceListMutex);
m_existingDevices.push_back(device); m_existingDevices.push_back(device);
return device; return device;
@@ -1357,7 +1334,7 @@ expected_str<QPair<Utils::OsType, Utils::OsArch>> DockerDevicePrivate::osTypeAnd
Process proc; Process proc;
proc.setCommand( proc.setCommand(
{settings().dockerBinaryPath(), {settings().dockerBinaryPath(),
{"image", "inspect", repoAndTag(), "--format", "{{.Os}}\t{{.Architecture}}"}}); {"image", "inspect", q->repoAndTag(), "--format", "{{.Os}}\t{{.Architecture}}"}});
proc.runBlocking(); proc.runBlocking();
if (proc.result() != ProcessResult::FinishedWithSuccess) if (proc.result() != ProcessResult::FinishedWithSuccess)
return make_unexpected(Tr::tr("Failed to inspect image: %1").arg(proc.allOutput())); return make_unexpected(Tr::tr("Failed to inspect image: %1").arg(proc.allOutput()));
@@ -1398,8 +1375,8 @@ void DockerDevicePrivate::shutdown()
void DockerDevicePrivate::changeMounts(QStringList newMounts) void DockerDevicePrivate::changeMounts(QStringList newMounts)
{ {
newMounts.removeDuplicates(); newMounts.removeDuplicates();
if (deviceSettings->mounts.value() != newMounts) { if (q->mounts.value() != newMounts) {
deviceSettings->mounts.value() = newMounts; q->mounts.value() = newMounts;
stopCurrentContainer(); // Force re-start with new mounts. stopCurrentContainer(); // Force re-start with new mounts.
} }
} }
@@ -1407,7 +1384,7 @@ void DockerDevicePrivate::changeMounts(QStringList newMounts)
expected_str<FilePath> DockerDevicePrivate::localSource(const FilePath &other) const expected_str<FilePath> DockerDevicePrivate::localSource(const FilePath &other) const
{ {
const auto devicePath = FilePath::fromString(other.path()); const auto devicePath = FilePath::fromString(other.path());
for (const FilePath &mount : deviceSettings->mounts()) { for (const FilePath &mount : q->mounts()) {
const FilePath mountPoint = mount; const FilePath mountPoint = mount;
if (devicePath.isChildOf(mountPoint)) { if (devicePath.isChildOf(mountPoint)) {
const FilePath relativePath = devicePath.relativeChildPath(mountPoint); const FilePath relativePath = devicePath.relativeChildPath(mountPoint);
@@ -1423,7 +1400,7 @@ bool DockerDevicePrivate::ensureReachable(const FilePath &other)
if (other.isSameDevice(q->rootPath())) if (other.isSameDevice(q->rootPath()))
return true; return true;
for (const FilePath &mount : deviceSettings->mounts()) { for (const FilePath &mount : q->mounts()) {
if (other.isChildOf(mount)) if (other.isChildOf(mount))
return true; return true;

View File

@@ -12,46 +12,18 @@
namespace Docker::Internal { namespace Docker::Internal {
class DockerDeviceSettings : public ProjectExplorer::DeviceSettings
{
public:
DockerDeviceSettings();
void fromMap(const Utils::Store &map) override;
QString repoAndTag() const;
QString repoAndTagEncoded() const;
Utils::FilePath rootPath() const;
Utils::StringAspect imageId{this};
Utils::StringAspect repo{this};
Utils::StringAspect tag{this};
Utils::BoolAspect useLocalUidGid{this};
Utils::FilePathListAspect mounts{this};
Utils::BoolAspect keepEntryPoint{this};
Utils::BoolAspect enableLldbFlags{this};
Utils::FilePathAspect clangdExecutable{this};
Utils::StringSelectionAspect network{this};
Utils::StringAspect extraArgs{this};
Utils::TextDisplay containerStatus{this};
};
class DockerDevice : public ProjectExplorer::IDevice class DockerDevice : public ProjectExplorer::IDevice
{ {
public: public:
using Ptr = std::shared_ptr<DockerDevice>; using Ptr = std::shared_ptr<DockerDevice>;
using ConstPtr = std::shared_ptr<const DockerDevice>; using ConstPtr = std::shared_ptr<const DockerDevice>;
explicit DockerDevice(std::unique_ptr<DockerDeviceSettings> settings); DockerDevice();
~DockerDevice(); ~DockerDevice();
void shutdown(); void shutdown();
static Ptr create(std::unique_ptr<DockerDeviceSettings> settings) static Ptr create() { return Ptr(new DockerDevice); }
{
return Ptr(new DockerDevice(std::move(settings)));
}
Utils::CommandLine createCommandLine() const; Utils::CommandLine createCommandLine() const;
@@ -85,6 +57,22 @@ public:
bool prepareForBuild(const ProjectExplorer::Target *target) override; bool prepareForBuild(const ProjectExplorer::Target *target) override;
std::optional<Utils::FilePath> clangdExecutable() const override; std::optional<Utils::FilePath> clangdExecutable() const override;
QString repoAndTag() const;
QString repoAndTagEncoded() const;
Utils::StringAspect imageId{this};
Utils::StringAspect repo{this};
Utils::StringAspect tag{this};
Utils::BoolAspect useLocalUidGid{this};
Utils::FilePathListAspect mounts{this};
Utils::BoolAspect keepEntryPoint{this};
Utils::BoolAspect enableLldbFlags{this};
Utils::FilePathAspect clangdExecutableAspect{this};
Utils::StringSelectionAspect network{this};
Utils::StringAspect extraArgs{this};
Utils::TextDisplay containerStatus{this};
protected: protected:
void fromMap(const Utils::Store &map) final; void fromMap(const Utils::Store &map) final;
void toMap(Utils::Store &map) const final; void toMap(Utils::Store &map) const final;

View File

@@ -34,8 +34,6 @@ DockerDeviceWidget::DockerDeviceWidget(const IDevice::Ptr &device)
auto dockerDevice = std::dynamic_pointer_cast<DockerDevice>(device); auto dockerDevice = std::dynamic_pointer_cast<DockerDevice>(device);
QTC_ASSERT(dockerDevice, return); QTC_ASSERT(dockerDevice, return);
DockerDeviceSettings *deviceSettings = static_cast<DockerDeviceSettings *>(device->settings());
using namespace Layouting; using namespace Layouting;
auto daemonStateLabel = new QLabel(Tr::tr("Daemon state:")); auto daemonStateLabel = new QLabel(Tr::tr("Daemon state:"));
@@ -58,13 +56,13 @@ DockerDeviceWidget::DockerDeviceWidget(const IDevice::Ptr &device)
auto pathListLabel = new InfoLabel(Tr::tr("Paths to mount:")); auto pathListLabel = new InfoLabel(Tr::tr("Paths to mount:"));
pathListLabel->setAdditionalToolTip(Tr::tr("Source directory list should not be empty.")); pathListLabel->setAdditionalToolTip(Tr::tr("Source directory list should not be empty."));
auto markupMounts = [deviceSettings, pathListLabel] { auto markupMounts = [dockerDevice, pathListLabel] {
const bool isEmpty = deviceSettings->mounts.volatileValue().isEmpty(); const bool isEmpty = dockerDevice->mounts.volatileValue().isEmpty();
pathListLabel->setType(isEmpty ? InfoLabel::Warning : InfoLabel::None); pathListLabel->setType(isEmpty ? InfoLabel::Warning : InfoLabel::None);
}; };
markupMounts(); markupMounts();
connect(&deviceSettings->mounts, &FilePathListAspect::volatileValueChanged, this, markupMounts); connect(&dockerDevice->mounts, &FilePathListAspect::volatileValueChanged, this, markupMounts);
auto logView = new QTextBrowser; auto logView = new QTextBrowser;
connect(&m_kitItemDetector, &KitDetector::logOutput, connect(&m_kitItemDetector, &KitDetector::logOutput,
@@ -104,7 +102,7 @@ DockerDeviceWidget::DockerDeviceWidget(const IDevice::Ptr &device)
connect(autoDetectButton, connect(autoDetectButton,
&QPushButton::clicked, &QPushButton::clicked,
this, this,
[this, logView, dockerDevice, searchPaths, deviceSettings] { [this, logView, dockerDevice, searchPaths] {
logView->clear(); logView->clear();
expected_str<void> startResult = dockerDevice->updateContainerAccess(); expected_str<void> startResult = dockerDevice->updateContainerAccess();
@@ -121,7 +119,7 @@ DockerDeviceWidget::DockerDeviceWidget(const IDevice::Ptr &device)
}); });
if (!clangdPath.isEmpty()) if (!clangdPath.isEmpty())
deviceSettings->clangdExecutable.setValue(clangdPath); dockerDevice->clangdExecutableAspect.setValue(clangdPath);
m_kitItemDetector.autoDetect(dockerDevice->id().toString(), searchPaths()); m_kitItemDetector.autoDetect(dockerDevice->id().toString(), searchPaths());
@@ -169,20 +167,20 @@ DockerDeviceWidget::DockerDeviceWidget(const IDevice::Ptr &device)
Column { Column {
noMargin, noMargin,
Form { Form {
deviceSettings->repo, br, dockerDevice->repo, br,
deviceSettings->tag, br, dockerDevice->tag, br,
deviceSettings->imageId, br, dockerDevice->imageId, br,
daemonStateLabel, m_daemonReset, m_daemonState, br, daemonStateLabel, m_daemonReset, m_daemonState, br,
Tr::tr("Container state:"), deviceSettings->containerStatus, br, Tr::tr("Container state:"), dockerDevice->containerStatus, br,
deviceSettings->useLocalUidGid, br, dockerDevice->useLocalUidGid, br,
deviceSettings->keepEntryPoint, br, dockerDevice->keepEntryPoint, br,
deviceSettings->enableLldbFlags, br, dockerDevice->enableLldbFlags, br,
deviceSettings->clangdExecutable, br, dockerDevice->clangdExecutableAspect, br,
deviceSettings->network, br, dockerDevice->network, br,
deviceSettings->extraArgs, br, dockerDevice->extraArgs, br,
Column { Column {
pathListLabel, pathListLabel,
deviceSettings->mounts, dockerDevice->mounts,
}, br, }, br,
If { dockerDevice->isAutoDetected(), {}, {detectionControls} }, If { dockerDevice->isAutoDetected(), {}, {detectionControls} },
noMargin, noMargin,
@@ -199,7 +197,7 @@ DockerDeviceWidget::DockerDeviceWidget(const IDevice::Ptr &device)
}; };
QObject::connect(searchDirsComboBox, &QComboBox::activated, this, updateDirectoriesLineEdit); QObject::connect(searchDirsComboBox, &QComboBox::activated, this, updateDirectoriesLineEdit);
connect(deviceSettings, &AspectContainer::applied, this, [createLineLabel, dockerDevice] { connect(&*dockerDevice, &AspectContainer::applied, this, [createLineLabel, dockerDevice] {
createLineLabel->setText(dockerDevice->createCommandLine().toUserOutput()); createLineLabel->setText(dockerDevice->createCommandLine().toUserOutput());
}); });
} }

View File

@@ -107,7 +107,7 @@ IosDevice::IosDevice(CtorHelper)
: m_lastPort(Constants::IOS_DEVICE_PORT_START) : m_lastPort(Constants::IOS_DEVICE_PORT_START)
{ {
setType(Constants::IOS_DEVICE_TYPE); setType(Constants::IOS_DEVICE_TYPE);
settings()->displayName.setDefaultValue(IosDevice::name()); displayName.setDefaultValue(IosDevice::name());
setDisplayType(Tr::tr("iOS")); setDisplayType(Tr::tr("iOS"));
setMachineType(IDevice::Hardware); setMachineType(IDevice::Hardware);
setOsType(Utils::OsTypeMac); setOsType(Utils::OsTypeMac);
@@ -248,7 +248,7 @@ void IosDeviceManager::deviceConnected(const QString &uid, const QString &name)
if (!dev) { if (!dev) {
auto newDev = new IosDevice(uid); auto newDev = new IosDevice(uid);
if (!name.isNull()) if (!name.isNull())
newDev->settings()->displayName.setValue(name); newDev->displayName.setValue(name);
qCDebug(detectLog) << "adding ios device " << uid; qCDebug(detectLog) << "adding ios device " << uid;
devManager->addDevice(IDevice::ConstPtr(newDev)); devManager->addDevice(IDevice::ConstPtr(newDev));
} else if (dev->deviceState() != IDevice::DeviceConnected && } else if (dev->deviceState() != IDevice::DeviceConnected &&
@@ -364,7 +364,7 @@ void IosDeviceManager::deviceInfo(const QString &uid,
} }
if (!skipUpdate) { if (!skipUpdate) {
if (info.contains(kDeviceName)) if (info.contains(kDeviceName))
newDev->settings()->displayName.setValue(info.value(kDeviceName)); newDev->displayName.setValue(info.value(kDeviceName));
newDev->m_extraInfo = info; newDev->m_extraInfo = info;
newDev->m_handler = handler; newDev->m_handler = handler;
qCDebug(detectLog) << "updated info of ios device " << uid; qCDebug(detectLog) << "updated info of ios device " << uid;

View File

@@ -28,7 +28,7 @@ IosSimulator::IosSimulator(Id id)
setType(Constants::IOS_SIMULATOR_TYPE); setType(Constants::IOS_SIMULATOR_TYPE);
setMachineType(IDevice::Emulator); setMachineType(IDevice::Emulator);
setOsType(Utils::OsTypeMac); setOsType(Utils::OsTypeMac);
settings()->displayName.setDefaultValue(Tr::tr("iOS Simulator")); displayName.setDefaultValue(Tr::tr("iOS Simulator"));
setDisplayType(Tr::tr("iOS Simulator")); setDisplayType(Tr::tr("iOS Simulator"));
setDeviceState(DeviceStateUnknown); setDeviceState(DeviceStateUnknown);
} }

View File

@@ -16,7 +16,7 @@ McuSupportDevice::McuSupportDevice()
setupId(IDevice::AutoDetected, Constants::DEVICE_ID); setupId(IDevice::AutoDetected, Constants::DEVICE_ID);
setType(Constants::DEVICE_TYPE); setType(Constants::DEVICE_TYPE);
const QString displayNameAndType = Tr::tr("MCU Device"); const QString displayNameAndType = Tr::tr("MCU Device");
settings()->displayName.setDefaultValue(displayNameAndType); displayName.setDefaultValue(displayNameAndType);
setDisplayType(displayNameAndType); setDisplayType(displayNameAndType);
setDeviceState(IDevice::DeviceStateUnknown); setDeviceState(IDevice::DeviceStateUnknown);
setMachineType(IDevice::Hardware); setMachineType(IDevice::Hardware);

View File

@@ -42,7 +42,7 @@ DesktopDevice::DesktopDevice()
setupId(IDevice::AutoDetected, DESKTOP_DEVICE_ID); setupId(IDevice::AutoDetected, DESKTOP_DEVICE_ID);
setType(DESKTOP_DEVICE_TYPE); setType(DESKTOP_DEVICE_TYPE);
settings()->displayName.setDefaultValue(Tr::tr("Local PC")); displayName.setDefaultValue(Tr::tr("Local PC"));
setDisplayType(Tr::tr("Desktop")); setDisplayType(Tr::tr("Desktop"));
setDeviceState(IDevice::DeviceStateUnknown); setDeviceState(IDevice::DeviceStateUnknown);

View File

@@ -261,8 +261,7 @@ void DeviceManager::addDevice(const IDevice::ConstPtr &_device)
} }
// TODO: make it thread safe? // TODO: make it thread safe?
device->settings()->displayName.setValue( device->displayName.setValue(Utils::makeUniquelyNumbered(device->displayName(), names));
Utils::makeUniquelyNumbered(device->displayName(), names));
const int pos = d->indexForId(device->id()); const int pos = d->indexForId(device->id());
@@ -568,7 +567,7 @@ void ProjectExplorerTest::testDeviceManager()
TestDeviceFactory factory; TestDeviceFactory factory;
TestDevice::Ptr dev = IDevice::Ptr(new TestDevice); TestDevice::Ptr dev = IDevice::Ptr(new TestDevice);
dev->settings()->displayName.setValue(QLatin1String("blubbdiblubbfurz!")); dev->displayName.setValue(QLatin1String("blubbdiblubbfurz!"));
QVERIFY(dev->isAutoDetected()); QVERIFY(dev->isAutoDetected());
QCOMPARE(dev->deviceState(), IDevice::DeviceStateUnknown); QCOMPARE(dev->deviceState(), IDevice::DeviceStateUnknown);
QCOMPARE(dev->type(), TestDevice::testTypeId()); QCOMPARE(dev->type(), TestDevice::testTypeId());
@@ -629,7 +628,7 @@ void ProjectExplorerTest::testDeviceManager()
TestDevice::Ptr dev3 = IDevice::Ptr(new TestDevice); TestDevice::Ptr dev3 = IDevice::Ptr(new TestDevice);
QVERIFY(dev->id() != dev3->id()); QVERIFY(dev->id() != dev3->id());
dev3->settings()->displayName.setValue(dev->displayName()); dev3->displayName.setValue(dev->displayName());
mgr->addDevice(dev3); mgr->addDevice(dev3);
QCOMPARE(mgr->deviceAt(mgr->deviceCount() - 1)->displayName(), QCOMPARE(mgr->deviceAt(mgr->deviceCount() - 1)->displayName(),
QString(dev3->displayName() + QLatin1Char('2'))); QString(dev3->displayName() + QLatin1Char('2')));

View File

@@ -274,7 +274,7 @@ void DeviceSettingsWidget::setDeviceInfoWidgetsEnabled(bool enable)
void DeviceSettingsWidget::updateDeviceFromUi() void DeviceSettingsWidget::updateDeviceFromUi()
{ {
currentDevice()->settings()->apply(); currentDevice()->doApply();
if (m_configWidget) if (m_configWidget)
m_configWidget->updateDeviceFromUi(); m_configWidget->updateDeviceFromUi();
} }
@@ -340,7 +340,7 @@ void DeviceSettingsWidget::currentDeviceChanged(int index)
} }
Layouting::Column item{Layouting::noMargin}; Layouting::Column item{Layouting::noMargin};
device->settings()->displayName.addToLayout(item); device->displayName.addToLayout(item);
QWidget *newEdit = item.emerge(); QWidget *newEdit = item.emerge();
QLayoutItem *oldItem = m_generalFormLayout->replaceWidget(m_deviceNameEditWidget, newEdit); QLayoutItem *oldItem = m_generalFormLayout->replaceWidget(m_deviceNameEditWidget, newEdit);
QTC_CHECK(oldItem); QTC_CHECK(oldItem);

View File

@@ -120,16 +120,10 @@ const IDevice::MachineType DefaultMachineType = IDevice::Hardware;
const int DefaultTimeout = 10; const int DefaultTimeout = 10;
namespace Internal { namespace Internal {
class IDevicePrivate class IDevicePrivate
{ {
public: public:
IDevicePrivate(std::unique_ptr<DeviceSettings> s)
: settings(std::move(s))
{
if (!settings)
settings = std::make_unique<DeviceSettings>();
}
QString displayType; QString displayType;
Id type; Id type;
IDevice::Origin origin = IDevice::AutoDetected; IDevice::Origin origin = IDevice::AutoDetected;
@@ -153,12 +147,14 @@ public:
QList<IDevice::DeviceAction> deviceActions; QList<IDevice::DeviceAction> deviceActions;
Store extraData; Store extraData;
IDevice::OpenTerminal openTerminal; IDevice::OpenTerminal openTerminal;
std::unique_ptr<DeviceSettings> settings;
}; };
} // namespace Internal } // namespace Internal
DeviceSettings::DeviceSettings() DeviceTester::DeviceTester(QObject *parent) : QObject(parent) { }
IDevice::IDevice()
: d(new Internal::IDevicePrivate)
{ {
setAutoApply(false); setAutoApply(false);
@@ -201,13 +197,6 @@ DeviceSettings::DeviceSettings()
}); });
} }
DeviceTester::DeviceTester(QObject *parent) : QObject(parent) { }
IDevice::IDevice(std::unique_ptr<DeviceSettings> settings)
: d(new Internal::IDevicePrivate(std::move(settings)))
{
}
IDevice::~IDevice() = default; IDevice::~IDevice() = default;
void IDevice::setOpenTerminal(const IDevice::OpenTerminal &openTerminal) void IDevice::setOpenTerminal(const IDevice::OpenTerminal &openTerminal)
@@ -319,11 +308,6 @@ expected_str<Environment> IDevice::systemEnvironmentWithError() const
return access->deviceEnvironment(); return access->deviceEnvironment();
} }
QString IDevice::displayName() const
{
return d->settings->displayName();
}
QString IDevice::displayType() const QString IDevice::displayType() const
{ {
return d->displayType; return d->displayType;
@@ -495,8 +479,8 @@ Id IDevice::idFromMap(const Store &map)
void IDevice::fromMap(const Store &map) void IDevice::fromMap(const Store &map)
{ {
AspectContainer::fromMap(map);
d->type = typeFromMap(map); d->type = typeFromMap(map);
settings()->fromMap(map);
d->id = Id::fromSetting(map.value(IdKey)); d->id = Id::fromSetting(map.value(IdKey));
d->osType = osTypeFromString(map.value(ClientOsTypeKey).toString()).value_or(OsTypeLinux); d->osType = osTypeFromString(map.value(ClientOsTypeKey).toString()).value_or(OsTypeLinux);
@@ -543,7 +527,7 @@ void IDevice::fromMap(const Store &map)
void IDevice::toMap(Store &map) const void IDevice::toMap(Store &map) const
{ {
d->settings->toMap(map); AspectContainer::toMap(map);
map.insert(TypeKey, d->type.toString()); map.insert(TypeKey, d->type.toString());
map.insert(ClientOsTypeKey, osTypeToString(d->osType)); map.insert(ClientOsTypeKey, osTypeToString(d->osType));
@@ -587,11 +571,6 @@ IDevice::Ptr IDevice::clone() const
return device; return device;
} }
DeviceSettings *IDevice::settings() const
{
return d->settings.get();
}
QString IDevice::deviceStateToString() const QString IDevice::deviceStateToString() const
{ {
switch (d->deviceState) { switch (d->deviceState) {
@@ -725,6 +704,11 @@ std::optional<Utils::FilePath> IDevice::clangdExecutable() const
return std::nullopt; return std::nullopt;
} }
void IDevice::doApply() const
{
const_cast<IDevice *>(this)->apply();
}
void DeviceProcessSignalOperation::setDebuggerCommand(const FilePath &cmd) void DeviceProcessSignalOperation::setDebuggerCommand(const FilePath &cmd)
{ {
m_debuggerCommand = cmd; m_debuggerCommand = cmd;

View File

@@ -83,16 +83,9 @@ public:
std::function<QList<Utils::Port>(const QByteArray &commandOutput)> parsePorts; std::function<QList<Utils::Port>(const QByteArray &commandOutput)> parsePorts;
}; };
class PROJECTEXPLORER_EXPORT DeviceSettings : public Utils::AspectContainer
{
public:
DeviceSettings();
Utils::StringAspect displayName{this};
};
// See cpp file for documentation. // See cpp file for documentation.
class PROJECTEXPLORER_EXPORT IDevice : public std::enable_shared_from_this<IDevice> class PROJECTEXPLORER_EXPORT IDevice
: public Utils::AspectContainer, public std::enable_shared_from_this<IDevice>
{ {
friend class Internal::IDevicePrivate; friend class Internal::IDevicePrivate;
public: public:
@@ -107,9 +100,7 @@ public:
virtual Ptr clone() const; virtual Ptr clone() const;
DeviceSettings *settings() const; Utils::StringAspect displayName{this};
QString displayName() const;
// Provide some information on the device suitable for formated // Provide some information on the device suitable for formated
// output, e.g. in tool tips. Get a list of name value pairs. // output, e.g. in tool tips. Get a list of name value pairs.
@@ -229,8 +220,10 @@ public:
virtual void checkOsType() {} virtual void checkOsType() {}
void doApply() const;
protected: protected:
IDevice(std::unique_ptr<DeviceSettings> settings = nullptr); IDevice();
virtual void fromMap(const Utils::Store &map); virtual void fromMap(const Utils::Store &map);
virtual void toMap(Utils::Store &map) const; virtual void toMap(Utils::Store &map) const;

View File

@@ -79,7 +79,7 @@ IDevice::Ptr IDeviceFactory::construct() const
IDevice::Ptr device = m_constructor(); IDevice::Ptr device = m_constructor();
QTC_ASSERT(device, return {}); QTC_ASSERT(device, return {});
device->settings()->displayName.setDefaultValue(displayName()); device->displayName.setDefaultValue(displayName());
return device; return device;
} }

View File

@@ -1313,7 +1313,7 @@ void BuildDeviceKitAspectFactory::addToMacroExpander(Kit *kit, MacroExpander *ex
}); });
expander->registerVariable("BuildDevice:Name", Tr::tr("Build device name"), [kit] { expander->registerVariable("BuildDevice:Name", Tr::tr("Build device name"), [kit] {
const IDevice::ConstPtr device = BuildDeviceKitAspect::device(kit); const IDevice::ConstPtr device = BuildDeviceKitAspect::device(kit);
return device ? device->settings()->displayName() : QString(); return device ? device->displayName() : QString();
}); });
expander expander
->registerFileVariables("BuildDevice::Root", Tr::tr("Build device root directory"), [kit] { ->registerFileVariables("BuildDevice::Root", Tr::tr("Build device root directory"), [kit] {

View File

@@ -64,7 +64,7 @@ public:
QnxDevice() QnxDevice()
{ {
setDisplayType(Tr::tr("QNX")); setDisplayType(Tr::tr("QNX"));
settings()->displayName.setDefaultValue(Tr::tr("QNX Device")); displayName.setDefaultValue(Tr::tr("QNX Device"));
setOsType(OsTypeOtherUnix); setOsType(OsTypeOtherUnix);
setupId(IDevice::ManuallyAdded); setupId(IDevice::ManuallyAdded);
setType(Constants::QNX_QNX_OS_TYPE); setType(Constants::QNX_QNX_OS_TYPE);

View File

@@ -307,12 +307,6 @@ public:
LinuxDevicePrivate *m_dev; LinuxDevicePrivate *m_dev;
}; };
class LinuxDeviceSettings : public DeviceSettings
{
public:
LinuxDeviceSettings() { displayName.setDefaultValue(Tr::tr("Remote Linux Device")); }
};
class LinuxDevicePrivate class LinuxDevicePrivate
{ {
public: public:
@@ -1019,12 +1013,12 @@ private:
// LinuxDevice // LinuxDevice
LinuxDevice::LinuxDevice() LinuxDevice::LinuxDevice()
: IDevice(std::make_unique<LinuxDeviceSettings>()) : d(new LinuxDevicePrivate(this))
, d(new LinuxDevicePrivate(this))
{ {
setFileAccess(&d->m_fileAccess); setFileAccess(&d->m_fileAccess);
setDisplayType(Tr::tr("Remote Linux")); setDisplayType(Tr::tr("Remote Linux"));
setOsType(OsTypeLinux); setOsType(OsTypeLinux);
displayName.setDefaultValue(Tr::tr("Remote Linux Device"));
setupId(IDevice::ManuallyAdded, Utils::Id()); setupId(IDevice::ManuallyAdded, Utils::Id());
setType(Constants::GenericLinuxOsType); setType(Constants::GenericLinuxOsType);

View File

@@ -77,7 +77,7 @@ private:
&& !m_userNameLineEdit->text().trimmed().isEmpty(); && !m_userNameLineEdit->text().trimmed().isEmpty();
} }
bool validatePage() final { bool validatePage() final {
m_device->settings()->displayName.setValue(m_nameLineEdit->text().trimmed()); m_device->displayName.setValue(m_nameLineEdit->text().trimmed());
SshParameters sshParams = m_device->sshParameters(); SshParameters sshParams = m_device->sshParameters();
sshParams.setHost(m_hostNameLineEdit->text().trimmed()); sshParams.setHost(m_hostNameLineEdit->text().trimmed());
sshParams.setUserName(m_userNameLineEdit->text().trimmed()); sshParams.setUserName(m_userNameLineEdit->text().trimmed());

View File

@@ -35,7 +35,7 @@ public:
setupId(IDevice::AutoDetected, Constants::WEBASSEMBLY_DEVICE_DEVICE_ID); setupId(IDevice::AutoDetected, Constants::WEBASSEMBLY_DEVICE_DEVICE_ID);
setType(Constants::WEBASSEMBLY_DEVICE_TYPE); setType(Constants::WEBASSEMBLY_DEVICE_TYPE);
const QString displayNameAndType = Tr::tr("Web Browser"); const QString displayNameAndType = Tr::tr("Web Browser");
settings()->displayName.setDefaultValue(displayNameAndType); displayName.setDefaultValue(displayNameAndType);
setDisplayType(displayNameAndType); setDisplayType(displayNameAndType);
setDeviceState(IDevice::DeviceStateUnknown); setDeviceState(IDevice::DeviceStateUnknown);
setMachineType(IDevice::Hardware); setMachineType(IDevice::Hardware);