RemoteLinux: Inline wizard pages

Change-Id: I058c001e34653f7dfa96cd8886daea84be7dc6a1
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Jarek Kobus
2023-07-21 01:02:08 +02:00
parent 760b8d7139
commit 4267d6ad81
5 changed files with 204 additions and 351 deletions

View File

@@ -8,7 +8,6 @@ add_qtc_plugin(RemoteLinux
genericdirectuploadstep.cpp genericdirectuploadstep.h
genericlinuxdeviceconfigurationwidget.cpp genericlinuxdeviceconfigurationwidget.h
genericlinuxdeviceconfigurationwizard.cpp genericlinuxdeviceconfigurationwizard.h
genericlinuxdeviceconfigurationwizardpages.cpp genericlinuxdeviceconfigurationwizardpages.h
killappstep.cpp killappstep.h
linuxdevice.cpp linuxdevice.h
linuxdevicetester.cpp linuxdevicetester.h

View File

@@ -3,21 +3,220 @@
#include "genericlinuxdeviceconfigurationwizard.h"
#include "genericlinuxdeviceconfigurationwizardpages.h"
#include "publickeydeploymentdialog.h"
#include "remotelinuxtr.h"
#include "sshkeycreationdialog.h"
#include <coreplugin/icore.h>
#include <projectexplorer/devicesupport/idevice.h>
#include <projectexplorer/devicesupport/sshparameters.h>
#include <utils/fancylineedit.h>
#include <utils/fileutils.h>
#include <utils/layoutbuilder.h>
#include <utils/pathchooser.h>
#include <utils/utilsicons.h>
#include <QLabel>
#include <QPushButton>
#include <QSpinBox>
using namespace ProjectExplorer;
using namespace Utils;
namespace RemoteLinux {
class SetupPage : public QWizardPage
{
public:
explicit SetupPage(QWidget *parent = nullptr)
: QWizardPage(parent)
{
setTitle(Tr::tr("Connection"));
setWindowTitle(Tr::tr("WizardPage"));
m_nameLineEdit = new FancyLineEdit(this);
m_nameLineEdit->setHistoryCompleter("DeviceName");
m_hostNameLineEdit = new FancyLineEdit(this);
m_hostNameLineEdit->setHistoryCompleter("HostName");
m_sshPortSpinBox = new QSpinBox(this);
m_userNameLineEdit = new FancyLineEdit(this);
m_userNameLineEdit->setHistoryCompleter("UserName");
using namespace Layouting;
Form {
Tr::tr("The name to identify this configuration:"), m_nameLineEdit, br,
Tr::tr("The device's host name or IP address:"), m_hostNameLineEdit, st, br,
Tr::tr("The device's SSH port number:"), m_sshPortSpinBox, st, br,
Tr::tr("The username to log into the device:"), m_userNameLineEdit, st, br
}.attachTo(this);
setSubTitle(QLatin1String(" ")); // For Qt bug (background color)
connect(m_nameLineEdit, &QLineEdit::textChanged, this, &QWizardPage::completeChanged);
connect(m_hostNameLineEdit, &QLineEdit::textChanged, this, &QWizardPage::completeChanged);
connect(m_sshPortSpinBox, &QSpinBox::valueChanged, this, &QWizardPage::completeChanged);
connect(m_userNameLineEdit, &QLineEdit::textChanged, this, &QWizardPage::completeChanged);
}
void setDevice(const ProjectExplorer::IDevicePtr &device) { m_device = device; }
private:
void initializePage() final {
m_nameLineEdit->setText(m_device->displayName());
m_hostNameLineEdit->setText(m_device->sshParameters().host());
m_sshPortSpinBox->setValue(22);
m_sshPortSpinBox->setRange(1, 65535);
m_userNameLineEdit->setText(m_device->sshParameters().userName());
}
bool isComplete() const final {
return !configurationName().isEmpty()
&& !m_hostNameLineEdit->text().trimmed().isEmpty()
&& !m_userNameLineEdit->text().trimmed().isEmpty();
}
bool validatePage() final {
m_device->setDisplayName(configurationName());
SshParameters sshParams = m_device->sshParameters();
sshParams.setHost(m_hostNameLineEdit->text().trimmed());
sshParams.setUserName(m_userNameLineEdit->text().trimmed());
sshParams.setPort(m_sshPortSpinBox->value());
m_device->setSshParameters(sshParams);
return true;
}
QString configurationName() const { return m_nameLineEdit->text().trimmed(); }
FancyLineEdit *m_nameLineEdit;
FancyLineEdit *m_hostNameLineEdit;
QSpinBox *m_sshPortSpinBox;
FancyLineEdit *m_userNameLineEdit;
IDevicePtr m_device;
};
class KeyDeploymentPage : public QWizardPage
{
public:
explicit KeyDeploymentPage(QWidget *parent = nullptr)
: QWizardPage(parent)
{
setTitle(Tr::tr("Key Deployment"));
setSubTitle(" ");
const QString info = Tr::tr("We recommend that you log into your device using public key "
"authentication.\n"
"If your device is already set up for this, you do not have to do "
"anything here.\n"
"Otherwise, please deploy the public key for the private key "
"with which to connect in the future.\n"
"If you do not have a private key yet, you can also "
"create one here.");
m_keyFileChooser.setExpectedKind(PathChooser::File);
m_keyFileChooser.setHistoryCompleter("Ssh.KeyFile.History");
m_keyFileChooser.setPromptDialogTitle(Tr::tr("Choose a Private Key File"));
auto const deployButton = new QPushButton(Tr::tr("Deploy Public Key"), this);
connect(deployButton, &QPushButton::clicked, this, [this] {
PublicKeyDeploymentDialog dlg(m_device,
m_keyFileChooser.filePath().stringAppended(".pub"), this);
m_iconLabel.setPixmap((dlg.exec() == QDialog::Accepted ? Icons::OK : Icons::BROKEN).pixmap());
});
auto const createButton = new QPushButton(Tr::tr("Create New Key Pair"), this);
connect(createButton, &QPushButton::clicked, this, [this] {
SshKeyCreationDialog dlg(this);
if (dlg.exec() == QDialog::Accepted)
m_keyFileChooser.setFilePath(dlg.privateKeyFilePath());
});
auto const mainLayout = new QVBoxLayout(this);
auto const keyLayout = new QHBoxLayout;
auto const deployLayout = new QHBoxLayout;
mainLayout->addWidget(new QLabel(info));
keyLayout->addWidget(new QLabel(Tr::tr("Private key file:")));
keyLayout->addWidget(&m_keyFileChooser);
keyLayout->addWidget(createButton);
keyLayout->addStretch();
mainLayout->addLayout(keyLayout);
deployLayout->addWidget(deployButton);
deployLayout->addWidget(&m_iconLabel);
deployLayout->addStretch();
mainLayout->addLayout(deployLayout);
connect(&m_keyFileChooser, &PathChooser::textChanged, this, [this, deployButton] {
deployButton->setEnabled(m_keyFileChooser.filePath().exists());
m_iconLabel.clear();
emit completeChanged();
});
for (const FilePath &defaultKey : defaultKeys()) {
if (defaultKey.exists()) {
m_keyFileChooser.setFilePath(defaultKey);
break;
}
}
}
void setDevice(const ProjectExplorer::IDevicePtr &device) { m_device = device; }
private:
void initializePage() final {
if (!m_device->sshParameters().privateKeyFile.isEmpty())
m_keyFileChooser.setFilePath(m_keyFileChooser.filePath());
m_iconLabel.clear();
}
bool isComplete() const final {
return m_keyFileChooser.filePath().toString().isEmpty()
|| m_keyFileChooser.filePath().exists();
}
bool validatePage() final {
if (!defaultKeys().contains(m_keyFileChooser.filePath())) {
SshParameters sshParams = m_device->sshParameters();
sshParams.authenticationType = SshParameters::AuthenticationTypeSpecificKey;
sshParams.privateKeyFile = m_keyFileChooser.filePath();
m_device->setSshParameters(sshParams);
}
return true;
}
FilePaths defaultKeys() const {
const FilePath baseDir = FileUtils::homePath() / ".ssh";
return {baseDir / "id_rsa", baseDir / "id_ecdsa", baseDir / "id_ed25519"};
}
PathChooser m_keyFileChooser;
QLabel m_iconLabel;
IDevicePtr m_device;
};
class FinalPage final : public QWizardPage
{
public:
FinalPage(QWidget *parent = nullptr)
: QWizardPage(parent)
{
setTitle(Tr::tr("Summary"));
setSubTitle(QLatin1String(" ")); // For Qt bug (background color)
m_infoLabel.setWordWrap(true);
auto const layout = new QVBoxLayout(this);
layout->addWidget(&m_infoLabel);
}
private:
void initializePage() final {
m_infoLabel.setText(Tr::tr("The new device configuration will now be created.\n"
"In addition, device connectivity will be tested."));
}
QLabel m_infoLabel;
};
GenericLinuxDeviceConfigurationWizard::GenericLinuxDeviceConfigurationWizard(
const QString &title, const ProjectExplorer::IDevicePtr &device)
: Utils::Wizard(Core::ICore::dialogParent())
: Wizard(Core::ICore::dialogParent())
{
setWindowTitle(title);
auto setupPage = new GenericLinuxDeviceConfigurationWizardSetupPage;
auto keyDeploymentPage = new GenericLinuxDeviceConfigurationWizardKeyDeploymentPage;
auto finalPage = new GenericLinuxDeviceConfigurationWizardFinalPage;
auto setupPage = new SetupPage;
auto keyDeploymentPage = new KeyDeploymentPage;
auto finalPage = new FinalPage;
addPage(setupPage);
addPage(keyDeploymentPage);

View File

@@ -1,265 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "genericlinuxdeviceconfigurationwizardpages.h"
#include "publickeydeploymentdialog.h"
#include "remotelinuxtr.h"
#include "sshkeycreationdialog.h"
#include <projectexplorer/devicesupport/sshparameters.h>
#include <utils/filepath.h>
#include <utils/fileutils.h>
#include <utils/fancylineedit.h>
#include <utils/layoutbuilder.h>
#include <utils/pathchooser.h>
#include <utils/utilsicons.h>
#include <QHBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <QSpinBox>
using namespace ProjectExplorer;
using namespace Utils;
namespace RemoteLinux {
namespace Internal {
class GenericLinuxDeviceConfigurationWizardSetupPagePrivate
{
public:
FancyLineEdit *nameLineEdit;
FancyLineEdit *hostNameLineEdit;
QSpinBox *sshPortSpinBox;
FancyLineEdit *userNameLineEdit;
IDevicePtr device;
};
class GenericLinuxDeviceConfigurationWizardFinalPagePrivate
{
public:
QLabel infoLabel;
};
} // namespace Internal
GenericLinuxDeviceConfigurationWizardSetupPage::GenericLinuxDeviceConfigurationWizardSetupPage(
QWidget *parent) :
QWizardPage(parent), d(new Internal::GenericLinuxDeviceConfigurationWizardSetupPagePrivate)
{
setTitle(Tr::tr("Connection"));
setWindowTitle(Tr::tr("WizardPage"));
d->nameLineEdit = new FancyLineEdit(this);
d->nameLineEdit->setHistoryCompleter("DeviceName");
d->hostNameLineEdit = new FancyLineEdit(this);
d->hostNameLineEdit->setHistoryCompleter("HostName");
d->sshPortSpinBox = new QSpinBox(this);
d->userNameLineEdit = new FancyLineEdit(this);
d->userNameLineEdit->setHistoryCompleter("UserName");
using namespace Layouting;
Form {
Tr::tr("The name to identify this configuration:"), d->nameLineEdit, br,
Tr::tr("The device's host name or IP address:"), d->hostNameLineEdit, st, br,
Tr::tr("The device's SSH port number:"), d->sshPortSpinBox, st, br,
Tr::tr("The username to log into the device:"), d->userNameLineEdit, st, br
}.attachTo(this);
setSubTitle(QLatin1String(" ")); // For Qt bug (background color)
connect(d->nameLineEdit, &QLineEdit::textChanged, this, &QWizardPage::completeChanged);
connect(d->hostNameLineEdit, &QLineEdit::textChanged, this, &QWizardPage::completeChanged);
connect(d->sshPortSpinBox, &QSpinBox::valueChanged, this, &QWizardPage::completeChanged);
connect(d->userNameLineEdit, &QLineEdit::textChanged, this, &QWizardPage::completeChanged);
}
GenericLinuxDeviceConfigurationWizardSetupPage::~GenericLinuxDeviceConfigurationWizardSetupPage()
{
delete d;
}
void GenericLinuxDeviceConfigurationWizardSetupPage::initializePage()
{
d->nameLineEdit->setText(d->device->displayName());
d->hostNameLineEdit->setText(d->device->sshParameters().host());
d->sshPortSpinBox->setValue(22);
d->sshPortSpinBox->setRange(1, 65535);
d->userNameLineEdit->setText(d->device->sshParameters().userName());
}
bool GenericLinuxDeviceConfigurationWizardSetupPage::isComplete() const
{
return !configurationName().isEmpty()
&& !d->hostNameLineEdit->text().trimmed().isEmpty()
&& !d->userNameLineEdit->text().trimmed().isEmpty();
}
bool GenericLinuxDeviceConfigurationWizardSetupPage::validatePage()
{
d->device->setDisplayName(configurationName());
SshParameters sshParams = d->device->sshParameters();
sshParams.setHost(d->hostNameLineEdit->text().trimmed());
sshParams.setUserName(d->userNameLineEdit->text().trimmed());
sshParams.setPort(d->sshPortSpinBox->value());
d->device->setSshParameters(sshParams);
return true;
}
QString GenericLinuxDeviceConfigurationWizardSetupPage::configurationName() const
{
return d->nameLineEdit->text().trimmed();
}
void GenericLinuxDeviceConfigurationWizardSetupPage::setDevice(
const ProjectExplorer::IDevicePtr &device)
{
d->device = device;
}
GenericLinuxDeviceConfigurationWizardFinalPage::GenericLinuxDeviceConfigurationWizardFinalPage(
QWidget *parent)
: QWizardPage(parent), d(new Internal::GenericLinuxDeviceConfigurationWizardFinalPagePrivate)
{
setTitle(Tr::tr("Summary"));
setSubTitle(QLatin1String(" ")); // For Qt bug (background color)
d->infoLabel.setWordWrap(true);
auto const layout = new QVBoxLayout(this);
layout->addWidget(&d->infoLabel);
}
GenericLinuxDeviceConfigurationWizardFinalPage::~GenericLinuxDeviceConfigurationWizardFinalPage()
{
delete d;
}
void GenericLinuxDeviceConfigurationWizardFinalPage::initializePage()
{
d->infoLabel.setText(infoText());
}
QString GenericLinuxDeviceConfigurationWizardFinalPage::infoText() const
{
return Tr::tr("The new device configuration will now be created.\n"
"In addition, device connectivity will be tested.");
}
struct GenericLinuxDeviceConfigurationWizardKeyDeploymentPage::Private
{
FilePaths defaultKeys() const
{
const FilePath baseDir = FileUtils::homePath() / ".ssh";
return {baseDir / "id_rsa", baseDir / "id_ecdsa", baseDir / "id_ed25519"};
}
PathChooser keyFileChooser;
QLabel iconLabel;
IDevicePtr device;
};
GenericLinuxDeviceConfigurationWizardKeyDeploymentPage::GenericLinuxDeviceConfigurationWizardKeyDeploymentPage(QWidget *parent)
: QWizardPage(parent), d(new Private)
{
setTitle(Tr::tr("Key Deployment"));
setSubTitle(" ");
const QString info = Tr::tr("We recommend that you log into your device using public key "
"authentication.\n"
"If your device is already set up for this, you do not have to do "
"anything here.\n"
"Otherwise, please deploy the public key for the private key "
"with which to connect in the future.\n"
"If you do not have a private key yet, you can also "
"create one here.");
d->keyFileChooser.setExpectedKind(PathChooser::File);
d->keyFileChooser.setHistoryCompleter("Ssh.KeyFile.History");
d->keyFileChooser.setPromptDialogTitle(Tr::tr("Choose a Private Key File"));
auto const deployButton = new QPushButton(Tr::tr("Deploy Public Key"), this);
connect(deployButton, &QPushButton::clicked,
this, &GenericLinuxDeviceConfigurationWizardKeyDeploymentPage::deployKey);
auto const createButton = new QPushButton(Tr::tr("Create New Key Pair"), this);
connect(createButton, &QPushButton::clicked,
this, &GenericLinuxDeviceConfigurationWizardKeyDeploymentPage::createKey);
auto const mainLayout = new QVBoxLayout(this);
auto const keyLayout = new QHBoxLayout;
auto const deployLayout = new QHBoxLayout;
mainLayout->addWidget(new QLabel(info));
keyLayout->addWidget(new QLabel(Tr::tr("Private key file:")));
keyLayout->addWidget(&d->keyFileChooser);
keyLayout->addWidget(createButton);
keyLayout->addStretch();
mainLayout->addLayout(keyLayout);
deployLayout->addWidget(deployButton);
deployLayout->addWidget(&d->iconLabel);
deployLayout->addStretch();
mainLayout->addLayout(deployLayout);
connect(&d->keyFileChooser, &PathChooser::textChanged, this, [this, deployButton] {
deployButton->setEnabled(d->keyFileChooser.filePath().exists());
d->iconLabel.clear();
emit completeChanged();
});
for (const FilePath &defaultKey : d->defaultKeys()) {
if (defaultKey.exists()) {
d->keyFileChooser.setFilePath(defaultKey);
break;
}
}
}
GenericLinuxDeviceConfigurationWizardKeyDeploymentPage::~GenericLinuxDeviceConfigurationWizardKeyDeploymentPage()
{
delete d;
}
void GenericLinuxDeviceConfigurationWizardKeyDeploymentPage::setDevice(
const ProjectExplorer::IDevicePtr &device)
{
d->device = device;
}
void GenericLinuxDeviceConfigurationWizardKeyDeploymentPage::initializePage()
{
if (!d->device->sshParameters().privateKeyFile.isEmpty())
d->keyFileChooser.setFilePath(privateKeyFilePath());
d->iconLabel.clear();
}
bool GenericLinuxDeviceConfigurationWizardKeyDeploymentPage::isComplete() const
{
return d->keyFileChooser.filePath().toString().isEmpty() || d->keyFileChooser.filePath().exists();
}
bool GenericLinuxDeviceConfigurationWizardKeyDeploymentPage::validatePage()
{
if (!d->defaultKeys().contains(d->keyFileChooser.filePath())) {
SshParameters sshParams = d->device->sshParameters();
sshParams.authenticationType = SshParameters::AuthenticationTypeSpecificKey;
sshParams.privateKeyFile = d->keyFileChooser.filePath();
d->device->setSshParameters(sshParams);
}
return true;
}
FilePath GenericLinuxDeviceConfigurationWizardKeyDeploymentPage::privateKeyFilePath() const
{
return d->keyFileChooser.filePath();
}
void GenericLinuxDeviceConfigurationWizardKeyDeploymentPage::createKey()
{
SshKeyCreationDialog dlg(this);
if (dlg.exec() == QDialog::Accepted)
d->keyFileChooser.setFilePath(dlg.privateKeyFilePath());
}
void GenericLinuxDeviceConfigurationWizardKeyDeploymentPage::deployKey()
{
PublicKeyDeploymentDialog dlg(d->device, privateKeyFilePath().stringAppended(".pub"), this);
d->iconLabel.setPixmap((dlg.exec() == QDialog::Accepted ? Icons::OK : Icons::BROKEN).pixmap());
}
} // namespace RemoteLinux

View File

@@ -1,78 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#pragma once
#include "remotelinux_export.h"
#include "linuxdevice.h"
#include <QWizardPage>
namespace RemoteLinux {
class LinuxDevice;
namespace Internal {
class GenericLinuxDeviceConfigurationWizardSetupPagePrivate;
class GenericLinuxDeviceConfigurationWizardFinalPagePrivate;
} // namespace Internal
class REMOTELINUX_EXPORT GenericLinuxDeviceConfigurationWizardSetupPage : public QWizardPage
{
Q_OBJECT
public:
explicit GenericLinuxDeviceConfigurationWizardSetupPage(QWidget *parent = nullptr);
~GenericLinuxDeviceConfigurationWizardSetupPage() override;
void setDevice(const ProjectExplorer::IDevicePtr &device);
private:
void initializePage() override;
bool isComplete() const override;
bool validatePage() override;
QString configurationName() const;
Internal::GenericLinuxDeviceConfigurationWizardSetupPagePrivate * const d;
};
class REMOTELINUX_EXPORT GenericLinuxDeviceConfigurationWizardKeyDeploymentPage : public QWizardPage
{
Q_OBJECT
public:
explicit GenericLinuxDeviceConfigurationWizardKeyDeploymentPage(QWidget *parent = nullptr);
~GenericLinuxDeviceConfigurationWizardKeyDeploymentPage() override;
void setDevice(const ProjectExplorer::IDevicePtr &device);
private:
void initializePage() override;
bool isComplete() const override;
bool validatePage() override;
Utils::FilePath privateKeyFilePath() const;
void createKey();
void deployKey();
struct Private;
Private * const d;
};
class REMOTELINUX_EXPORT GenericLinuxDeviceConfigurationWizardFinalPage final : public QWizardPage
{
Q_OBJECT
public:
GenericLinuxDeviceConfigurationWizardFinalPage(QWidget *parent = nullptr);
~GenericLinuxDeviceConfigurationWizardFinalPage() override;
protected:
virtual QString infoText() const;
private:
void initializePage() override;
Internal::GenericLinuxDeviceConfigurationWizardFinalPagePrivate * const d;
};
} // namespace RemoteLinux

View File

@@ -25,8 +25,6 @@ Project {
"genericlinuxdeviceconfigurationwidget.h",
"genericlinuxdeviceconfigurationwizard.cpp",
"genericlinuxdeviceconfigurationwizard.h",
"genericlinuxdeviceconfigurationwizardpages.cpp",
"genericlinuxdeviceconfigurationwizardpages.h",
"killappstep.cpp",
"killappstep.h",
"linuxdevice.cpp",