Milestone 8 UX: folder tree workflows, about dialog, and app icon polish
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
#include <QComboBox>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QFileDialog>
|
||||
#include <QFileInfo>
|
||||
#include <QFormLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
@@ -24,6 +25,28 @@ int standardPortForProtocol(const QString& protocol)
|
||||
}
|
||||
return 22; // SSH default
|
||||
}
|
||||
|
||||
QString normalizedProtocol(const QString& protocol)
|
||||
{
|
||||
if (protocol.compare(QStringLiteral("RDP"), Qt::CaseInsensitive) == 0) {
|
||||
return QStringLiteral("RDP");
|
||||
}
|
||||
if (protocol.compare(QStringLiteral("VNC"), Qt::CaseInsensitive) == 0) {
|
||||
return QStringLiteral("VNC");
|
||||
}
|
||||
return QStringLiteral("SSH");
|
||||
}
|
||||
|
||||
QString normalizedAuthMode(const QString& protocol, const QString& authMode)
|
||||
{
|
||||
if (protocol != QStringLiteral("SSH")) {
|
||||
return QStringLiteral("Password");
|
||||
}
|
||||
if (authMode.compare(QStringLiteral("Private Key"), Qt::CaseInsensitive) == 0) {
|
||||
return QStringLiteral("Private Key");
|
||||
}
|
||||
return QStringLiteral("Password");
|
||||
}
|
||||
}
|
||||
|
||||
ProfileDialog::ProfileDialog(QWidget* parent)
|
||||
@@ -33,15 +56,18 @@ ProfileDialog::ProfileDialog(QWidget* parent)
|
||||
m_portInput(new QSpinBox(this)),
|
||||
m_usernameInput(new QLineEdit(this)),
|
||||
m_domainInput(new QLineEdit(this)),
|
||||
m_tagsInput(new QLineEdit(this)),
|
||||
m_protocolInput(new QComboBox(this)),
|
||||
m_authModeInput(new QComboBox(this)),
|
||||
m_privateKeyPathInput(new QLineEdit(this)),
|
||||
m_browsePrivateKeyButton(new QPushButton(QStringLiteral("Browse"), this)),
|
||||
m_knownHostsPolicyInput(new QComboBox(this)),
|
||||
m_rdpSecurityModeInput(new QComboBox(this)),
|
||||
m_rdpPerformanceProfileInput(new QComboBox(this))
|
||||
m_rdpPerformanceProfileInput(new QComboBox(this)),
|
||||
m_protocolHint(new QLabel(this)),
|
||||
m_folderHint(new QLabel(this))
|
||||
{
|
||||
resize(520, 340);
|
||||
resize(560, 360);
|
||||
|
||||
auto* layout = new QVBoxLayout(this);
|
||||
auto* form = new QFormLayout();
|
||||
@@ -52,6 +78,7 @@ ProfileDialog::ProfileDialog(QWidget* parent)
|
||||
m_portInput->setValue(22);
|
||||
m_usernameInput->setPlaceholderText(QStringLiteral("deploy"));
|
||||
m_domainInput->setPlaceholderText(QStringLiteral("CONTOSO"));
|
||||
m_tagsInput->setPlaceholderText(QStringLiteral("prod, linux, db"));
|
||||
|
||||
m_protocolInput->addItems({QStringLiteral("SSH"), QStringLiteral("RDP"), QStringLiteral("VNC")});
|
||||
m_authModeInput->addItems({QStringLiteral("Password"), QStringLiteral("Private Key")});
|
||||
@@ -107,6 +134,7 @@ ProfileDialog::ProfileDialog(QWidget* parent)
|
||||
form->addRow(QStringLiteral("Port"), m_portInput);
|
||||
form->addRow(QStringLiteral("Username"), m_usernameInput);
|
||||
form->addRow(QStringLiteral("Domain"), m_domainInput);
|
||||
form->addRow(QStringLiteral("Tags"), m_tagsInput);
|
||||
form->addRow(QStringLiteral("Protocol"), m_protocolInput);
|
||||
form->addRow(QStringLiteral("Auth Mode"), m_authModeInput);
|
||||
form->addRow(QStringLiteral("Private Key"), privateKeyRow);
|
||||
@@ -118,12 +146,16 @@ ProfileDialog::ProfileDialog(QWidget* parent)
|
||||
QStringLiteral("Passwords are requested at connect time and are not stored."),
|
||||
this);
|
||||
note->setWordWrap(true);
|
||||
m_protocolHint->setWordWrap(true);
|
||||
m_folderHint->setWordWrap(true);
|
||||
|
||||
auto* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
|
||||
connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
||||
connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||
|
||||
layout->addLayout(form);
|
||||
layout->addWidget(m_protocolHint);
|
||||
layout->addWidget(m_folderHint);
|
||||
layout->addWidget(note);
|
||||
layout->addWidget(buttons);
|
||||
|
||||
@@ -135,6 +167,12 @@ void ProfileDialog::setDialogTitle(const QString& title)
|
||||
setWindowTitle(title);
|
||||
}
|
||||
|
||||
void ProfileDialog::setDefaultFolderPath(const QString& folderPath)
|
||||
{
|
||||
m_defaultFolderPath = folderPath.trimmed();
|
||||
refreshAuthFields();
|
||||
}
|
||||
|
||||
void ProfileDialog::setProfile(const Profile& profile)
|
||||
{
|
||||
m_nameInput->setText(profile.name);
|
||||
@@ -142,6 +180,8 @@ void ProfileDialog::setProfile(const Profile& profile)
|
||||
m_portInput->setValue(profile.port > 0 ? profile.port : 22);
|
||||
m_usernameInput->setText(profile.username);
|
||||
m_domainInput->setText(profile.domain);
|
||||
m_defaultFolderPath = profile.folderPath.trimmed();
|
||||
m_tagsInput->setText(profile.tags);
|
||||
m_privateKeyPathInput->setText(profile.privateKeyPath);
|
||||
|
||||
const int protocolIndex = m_protocolInput->findText(profile.protocol);
|
||||
@@ -169,18 +209,31 @@ void ProfileDialog::setProfile(const Profile& profile)
|
||||
Profile ProfileDialog::profile() const
|
||||
{
|
||||
Profile profile;
|
||||
const QString protocol = normalizedProtocol(m_protocolInput->currentText());
|
||||
const QString authMode = normalizedAuthMode(protocol, m_authModeInput->currentText());
|
||||
|
||||
profile.id = -1;
|
||||
profile.name = m_nameInput->text().trimmed();
|
||||
profile.host = m_hostInput->text().trimmed();
|
||||
profile.port = m_portInput->value();
|
||||
profile.username = m_usernameInput->text().trimmed();
|
||||
profile.domain = m_domainInput->text().trimmed();
|
||||
profile.protocol = m_protocolInput->currentText();
|
||||
profile.authMode = m_authModeInput->currentText();
|
||||
profile.privateKeyPath = m_privateKeyPathInput->text().trimmed();
|
||||
profile.knownHostsPolicy = m_knownHostsPolicyInput->currentText();
|
||||
profile.rdpSecurityMode = m_rdpSecurityModeInput->currentText();
|
||||
profile.rdpPerformanceProfile = m_rdpPerformanceProfileInput->currentText();
|
||||
profile.domain = protocol == QStringLiteral("RDP") ? m_domainInput->text().trimmed() : QString();
|
||||
profile.folderPath = m_defaultFolderPath.trimmed();
|
||||
profile.tags = m_tagsInput->text().trimmed();
|
||||
profile.protocol = protocol;
|
||||
profile.authMode = authMode;
|
||||
profile.privateKeyPath = (protocol == QStringLiteral("SSH")
|
||||
&& authMode == QStringLiteral("Private Key"))
|
||||
? m_privateKeyPathInput->text().trimmed()
|
||||
: QString();
|
||||
profile.knownHostsPolicy = protocol == QStringLiteral("SSH") ? m_knownHostsPolicyInput->currentText()
|
||||
: QStringLiteral("Ask");
|
||||
profile.rdpSecurityMode = protocol == QStringLiteral("RDP")
|
||||
? m_rdpSecurityModeInput->currentText()
|
||||
: QStringLiteral("Negotiate");
|
||||
profile.rdpPerformanceProfile = protocol == QStringLiteral("RDP")
|
||||
? m_rdpPerformanceProfileInput->currentText()
|
||||
: QStringLiteral("Balanced");
|
||||
return profile;
|
||||
}
|
||||
|
||||
@@ -209,14 +262,40 @@ void ProfileDialog::accept()
|
||||
return;
|
||||
}
|
||||
|
||||
if (protocol == QStringLiteral("SSH")
|
||||
&& m_authModeInput->currentText() == QStringLiteral("Private Key")) {
|
||||
const QString privateKeyPath = m_privateKeyPathInput->text().trimmed();
|
||||
if (privateKeyPath.isEmpty()) {
|
||||
QMessageBox::warning(this,
|
||||
QStringLiteral("Validation Error"),
|
||||
QStringLiteral("Private key path is required for SSH private key authentication."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!QFileInfo::exists(privateKeyPath)) {
|
||||
QMessageBox::warning(this,
|
||||
QStringLiteral("Validation Error"),
|
||||
QStringLiteral("Private key file does not exist: %1").arg(privateKeyPath));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
void ProfileDialog::refreshAuthFields()
|
||||
{
|
||||
const bool isSsh = m_protocolInput->currentText() == QStringLiteral("SSH");
|
||||
const bool isRdp = m_protocolInput->currentText() == QStringLiteral("RDP");
|
||||
const bool isPrivateKey = m_authModeInput->currentText() == QStringLiteral("Private Key");
|
||||
const QString protocol = normalizedProtocol(m_protocolInput->currentText());
|
||||
const bool isSsh = protocol == QStringLiteral("SSH");
|
||||
const bool isRdp = protocol == QStringLiteral("RDP");
|
||||
const bool isVnc = protocol == QStringLiteral("VNC");
|
||||
|
||||
const QString normalizedMode = normalizedAuthMode(protocol, m_authModeInput->currentText());
|
||||
if (normalizedMode != m_authModeInput->currentText()) {
|
||||
const QSignalBlocker blocker(m_authModeInput);
|
||||
m_authModeInput->setCurrentText(normalizedMode);
|
||||
}
|
||||
const bool isPrivateKey = normalizedMode == QStringLiteral("Private Key");
|
||||
|
||||
m_authModeInput->setEnabled(isSsh);
|
||||
m_privateKeyPathInput->setEnabled(isSsh && isPrivateKey);
|
||||
@@ -225,4 +304,22 @@ void ProfileDialog::refreshAuthFields()
|
||||
m_domainInput->setEnabled(isRdp);
|
||||
m_rdpSecurityModeInput->setEnabled(isRdp);
|
||||
m_rdpPerformanceProfileInput->setEnabled(isRdp);
|
||||
|
||||
if (isSsh) {
|
||||
m_usernameInput->setPlaceholderText(QStringLiteral("deploy"));
|
||||
m_protocolHint->setText(
|
||||
QStringLiteral("SSH: username is required. Choose Password or Private Key auth."));
|
||||
} else if (isRdp) {
|
||||
m_usernameInput->setPlaceholderText(QStringLiteral("Administrator"));
|
||||
m_protocolHint->setText(
|
||||
QStringLiteral("RDP: username and password are required. Domain is optional."));
|
||||
} else if (isVnc) {
|
||||
m_usernameInput->setPlaceholderText(QStringLiteral("optional"));
|
||||
m_protocolHint->setText(
|
||||
QStringLiteral("VNC: host and port are required. Username/domain are optional and ignored by most servers."));
|
||||
}
|
||||
|
||||
m_folderHint->setText(m_defaultFolderPath.isEmpty()
|
||||
? QStringLiteral("Target folder: root")
|
||||
: QStringLiteral("Target folder: %1").arg(m_defaultFolderPath));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user