diff --git a/ChangeLog b/ChangeLog index a00d0ba4ec..752f2cb6ac 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,6 +7,7 @@ Bug fixes: Enhancements: - #6954 Move language selection to advanced section +- #6959 Update synergy UI. Setup wizard - #6962 | #6965 Add macOS 10.13 builder =========== diff --git a/src/gui/res/Synergy.qrc b/src/gui/res/Synergy.qrc index d987679e32..f1f2e2c568 100644 --- a/src/gui/res/Synergy.qrc +++ b/src/gui/res/Synergy.qrc @@ -19,5 +19,6 @@ icons/64x64/synergy-light-transfering.png icons/64x64/synergy-light-disconnected.png icons/64x64/synergy-light-connected.png + image/welcome.png diff --git a/src/gui/res/image/welcome.png b/src/gui/res/image/welcome.png new file mode 100644 index 0000000000..0c54917233 Binary files /dev/null and b/src/gui/res/image/welcome.png differ diff --git a/src/gui/src/AppConfig.cpp b/src/gui/src/AppConfig.cpp index 69af66990a..a53b1b15a8 100644 --- a/src/gui/src/AppConfig.cpp +++ b/src/gui/src/AppConfig.cpp @@ -267,7 +267,7 @@ void AppConfig::loadSettings() void AppConfig::saveSettings() { - setCommonSetting(kWizardLastRun, kWizardVersion); + setCommonSetting(kWizardLastRun, m_WizardLastRun); setCommonSetting(kLoadSystemSettings, m_LoadFromSystemScope); if (isWritable()) { diff --git a/src/gui/src/ScreenNameValidator.cpp b/src/gui/src/ScreenNameValidator.cpp index b00c8fc68a..a3e5027287 100644 --- a/src/gui/src/ScreenNameValidator.cpp +++ b/src/gui/src/ScreenNameValidator.cpp @@ -17,8 +17,138 @@ */ #include "ScreenNameValidator.h" -ScreenNameValidator::ScreenNameValidator(QObject *parent) : - QRegExpValidator(QRegExp("[a-z0-9\\._-]{,255}", Qt::CaseInsensitive), parent) +namespace { + + +class EmptyNameValidator : public INameValidator +{ +public: + bool validate(const QString& input) const override + { + return !input.isEmpty(); + } + + QString getMessage() const override + { + return "Computer name can't be empty"; + } +}; + +class SpacesValidator : public INameValidator +{ +public: + bool validate(const QString& input) const override + { + return !input.contains(' '); + } + + QString getMessage() const override + { + return "Remove spaces"; + } +}; + +class SpecialCharactersValidator : public INameValidator { +public: + bool validate(const QString& input) const override + { + auto validator = QRegExp("[a-z0-9\\._-]{,255}", Qt::CaseInsensitive); + return (validator.exactMatch(input)); + } + + QString getMessage() const override + { + return "Remove unsupported characters"; + } +}; + +class DuplicationsValidator : public INameValidator +{ + const QString m_defaultName; + const ScreenList* m_pScreenList = nullptr; + +public: + DuplicationsValidator(const QString defaultName,const ScreenList* pScreens) : + m_defaultName(defaultName), + m_pScreenList(pScreens) + { + + } + + bool validate(const QString& input) const override + { + bool result = true; + + if (m_pScreenList) + { + for(const auto& screen : (*m_pScreenList)) + { + if (m_defaultName != input && input == screen.name()) + { + result = false; + break; + } + } + } + + return result; + } + + QString getMessage() const override + { + return "Computer with this name already exists"; + } +}; + + + +} + +ScreenNameValidator::ScreenNameValidator(QLineEdit* parent, QLabel* errors, const ScreenList* pScreens) : + m_pErrors(errors), + m_pControl(parent) +{ + if (m_pErrors) { + m_pErrors->hide(); + } + + m_Validators.push_back(std::make_unique()); + m_Validators.push_back(std::make_unique()); + m_Validators.push_back(std::make_unique()); + m_Validators.push_back(std::make_unique(m_pControl ? m_pControl->text() : "", pScreens)); +} + +QValidator::State ScreenNameValidator::validate(QString& input, int& pos) const +{ + if (m_pControl) { + showError(""); + m_pControl->setStyleSheet(""); + + for(const auto& validator : m_Validators) + { + if (!validator->validate(input)) + { + m_pControl->setStyleSheet("border: 1px solid #EC4C47"); + showError(validator->getMessage()); + break; + } + } + } + + return Acceptable; +} + +void ScreenNameValidator::showError(const QString& message) const +{ + if (m_pErrors) { + m_pErrors->setText(message); + if (m_pErrors->text().isEmpty()) { + m_pErrors->hide(); + } + else { + m_pErrors->show(); + } + } } diff --git a/src/gui/src/ScreenNameValidator.h b/src/gui/src/ScreenNameValidator.h index 4517ab1bdf..6bf45abfe6 100644 --- a/src/gui/src/ScreenNameValidator.h +++ b/src/gui/src/ScreenNameValidator.h @@ -18,12 +18,33 @@ #ifndef SCREENNAMEVALIDATOR_H #define SCREENNAMEVALIDATOR_H +#include +#include #include +#include +#include +#include "Screen.h" -class ScreenNameValidator : public QRegExpValidator +class INameValidator { public: - explicit ScreenNameValidator(QObject *parent = nullptr); + virtual bool validate(const QString& input) const = 0; + virtual QString getMessage() const = 0; + virtual ~INameValidator() = default; +}; + +class ScreenNameValidator : public QValidator +{ +public: + explicit ScreenNameValidator(QLineEdit* parent = nullptr, QLabel* errors = nullptr, const ScreenList* pScreens = nullptr); + QValidator::State validate(QString& input, int& pos) const override; + +private: + QLabel* m_pErrors = nullptr; + QLineEdit* m_pControl = nullptr; + std::vector> m_Validators; + + void showError(const QString& message) const; }; #endif // SCREENNAMEVALIDATOR_H diff --git a/src/gui/src/ScreenSettingsDialog.cpp b/src/gui/src/ScreenSettingsDialog.cpp index 88f486c56e..01855c1334 100644 --- a/src/gui/src/ScreenSettingsDialog.cpp +++ b/src/gui/src/ScreenSettingsDialog.cpp @@ -24,7 +24,7 @@ #include #include -ScreenSettingsDialog::ScreenSettingsDialog(QWidget* parent, Screen* pScreen) : +ScreenSettingsDialog::ScreenSettingsDialog(QWidget* parent, Screen* pScreen,const ScreenList* pScreens) : QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint), Ui::ScreenSettingsDialogBase(), m_pScreen(pScreen) @@ -32,7 +32,7 @@ ScreenSettingsDialog::ScreenSettingsDialog(QWidget* parent, Screen* pScreen) : setupUi(this); m_pLineEditName->setText(m_pScreen->name()); - m_pLineEditName->setValidator(new ScreenNameValidator(m_pLineEditName)); + m_pLineEditName->setValidator(new ScreenNameValidator(m_pLineEditName, m_pLabelNameError, pScreens)); m_pLineEditName->selectAll(); m_pLineEditAlias->setValidator(new ScreenNameValidator(m_pLineEditName)); @@ -68,6 +68,9 @@ void ScreenSettingsDialog::accept() "Please either fill in a name or cancel the dialog.")); return; } + else if (!m_pLabelNameError->text().isEmpty()) { + return; + } m_pScreen->init(); diff --git a/src/gui/src/ScreenSettingsDialog.h b/src/gui/src/ScreenSettingsDialog.h index 620acc84c7..45f6f02929 100644 --- a/src/gui/src/ScreenSettingsDialog.h +++ b/src/gui/src/ScreenSettingsDialog.h @@ -28,13 +28,14 @@ class QWidget; class QString; class Screen; +using ScreenList = QList; class ScreenSettingsDialog : public QDialog, public Ui::ScreenSettingsDialogBase { Q_OBJECT public: - ScreenSettingsDialog(QWidget* parent, Screen* pScreen = NULL); + ScreenSettingsDialog(QWidget* parent, Screen* pScreen = nullptr, const ScreenList* pScreens = nullptr); public slots: void accept(); diff --git a/src/gui/src/ScreenSettingsDialogBase.ui b/src/gui/src/ScreenSettingsDialogBase.ui index cd42227911..1ba7b5f680 100644 --- a/src/gui/src/ScreenSettingsDialogBase.ui +++ b/src/gui/src/ScreenSettingsDialogBase.ui @@ -31,6 +31,22 @@ + + + + color: #EC4C47; +font-size: 13px; +font-family: Arial; +font-weight: bold; + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + diff --git a/src/gui/src/ScreenSetupView.cpp b/src/gui/src/ScreenSetupView.cpp index 0580cf2de8..a77161f5ec 100644 --- a/src/gui/src/ScreenSetupView.cpp +++ b/src/gui/src/ScreenSetupView.cpp @@ -74,7 +74,7 @@ void ScreenSetupView::mouseDoubleClickEvent(QMouseEvent* event) if (!model()->screen(col, row).isNull()) { - ScreenSettingsDialog dlg(this, &model()->screen(col, row)); + ScreenSettingsDialog dlg(this, &model()->screen(col, row), &model()->m_Screens); dlg.exec(); } } diff --git a/src/gui/src/SettingsDialog.cpp b/src/gui/src/SettingsDialog.cpp index 85f81647ca..7cc5da2e37 100644 --- a/src/gui/src/SettingsDialog.cpp +++ b/src/gui/src/SettingsDialog.cpp @@ -51,18 +51,20 @@ SettingsDialog::SettingsDialog(QWidget* parent, AppConfig& config) : m_isSystemAtStart = appConfig().isSystemScoped(); buttonBox->button(QDialogButtonBox::Save)->setEnabled(false); enableControls(appConfig().isWritable()); - m_pLineEditScreenName->setValidator(new ScreenNameValidator(m_pLineEditScreenName)); - connect(m_pLineEditLogFilename, SIGNAL(textChanged(const QString&)), this, SLOT(onChange())); - connect(m_pComboLogLevel, SIGNAL(currentIndexChanged(int)), this, SLOT(onChange())); - connect(m_pLineEditCertificatePath, SIGNAL(textChanged(const QString&)), this, SLOT(onChange())); - connect(m_pCheckBoxAutoConfig, SIGNAL(clicked()), this, SLOT(onChange())); - connect(m_pCheckBoxMinimizeToTray, SIGNAL(clicked()), this, SLOT(onChange())); - connect(m_pCheckBoxAutoHide, SIGNAL(clicked()), this, SLOT(onChange())); - connect(m_pLineEditInterface, SIGNAL(textEdited(const QString&)), this, SLOT(onChange())); - connect(m_pSpinBoxPort, SIGNAL(valueChanged(int)), this, SLOT(onChange())); - connect(m_pLineEditScreenName, SIGNAL(textEdited(const QString&)), this, SLOT(onChange())); - connect(m_pComboElevate, SIGNAL(currentIndexChanged(int)), this, SLOT(onChange())); + const auto& serveConfig = m_pMainWindow->serverConfig(); + m_pLineEditScreenName->setValidator(new ScreenNameValidator(m_pLineEditScreenName, m_pLabelNameError, (&serveConfig.screens()))); + + connect(m_pLineEditLogFilename, SIGNAL(textChanged(QString)), this, SLOT(onChange())); + connect(m_pComboLogLevel, SIGNAL(currentIndexChanged(int)), this, SLOT(onChange())); + connect(m_pLineEditCertificatePath, SIGNAL(textChanged(QString)), this, SLOT(onChange())); + connect(m_pCheckBoxAutoConfig, SIGNAL(clicked()), this, SLOT(onChange())); + connect(m_pCheckBoxMinimizeToTray, SIGNAL(clicked()), this, SLOT(onChange())); + connect(m_pCheckBoxAutoHide, SIGNAL(clicked()), this, SLOT(onChange())); + connect(m_pLineEditInterface, SIGNAL(textEdited(QString)), this, SLOT(onChange())); + connect(m_pSpinBoxPort, SIGNAL(valueChanged(int)), this, SLOT(onChange())); + connect(m_pLineEditScreenName, SIGNAL(textEdited(QString)), this, SLOT(onChange())); + connect(m_pComboElevate, SIGNAL(currentIndexChanged(int)), this, SLOT(onChange())); } void SettingsDialog::accept() @@ -308,6 +310,7 @@ void SettingsDialog::updateKeyLengthOnFile(const QString &path) { bool SettingsDialog::isModified() { return (!m_pLineEditScreenName->text().isEmpty() && + m_pLabelNameError->text().isEmpty() && (appConfig().screenName() != m_pLineEditScreenName->text() || appConfig().port() != m_pSpinBoxPort->value() || appConfig().networkInterface() != m_pLineEditInterface->text() diff --git a/src/gui/src/SettingsDialogBase.ui b/src/gui/src/SettingsDialogBase.ui index 693eef594e..5bc8889dfb 100644 --- a/src/gui/src/SettingsDialogBase.ui +++ b/src/gui/src/SettingsDialogBase.ui @@ -7,7 +7,7 @@ 0 0 396 - 857 + 879 @@ -44,33 +44,7 @@ &Miscellaneous - - - - P&ort: - - - m_pSpinBoxPort - - - - - - - - 75 - 0 - - - - Sc&reen name: - - - m_pLineEditScreenName - - - - + Specify when the Synergy service should run at an elevated privilege level @@ -95,28 +69,34 @@ - - - - true - - - - + - Elevate + &Interface: + + + m_pLineEditInterface - + Minimize to System &Tray - + + + + true + + + 15 + + + + true @@ -135,30 +115,75 @@ - - + + + + + 75 + 0 + + - &Interface: + Sc&reen name: - m_pLineEditInterface + m_pLineEditScreenName - + + + + P&ort: + + + m_pSpinBoxPort + + + + + + + Elevate + + + + &Hide on startup - + true + + + + + 0 + 0 + + + + color: #EC4C47; +font-size: 13px; +font-family: Arial; +font-weight: bold; + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + diff --git a/src/gui/src/SetupWizard.cpp b/src/gui/src/SetupWizard.cpp index d022f9a6ea..640c023bf7 100644 --- a/src/gui/src/SetupWizard.cpp +++ b/src/gui/src/SetupWizard.cpp @@ -17,118 +17,39 @@ #include "SetupWizard.h" #include "MainWindow.h" -#include "ActivationNotifier.h" -#include "LicenseManager.h" -#include "QSynergyApplication.h" -#include "QUtility.h" +#include "ScreenNameValidator.h" -#include - -SetupWizard::SetupWizard(MainWindow& mainWindow, bool startMain) : - m_MainWindow(mainWindow), - m_StartMain(startMain) +SetupWizard::SetupWizard(MainWindow& mainWindow) : + m_MainWindow(mainWindow) { - setupUi(this); + setupUi(this); -#if defined(Q_OS_MAC) + m_pLineEditName->setText(m_MainWindow.appConfig().screenName()); + m_pLineEditName->setValidator(new ScreenNameValidator(m_pLineEditName, label_ErrorMessage)); - // the mac style needs a little more room because of the - // graphic on the left. - resize(600, 500); - setMinimumSize(size()); - - // additionally, we identified an issue with presenting dots, see SYNERGY-719 - duplicateSpaces(); - -#elif defined(Q_OS_WIN) - - // when areo is disabled on windows, the next/back buttons - // are hidden (must be a qt bug) -- resizing the window - // to +1 of the original height seems to fix this. - // NOTE: calling setMinimumSize after this will break - // it again, so don't do that. - resize(size().width(), size().height() + 1); - -#endif - - connect(m_pServerRadioButton, SIGNAL(toggled(bool)), m_MainWindow.m_pGroupServer, SLOT(setChecked(bool))); - connect(m_pClientRadioButton, SIGNAL(toggled(bool)), m_MainWindow.m_pGroupClient, SLOT(setChecked(bool))); -} - -SetupWizard::~SetupWizard() -{ -} - -bool SetupWizard::validateCurrentPage() -{ - QMessageBox message; - message.setWindowTitle(tr("Setup Synergy")); - message.setIcon(QMessageBox::Information); - - if (currentPage() == m_pNodePage) - { - bool result = m_pClientRadioButton->isChecked() || - m_pServerRadioButton->isChecked(); - - if (!result) - { - message.setText(tr("Please select an option.")); - message.exec(); - return false; - } - } - - return true; + connect(m_pButtonApply, SIGNAL(clicked()), this, SLOT(accept())); + connect(m_pLineEditName, SIGNAL(textEdited(QString)), this, SLOT(onNameChanged())); } void SetupWizard::accept() { - AppConfig& appConfig = m_MainWindow.appConfig(); + AppConfig& appConfig = m_MainWindow.appConfig(); - appConfig.setWizardHasRun(); - appConfig.saveSettings(); + appConfig.setWizardHasRun(); + appConfig.setScreenName(m_pLineEditName->text()); + appConfig.saveSettings(); - QSettings& settings = m_MainWindow.settings(); - if (m_pServerRadioButton->isChecked()) - { - settings.setValue("groupServerChecked", true); - settings.setValue("groupClientChecked", false); - } - if (m_pClientRadioButton->isChecked()) - { - settings.setValue("groupClientChecked", true); - settings.setValue("groupServerChecked", false); - } + m_MainWindow.open(); + QDialog::accept(); +} - QWizard::accept(); - - if (m_StartMain) - { - m_MainWindow.open(); - } +void SetupWizard::onNameChanged() +{ + m_pButtonApply->setEnabled(label_ErrorMessage->text().isEmpty()); } void SetupWizard::reject() { - QSynergyApplication::getInstance()->switchTranslator(m_MainWindow.appConfig().language()); - - if (m_StartMain) - { - m_MainWindow.open(); - } - - QWizard::reject(); + QDialog::reject(); + QApplication::exit(); } - -#if defined(Q_OS_MAC) -void SetupWizard::duplicateSpaces() -{ - auto list = this->findChildren(); - foreach(QLabel *l, list) { - if (l->wordWrap()) { - l->setText(l->text().replace(". ", ". ")); - l->setText(l->text().replace(", ", ", ")); - } - } -} -#endif // defined(Q_OS_MAC) diff --git a/src/gui/src/SetupWizard.h b/src/gui/src/SetupWizard.h index 8f7df961fc..78a403a51b 100644 --- a/src/gui/src/SetupWizard.h +++ b/src/gui/src/SetupWizard.h @@ -18,36 +18,24 @@ #pragma once #include "ui_SetupWizardBase.h" -#include "SynergyLocale.h" - -#include -#include +#include class MainWindow; -class SetupWizard : public QWizard, public Ui::SetupWizardBase +class SetupWizard : public QDialog, public Ui::SetupWizardBase { - Q_OBJECT -public: - enum { - kMaximiumLoginAttemps = 3 - }; + Q_OBJECT public: - SetupWizard(MainWindow& mainWindow, bool startMain); - virtual ~SetupWizard(); - bool validateCurrentPage(); + explicit SetupWizard(MainWindow& mainWindow); protected: - void accept(); - void reject(); + void accept(); + void reject(); private: - MainWindow& m_MainWindow; - bool m_StartMain; - SynergyLocale m_Locale; + MainWindow& m_MainWindow; -#if defined(Q_OS_MAC) - void duplicateSpaces(); -#endif // defined(Q_OS_MAC) +private slots: + void onNameChanged(); }; diff --git a/src/gui/src/SetupWizardBase.ui b/src/gui/src/SetupWizardBase.ui index c6a84d0364..dc98f2263f 100644 --- a/src/gui/src/SetupWizardBase.ui +++ b/src/gui/src/SetupWizardBase.ui @@ -1,13 +1,13 @@ SetupWizardBase - + 0 0 - 556 - 464 + 720 + 552 @@ -18,173 +18,201 @@ - 500 - 390 + 720 + 552 + + + 720 + 552 + + + + + 720 + 552 + + + + Qt::NoContextMenu + Setup Synergy - - - Welcome + + 1.000000000000000 + + + + + 270 + 70 + 181 + 161 + - - - - - - - - Thanks for installing Synergy! - - - true - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 10 - - - - - - - - - - - Synergy lets you easily share your mouse and keyboard between multiple computers on your desk. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, macOS and Linux). - - - true - - - - - - - - - 0 - 0 - - - - Server or Client? - - + + + + + :/res/image/welcome.png + + + + + + 270 + 253 + 261 + 21 + + + + + Arial + 75 + true + + + + <html><head/><body><p style="font-size:18px">Name your computer</p></body></html> + + + Qt::RichText + + + + + + 184 + 294 + 111 + 16 + + + + + Arial + 75 + true + + + + <html><head/><body><p style="font-size:13px;">Computer name</p></body></html> + + + Qt::RichText + + + + + + 300 + 293 + 230 + 20 + + + + + 230 + 20 + + + + 255 + + + + + + 132 + 354 + 481 + 16 + + + + + Arial + 75 + true + + + + <html><head/><body><p style="font-size: 13px;">Call your computer something short and meaningful, but it must have: </p></body></html> + + + Qt::RichText + + + + + + 193 + 380 + 311 + 81 + + + + + Arial + 20 + 75 + true + + + + <html><head/><body><ul style="list-style-type:none; font-size: 13px;"><li style="line-height:140%">- A different name from other computers </li><li style="line-height:140%">- Only these special characters _ - .</li><li style="line-height:140%">- No spaces </li><li style="line-height:140%">- Only english characters and numbers</li></body></html> + + + Qt::RichText + + + + + + 650 + 510 + 56 + 25 + + + + + Arial + 50 + false + + + + Apply + + + + + + 300 + 320 + 391 + 16 + + + + color: #EC4C47; +font-size: 13px; +font-family: Arial; +font-weight: bold; + + - - - - - - 75 - true - - - - &Server (share this computer's mouse and keyboard) - - - - - - - - 0 - 0 - - - - My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup. - - - true - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 20 - - - - - - - - - 75 - true - - - - &Client (use another computer's mouse and keyboard) - - - - - - - - 0 - 0 - - - - You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup. - - - true - - - - - - - Qt::Vertical - - - QSizePolicy::MinimumExpanding - - - - 0 - 0 - - - - - - - m_pServerRadioButton - m_pClientRadioButton - - + + + diff --git a/src/gui/src/main.cpp b/src/gui/src/main.cpp index 2de9b6f188..7fe74749b8 100644 --- a/src/gui/src/main.cpp +++ b/src/gui/src/main.cpp @@ -100,7 +100,7 @@ int main(int argc, char* argv[]) std::unique_ptr setupWizard; if (appConfig.wizardShouldRun()) { - setupWizard.reset(new SetupWizard(mainWindow, true)); + setupWizard.reset(new SetupWizard(mainWindow)); setupWizard->show(); } else