diff --git a/ChangeLog b/ChangeLog index 7bd37c2bb..9e6a4677c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -64,6 +64,7 @@ Enhancements: - #7415 Assert arg value `num > 0` for BSD socket poll unblock pipe - #7416 Catch exception propagating to `Server` dtor - #7421 Only load core after settings have fully loaded +- #7419 Introduce 'Advanced' tab to Preferences window # 1.14.6 diff --git a/cmake/Libraries.cmake b/cmake/Libraries.cmake index e3a487c6f..406f63749 100644 --- a/cmake/Libraries.cmake +++ b/cmake/Libraries.cmake @@ -291,6 +291,8 @@ macro(config_qt) COMPONENTS Core Widgets Network REQUIRED) + message(STATUS "Qt version: ${Qt6_VERSION}") + endmacro() macro(configure_openssl) diff --git a/cspell.json b/cspell.json index e46f60f85..1477c86f9 100644 --- a/cspell.json +++ b/cspell.json @@ -4,6 +4,7 @@ "dictionaryDefinitions": [], "dictionaries": [], "words": [ + "Schoeneman", "aqtinstall", "codesign", "codesigning", diff --git a/scripts/lint_clang.py b/scripts/lint_clang.py index 5c2152abc..e63df0c61 100755 --- a/scripts/lint_clang.py +++ b/scripts/lint_clang.py @@ -25,6 +25,7 @@ def main(): """ parser = argparse.ArgumentParser() parser.add_argument( + "-f", "--format", action="store_true", help="In-place format all files", diff --git a/scripts/lint_cmake.py b/scripts/lint_cmake.py index 7e278a37b..719a9b1d2 100755 --- a/scripts/lint_cmake.py +++ b/scripts/lint_cmake.py @@ -23,6 +23,7 @@ def main(): """ parser = argparse.ArgumentParser() parser.add_argument( + "-f", "--format", action="store_true", help="In-place format all files", diff --git a/src/gui/src/AboutDialog.cpp b/src/gui/src/AboutDialog.cpp index 929e2c83c..538e7fe7e 100644 --- a/src/gui/src/AboutDialog.cpp +++ b/src/gui/src/AboutDialog.cpp @@ -51,19 +51,11 @@ AboutDialog::AboutDialog(MainWindow *parent, const AppConfig &config) int AboutDialog::exec() { m_pDevelopersLabel->setText(getImportantDevelopers()); m_pCopyrightLabel->setText(getCopyright()); - resizeWindow(); updateLogo(); return QDialog::exec(); } -void AboutDialog::resizeWindow() { - QSize size(600, 310); - setMaximumSize(size); - setMinimumSize(size); - resize(size); -} - void AboutDialog::updateLogo() const { #if defined(Q_OS_MAC) if (isOSXInterfaceStyleDark()) { diff --git a/src/gui/src/AboutDialog.h b/src/gui/src/AboutDialog.h index 2622ae03f..7bcbda5ea 100644 --- a/src/gui/src/AboutDialog.h +++ b/src/gui/src/AboutDialog.h @@ -37,7 +37,6 @@ private: VersionChecker m_versionChecker; void updateLogo() const; - virtual void resizeWindow(); virtual QString getCopyright() const; virtual QString getImportantDevelopers() const; }; diff --git a/src/gui/src/ActivationDialog.cpp b/src/gui/src/ActivationDialog.cpp index 63be610e2..e1cd4ea59 100644 --- a/src/gui/src/ActivationDialog.cpp +++ b/src/gui/src/ActivationDialog.cpp @@ -17,17 +17,15 @@ #include "ActivationDialog.h" -#include "gui/license_notices.h" -#include "ui_ActivationDialog.h" - -#include "AppConfig.h" #include "CancelActivationDialog.h" #include "MainWindow.h" +#include "gui/AppConfig.h" #include "gui/LicenseHandler.h" #include "gui/constants.h" #include "gui/license_notices.h" #include "license/ProductEdition.h" #include "license/parse_serial_key.h" +#include "ui_ActivationDialog.h" #include #include @@ -44,6 +42,9 @@ ActivationDialog::ActivationDialog( m_licenseHandler(licenseHandler) { m_ui->setupUi(this); + + m_ui->m_pLabelNotice->setStyleSheet(kStyleNoticeLabel); + refreshSerialKey(); if (!m_licenseHandler.license().isExpired()) { @@ -64,7 +65,7 @@ void ActivationDialog::refreshSerialKey() { const auto &license = m_licenseHandler.license(); if (license.isTimeLimited()) { - m_ui->m_labelNotice->setText(licenseNotice(license)); + m_ui->m_pLabelNotice->setText(licenseNotice(license)); } } @@ -78,9 +79,9 @@ void ActivationDialog::reject() { return; } - // the user is told that the 'No' button will exit the app. + // the accept button should be labeled "Exit" on the cancel dialoig. CancelActivationDialog cancelActivationDialog(this); - if (cancelActivationDialog.exec() == QDialog::Rejected) { + if (cancelActivationDialog.exec() == QDialog::Accepted) { QApplication::exit(); } } @@ -126,19 +127,21 @@ void ActivationDialog::showResultDialog( case kInvalid: QMessageBox::critical( this, title, - QString("Invalid serial key. " - R"(Please contact us for help.)") + QString( + "Invalid serial key. " + R"(Please contact us for help.)") .arg(kUrlContact) - .arg(kLinkStyleSecondary)); + .arg(kColorSecondary)); break; case kExpired: QMessageBox::warning( this, title, - QString("Sorry, that serial key has expired. " - R"(Please renew your license.)") + QString( + "Sorry, that serial key has expired. " + R"(Please renew your license.)") .arg(kUrlPurchase) - .arg(kLinkStyleSecondary)); + .arg(kColorSecondary)); break; default: @@ -180,11 +183,11 @@ void ActivationDialog::showSuccessDialog() { void ActivationDialog::showErrorDialog(const QString &message) { QString fullMessage = QString("

There was a problem activating Synergy.

" - R"(

Please contact us )" + R"(

Please contact us )" "and provide the following information:

" "%3") .arg(kUrlContact) - .arg(kLinkStyleSecondary) + .arg(kColorSecondary) .arg(message); QMessageBox::critical(this, "Activation failed", fullMessage); } diff --git a/src/gui/src/ActivationDialog.ui b/src/gui/src/ActivationDialog.ui index a60639797..634b0ec4a 100644 --- a/src/gui/src/ActivationDialog.ui +++ b/src/gui/src/ActivationDialog.ui @@ -75,16 +75,9 @@ li.checked::marker { content: "\2612"; } 8 - - - padding: 3px 5px; -border-radius: 3px; -background-color: #3B67D3; -color: #ffffff; -top: 3px; - + - m_labelNotice + m_pLabelNotice true @@ -94,7 +87,7 @@ top: 3px; - Qt::Orientation::Horizontal + Qt::Horizontal @@ -110,10 +103,10 @@ top: 3px; - Qt::Orientation::Horizontal + Qt::Horizontal - QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok + QDialogButtonBox::Cancel|QDialogButtonBox::Ok diff --git a/src/gui/src/CancelActivationDialog.cpp b/src/gui/src/CancelActivationDialog.cpp index cf6b08652..d766f8382 100644 --- a/src/gui/src/CancelActivationDialog.cpp +++ b/src/gui/src/CancelActivationDialog.cpp @@ -1,10 +1,33 @@ +/* + * synergy -- mouse and keyboard sharing utility + * Copyright (C) 2016 Symless Ltd. + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #include "CancelActivationDialog.h" + #include "ui_CancelActivationDialog.h" +#include "QPushButton" + CancelActivationDialog::CancelActivationDialog(QWidget *parent) : QDialog(parent), ui(new Ui::CancelActivationDialog) { ui->setupUi(this); + + ui->m_pButtonBox->button(QDialogButtonBox::Cancel)->setText("&Back"); + ui->m_pButtonBox->button(QDialogButtonBox::Ok)->setText("&Exit"); } CancelActivationDialog::~CancelActivationDialog() { delete ui; } diff --git a/src/gui/src/CancelActivationDialog.h b/src/gui/src/CancelActivationDialog.h index a37f53b15..483960979 100644 --- a/src/gui/src/CancelActivationDialog.h +++ b/src/gui/src/CancelActivationDialog.h @@ -1,5 +1,21 @@ -#ifndef CANCELACTIVATIONDIALOG_H -#define CANCELACTIVATIONDIALOG_H +/* + * synergy -- mouse and keyboard sharing utility + * Copyright (C) 2016 Symless Ltd. + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once #include @@ -17,5 +33,3 @@ public: private: Ui::CancelActivationDialog *ui; }; - -#endif // CANCELACTIVATIONDIALOG_H diff --git a/src/gui/src/CancelActivationDialog.ui b/src/gui/src/CancelActivationDialog.ui index c34d487ad..c9fff355c 100644 --- a/src/gui/src/CancelActivationDialog.ui +++ b/src/gui/src/CancelActivationDialog.ui @@ -6,18 +6,18 @@ 0 0 - 400 - 246 + 429 + 273 Cancel Activation - + - <html><head/><body><p>You'll need to purchase a license to use this build of Synergy.</p><p><a href="https://symless.com/synergy/purchase?source=gui"><span style=" text-decoration: underline; color:#007af4;">Purchase Synergy</span></a></p><p>If you'd prefer to use the community edition instead, visit us on GitHub.</p><p><a href="https://github.com/symless/synergy-core"><span style=" text-decoration: underline; color:#007af4;">GitHub project</span></a></p><p>Would you like to go back and enter a serial key?</p><p>Choosing 'No' will quit Synergy.</p></body></html> + <html><head/><body><p>You'll need to purchase a license to use this build of Synergy.</p><p><a href="https://symless.com/synergy/purchase?source=gui"><span style=" text-decoration: underline; color:#007af4;">Purchase Synergy</span></a></p><p>If you'd prefer to use the community edition instead, visit us on GitHub.</p><p><a href="https://github.com/symless/synergy-core"><span style=" text-decoration: underline; color:#007af4;">GitHub project</span></a></p></body></html> true @@ -28,25 +28,12 @@ - + - Qt::Vertical - - - - 20 - 40 - - - - - - - - Qt::Horizontal + Qt::Orientation::Horizontal - QDialogButtonBox::No|QDialogButtonBox::Yes + QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok @@ -55,7 +42,7 @@ - buttonBox + m_pButtonBox accepted() CancelActivationDialog accept() @@ -71,7 +58,7 @@ - buttonBox + m_pButtonBox rejected() CancelActivationDialog reject() diff --git a/src/gui/src/MainWindow.cpp b/src/gui/src/MainWindow.cpp index ab4e46150..6c640eced 100644 --- a/src/gui/src/MainWindow.cpp +++ b/src/gui/src/MainWindow.cpp @@ -94,19 +94,89 @@ MainWindow::MainWindow(AppConfig &appConfig) m_ServerConfig(5, 3, &m_AppConfig, this), m_ServerConnection(*this), m_ClientConnection(*this), - m_TlsUtility(appConfig, m_LicenseHandler.license()) { + m_TlsUtility(appConfig, m_LicenseHandler.license()), + m_WindowSaveTimer(this) { setupUi(this); + setupControls(); connectSlots(); + +#if defined(Q_OS_WIN) + + // TODO: only connect permenantly to ipc when switching to service mode. + // if switching from service to desktop, connect only to stop the service + // and don't retry. + m_IpcClient.connectToHost(); + +#endif + + emit created(); +} + +MainWindow::~MainWindow() { + try { + if (appConfig().processMode() == ProcessMode::kDesktop) { + m_ExpectedRunningState = RuningState::Stopped; + stopDesktop(); + } + } catch (const std::exception &e) { + qFatal("failed to stop core on main window close: %s", e.what()); + } + + try { + saveWindow(); + } catch (const std::exception &e) { + qFatal("failed to save window on main window close: %s", e.what()); + } +} + +void MainWindow::restoreWindow() { + + const auto &config = appConfig(); + + const auto &size = config.mainWindowSize(); + if (size.has_value()) { + qDebug("restoring main window size"); + resize(size.value()); + } + + const auto &position = config.mainWindowPosition(); + if (position.has_value()) { + qDebug("restoring main window position"); + move(position.value()); + } + + // give the window chance to restore its size and position before the window + // size and position are saved. this prevents the window from being saved + // with the wrong size and position. + m_SaveWindow = true; +} + +void MainWindow::saveWindow() { + if (!m_SaveWindow) { + qDebug("not yet ready to save window size and position, skipping"); + return; + } + + qDebug("saving window size and position"); + auto &config = appConfig(); + config.setMainWindowSize(size()); + config.setMainWindowPosition(pos()); + config.saveSettings(); +} + +void MainWindow::setupControls() { createMenuBar(); secureSocket(false); + m_pLabelUpdate->setStyleSheet(kStyleNoticeLabel); m_pLabelUpdate->hide(); - m_pLabelIpAddresses->setText( - tr("This computer's IP addresses: %1").arg(getIPAddresses())); + m_pLabelNotice->setStyleSheet(kStyleNoticeLabel); + m_pLabelNotice->hide(); - m_labelNotice->hide(); + m_pLabelIpAddresses->setText( + QString("This computer's IP addresses: %1").arg(getIPAddresses())); if (m_AppConfig.lastVersion() != SYNERGY_VERSION) { m_AppConfig.setLastVersion(SYNERGY_VERSION); @@ -118,34 +188,10 @@ MainWindow::MainWindow(AppConfig &appConfig) #if defined(Q_OS_MAC) - resize(720, 550); - setMinimumSize(size()); - m_pRadioGroupServer->setAttribute(Qt::WA_MacShowFocusRect, 0); m_pRadioGroupClient->setAttribute(Qt::WA_MacShowFocusRect, 0); -#elif defined(Q_OS_LINUX) - - resize(700, 530); - setMinimumSize(size()); - -#elif defined(Q_OS_WIN) - - // TODO: only connect permenantly to ipc when switching to service mode. - // if switching from service to desktop, connect only to stop the service and - // don't retry. - m_IpcClient.connectToHost(); - #endif - - emit created(); -} - -MainWindow::~MainWindow() { - if (appConfig().processMode() == ProcessMode::kDesktop) { - m_ExpectedRunningState = RuningState::Stopped; - stopDesktop(); - } } ////////////////////////////////////////////////////////////////////////////// @@ -175,7 +221,7 @@ void MainWindow::connectSlots() const { &MainWindow::onAppConfigScreenNameChanged); connect( - &m_AppConfig, &AppConfig::invertConnection, this, + &m_AppConfig, &AppConfig::invertConnectionChanged, this, &MainWindow::onAppConfigInvertConnection); connect( @@ -215,6 +261,10 @@ void MainWindow::connectSlots() const { connect( &m_VersionChecker, &VersionChecker::updateFound, this, &MainWindow::onVersionCheckerUpdateFound); + + connect( + &m_WindowSaveTimer, &QTimer::timeout, this, + &MainWindow::onWindowSaveTimerTimeout); } void MainWindow::onAppAboutToQuit() { m_AppConfig.saveSettings(); } @@ -263,8 +313,10 @@ void MainWindow::onAppConfigLoaded() { if (!m_AppConfig.serialKey().isEmpty()) { m_LicenseHandler.changeSerialKey(m_AppConfig.serialKey()); } + updateScreenName(); applyConfig(); + restoreWindow(); } void MainWindow::onAppConfigTlsChanged() { @@ -315,7 +367,7 @@ void MainWindow::onCoreProcessReadyReadStandardError() { } void MainWindow::onVersionCheckerUpdateFound(const QString &version) { - const auto link = QString(kLinkDownload).arg(kUrlDownload, kLinkStyleWhite); + const auto link = QString(kLinkDownload).arg(kUrlDownload, kColorWhite); const auto text = QString("A new version is available (v%1). %2").arg(version, link); @@ -367,11 +419,12 @@ void MainWindow::onCoreProcessFinished(int exitCode, QProcess::ExitStatus) { bool MainWindow::on_m_pActionSave_triggered() { QString fileName = - QFileDialog::getSaveFileName(this, tr("Save configuration as...")); + QFileDialog::getSaveFileName(this, QString("Save configuration as...")); if (!fileName.isEmpty() && !serverConfig().save(fileName)) { QMessageBox::warning( - this, tr("Save failed"), tr("Could not save configuration to file.")); + this, QString("Save failed"), + QString("Could not save configuration to file.")); return true; } @@ -439,10 +492,28 @@ void MainWindow::on_m_pButtonConnectToClient_clicked() { on_m_pButtonApply_clicked(); } +void MainWindow::onWindowSaveTimerTimeout() { saveWindow(); } + ////////////////////////////////////////////////////////////////////////////// // End slots ////////////////////////////////////////////////////////////////////////////// +void MainWindow::resizeEvent(QResizeEvent *event) { + QMainWindow::resizeEvent(event); + + // postpone save so that settings are not written every delta change. + m_WindowSaveTimer.setSingleShot(true); + m_WindowSaveTimer.start(1000); +} + +void MainWindow::moveEvent(QMoveEvent *event) { + QMainWindow::moveEvent(event); + + // postpone save so that settings are not written every delta change. + m_WindowSaveTimer.setSingleShot(true); + m_WindowSaveTimer.start(1000); +} + void MainWindow::open() { std::array trayMenu = { @@ -522,7 +593,7 @@ void MainWindow::saveSettings() { appConfig().setServerHostname(m_pLineEditHostname->text()); serverConfig().setClientAddress(m_pLineEditClientIp->text()); - appConfig().config().saveAll(); + appConfig().scopes().saveAll(); } void MainWindow::setIcon(CoreState state) const { @@ -555,7 +626,7 @@ void MainWindow::appendLogInfo(const QString &text) { } void MainWindow::appendLogDebug(const QString &text) { - qDebug() << text; + qDebug("%s", text.toStdString().c_str()); if (appConfig().logLevel() >= kDebugLogLevel) { processCoreLogLine(getTimeStamp() + " DEBUG: " + text); @@ -621,9 +692,9 @@ void MainWindow::checkConnected(const QString &line) { if (!appConfig().startedBefore() && isVisible()) { QMessageBox::information( this, "Synergy", - tr("Synergy is now connected. You can close the " - "config window and Synergy will remain connected in " - "the background.")); + QString("Synergy is now connected. You can close the " + "config window and Synergy will remain connected in " + "the background.")); appConfig().setStartedBefore(true); } @@ -663,15 +734,16 @@ void MainWindow::checkFingerprint(const QString &line) { messageBoxAlreadyShown = true; QMessageBox::StandardButton fingerprintReply = QMessageBox::information( - this, tr("Security question"), - tr("You are connecting to a server. Here is it's fingerprint:\n\n" - "%1\n\n" - "Compare this fingerprint to the one on your server's screen." - "If the two don't match exactly, then it's probably not the server " - "you're expecting (it could be a malicious user).\n\n" - "To automatically trust this fingerprint for future " - "connections, click Yes. To reject this fingerprint and " - "disconnect from the server, click No.") + this, QString("Security question"), + QString( + "You are connecting to a server. Here is it's fingerprint:\n\n" + "%1\n\n" + "Compare this fingerprint to the one on your server's screen." + "If the two don't match exactly, then it's probably not the server " + "you're expecting (it could be a malicious user).\n\n" + "To automatically trust this fingerprint for future " + "connections, click Yes. To reject this fingerprint and " + "disconnect from the server, click No.") .arg(fingerprint), QMessageBox::Yes | QMessageBox::No); @@ -806,7 +878,7 @@ void MainWindow::startCore() { args << "--profile-dir" << getProfileRootForArg(); } catch (const std::exception &e) { qDebug() << e.what(); - qFatal("Failed to get profile dir, skipping arg"); + qFatal("failed to get profile dir, skipping arg"); } #else @@ -861,11 +933,12 @@ void MainWindow::startCore() { if (!m_pCoreProcess->waitForStarted()) { show(); QMessageBox::warning( - this, tr("Program can not be started"), + this, QString("Program can not be started"), QString( - tr("The executable

%1

could not be successfully " - "started, although it does exist. Please check if you have " - "sufficient permissions to run this program.") + QString( + "The executable

%1

could not be successfully " + "started, although it does exist. Please check if you have " + "sufficient permissions to run this program.") .arg(app))); return; } @@ -881,8 +954,8 @@ bool MainWindow::clientArgs(QStringList &args, QString &app) { if (!QFile::exists(app)) { show(); QMessageBox::warning( - this, tr("Synergy client not found"), - tr("The executable for the synergy client does not exist.")); + this, QString("Synergy client not found"), + QString("The executable for the synergy client does not exist.")); return false; } @@ -906,8 +979,8 @@ bool MainWindow::clientArgs(QStringList &args, QString &app) { if (m_pLineEditHostname->text().isEmpty()) { show(); QMessageBox::warning( - this, tr("IP/hostname is empty"), - tr("Please enter a server hostname or IP address.")); + this, QString("IP/hostname is empty"), + QString("Please enter a server hostname or IP address.")); return false; } @@ -937,15 +1010,15 @@ QString MainWindow::configFilename() { {QStandardPaths::AppDataLocation, QStandardPaths::AppConfigLocation}) { auto configDirPath = QStandardPaths::writableLocation(path); if (!QDir().mkpath(configDirPath)) { - errors.push_back( - tr("Failed to create config folder \"%1\"").arg(configDirPath)); + errors.push_back(QString("Failed to create config folder \"%1\"") + .arg(configDirPath)); continue; } QFile configFile(configDirPath + "/LastConfig.cfg"); if (!configFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) { errors.push_back( - tr("File:\"%1\" Error:%2") + QString("File:\"%1\" Error:%2") .arg(configFile.fileName(), configFile.errorString())); continue; } @@ -959,7 +1032,7 @@ QString MainWindow::configFilename() { if (configFullPath.isEmpty()) { QMessageBox::critical( - this, tr("Cannot write configuration file"), errors.join('\n')); + this, QString("Cannot write configuration file"), errors.join('\n')); } } @@ -990,15 +1063,15 @@ bool MainWindow::serverArgs(QStringList &args, QString &app) { if (!QFile::exists(app)) { QMessageBox::warning( - this, tr("Synergy server not found"), - tr("The executable for the synergy server does not exist.")); + this, QString("Synergy server not found"), + QString("The executable for the synergy server does not exist.")); return false; } if (appConfig().invertConnection() && m_pLineEditClientIp->text().isEmpty()) { QMessageBox::warning( - this, tr("Client IP address or name is empty"), - tr("Please fill in a client IP address or name.")); + this, QString("Client IP address or name is empty"), + QString("Please fill in a client IP address or name.")); return false; } @@ -1080,7 +1153,7 @@ void MainWindow::setCoreState(CoreState state) { m_pButtonToggleStart, &QPushButton::clicked, m_pActionStopCore, &QAction::trigger); - m_pButtonToggleStart->setText(tr("&Stop")); + m_pButtonToggleStart->setText(QString("&Stop")); m_pButtonApply->setEnabled(true); m_pActionStartCore->setEnabled(false); @@ -1094,7 +1167,7 @@ void MainWindow::setCoreState(CoreState state) { m_pButtonToggleStart, &QPushButton::clicked, m_pActionStartCore, &QAction::trigger); - m_pButtonToggleStart->setText(tr("&Start")); + m_pButtonToggleStart->setText(QString("&Start")); m_pButtonApply->setEnabled(false); m_pActionStartCore->setEnabled(true); @@ -1106,8 +1179,7 @@ void MainWindow::setCoreState(CoreState state) { case Listening: { if (coreMode() == CoreMode::Server) { - setStatus( - tr("Synergy is waiting for clients").arg(m_SecureSocketVersion)); + setStatus("Synergy is waiting for clients"); } break; @@ -1115,21 +1187,20 @@ void MainWindow::setCoreState(CoreState state) { case Connected: { if (m_SecureSocket) { setStatus( - tr("Synergy is connected (with %1)").arg(m_SecureSocketVersion)); + QString("Synergy is connected (with %1)").arg(m_SecureSocketVersion)); } else { - setStatus(tr("Synergy is running (without TLS encryption)") - .arg(m_SecureSocketVersion)); + setStatus("Synergy is running (without TLS encryption)"); } break; } case Connecting: - setStatus(tr("Synergy is starting...")); + setStatus("Synergy is starting..."); break; case PendingRetry: - setStatus(tr("There was an error, retrying...")); + setStatus("There was an error, retrying..."); break; case Disconnected: - setStatus(tr("Synergy is not running")); + setStatus("Synergy is not running"); break; } @@ -1176,8 +1247,8 @@ QString MainWindow::getIPAddresses() const { // usually 192.168.x.x is a useful ip for the user, so indicate // this by making it bold. if (!hinted && address.isInSubnet(localnet)) { - QString format = "%1"; - result.append(format.arg(address.toString())); + QString format = R"(%2)"; + result.append(format.arg(kColorTertiary, address.toString())); hinted = true; } else { result.append(address.toString()); @@ -1186,7 +1257,7 @@ QString MainWindow::getIPAddresses() const { } if (result.isEmpty()) { - result.append(tr("Unknown")); + result.append("Unknown"); } return result.join(", "); @@ -1196,10 +1267,10 @@ void MainWindow::showLicenseNotice() { const auto &license = m_LicenseHandler.license(); const bool timeLimited = license.isTimeLimited(); - m_labelNotice->setVisible(timeLimited); + m_pLabelNotice->setVisible(timeLimited); if (timeLimited) { auto notice = licenseNotice(m_LicenseHandler.license()); - this->m_labelNotice->setText(notice); + this->m_pLabelNotice->setText(notice); } } @@ -1209,7 +1280,7 @@ void MainWindow::updateLocalFingerprint() { fingerprintExists = TlsFingerprint::local().fileExists(); } catch (const std::exception &e) { qDebug() << e.what(); - qFatal("Failed to check if fingerprint exists"); + qFatal("failed to check if fingerprint exists"); } if (m_AppConfig.tlsEnabled() && fingerprintExists && @@ -1244,13 +1315,13 @@ void MainWindow::autoAddScreen(const QString name) { if (r != kAutoAddScreenOk) { switch (r) { case kAutoAddScreenManualServer: - showConfigureServer(tr("Please add the server (%1) to the grid.") + showConfigureServer(QString("Please add the server (%1) to the grid.") .arg(appConfig().screenName())); break; case kAutoAddScreenManualClient: - showConfigureServer(tr("Please drag the new client screen (%1) " - "to the desired position on the grid.") + showConfigureServer(QString("Please drag the new client screen (%1) " + "to the desired position on the grid.") .arg(name)); break; } @@ -1316,17 +1387,12 @@ void MainWindow::secureSocket(bool secureSocket) { } } -void MainWindow::windowStateChanged() { - if (windowState() == Qt::WindowMinimized && appConfig().minimizeToTray()) - hide(); -} - void MainWindow::updateScreenName() { m_pLabelComputerName->setText( QString("This computer's name: %1 " - R"((change))") + R"((change))") .arg(appConfig().screenName()) - .arg(kLinkStyleSecondary)); + .arg(kColorSecondary)); serverConfig().updateServerName(); } diff --git a/src/gui/src/MainWindow.h b/src/gui/src/MainWindow.h index 0e75901e5..10ddcf4b4 100644 --- a/src/gui/src/MainWindow.h +++ b/src/gui/src/MainWindow.h @@ -29,13 +29,13 @@ #include "ui_MainWindowBase.h" #include "ActivationDialog.h" -#include "AppConfig.h" #include "ClientConnection.h" -#include "Config.h" #include "ServerConfig.h" #include "ServerConnection.h" #include "TrayIcon.h" #include "global/Ipc.h" +#include "gui/AppConfig.h" +#include "gui/ConfigScopes.h" #include "gui/QIpcClient.h" #include "gui/TlsUtility.h" #include "gui/VersionChecker.h" @@ -126,6 +126,9 @@ private slots: void onActionStopCoreTriggered(); void onCoreProcessReadyReadStandardOutput(); void onCoreProcessReadyReadStandardError(); + void onWindowSaveTimerTimeout(); + + // autoconnect slots void on_m_pButtonApply_clicked(); void on_m_pLabelComputerName_linkActivated(const QString &link); void on_m_pLabelFingerprint_linkActivated(const QString &link); @@ -141,7 +144,7 @@ private slots: void on_m_pActivate_triggered(); private: - QSettings &settings() { return *appConfig().config().currentSettings(); } + QSettings &settings() { return *appConfig().scopes().currentSettings(); } AppConfig &appConfig() { return m_AppConfig; } AppConfig const &appConfig() const { return m_AppConfig; } void createMenuBar(); @@ -184,6 +187,11 @@ private: void showConfigureServer() { showConfigureServer(""); } void showLicenseNotice(); void stopCore(); + void restoreWindow(); + void saveWindow(); + void setupControls(); + void resizeEvent(QResizeEvent *event) override; + void moveEvent(QMoveEvent *event) override; #ifdef Q_OS_MAC void checkOSXNotification(const QString &line); @@ -207,6 +215,7 @@ private: bool m_AlreadyHidden = false; bool m_SecureSocket = false; QString m_SecureSocketVersion = ""; + bool m_SaveWindow = false; AppConfig &m_AppConfig; LicenseHandler m_LicenseHandler; @@ -214,4 +223,5 @@ private: ServerConnection m_ServerConnection; ClientConnection m_ClientConnection; synergy::gui::TlsUtility m_TlsUtility; + QTimer m_WindowSaveTimer; }; diff --git a/src/gui/src/MainWindowBase.ui b/src/gui/src/MainWindowBase.ui index 8181aaf2b..12fa3eb35 100644 --- a/src/gui/src/MainWindowBase.ui +++ b/src/gui/src/MainWindowBase.ui @@ -6,8 +6,8 @@ 0 0 - 750 - 700 + 800 + 600
@@ -57,13 +57,6 @@
- - padding: 3px 5px; -border-radius: 3px; -background-color: #3B67D3; -color: #ffffff; -top: 3px; - m_pLabelUpdate @@ -92,6 +85,9 @@ top: 3px; + + <html><head/><body><p>The highlighted IP is the one we think you should use. The server listens on all IPs, so the other IPs may work as well.</p></body></html> + This computer's IP addresses: @@ -106,21 +102,6 @@ top: 3px; - - 16 - - - 0 - - - 15 - - - 0 - - - 8 - @@ -129,29 +110,30 @@ top: 3px; 0 - - .QFrame{ -border: 1px solid rgba(192,192,192, 0.2);; -border-radius: 4px; -background-color: rgba(192,192,192, 0.1); -} - 15 - - - - QRadioButton::indicator{ - top: -7px; -} - - - Use this computer's keyboard and mouse -(make this computer the &server) - - + + + + + + Use this computer's keyboard and mouse + + + + + + + (make this computer the server) + + + 20 + + + + @@ -293,32 +275,30 @@ background-color: rgba(192,192,192, 0.1); 0 - - .QFrame{ -border: 1px solid rgba(192,192,192, 0.2); -border-radius: 4px; -background-color: rgba(192,192,192, 0.1); -} - 15 - - 11 - - - - - QRadioButton::indicator{ - top: -7px; -} - - - Use another computer’s mouse and keyboard -(make this computer the &client) - - + + + + + + Use another computer’s mouse and keyboard + + + + + + + (make this computer the client) + + + 20 + + + + @@ -409,9 +389,6 @@ background-color: rgba(192,192,192, 0.1); - - - Logs @@ -441,13 +418,6 @@ background-color: rgba(192,192,192, 0.1); 0 - - .QFrame{ -border: 1px solid rgba(192,192,192, 0.2);; -border-radius: 4px; -background-color: rgba(192,192,192, 0.1); -} - QFrame::StyledPanel @@ -481,9 +451,6 @@ background-color: rgba(192,192,192, 0.1); true - - false - false @@ -546,19 +513,12 @@ background-color: rgba(192,192,192, 0.1); - + false - - padding: 3px 5px; -border-radius: 3px; -background-color: #3B67D3; -color: #ffffff; -top: 3px; - - m_labelNotice + m_pLabelNotice Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter @@ -736,6 +696,18 @@ top: 3px;
widgets/ClientStateLabel.h
+ + m_pRadioGroupServer + m_pRadioGroupClient + m_pLineEditClientIp + m_pButtonConnectToClient + m_pButtonConfigureServer + m_pLineEditHostname + m_pButtonConnect + m_pLogOutput + m_pButtonApply + m_pButtonToggleStart + diff --git a/src/gui/src/QSynergyApplication.cpp b/src/gui/src/QSynergyApplication.cpp index ce6a6bc30..76e9d5695 100644 --- a/src/gui/src/QSynergyApplication.cpp +++ b/src/gui/src/QSynergyApplication.cpp @@ -26,12 +26,6 @@ QSynergyApplication::QSynergyApplication(int &argc, char **argv) : QApplication(argc, argv) { - QFontDatabase::addApplicationFont(":/res/fonts/Arial.ttf"); - QFont Arial("Arial"); - Arial.setPixelSize(13); - Arial.setStyleHint(QFont::SansSerif); - setFont(Arial); - // Setting the style to 'Fusion' seems to fix issues such as text being // rendered as black on black. This may not be the style we want long-term // but it does fix the style issues for now. diff --git a/src/gui/src/ScreenSettingsDialog.cpp b/src/gui/src/ScreenSettingsDialog.cpp index 530d15f88..9dbb7b581 100644 --- a/src/gui/src/ScreenSettingsDialog.cpp +++ b/src/gui/src/ScreenSettingsDialog.cpp @@ -18,8 +18,10 @@ #include "ScreenSettingsDialog.h" #include "Screen.h" +#include "gui/constants.h" #include "validators/AliasValidator.h" #include "validators/ScreenNameValidator.h" +#include "validators/ValidationError.h" #include #include @@ -30,15 +32,21 @@ ScreenSettingsDialog::ScreenSettingsDialog( : QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint), Ui::ScreenSettingsDialogBase(), m_pScreen(pScreen) { + setupUi(this); + m_pLabelAliasError->setStyleSheet(kStyleErrorActiveLabel); + m_pLabelNameError->setStyleSheet(kStyleErrorActiveLabel); + m_pLineEditName->setText(m_pScreen->name()); m_pLineEditName->setValidator(new validators::ScreenNameValidator( - m_pLineEditName, m_pLabelNameError, pScreens)); + m_pLineEditName, new validators::ValidationError(this, m_pLabelNameError), + pScreens)); m_pLineEditName->selectAll(); - m_pLineEditAlias->setValidator( - new validators::AliasValidator(m_pLineEditAlias, m_pLabelAliasError)); + m_pLineEditAlias->setValidator(new validators::AliasValidator( + m_pLineEditAlias, + new validators::ValidationError(this, m_pLabelAliasError))); for (int i = 0; i < m_pScreen->aliases().count(); i++) new QListWidgetItem(m_pScreen->aliases()[i], m_pListAliases); diff --git a/src/gui/src/ScreenSettingsDialog.h b/src/gui/src/ScreenSettingsDialog.h index ec0cda1a7..4d483fe91 100644 --- a/src/gui/src/ScreenSettingsDialog.h +++ b/src/gui/src/ScreenSettingsDialog.h @@ -1,6 +1,6 @@ /* * synergy -- mouse and keyboard sharing utility - * Copyright (C) 2012-2016 Symless Ltd. + * Copyright (C) 2012 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) * * This package is free software; you can redistribute it and/or @@ -16,10 +16,7 @@ * along with this program. If not, see . */ -#if !defined(SCREENSETTINGSDIALOG__H) - -#define SCREENSETTINGSDIALOG__H -#include +#pragma once #include @@ -52,5 +49,3 @@ private slots: private: Screen *m_pScreen; }; - -#endif diff --git a/src/gui/src/ScreenSettingsDialogBase.ui b/src/gui/src/ScreenSettingsDialogBase.ui index a1c3b8042..4262e3fdc 100644 --- a/src/gui/src/ScreenSettingsDialogBase.ui +++ b/src/gui/src/ScreenSettingsDialogBase.ui @@ -6,8 +6,8 @@ 0 0 - 403 - 675 + 440 + 739
@@ -43,13 +43,6 @@ - - .QFrame{ -border: 1px solid rgba(192,192,192, 0.2); -border-radius: 4px; -background-color: rgba(192,192,192, 0.1); -} - QFrame::StyledPanel @@ -106,14 +99,8 @@ background-color: rgba(192,192,192, 0.1); 0 - - color: #EC4C47; -font-size: 13px; -font-family: Arial; -font-weight: bold; - - + m_pLabelNameError Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter @@ -154,13 +141,6 @@ font-weight: bold; - - .QFrame{ -border: 1px solid rgba(192,192,192, 0.2); -border-radius: 4px; -background-color: rgba(192,192,192, 0.1); -} - QFrame::StyledPanel @@ -477,13 +457,6 @@ background-color: rgba(192,192,192, 0.1); 0 - - .QFrame{ -border: 1px solid rgba(192,192,192, 0.2); -border-radius: 4px; -background-color: rgba(192,192,192, 0.1); -} - QFrame::StyledPanel @@ -648,13 +621,6 @@ background-color: rgba(192,192,192, 0.1); - - .QFrame{ -border: 1px solid rgba(192,192,192, 0.2); -border-radius: 4px; -background-color: rgba(192,192,192, 0.1); -} - QFrame::StyledPanel @@ -760,19 +726,6 @@ background-color: rgba(192,192,192, 0.1); - - - 0 - 0 - - - - .QFrame{ -border: 1px solid rgba(192,192,192, 0.2); -border-radius: 4px; -background-color: rgba(192,192,192, 0.1); -} - QFrame::StyledPanel @@ -809,26 +762,6 @@ background-color: rgba(192,192,192, 0.1); false - - - 0 - 0 - - - - - 43 - 20 - - - - Qt::LeftToRight - - - QPushButton#m_pButtonAddAlias{ -left: 30px; -} - &Add @@ -848,9 +781,6 @@ left: 30px; 20 - - - 255 @@ -876,14 +806,8 @@ left: 30px; 16777215 - - color: #EC4C47; -font-size: 13px; -font-family: Arial; -font-weight: bold; - - + m_pLabelNameError true @@ -933,9 +857,6 @@ font-weight: bold; 16777215 - - - QAbstractItemView::ExtendedSelection @@ -946,12 +867,6 @@ font-weight: bold; false - - - 0 - 0 - - &Remove diff --git a/src/gui/src/ScreenSetupModel.cpp b/src/gui/src/ScreenSetupModel.cpp index 39e217b5a..b68021b1c 100644 --- a/src/gui/src/ScreenSetupModel.cpp +++ b/src/gui/src/ScreenSetupModel.cpp @@ -35,14 +35,14 @@ ScreenSetupModel::ScreenSetupModel( // this is unlikely to happen, as the grid size is only 3x9. if (m_NumColumns > 100 || m_NumRows > 100) { qFatal( - "Grid size out of bounds: %d columns x %d rows", m_NumColumns, + "grid size out of bounds: %d columns x %d rows", m_NumColumns, m_NumRows); return; } if (m_NumColumns * m_NumRows > screens.size()) { qFatal( - "Scrren list (%lld) too small for %d columns x %d rows", screens.size(), + "scrren list (%lld) too small for %d columns x %d rows", screens.size(), m_NumColumns, m_NumRows); } } diff --git a/src/gui/src/ScreenSetupView.cpp b/src/gui/src/ScreenSetupView.cpp index 5bf8027cf..6821c826c 100644 --- a/src/gui/src/ScreenSetupView.cpp +++ b/src/gui/src/ScreenSetupView.cpp @@ -91,8 +91,9 @@ void ScreenSetupView::dragMoveEvent(QDragMoveEvent *event) { event->setDropAction(Qt::MoveAction); event->accept(); } else { - int col = columnAt(event->pos().x()); - int row = rowAt(event->pos().y()); + const auto &point = event->position().toPoint(); + int col = columnAt(point.x()); + int row = rowAt(point.y()); // a drop from outside is not allowed if there's a screen already there. if (!model()->screen(col, row).isNull()) diff --git a/src/gui/src/ServerConfig.cpp b/src/gui/src/ServerConfig.cpp index 478d220d8..a2abe10f4 100644 --- a/src/gui/src/ServerConfig.cpp +++ b/src/gui/src/ServerConfig.cpp @@ -19,9 +19,9 @@ #include "ServerConfig.h" #include "AddClientDialog.h" -#include "Config.h" #include "Hotkey.h" #include "MainWindow.h" +#include "gui/ConfigScopes.h" #include "gui/constants.h" #include @@ -51,7 +51,7 @@ ServerConfig::ServerConfig( m_NumColumns(numColumns), m_NumRows(numRows), m_ClipboardSharingSize(defaultClipboardSharingSize()) { - appConfig->config().registerReceiever(this); + appConfig->scopes().registerReceiver(this); } ServerConfig::~ServerConfig() { @@ -553,5 +553,5 @@ QString ServerConfig::getClientAddress() const { } QSettings &ServerConfig::settings() { - return *m_pAppConfig->config().currentSettings(); + return *m_pAppConfig->scopes().currentSettings(); } diff --git a/src/gui/src/ServerConfig.h b/src/gui/src/ServerConfig.h index 0188a5836..320c6ddd5 100644 --- a/src/gui/src/ServerConfig.h +++ b/src/gui/src/ServerConfig.h @@ -18,12 +18,12 @@ #pragma once -#include - -#include "CommonConfig.h" #include "Hotkey.h" #include "ScreenConfig.h" #include "ScreenList.h" +#include "gui/CommonConfig.h" + +#include class QTextStream; class QSettings; diff --git a/src/gui/src/ServerConfigDialog.cpp b/src/gui/src/ServerConfigDialog.cpp index e71f232a7..e82ae9a3f 100644 --- a/src/gui/src/ServerConfigDialog.cpp +++ b/src/gui/src/ServerConfigDialog.cpp @@ -17,13 +17,11 @@ */ #include "ServerConfigDialog.h" + #include "ActionDialog.h" #include "HotkeyDialog.h" #include "ScreenSettingsDialog.h" #include "ServerConfig.h" -#include "UpgradeDialog.h" -#include "gui/constants.h" -#include "license/ProductEdition.h" #include #include @@ -43,8 +41,13 @@ ServerConfigDialog::ServerConfigDialog( serverConfig().numRows()), m_Message(""), m_appConfig(appConfig) { + setupUi(this); + // force the first tab, since qt creator sets the active tab as the last one + // the developer was looking at, and it's easy to accidentally save that. + m_pTabWidget->setCurrentIndex(0); + m_pEditConfigFile->setText(serverConfig().configFile()); m_pCheckBoxUseExternalConfig->setChecked(serverConfig().useExternalConfig()); m_pCheckBoxHeartbeat->setChecked(serverConfig().hasHeartbeat()); diff --git a/src/gui/src/ServerConfigDialog.h b/src/gui/src/ServerConfigDialog.h index 3fbf7f8d7..2d3d94d57 100644 --- a/src/gui/src/ServerConfigDialog.h +++ b/src/gui/src/ServerConfigDialog.h @@ -20,10 +20,9 @@ #define SERVERCONFIGDIALOG__H -#include "AppConfig.h" #include "ScreenSetupModel.h" #include "ServerConfig.h" - +#include "gui/AppConfig.h" #include "ui_ServerConfigDialogBase.h" #include diff --git a/src/gui/src/ServerConfigDialogBase.ui b/src/gui/src/ServerConfigDialogBase.ui index 89fac56b9..c987799c9 100644 --- a/src/gui/src/ServerConfigDialogBase.ui +++ b/src/gui/src/ServerConfigDialogBase.ui @@ -6,8 +6,8 @@ 0 0 - 799 - 508 + 814 + 588 @@ -29,7 +29,7 @@ - 0 + 3 @@ -359,12 +359,6 @@ true - - QGroupBox::title{ - left: -5px; - top: -2px; -} - &Switch computer @@ -510,12 +504,6 @@ true - - QGroupBox::title{ - left: -2px; - top: -2px; -} - Clipboard sharing @@ -617,12 +605,6 @@ true - - QGroupBox::title{ - left: -5px; - top: -2px; -} - &Dead corners for this computer @@ -707,12 +689,6 @@ false - - QGroupBox::title{ - left: -5px; - top: -2px; -} - &Options @@ -738,9 +714,6 @@ true - - padding-left: 2px; - Use &relative mouse moves @@ -759,9 +732,6 @@ true - - left: -2px; - &Check clients every @@ -816,9 +786,6 @@ - - padding-left: 2px; - Ignore auto config clients @@ -826,9 +793,6 @@ - - padding-left: 2px; - Disable lock to screen @@ -839,9 +803,6 @@ true - - padding-left: 2px; - Don't take &foreground window on Windows servers @@ -1110,9 +1071,6 @@ PointingHandCursor - - margin: 0px; padding: 0px; - @@ -1193,6 +1151,39 @@
TrashScreenWidget.h
+ + m_pButtonBrowseConfigFile + m_pButtonAddComputer + m_pScreenSetupView + m_pListHotkeys + m_pButtonNewHotkey + m_pButtonEditHotkey + m_pButtonRemoveHotkey + m_pListActions + m_pButtonNewAction + m_pButtonEditAction + m_pButtonRemoveAction + m_pCheckBoxSwitchDelay + m_pSpinBoxSwitchDelay + m_pCheckBoxSwitchDoubleTap + m_pSpinBoxSwitchDoubleTap + m_pCheckBoxEnableClipboard + m_pSpinBoxClipboardSizeLimit + m_pCheckBoxHeartbeat + m_pSpinBoxHeartbeat + m_pCheckBoxRelativeMouseMoves + m_pCheckBoxWin32KeepForeground + m_pCheckBoxIgnoreAutoConfigClient + m_pCheckBoxDisableLockToScreen + m_pCheckBoxCornerTopLeft + m_pCheckBoxCornerBottomLeft + m_pCheckBoxCornerTopRight + m_pCheckBoxCornerBottomRight + m_pSpinBoxSwitchCornerSize + m_pCheckBoxUseExternalConfig + m_pEditConfigFile + m_pTabWidget + diff --git a/src/gui/src/ServerConnection.cpp b/src/gui/src/ServerConnection.cpp index a5359667d..7d769bd02 100644 --- a/src/gui/src/ServerConnection.cpp +++ b/src/gui/src/ServerConnection.cpp @@ -18,10 +18,10 @@ #include "ServerConnection.h" -#include "AppConfig.h" #include "MainWindow.h" #include "ServerConfigDialog.h" #include "ServerMessage.h" +#include "gui/AppConfig.h" #include diff --git a/src/gui/src/SettingsDialog.cpp b/src/gui/src/SettingsDialog.cpp index 033c6e95f..e12cb05ce 100644 --- a/src/gui/src/SettingsDialog.cpp +++ b/src/gui/src/SettingsDialog.cpp @@ -18,18 +18,19 @@ #include "SettingsDialog.h" -#include "AppConfig.h" #include "MainWindow.h" #include "UpgradeDialog.h" +#include "gui/AppConfig.h" #include "gui/TlsCertificate.h" #include "gui/constants.h" +#include "validators/ScreenNameValidator.h" +#include "validators/ValidationError.h" #include #include #include #include #include -#include using namespace synergy::license; @@ -45,6 +46,10 @@ SettingsDialog::SettingsDialog( setupUi(this); + // force the first tab, since qt creator sets the active tab as the last one + // the developer was looking at, and it's easy to accidentally save that. + m_pTabWidget->setCurrentIndex(0); + m_pMainWindow = dynamic_cast(parent); loadFromConfig(); @@ -52,45 +57,16 @@ SettingsDialog::SettingsDialog( updateControlsEnabled(); const auto &serveConfig = m_pMainWindow->serverConfig(); - m_screenNameValidator = std::make_unique( - m_pLineEditScreenName, nullptr, (&serveConfig.screens())); - connect( - m_screenNameValidator.get(), SIGNAL(finished(QString)), this, - SLOT(on_m_pScreenNameValidator_finished(QString))); - m_pLineEditScreenName->setValidator(m_screenNameValidator.get()); - 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_pCheckBoxMinimizeToTray, SIGNAL(clicked()), this, SLOT(onChange())); - connect(m_pCheckBoxAutoHide, SIGNAL(clicked()), this, SLOT(onChange())); - connect(m_pCheckBoxPreventSleep, 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())); - connect(m_pCheckBoxLanguageSync, SIGNAL(clicked()), this, SLOT(onChange())); - connect( - m_pCheckBoxScrollDirection, SIGNAL(clicked()), this, SLOT(onChange())); - - adjustSize(); + m_pScreenNameError = new validators::ValidationError(this); + m_pLineEditScreenName->setValidator(new validators::ScreenNameValidator( + m_pLineEditScreenName, m_pScreenNameError, &serveConfig.screens())); } void SettingsDialog::accept() { - if (!m_nameError.isEmpty()) { - QMessageBox::warning(this, tr("Invalid screen name"), m_nameError); + if (!m_pLineEditScreenName->hasAcceptableInput()) { + QMessageBox::warning( + this, tr("Invalid screen name"), m_pScreenNameError->message()); return; } @@ -105,7 +81,6 @@ void SettingsDialog::accept() { static_cast(m_pComboElevate->currentIndex())); appConfig().setAutoHide(m_pCheckBoxAutoHide->isChecked()); appConfig().setPreventSleep(m_pCheckBoxPreventSleep->isChecked()); - appConfig().setMinimizeToTray(m_pCheckBoxMinimizeToTray->isChecked()); appConfig().setTlsCertPath(m_pLineEditCertificatePath->text()); appConfig().setTlsKeyLength(m_pComboBoxKeyLength->currentText()); appConfig().setTlsEnabled(m_pCheckBoxEnableCrypto->isChecked()); @@ -138,7 +113,6 @@ void SettingsDialog::loadFromConfig() { m_pLineEditLogFilename->setText(appConfig().logFilename()); m_pCheckBoxAutoHide->setChecked(appConfig().autoHide()); m_pCheckBoxPreventSleep->setChecked(appConfig().preventSleep()); - m_pCheckBoxMinimizeToTray->setChecked(appConfig().minimizeToTray()); m_pLineEditCertificatePath->setText(appConfig().tlsCertPath()); m_pCheckBoxEnableCrypto->setChecked(m_appConfig.tlsEnabled()); m_pCheckBoxLanguageSync->setChecked(m_appConfig.languageSync()); @@ -179,7 +153,7 @@ void SettingsDialog::updateTlsControlsEnabled() { auto enabled = !clientMode && tlsAvailable && tlsChecked; qDebug( - "TLS controls enabled=%d, client=%d, available=%d, checked=%d", enabled, + "tls enabled=%d, client=%d, available=%d, checked=%d", enabled, clientMode, tlsAvailable, tlsChecked); m_pLabelKeyLength->setEnabled(enabled); @@ -290,7 +264,6 @@ void SettingsDialog::updateControlsEnabled() { m_pComboElevate->setEnabled(writable); m_pCheckBoxAutoHide->setEnabled(writable); m_pCheckBoxPreventSleep->setEnabled(writable); - m_pCheckBoxMinimizeToTray->setEnabled(writable); m_pLineEditCertificatePath->setEnabled(writable); m_pComboBoxKeyLength->setEnabled(writable); m_pPushButtonBrowseCert->setEnabled(writable); @@ -326,7 +299,3 @@ void SettingsDialog::updateControlsEnabled() { updateTlsControls(); } - -void SettingsDialog::on_m_pScreenNameValidator_finished(const QString &error) { - m_nameError = error; -} diff --git a/src/gui/src/SettingsDialog.h b/src/gui/src/SettingsDialog.h index 83d820422..ca9b44d71 100644 --- a/src/gui/src/SettingsDialog.h +++ b/src/gui/src/SettingsDialog.h @@ -18,15 +18,14 @@ #pragma once -#include "gui/TlsUtility.h" #include "ui_SettingsDialogBase.h" #include "gui/CoreInterface.h" +#include "gui/TlsUtility.h" #include "license/License.h" -#include "validators/ScreenNameValidator.h" +#include "validators/ValidationError.h" #include -#include class MainWindow; class AppConfig; @@ -67,13 +66,12 @@ protected: void updateTlsControlsEnabled(); private: - QString m_nameError = ""; MainWindow *m_pMainWindow; AppConfig &m_appConfig; CoreInterface m_coreInterface; const synergy::license::License &m_license; synergy::gui::TlsUtility m_tlsUtility; - std::unique_ptr m_screenNameValidator; + validators::ValidationError *m_pScreenNameError; /// @brief Stores settings scope at start of settings dialog /// This is neccessary to restore state if user changes @@ -84,23 +82,8 @@ private slots: void on_m_pCheckBoxEnableCrypto_clicked(bool checked); void on_m_pCheckBoxLogToFile_stateChanged(int); void on_m_pButtonBrowseLog_clicked(); - - /// @brief Handles the toggling of the system scoped radio button - /// As the user scope radio is connected this will fire for either - /// radio button void on_m_pRadioSystemScope_toggled(bool checked); - - /// @brief Handles the click event of the Cert Path browse button - /// displaying a file browser void on_m_pPushButtonBrowseCert_clicked(); - - /// @brief Handles the TLS cert key length changed event void on_m_pComboBoxKeyLength_currentIndexChanged(int index); - - /// @brief handels the regenerate cert button event - /// This will regenerate the TLS certificate as long as the settings - /// haven't changed void on_m_pPushButtonRegenCert_clicked(); - - void on_m_pScreenNameValidator_finished(const QString &error); }; diff --git a/src/gui/src/SettingsDialogBase.ui b/src/gui/src/SettingsDialogBase.ui index bf7374c93..fb4ddd1c9 100644 --- a/src/gui/src/SettingsDialogBase.ui +++ b/src/gui/src/SettingsDialogBase.ui @@ -6,8 +6,8 @@ 0 0 - 500 - 830 + 550 + 582 @@ -16,282 +16,705 @@ 0 - - - 400 - 620 - - Preferences - - - 11 + + + 15 - - 11 - - - 11 - - - 5 - - - - - .QFrame{ -border: 1px solid rgba(192,192,192, 0.2); -border-radius: 4px; -background-color: rgba(192,192,192, 0.1); -} - + + + + QTabWidget::North - - QFrame::Shape::StyledPanel + + 1 - - QFrame::Shadow::Raised - - - - 17 - - - 17 - - - - - - - - 0 - 0 - + + + &Regular + + + + 15 + + + 15 + + + + + Basics + + + + + + + + + 0 + 0 + + + + + 75 + 0 + + + + Computer name + + + + + + + Qt::Horizontal + + + QSizePolicy::Maximum + + + + 20 + 20 + + + + + + + + true + + + 255 + + + + + + + + + Prevent this computer from going to sleep + + + + + + + Use server's keyboard language on this computer (client mode) + + + + + + + Invert scroll direction on this computer (client mode) + + + + + + + + + + App + + + + + + Leave app running in notification area when the window is closed + + + + + + + Hide the window when the app starts + + + + + + + + + + Security + + + + 5 - - - 75 - 0 - + + 9 - - Computer &name + + 9 - - m_pLineEditScreenName + + + + 0 + + + + + true + + + Enable TLS encryption + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + Key length + + + + + + + 1024 + + + + 1024 + + + + + 2048 + + + + + 4096 + + + + + + + + + + 0 + + + + + + 0 + 0 + + + + Certificate + + + + + + + Qt::Horizontal + + + QSizePolicy::Minimum + + + + 30 + 20 + + + + + + + + + 0 + 0 + + + + + + + + PointingHandCursor + + + + + + + :/res/icons/64x64/folder.png:/res/icons/64x64/folder.png + + + + 20 + 13 + + + + true + + + + + + + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Regenerate certificate + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + &Advanced + + + + 15 + + + 15 + + + + + Networking + + + + + + 0 + + + + + + 0 + 0 + + + + Port + + + + + + + true + + + + 0 + 0 + + + + 65535 + + + 24800 + + + + + + + + 0 + 0 + + + + Network IP + + + + + + + true + + + + + + + + + false + + + Invert server/client TCP connection (business edition) + + + + + + + + + + Logs + + + + 15 - - - - - - Qt::Orientation::Horizontal + + 15 - - QSizePolicy::Policy::Maximum + + 7 - - - 20 - 20 - + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Log to file + + + + + + + + Info + + + + + Debug + + + + + Debug1 + + + + + Debug2 + + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + Level + + + + + + + 3 + + + 0 + + + + + + 0 + 0 + + + + Log path + + + + + + + Qt::Horizontal + + + QSizePolicy::Minimum + + + + 30 + 20 + + + + + + + + false + + + + 0 + 0 + + + + + + + + false + + + PointingHandCursor + + + + + + + :/res/icons/64x64/folder.png:/res/icons/64x64/folder.png + + + + 20 + 13 + + + + true + + + + + + + + + + + + + 0 + 0 + + + + Service + + + + + + + + + 0 + 0 + + + + Launch with elevated privilages + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + Specify when the Synergy service should run at an elevated privilege level + + + 0 + + + + Automatic (as needed) + + + + + Always elevate + + + + + Never elevate + + + + + + + + + + Use background service (daemon) + + + + + + + + + + Use settings profile from + + + + 5 - - - - - - true - - - 255 - - - - - - - - - 0 - - - - - - 0 - 0 - - - - P&ort - - - m_pSpinBoxPort - - - - - - - true - - - - 0 - 0 - - - - 65535 - - - 24800 - - - - - - - - 0 - 0 - - - - Network IP - - - m_pLineEditInterface - - - - - - - true - - - - - - - - - 0 - - - - - Minimize to tray on close - - - - - - - Qt::Orientation::Horizontal - - - - 40 - 20 - - - - - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 16777215 - 16777215 - - - - Qt::LayoutDirection::LeftToRight - - - Minimize to system &tray - - - - - - - - - Hide window on start - - - - + + + + All users + + + false + + + + + + + Current user + + + true + + + + +
+
+ + + + Qt::Vertical + + + + 20 + 40 + + + + +
+
- + - Qt::Orientation::Vertical - - - QSizePolicy::Policy::Fixed - - - - 20 - 3 - - - - - - - - - 0 - 0 - - - - Advanced - - - - - - - Qt::Orientation::Vertical - - - QSizePolicy::Policy::Fixed - - - - 20 - 3 - - - - - - - - Qt::Orientation::Vertical + Qt::Vertical @@ -301,629 +724,22 @@ background-color: rgba(192,192,192, 0.1); - - - - - 0 - 0 - - - - Logs - - - - - - - - 0 - 0 - - - - .QFrame{ -border: 1px solid rgba(192,192,192, 0.2); -border-radius: 4px; -background-color: rgba(192,192,192, 0.1); -} - - - - QFrame::Shape::StyledPanel - - - QFrame::Shadow::Raised - - - - - - Stop this computer from sleeping - - - - - - - Invert scroll direction on this computer (client mode) - - - - - - - false - - - Invert server/client TCP connection (business edition) - - - - - - - Use server's keyboard language on this computer (client mode) - - - - - - - - - - 0 - 0 - - - - Elevate privileges (service required) - - - - - - - - 0 - 0 - - - - - 0 - 0 - - - - Specify when the Synergy service should run at an elevated privilege level - - - 0 - - - - As Needed - - - - - Always - - - - - Never - - - - - - - - - - Use background service (daemon) - - - - - - - - - - - 0 - 0 - - - - Use settings profile from - - - - - - - Qt::Orientation::Vertical - - - QSizePolicy::Policy::Fixed - - - - 20 - 3 - - - - - - - - .QFrame{ -border: 1px solid rgba(192,192,192, 0.2); -border-radius: 4px; -background-color: rgba(192,192,192, 0.1); -} - - - - QFrame::Shape::StyledPanel - - - QFrame::Shadow::Raised - - - - 15 - - - 15 - - - 6 - - - - - All users - - - true - - - - - - - Current user - - - - - - - - - - .QFrame{ -border: 1px solid rgba(192,192,192, 0.2); -border-radius: 4px; -background-color: rgba(192,192,192, 0.1); -} - - - - QFrame::Shape::StyledPanel - - - QFrame::Shadow::Raised - - - - 5 - - - 9 - - - 9 - - - - - 0 - - - - - true - - - Enable TLS encryption - - - - - - - Qt::Orientation::Horizontal - - - - 40 - 20 - - - - - - - - - 0 - 0 - - - - Key length - - - - - - - 1024 - - - - 1024 - - - - - 2048 - - - - - 4096 - - - - - - - - - - 0 - - - - - - 0 - 0 - - - - Certificate - - - - - - - Qt::Orientation::Horizontal - - - QSizePolicy::Policy::Minimum - - - - 30 - 20 - - - - - - - - - 0 - 0 - - - - - - - - PointingHandCursor - - - margin: 0px; padding: 0px; - - - - - - - :/res/icons/64x64/folder.png:/res/icons/64x64/folder.png - - - - 20 - 13 - - - - true - - - - - - - - - 0 - - - - - Qt::Orientation::Horizontal - - - - 40 - 20 - - - - - - - - Regenerate certificate - - - - - - - - - + - Qt::Orientation::Horizontal + Qt::Horizontal - QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Save + QDialogButtonBox::Cancel|QDialogButtonBox::Save - - - - .QFrame{ -border: 1px solid rgba(192,192,192, 0.2); -border-radius: 4px; -background-color: rgba(192,192,192, 0.1); -} - - - - QFrame::Shape::StyledPanel - - - QFrame::Shadow::Raised - - - - 15 - - - 15 - - - 7 - - - - - Qt::Orientation::Horizontal - - - - 40 - 20 - - - - - - - - Log to file - - - - - - - - Info - - - - - Debug - - - - - Debug1 - - - - - Debug2 - - - - - - - - - 0 - 0 - - - - - 0 - 0 - - - - Level - - - m_pComboLogLevel - - - - - - - 3 - - - 0 - - - - - - 0 - 0 - - - - Log path - - - - - - - Qt::Orientation::Horizontal - - - QSizePolicy::Policy::Minimum - - - - 30 - 20 - - - - - - - - false - - - - 0 - 0 - - - - - - - - false - - - PointingHandCursor - - - margin: 0px; padding: 0px; - - - - - - - :/res/icons/64x64/folder.png:/res/icons/64x64/folder.png - - - - 20 - 13 - - - - true - - - - - - - - - - - - - 0 - 0 - - - - Security - - - - - - - Qt::Orientation::Vertical - - - QSizePolicy::Policy::Fixed - - - - 20 - 3 - - - -
m_pLineEditScreenName m_pSpinBoxPort m_pLineEditInterface - m_pCheckBoxCloseToTray - m_pCheckBoxMinimizeToTray - m_pCheckBoxAutoHide m_pCheckBoxEnableCrypto m_pComboBoxKeyLength m_pLineEditCertificatePath @@ -935,8 +751,6 @@ background-color: rgba(192,192,192, 0.1); m_pButtonBrowseLog m_pRadioUserScope m_pRadioSystemScope - m_pCheckBoxPreventSleep - m_pCheckBoxServiceEnabled m_pComboElevate diff --git a/src/gui/src/SetupWizard.cpp b/src/gui/src/SetupWizard.cpp index 07d6ebf9d..ae6bded58 100644 --- a/src/gui/src/SetupWizard.cpp +++ b/src/gui/src/SetupWizard.cpp @@ -16,35 +16,41 @@ */ #include "SetupWizard.h" -#include "MainWindow.h" -#include "validators/ScreenNameValidator.h" -SetupWizard::SetupWizard(MainWindow &mainWindow) : m_MainWindow(mainWindow) { +#include "MainWindow.h" +#include "gui/constants.h" +#include "validators/ScreenNameValidator.h" +#include "validators/ValidationError.h" + +SetupWizard::SetupWizard(MainWindow &mainWindow) : m_mainWindow(mainWindow) { + setupUi(this); - m_pLineEditName->setText(m_MainWindow.appConfig().screenName()); - m_pLineEditName->setValidator( - new validators::ScreenNameValidator(m_pLineEditName, label_ErrorMessage)); + m_pLabelError->setStyleSheet(kStyleErrorActiveLabel); - connect(m_pButtonApply, SIGNAL(clicked()), this, SLOT(accept())); + m_pLineEditName->setText(m_mainWindow.appConfig().screenName()); + m_pLineEditName->setValidator(new validators::ScreenNameValidator( + m_pLineEditName, new validators::ValidationError(this, m_pLabelError))); + + connect(m_pButtonApply, &QPushButton::clicked, this, &SetupWizard::accept); connect( - m_pLineEditName, SIGNAL(textEdited(QString)), this, - SLOT(onNameChanged())); + m_pLineEditName, &QLineEdit::textChanged, this, + &SetupWizard::onLineEditNameChanged); } void SetupWizard::accept() { - AppConfig &appConfig = m_MainWindow.appConfig(); + AppConfig &appConfig = m_mainWindow.appConfig(); appConfig.setWizardHasRun(); appConfig.setScreenName(m_pLineEditName->text()); appConfig.saveSettings(); - m_MainWindow.open(); + m_mainWindow.open(); QDialog::accept(); } -void SetupWizard::onNameChanged() { - m_pButtonApply->setEnabled(label_ErrorMessage->text().isEmpty()); +void SetupWizard::onLineEditNameChanged(const QString &error) { + m_pButtonApply->setEnabled(m_pLineEditName->hasAcceptableInput()); } void SetupWizard::reject() { diff --git a/src/gui/src/SetupWizard.h b/src/gui/src/SetupWizard.h index a2b9fde8f..f55f2e149 100644 --- a/src/gui/src/SetupWizard.h +++ b/src/gui/src/SetupWizard.h @@ -1,6 +1,6 @@ /* * synergy -- mouse and keyboard sharing utility - * Copyright (C) 2012-2016 Symless Ltd. + * Copyright (C) 2012 Symless Ltd. * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -16,9 +16,11 @@ */ #pragma once + #include "ui_SetupWizardBase.h" + #include -#include +#include class MainWindow; @@ -33,8 +35,8 @@ protected: void reject(); private: - MainWindow &m_MainWindow; + MainWindow &m_mainWindow; -private slots: - void onNameChanged(); +public slots: + void onLineEditNameChanged(const QString &error); }; diff --git a/src/gui/src/SetupWizardBase.ui b/src/gui/src/SetupWizardBase.ui index 2a69d792d..728d16909 100644 --- a/src/gui/src/SetupWizardBase.ui +++ b/src/gui/src/SetupWizardBase.ui @@ -6,8 +6,8 @@ 0 0 - 720 - 552 + 772 + 634 @@ -16,18 +16,6 @@ 0 - - - 720 - 552 - - - - - 720 - 552 - - 720 @@ -43,173 +31,151 @@ 1.000000000000000 - - - - 270 - 70 - 181 - 161 - + + + 20 - - + + 100 - - :/res/image/welcome.png + + 100 - - - - - 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 - 91 - - - - - 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; - - - - - + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + :/res/image/welcome.png + + + 30 + + + + + + + + Cantarell + 18 + true + + + + Name your computer + + + Qt::PlainText + + + + + + + + + Computer name + + + Qt::PlainText + + + 2 + + + + + + + + 230 + 20 + + + + 255 + + + + + + + m_pLabelError + + + + + + + + + + 0 + 0 + + + + Call your computer something short and meaningful, but it must have: + +- No spaces +- Only these special characters: _ - . +- Only English characters and numbers +- A different name from other computers + + + + Qt::MarkdownText + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 0 + 0 + + + + + 150 + 40 + + + + Continue + + + + diff --git a/src/gui/src/SetupWizardBlocker.cpp b/src/gui/src/SetupWizardBlocker.cpp index 3fc0954bd..210f8f5e1 100644 --- a/src/gui/src/SetupWizardBlocker.cpp +++ b/src/gui/src/SetupWizardBlocker.cpp @@ -1,6 +1,6 @@ /* * synergy -- mouse and keyboard sharing utility - * Copyright (C) 2012-2016 Symless Ltd. + * Copyright (C) 2016 Symless Ltd. * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -15,18 +15,19 @@ * along with this program. If not, see . */ +#include "SetupWizardBlocker.h" + +#include "MainWindow.h" + #include #include -#include "MainWindow.h" -#include "SetupWizardBlocker.h" - static const std::vector blockerTitels = { - "No Wayland support", + "Wayland is not yet supported", }; static const std::vector blockerText = { - "We have detected your system is using Wayland. It is not currently \n" + "We have detected your system is using Wayland which is not currently \n" "supported, but we are working on it. It's top of our priority list. \n" "\n" "Please switch to Xorg if you wish to continue using Synergy today.", @@ -37,9 +38,8 @@ SetupWizardBlocker::SetupWizardBlocker( : m_MainWindow(mainWindow) { setupUi(this); - label_Title->setText(blockerTitels[static_cast(type)]); - - label_HelpInfo->setText(blockerText[static_cast(type)]); + m_pLabelTitle->setText(blockerTitels[static_cast(type)]); + m_pLabelInfo->setText(blockerText[static_cast(type)]); connect( m_pButtonSupport, &QPushButton::released, this, diff --git a/src/gui/src/SetupWizardBlocker.ui b/src/gui/src/SetupWizardBlocker.ui index de278e6ad..c9d59f8e7 100644 --- a/src/gui/src/SetupWizardBlocker.ui +++ b/src/gui/src/SetupWizardBlocker.ui @@ -6,39 +6,10 @@ 0 0 - 720 - 580 + 750 + 600 - - - 0 - 0 - - - - - 720 - 580 - - - - - 720 - 580 - - - - - 720 - 580 - - - - - Arial - - Qt::NoContextMenu @@ -48,127 +19,108 @@ 1.000000000000000 - - - - 278 - 87 - 165 - 165 - + + + 20 - - + + 40 - - :/res/image/setupBlocker.png - - - true - - - - - - 0 - 273 - 720 - 25 - - - - - Arial - 18 - 50 - false - - - - Test header - - - Qt::RichText - - - Qt::AlignHCenter|Qt::AlignTop - - - true - - - - - - 153 - 321 - 455 - 150 - - - - - Arial - 13 - 50 - false - - - - large text test large text test large text test - - - Qt::RichText - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - true - - - - - - 642 - 540 - 71 - 25 - - - - - Arial - 13 - 50 - false - - - - Cancel - - - - - - 500 - 540 - 131 - 25 - - - - - Arial - 13 - 50 - false - - - - Online support - - + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 0 + 0 + + + + + + + :/res/image/setupBlocker.png + + + true + + + 30 + + + + + + + + 18 + true + + + + m_pLabelTitle + + + + + + + m_pLabelInfo + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 0 + 0 + + + + Get technical support + + + + + + + + 0 + 0 + + + + Exit + + + + diff --git a/src/gui/src/main.cpp b/src/gui/src/main.cpp index 1ec3aeddd..cacbd51b2 100644 --- a/src/gui/src/main.cpp +++ b/src/gui/src/main.cpp @@ -16,11 +16,11 @@ * along with this program. If not, see . */ -#include "AppConfig.h" #include "MainWindow.h" #include "QSynergyApplication.h" #include "SetupWizard.h" #include "SetupWizardBlocker.h" +#include "gui/AppConfig.h" #include "gui/dotenv.h" #include diff --git a/src/gui/src/validators/AliasValidator.cpp b/src/gui/src/validators/AliasValidator.cpp index 7daf34703..010c54f54 100644 --- a/src/gui/src/validators/AliasValidator.cpp +++ b/src/gui/src/validators/AliasValidator.cpp @@ -1,7 +1,6 @@ /* * synergy -- mouse and keyboard sharing utility - * Copyright (C) 2012-2021 Symless Ltd. - * Copyright (C) 2008 Volker Lanz (vl@fidra.de) + * Copyright (C) 2021 Symless Ltd. * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -15,6 +14,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + #include "validators/ComputerNameValidator.h" #include "validators/SpacesValidator.h" @@ -24,8 +24,8 @@ namespace validators { -AliasValidator::AliasValidator(QLineEdit *parent, QLabel *errors) - : LineEditValidator(parent, errors) { +AliasValidator::AliasValidator(QLineEdit *parent, ValidationError *error) + : LineEditValidator(parent, error) { addValidator( std::make_unique("Computer name cannot contain spaces")); addValidator(std::make_unique( diff --git a/src/gui/src/validators/AliasValidator.h b/src/gui/src/validators/AliasValidator.h index f8bdfe73a..b3bbc366b 100644 --- a/src/gui/src/validators/AliasValidator.h +++ b/src/gui/src/validators/AliasValidator.h @@ -1,7 +1,6 @@ /* * synergy -- mouse and keyboard sharing utility - * Copyright (C) 2012-2021 Symless Ltd. - * Copyright (C) 2008 Volker Lanz (vl@fidra.de) + * Copyright (C) 2021 Symless Ltd. * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -15,19 +14,18 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -#ifndef ALIASVALIDATOR_H -#define ALIASVALIDATOR_H + +#pragma once #include "LineEditValidator.h" +#include "validators/ValidationError.h" namespace validators { class AliasValidator : public LineEditValidator { public: explicit AliasValidator( - QLineEdit *parent = nullptr, QLabel *errors = nullptr); + QLineEdit *parent = nullptr, ValidationError *error = nullptr); }; } // namespace validators - -#endif // ALIASVALIDATOR_H diff --git a/src/gui/src/validators/LineEditValidator.cpp b/src/gui/src/validators/LineEditValidator.cpp index d0192bed6..609d2c796 100644 --- a/src/gui/src/validators/LineEditValidator.cpp +++ b/src/gui/src/validators/LineEditValidator.cpp @@ -1,7 +1,6 @@ /* * synergy -- mouse and keyboard sharing utility - * Copyright (C) 2012-2021 Symless Ltd. - * Copyright (C) 2008 Volker Lanz (vl@fidra.de) + * Copyright (C) 2021 Symless Ltd. * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -15,15 +14,21 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + #include "LineEditValidator.h" +#include "gui/constants.h" +#include + namespace validators { -LineEditValidator::LineEditValidator(QLineEdit *parent, QLabel *errors) - : m_pErrors(errors), - m_pControl(parent) { - if (m_pErrors) { - m_pErrors->hide(); +LineEditValidator::LineEditValidator( + QLineEdit *lineEdit, ValidationError *error) + : m_pError(error), + m_pLineEdit(lineEdit) { + + if (!m_pLineEdit) { + qFatal("validator line edit not set"); } } @@ -33,40 +38,27 @@ void LineEditValidator::addValidator( } QValidator::State LineEditValidator::validate(QString &input, int &pos) const { - if (!m_pControl) { - qFatal("Validator control not set"); - return Invalid; - } + assert(m_pLineEdit); - QString error; + QString errorMessage; for (const auto &validator : m_Validators) { if (!validator->validate(input)) { - error = validator->getMessage(); + errorMessage = validator->getMessage(); break; } } - if (error.isEmpty()) { - m_pControl->setStyleSheet(""); + if (errorMessage.isEmpty()) { + m_pLineEdit->setStyleSheet(""); } else { - showError(error); - m_pControl->setStyleSheet("border: 1px solid #EC4C47"); + m_pLineEdit->setStyleSheet(kStyleLineEditErrorBorder); } - finished(error); - return Acceptable; -} - -void LineEditValidator::showError(const QString &message) const { - if (m_pErrors) { - m_pErrors->setText(message); - - if (m_pErrors->text().isEmpty()) { - m_pErrors->hide(); - } else { - m_pErrors->show(); - } + if (m_pError) { + m_pError->setMessage(errorMessage); } + + return errorMessage.isEmpty() ? Acceptable : Intermediate; } } // namespace validators diff --git a/src/gui/src/validators/LineEditValidator.h b/src/gui/src/validators/LineEditValidator.h index b82af7e55..9e07b2d97 100644 --- a/src/gui/src/validators/LineEditValidator.h +++ b/src/gui/src/validators/LineEditValidator.h @@ -1,7 +1,6 @@ /* * synergy -- mouse and keyboard sharing utility - * Copyright (C) 2012 Symless Ltd. - * Copyright (C) 2008 Volker Lanz (vl@fidra.de) + * Copyright (C) 2021 Symless Ltd. * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -20,32 +19,29 @@ #include "IStringValidator.h" +#include +#include #include -#include -#include #include #include +#include "ValidationError.h" + namespace validators { class LineEditValidator : public QValidator { - Q_OBJECT - public: explicit LineEditValidator( - QLineEdit *parent = nullptr, QLabel *errors = nullptr); + QLineEdit *lineEdit = nullptr, ValidationError *error = nullptr); QValidator::State validate(QString &input, int &pos) const override; void addValidator(std::unique_ptr validator); -signals: - void finished(const QString &message) const; - private: - QLabel *m_pErrors = nullptr; - QLineEdit *m_pControl = nullptr; + ValidationError *m_pError = nullptr; + QLineEdit *m_pLineEdit = nullptr; std::vector> m_Validators; - void showError(const QString &message) const; + void setError(const QString &message) const; }; } // namespace validators diff --git a/src/gui/src/validators/ScreenNameValidator.cpp b/src/gui/src/validators/ScreenNameValidator.cpp index a505c1d5d..74edf74df 100644 --- a/src/gui/src/validators/ScreenNameValidator.cpp +++ b/src/gui/src/validators/ScreenNameValidator.cpp @@ -17,10 +17,12 @@ */ #include "ScreenNameValidator.h" + #include "validators/ComputerNameValidator.h" #include "validators/EmptyStringValidator.h" #include "validators/ScreenDuplicationsValidator.h" #include "validators/SpacesValidator.h" +#include "validators/ValidationError.h" #include #include @@ -28,8 +30,8 @@ namespace validators { ScreenNameValidator::ScreenNameValidator( - QLineEdit *parent, QLabel *errors, const ScreenList *pScreens) - : LineEditValidator(parent, errors) { + QLineEdit *lineEdit, ValidationError *error, const ScreenList *pScreens) + : LineEditValidator(lineEdit, error) { addValidator( std::make_unique("Computer name cannot be empty")); addValidator( @@ -37,8 +39,8 @@ ScreenNameValidator::ScreenNameValidator( addValidator(std::make_unique( "Contains invalid characters or is too long")); addValidator(std::make_unique( - "A computer with this name already exists", parent ? parent->text() : "", - pScreens)); + "A computer with this name already exists", + lineEdit ? lineEdit->text() : "", pScreens)); } } // namespace validators diff --git a/src/gui/src/validators/ScreenNameValidator.h b/src/gui/src/validators/ScreenNameValidator.h index f34dabd55..872848106 100644 --- a/src/gui/src/validators/ScreenNameValidator.h +++ b/src/gui/src/validators/ScreenNameValidator.h @@ -1,7 +1,6 @@ /* * synergy -- mouse and keyboard sharing utility - * Copyright (C) 2012-2021 Symless Ltd. - * Copyright (C) 2008 Volker Lanz (vl@fidra.de) + * Copyright (C) 2021 Symless Ltd. * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -15,21 +14,20 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -#ifndef SCREENNAMEVALIDATOR_H -#define SCREENNAMEVALIDATOR_H + +#pragma once #include "LineEditValidator.h" #include "ScreenList.h" +#include "validators/ValidationError.h" namespace validators { class ScreenNameValidator : public LineEditValidator { public: explicit ScreenNameValidator( - QLineEdit *parent = nullptr, QLabel *errors = nullptr, + QLineEdit *lineEdit = nullptr, ValidationError *error = nullptr, const ScreenList *pScreens = nullptr); }; } // namespace validators - -#endif // SCREENNAMEVALIDATOR_H diff --git a/src/gui/src/validators/SpacesValidator.h b/src/gui/src/validators/SpacesValidator.h index 40f50f9da..f3d422679 100644 --- a/src/gui/src/validators/SpacesValidator.h +++ b/src/gui/src/validators/SpacesValidator.h @@ -15,6 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + #ifndef SPACESVALIDATOR_H #define SPACESVALIDATOR_H diff --git a/src/gui/src/validators/ValidationError.cpp b/src/gui/src/validators/ValidationError.cpp new file mode 100644 index 000000000..fbf2a2eb3 --- /dev/null +++ b/src/gui/src/validators/ValidationError.cpp @@ -0,0 +1,55 @@ +/* + * synergy -- mouse and keyboard sharing utility + * Copyright (C) 2024 Symless Ltd. + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "ValidationError.h" + +#include "gui/constants.h" + +namespace validators { + +void clear(QLabel *label) { + if (label) { + label->setStyleSheet(kStyleErrorInactiveLabel); + label->setText(""); + } +} + +ValidationError::ValidationError(QObject *parent, QLabel *label) + : QObject(parent), + m_pLabel(label) { + + if (m_pLabel) { + clear(m_pLabel); + } +} + +const QString &ValidationError::message() const { return m_message; } + +void ValidationError::setMessage(const QString &message) { + m_message = message; + + if (m_pLabel) { + if (message.isEmpty()) { + clear(m_pLabel); + } else { + m_pLabel->setStyleSheet(kStyleErrorActiveLabel); + m_pLabel->setText(message); + } + } +} + +} // namespace validators diff --git a/src/gui/src/validators/ValidationError.h b/src/gui/src/validators/ValidationError.h new file mode 100644 index 000000000..a1f257e9f --- /dev/null +++ b/src/gui/src/validators/ValidationError.h @@ -0,0 +1,36 @@ +/* + * synergy -- mouse and keyboard sharing utility + * Copyright (C) 2024 Symless Ltd. + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include +#include + +namespace validators { + +class ValidationError : QObject { + QString m_message; + QLabel *m_pLabel = nullptr; + +public: + explicit ValidationError(QObject *parent, QLabel *label = nullptr); + const QString &message() const; + void setMessage(const QString &message); +}; + +} // namespace validators \ No newline at end of file diff --git a/src/lib/arch/unix/ArchNetworkBSD.h b/src/lib/arch/unix/ArchNetworkBSD.h index a930ef97e..5de0991bf 100644 --- a/src/lib/arch/unix/ArchNetworkBSD.h +++ b/src/lib/arch/unix/ArchNetworkBSD.h @@ -128,7 +128,7 @@ private: void throwNameError(int); private: - ArchMutex m_mutex{}; - Deps &m_deps; static Deps s_deps; + Deps &m_deps; + ArchMutex m_mutex{}; }; diff --git a/src/gui/src/AppConfig.cpp b/src/lib/gui/AppConfig.cpp similarity index 67% rename from src/gui/src/AppConfig.cpp rename to src/lib/gui/AppConfig.cpp index 2a1626b96..79a4d6c2b 100644 --- a/src/gui/src/AppConfig.cpp +++ b/src/lib/gui/AppConfig.cpp @@ -18,16 +18,18 @@ #include "AppConfig.h" -#include "Config.h" -#include "gui/constants.h" +#include "ConfigScopes.h" #include #include #include +#include #include #include +#include -using synergy::gui::Config; +using ConfigScopes = synergy::gui::ConfigScopes; +using IConfigScopes = synergy::gui::IConfigScopes; // this should be incremented each time the wizard is changed, // which will force it to re-run for existing installations. @@ -64,7 +66,7 @@ const char *const AppConfig::m_SettingsName[] = { "lastVersion", "", // 15 = lastExpiringWarningTime, obsolete "activationHasRun", - "minimizeToTray", + "", // 17 = minimizeToTray, obsolete "", // 18 = ActivateEmail, obsolete "loadFromSystemScope", "groupServerChecked", // kServerGroupChecked @@ -85,23 +87,33 @@ const char *const AppConfig::m_SettingsName[] = { "", // 35 = clientHostMode, obsolete "", // 36 = serverClientMode, obsolete "serviceEnabled", - "closeToTray"}; + "closeToTray", + "mainWindowSize", + "mainWindowPosition", +}; static const char *logLevelNames[] = {"INFO", "DEBUG", "DEBUG1", "DEBUG2"}; -AppConfig::AppConfig() { m_Config.registerReceiever(this); } +AppConfig::Deps AppConfig::s_Deps; + +AppConfig::AppConfig(Deps &deps) : m_Deps(deps), m_ScreenName(deps.hostname()) { + + m_Deps.scopes().registerReceiver(this); +} void AppConfig::loadAllScopes() { - m_Config.loadAll(); + m_Deps.scopes().loadAll(); // User settings exist and the load from system scope variable is true - if (m_Config.hasSetting( - settingName(Setting::kLoadSystemSettings), Config::Scope::User)) { + if (m_Deps.scopes().hasSetting( + settingName(Setting::kLoadSystemSettings), + ConfigScopes::Scope::User)) { setLoadFromSystemScope(m_LoadFromSystemScope); } // If user setting don't exist but system ones do, load the system settings - else if (m_Config.hasSetting( - settingName(Setting::kScreenName), Config::Scope::System)) { + else if (m_Deps.scopes().hasSetting( + settingName(Setting::kScreenName), + ConfigScopes::Scope::System)) { setLoadFromSystemScope(true); } } @@ -111,66 +123,63 @@ void AppConfig::loadSettings() { qDebug("loading settings"); - m_ScreenName = - loadSetting(kScreenName, QHostInfo::localHostName()).toString(); - if (m_ScreenName.isEmpty()) { - m_ScreenName = QHostInfo::localHostName(); - } + loadCommonSettings(); + loadScopeSettings(); + loadSerialKey(); + loadElevateMode(); - m_Port = loadSetting(kPort, 24800).toInt(); - m_Interface = loadSetting(kInterface).toString(); - m_LogLevel = loadSetting(kLogLevel, 0).toInt(); - m_LogToFile = loadSetting(kLogToFile, false).toBool(); - m_LogFilename = - loadSetting(kLogFilename, logDir() + "synergy.log").toString(); - m_WizardLastRun = loadCommonSetting(kWizardLastRun, 0).toInt(); - m_StartedBefore = loadSetting(kStartedBefore, false).toBool(); + emit loaded(); +} - QVariant elevateMode = loadSetting(kElevateModeEnum); - if (!elevateMode.isValid()) { - elevateMode = loadSetting( - kElevateMode, QVariant(static_cast(kDefaultElevateMode))); - } - m_ElevateMode = static_cast(elevateMode.toInt()); +void AppConfig::loadCommonSettings() { + using enum Setting; - m_AutoHide = loadSetting(kAutoHide, false).toBool(); - m_LastVersion = loadSetting(kLastVersion, "Unknown").toString(); - m_ActivationHasRun = loadSetting(kActivationHasRun, false).toBool(); - m_MinimizeToTray = loadSetting(kMinimizeToTray, false).toBool(); + m_WizardLastRun = loadCommonSetting(kWizardLastRun, m_WizardLastRun).toInt(); m_LoadFromSystemScope = - loadCommonSetting(kLoadSystemSettings, false).toBool(); - m_ServerGroupChecked = loadSetting(kServerGroupChecked, false).toBool(); - m_UseExternalConfig = loadSetting(kUseExternalConfig, false).toBool(); - m_ConfigFile = - loadSetting(kConfigFile, QDir::homePath() + "/" + m_ConfigFilename) - .toString(); - m_UseInternalConfig = loadSetting(kUseInternalConfig, false).toBool(); - m_ClientGroupChecked = loadSetting(kClientGroupChecked, false).toBool(); - m_ServerHostname = loadSetting(kServerHostname).toString(); - m_PreventSleep = loadSetting(kPreventSleep, false).toBool(); - m_LanguageSync = loadSetting(kLanguageSync, false).toBool(); - m_InvertScrollDirection = loadSetting(kInvertScrollDirection, false).toBool(); - m_licenseNextCheck = loadCommonSetting(kLicenseNextCheck, 0).toULongLong(); - m_InvertConnection = loadSetting(kInvertConnection, false).toBool(); + loadCommonSetting(kLoadSystemSettings, m_LoadFromSystemScope).toBool(); + m_licenseNextCheck = + loadCommonSetting(kLicenseNextCheck, m_licenseNextCheck).toULongLong(); +} - // only change the serial key if the settings being loaded contains a key - bool loadSerial = m_Config.hasSetting( - settingName(kLoadSystemSettings), Config::Scope::Current); - - if (loadSerial) { - const auto &serialKey = loadSetting(kSerialKey, "").toString().trimmed(); - if (!serialKey.isEmpty()) { - m_SerialKey = serialKey; - } - } +void AppConfig::loadScopeSettings() { + using enum Setting; + m_ScreenName = loadSetting(kScreenName, m_ScreenName).toString(); + m_Port = loadSetting(kPort, m_Port).toInt(); + m_Interface = loadSetting(kInterface, m_Interface).toString(); + m_LogLevel = loadSetting(kLogLevel, m_LogLevel).toInt(); + m_LogToFile = loadSetting(kLogToFile, m_LogToFile).toBool(); + m_LogFilename = loadSetting(kLogFilename, m_LogFilename).toString(); + m_StartedBefore = loadSetting(kStartedBefore, m_StartedBefore).toBool(); + m_AutoHide = loadSetting(kAutoHide, m_AutoHide).toBool(); + m_LastVersion = loadSetting(kLastVersion, m_LastVersion).toString(); + m_ActivationHasRun = + loadSetting(kActivationHasRun, m_ActivationHasRun).toBool(); + m_ServerGroupChecked = + loadSetting(kServerGroupChecked, m_ServerGroupChecked).toBool(); + m_UseExternalConfig = + loadSetting(kUseExternalConfig, m_UseExternalConfig).toBool(); + m_ConfigFile = loadSetting(kConfigFile, m_ConfigFile).toString(); + m_UseInternalConfig = + loadSetting(kUseInternalConfig, m_UseInternalConfig).toBool(); + m_ClientGroupChecked = + loadSetting(kClientGroupChecked, m_ClientGroupChecked).toBool(); + m_ServerHostname = loadSetting(kServerHostname, m_ServerHostname).toString(); + m_PreventSleep = loadSetting(kPreventSleep, m_PreventSleep).toBool(); + m_LanguageSync = loadSetting(kLanguageSync, m_LanguageSync).toBool(); + m_InvertScrollDirection = + loadSetting(kInvertScrollDirection, m_InvertScrollDirection).toBool(); + m_InvertConnection = + loadSetting(kInvertConnection, m_InvertConnection).toBool(); m_ServiceEnabled = loadSetting(kServiceEnabled, m_ServiceEnabled).toBool(); m_CloseToTray = loadSetting(kCloseToTray, m_CloseToTray).toBool(); m_TlsEnabled = loadSetting(kTlsEnabled, m_TlsEnabled).toBool(); - m_TlsCertPath = loadSetting(kTlsCertPath, defaultTlsCertPath()).toString(); + m_TlsCertPath = loadSetting(kTlsCertPath, m_TlsCertPath).toString(); m_TlsKeyLength = loadSetting(kTlsKeyLength, m_TlsKeyLength).toString(); - - emit loaded(); + m_MainWindowPosition = loadOptional( + kMainWindowPosition, [](QVariant v) { return v.toPoint(); }); + m_MainWindowSize = loadOptional( + kMainWindowSize, [](QVariant v) { return v.toSize(); }); } void AppConfig::saveSettings() { @@ -192,13 +201,13 @@ void AppConfig::saveSettings() { setSetting(kLogToFile, m_LogToFile); setSetting(kLogFilename, m_LogFilename); setSetting(kStartedBefore, m_StartedBefore); - setSetting(kElevateModeEnum, static_cast(m_ElevateMode)); + setSetting(kElevateMode, static_cast(m_ElevateMode)); + setSetting(kElevateModeLegacy, m_ElevateMode == ElevateAlways); setSetting(kTlsEnabled, m_TlsEnabled); setSetting(kAutoHide, m_AutoHide); setSetting(kSerialKey, m_SerialKey); setSetting(kLastVersion, m_LastVersion); setSetting(kActivationHasRun, m_ActivationHasRun); - setSetting(kMinimizeToTray, m_MinimizeToTray); setSetting(kUseExternalConfig, m_UseExternalConfig); setSetting(kConfigFile, m_ConfigFile); setSetting(kUseInternalConfig, m_UseInternalConfig); @@ -209,13 +218,13 @@ void AppConfig::saveSettings() { setSetting(kInvertConnection, m_InvertConnection); setSetting(kServiceEnabled, m_ServiceEnabled); setSetting(kCloseToTray, m_CloseToTray); - - // See enum ElevateMode declaration to understand why this setting is bool - setSetting(kElevateMode, m_ElevateMode == ElevateAlways); + setOptional(kMainWindowSize, m_MainWindowSize); + setOptional(kMainWindowPosition, m_MainWindowPosition); } setModified(false); - saved(); + + emit saved(); if (m_TlsChanged) { m_TlsChanged = false; @@ -223,8 +232,49 @@ void AppConfig::saveSettings() { } } +void AppConfig::loadSerialKey() { + using enum Setting; + + // only set the serial key if the current settings scope has they key. + bool shouldLoad = m_Deps.scopes().hasSetting( + settingName(kLoadSystemSettings), ConfigScopes::Scope::Current); + + if (!shouldLoad) { + qDebug("no serial key in current scope, skipping"); + return; + } + + const auto &serialKey = + loadSetting(kSerialKey, m_SerialKey).toString().trimmed(); + + if (serialKey.isEmpty()) { + qDebug("serial key is empty, skipping"); + return; + } + + m_SerialKey = serialKey; +} + +void AppConfig::loadElevateMode() { + using enum Setting; + + if (!m_Deps.scopes().hasSetting(settingName(kElevateMode))) { + qDebug("elevate mode not set yet, skipping"); + return; + } + + QVariant elevateMode = loadSetting(kElevateMode); + if (!elevateMode.isValid()) { + qDebug("elevate mode not valid, loading legacy setting"); + elevateMode = loadSetting( + kElevateModeLegacy, QVariant(static_cast(kDefaultElevateMode))); + } + + m_ElevateMode = static_cast(elevateMode.toInt()); +} + QString AppConfig::defaultTlsCertPath() const { - QDir path(m_CoreInterface.getProfileDir()); + QDir path(m_Deps.profileDir()); path = path.filePath("SSL"); path = path.filePath("Synergy.pem"); return path.absolutePath(); @@ -236,16 +286,35 @@ QString AppConfig::settingName(Setting name) { } template void AppConfig::setSetting(Setting name, T value) { - m_Config.setSetting(settingName(name), value); + m_Deps.scopes().setSetting(settingName(name), value); } template void AppConfig::setCommonSetting(Setting name, T value) { - m_Config.setSetting(settingName(name), value, Config::Scope::User); - m_Config.setSetting(settingName(name), value, Config::Scope::System); + m_Deps.scopes().setSetting( + settingName(name), value, ConfigScopes::Scope::User); + m_Deps.scopes().setSetting( + settingName(name), value, ConfigScopes::Scope::System); } QVariant AppConfig::loadSetting(Setting name, const QVariant &defaultValue) { - return m_Config.loadSetting(settingName(name), defaultValue); + return m_Deps.scopes().loadSetting(settingName(name), defaultValue); +} + +template +std::optional +AppConfig::loadOptional(Setting name, std::function toType) const { + if (m_Deps.scopes().hasSetting(settingName(name))) { + return toType(m_Deps.scopes().loadSetting(settingName(name))); + } else { + return std::nullopt; + } +} + +template +void AppConfig::setOptional(Setting name, const std::optional &value) { + if (value.has_value()) { + m_Deps.scopes().setSetting(settingName(name), value.value()); + } } QVariant @@ -253,28 +322,30 @@ AppConfig::loadCommonSetting(Setting name, const QVariant &defaultValue) const { QVariant result(defaultValue); QString setting(settingName(name)); - if (m_Config.hasSetting(setting)) { - result = m_Config.loadSetting(setting, defaultValue); - } else if (m_Config.getScope() == Config::Scope::System) { - if (m_Config.hasSetting(setting, Config::Scope::User)) { - result = m_Config.loadSetting(setting, defaultValue, Config::Scope::User); + if (m_Deps.scopes().hasSetting(setting)) { + result = m_Deps.scopes().loadSetting(setting, defaultValue); + } else if (m_Deps.scopes().getScope() == ConfigScopes::Scope::System) { + if (m_Deps.scopes().hasSetting(setting, ConfigScopes::Scope::User)) { + result = m_Deps.scopes().loadSetting( + setting, defaultValue, ConfigScopes::Scope::User); } - } else if (m_Config.hasSetting(setting, Config::Scope::System)) { - result = m_Config.loadSetting(setting, defaultValue, Config::Scope::System); + } else if (m_Deps.scopes().hasSetting(setting, ConfigScopes::Scope::System)) { + result = m_Deps.scopes().loadSetting( + setting, defaultValue, ConfigScopes::Scope::System); } return result; } -void AppConfig::loadScope(Config::Scope scope) { +void AppConfig::loadScope(ConfigScopes::Scope scope) { - if (m_Config.getScope() != scope) { + if (m_Deps.scopes().getScope() != scope) { setDefaultValues(); - m_Config.setScope(scope); - if (m_Config.hasSetting( - settingName(Setting::kScreenName), m_Config.getScope())) { + m_Deps.scopes().setScope(scope); + if (m_Deps.scopes().hasSetting( + settingName(Setting::kScreenName), m_Deps.scopes().getScope())) { // If the user already has settings, then load them up now. - m_Config.loadAll(); + m_Deps.scopes().loadAll(); } } } @@ -285,10 +356,10 @@ void AppConfig::setLoadFromSystemScope(bool value) { if (value) { qDebug("loading system settings scope"); - loadScope(Config::Scope::System); + loadScope(ConfigScopes::Scope::System); } else { qDebug("loading user settings scope"); - loadScope(Config::Scope::User); + loadScope(ConfigScopes::Scope::User); } /* @@ -298,10 +369,10 @@ void AppConfig::setLoadFromSystemScope(bool value) { m_LoadFromSystemScope = value; } -bool AppConfig::isWritable() const { return m_Config.isWritable(); } +bool AppConfig::isWritable() const { return m_Deps.scopes().isWritable(); } bool AppConfig::isSystemScoped() const { - return m_Config.getScope() == Config::Scope::System; + return m_Deps.scopes().getScope() == ConfigScopes::Scope::System; } template @@ -329,12 +400,12 @@ void AppConfig::persistLogDir() const { // Begin getters /////////////////////////////////////////////////////////////////////////////// +IConfigScopes &AppConfig::scopes() { return m_Deps.scopes(); } + bool AppConfig::activationHasRun() const { return m_ActivationHasRun; } QString AppConfig::serialKey() const { return m_SerialKey; } -Config &AppConfig::config() { return m_Config; } - const QString &AppConfig::screenName() const { return m_ScreenName; } int AppConfig::port() const { return m_Port; } @@ -385,8 +456,6 @@ bool AppConfig::preventSleep() const { return m_PreventSleep; } bool AppConfig::invertConnection() const { return m_InvertConnection; } -bool AppConfig::minimizeToTray() const { return m_MinimizeToTray; } - QString AppConfig::tlsCertPath() const { return m_TlsCertPath; } QString AppConfig::tlsKeyLength() const { return m_TlsKeyLength; } @@ -409,6 +478,14 @@ QString AppConfig::serverHostname() const { return m_ServerHostname; } void AppConfig::setActivationHasRun(bool value) { m_ActivationHasRun = value; } +std::optional AppConfig::mainWindowSize() const { + return m_MainWindowSize; +} + +std::optional AppConfig::mainWindowPosition() const { + return m_MainWindowPosition; +} + /////////////////////////////////////////////////////////////////////////////// // End getters /////////////////////////////////////////////////////////////////////////////// @@ -497,10 +574,6 @@ void AppConfig::setElevateMode(ElevateMode em) { void AppConfig::setAutoHide(bool b) { setSettingModified(m_AutoHide, b); } -void AppConfig::setMinimizeToTray(bool newValue) { - setSettingModified(m_MinimizeToTray, newValue); -} - void AppConfig::setLicenseNextCheck(unsigned long long time) { setSettingModified(m_licenseNextCheck, time); } @@ -530,6 +603,14 @@ void AppConfig::setInvertConnection(bool value) { emit invertConnectionChanged(); } +void AppConfig::setMainWindowSize(const QSize &size) { + m_MainWindowSize = size; +} + +void AppConfig::setMainWindowPosition(const QPoint &position) { + m_MainWindowPosition = position; +} + /////////////////////////////////////////////////////////////////////////////// // End setters /////////////////////////////////////////////////////////////////////////////// diff --git a/src/gui/src/AppConfig.h b/src/lib/gui/AppConfig.h similarity index 82% rename from src/gui/src/AppConfig.h rename to src/lib/gui/AppConfig.h index d2797138a..ec822e567 100644 --- a/src/gui/src/AppConfig.h +++ b/src/lib/gui/AppConfig.h @@ -19,25 +19,24 @@ #pragma once #include "CommonConfig.h" -#include "Config.h" -#include "gui/CoreInterface.h" -#include "gui/ElevateMode.h" -#include "gui/IAppConfig.h" +#include "ConfigScopes.h" +#include "CoreInterface.h" +#include "ElevateMode.h" +#include "IAppConfig.h" +#include +#include #include +#include +#include #include #include #include -class QSettings; -class SettingsDialog; -class ServerConfig; -class LicenseHandler; -class ActivationDialog; - enum class ProcessMode { kService, kDesktop }; const ElevateMode kDefaultElevateMode = ElevateAsNeeded; +const QString kDefaultLogFile = "synergy.log"; #if defined(Q_OS_WIN) const ProcessMode kDefaultProcessMode = ProcessMode::kService; @@ -58,12 +57,6 @@ class AppConfig : public QObject, public synergy::gui::IAppConfig { Q_OBJECT - friend class SettingsDialog; - friend class MainWindow; - friend class SetupWizard; - friend class ServerConfig; - friend class ActivationDialog; - private: enum class Setting { kScreenName = 0, @@ -74,8 +67,8 @@ private: kLogFilename = 5, kWizardLastRun = 6, kStartedBefore = 7, - kElevateMode = 8, - kElevateModeEnum = 9, + kElevateModeLegacy = 8, + kElevateMode = 9, // 10 = edition, obsolete (using serial key instead) kTlsEnabled = 11, kAutoHide = 12, @@ -83,7 +76,7 @@ private: kLastVersion = 14, // 15 = last expire time, obsolete kActivationHasRun = 16, - kMinimizeToTray = 17, + // 17 = minimize to tray, obsolete // 18 = activate email, obsolete kLoadSystemSettings = 19, kServerGroupChecked = 20, @@ -105,21 +98,37 @@ private: // 36 = server-client-mode, obsolete kServiceEnabled = 37, kCloseToTray = 38, + kMainWindowSize = 39, + kMainWindowPosition = 40, }; public: - explicit AppConfig(); + struct Deps { + virtual ~Deps() = default; + virtual QString profileDir() const { + return m_coreInterface.getProfileDir(); + } + virtual synergy::gui::IConfigScopes &scopes() { return m_Scopes; } + virtual QString hostname() const { return QHostInfo::localHostName(); } - /// @brief Underlying configuration reader/writer - synergy::gui::Config &config(); + private: + [[no_unique_address]] CoreInterface m_coreInterface; + synergy::gui::ConfigScopes m_Scopes; + }; - /// @brief Saves the setting to the current scope + explicit AppConfig() : AppConfig(s_Deps) {} + explicit AppConfig(Deps &deps); + + synergy::gui::IConfigScopes &scopes(); void saveSettings() override; + void loadAllScopes(); + void loadSettings() override; /** * Getters */ + void setActivationHasRun(bool value); bool isWritable() const; bool isSystemScoped() const; const QString &screenName() const; @@ -151,19 +160,14 @@ public: QString serverHostname() const; QString lastVersion() const; bool serviceEnabled() const; - bool minimizeToTray() const; bool closeToTray() const; QString serialKey() const; bool activationHasRun() const; bool tlsEnabled() const override; QString tlsCertPath() const override; QString tlsKeyLength() const override; - -private: - /// @brief Loads the setting from the current scope - void loadSettings() override; - - static QString settingName(AppConfig::Setting name); + std::optional mainWindowSize() const; + std::optional mainWindowPosition() const; /** * Setters @@ -192,14 +196,14 @@ private: void setUseInternalConfig(bool); void setClientGroupChecked(bool); void setServerHostname(const QString &); - void setMinimizeToTray(bool b); void setLastVersion(const QString &version); void setServiceEnabled(bool enabled); void setCloseToTray(bool minimize); - void setActivationHasRun(bool value); void setTlsCertPath(const QString &path); void setTlsKeyLength(const QString &length); void setInvertConnection(bool value); + void setMainWindowSize(const QSize &size); + void setMainWindowPosition(const QPoint &position); /// @brief Sets the user preference to load from SystemScope. /// @param [in] value @@ -208,8 +212,27 @@ private: /// scope settings. void setLoadFromSystemScope(bool value); - /// @brief Loads config from the underlying reader/writer - void loadAllScopes(); +private: + static QString settingName(AppConfig::Setting name); + void loadSerialKey(); + void loadElevateMode(); + void loadCommonSettings(); + void loadScopeSettings(); + + /** + * @brief Loads a setting if it exists, otherwise returns `std::nullopt` + * + * @param toType A function to convert the QVariant to the desired type. + */ + template + std::optional + loadOptional(Setting name, std::function toType) const; + + /** + * @brief Sets a setting if the value is not `std::nullopt`. + */ + template + void setOptional(Setting name, const std::optional &value); /// @brief Sets the value of a setting /// @param [in] name The Setting to be saved @@ -243,7 +266,7 @@ private: /// @brief This method loads config from specified scope /// @param [in] scope which should be loaded. - void loadScope(synergy::gui::Config::Scope scope); + void loadScope(synergy::gui::ConfigScopes::Scope scope); /// @brief This function sets default values /// for settings that shouldn't be copied from between scopes. @@ -254,14 +277,14 @@ private: */ QString defaultTlsCertPath() const; - synergy::gui::Config m_Config; - CoreInterface m_CoreInterface; - QString m_ScreenName = ""; + static Deps s_Deps; + Deps &m_Deps; + QString m_ScreenName; int m_Port = 24800; QString m_Interface = ""; int m_LogLevel = 0; bool m_LogToFile = false; - QString m_LogFilename = ""; + QString m_LogFilename = logDir() + kDefaultLogFile; int m_WizardLastRun = 0; bool m_StartedBefore = false; ElevateMode m_ElevateMode = kDefaultElevateMode; @@ -272,21 +295,22 @@ private: QString m_LastVersion = ""; unsigned long long m_licenseNextCheck = 0; bool m_ActivationHasRun = false; - bool m_MinimizeToTray = true; bool m_InvertScrollDirection = false; bool m_LanguageSync = true; bool m_PreventSleep = false; bool m_InvertConnection = false; bool m_ServerGroupChecked = false; bool m_UseExternalConfig = false; - QString m_ConfigFile = ""; + QString m_ConfigFile = QDir::homePath() + "/" + m_ConfigFilename; bool m_UseInternalConfig = false; bool m_ClientGroupChecked = false; QString m_ServerHostname = ""; bool m_ServiceEnabled = kDefaultProcessMode == ProcessMode::kService; bool m_CloseToTray = false; - QString m_TlsCertPath = ""; + QString m_TlsCertPath = defaultTlsCertPath(); QString m_TlsKeyLength = "2048"; + std::optional m_MainWindowSize; + std::optional m_MainWindowPosition; /** * @brief Flag is set when any TLS is setting is changed, and is reset diff --git a/src/lib/gui/CommandProcess.cpp b/src/lib/gui/CommandProcess.cpp index b43b07102..c4fde3c57 100644 --- a/src/lib/gui/CommandProcess.cpp +++ b/src/lib/gui/CommandProcess.cpp @@ -47,9 +47,9 @@ QString CommandProcess::run() { if (int code = process.exitCode(); !success || code != 0) { qFatal( - "Command failed: %s %s\nCode: %d\nError: %s", qUtf8Printable(m_Command), + "command failed: %s %s\ncode: %d\nerror: %s", qUtf8Printable(m_Command), qUtf8Printable(m_Arguments.join(" ")), code, - error.isEmpty() ? "None" : qUtf8Printable(error)); + error.isEmpty() ? "none" : qUtf8Printable(error)); } emit finished(); diff --git a/src/gui/src/CommonConfig.h b/src/lib/gui/CommonConfig.h similarity index 100% rename from src/gui/src/CommonConfig.h rename to src/lib/gui/CommonConfig.h diff --git a/src/gui/src/Config.cpp b/src/lib/gui/ConfigScopes.cpp similarity index 78% rename from src/gui/src/Config.cpp rename to src/lib/gui/ConfigScopes.cpp index 81444542d..f159a5c0d 100644 --- a/src/gui/src/Config.cpp +++ b/src/lib/gui/ConfigScopes.cpp @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -#include "Config.h" +#include "ConfigScopes.h" #include "CommonConfig.h" @@ -68,7 +68,7 @@ void loadWindowsLegacy(QSettings &settings) { } #endif -Config::Config() { +ConfigScopes::ConfigScopes() { QSettings::setPath( QSettings::Format::IniFormat, QSettings::Scope::SystemScope, getSystemSettingPath()); @@ -88,20 +88,20 @@ Config::Config() { load(); } -Config::~Config() { - while (!m_pReceievers.empty()) { - m_pReceievers.pop_back(); +ConfigScopes::~ConfigScopes() { + while (!m_pReceivers.empty()) { + m_pReceivers.pop_back(); } } -void Config::load() { +void ConfigScopes::load() { #if defined(Q_OS_WIN) // This call is needed for backwardcapability with old settings. loadWindowsLegacy(*m_pSystemSettings); #endif } -bool Config::hasSetting(const QString &name, Scope scope) const { +bool ConfigScopes::hasSetting(const QString &name, Scope scope) const { switch (scope) { case Scope::User: return m_pUserSettings->contains(name); @@ -112,9 +112,11 @@ bool Config::hasSetting(const QString &name, Scope scope) const { } } -bool Config::isWritable() const { return currentSettings()->isWritable(); } +bool ConfigScopes::isWritable() const { + return currentSettings()->isWritable(); +} -QVariant Config::loadSetting( +QVariant ConfigScopes::loadSetting( const QString &name, const QVariant &defaultValue, Scope scope) const { switch (scope) { case Scope::User: @@ -126,21 +128,23 @@ QVariant Config::loadSetting( } } -void Config::setScope(Config::Scope scope) { m_CurrentScope = scope; } +void ConfigScopes::setScope(ConfigScopes::Scope scope) { + m_CurrentScope = scope; +} -Config::Scope Config::getScope() const { return m_CurrentScope; } +ConfigScopes::Scope ConfigScopes::getScope() const { return m_CurrentScope; } -void Config::loadAll() { - for (auto &i : m_pReceievers) { +void ConfigScopes::loadAll() { + for (auto &i : m_pReceivers) { i->loadSettings(); } } -void Config::saveAll() { +void ConfigScopes::saveAll() { // Save if there are any unsaved changes otherwise skip if (unsavedChanges()) { - for (auto &i : m_pReceievers) { + for (auto &i : m_pReceivers) { i->saveSettings(); } @@ -151,7 +155,7 @@ void Config::saveAll() { } } -QSettings *Config::currentSettings() const { +QSettings *ConfigScopes::currentSettings() const { if (m_CurrentScope == Scope::User) { return m_pUserSettings.get(); } else { @@ -159,16 +163,16 @@ QSettings *Config::currentSettings() const { } } -void Config::registerReceiever(CommonConfig *receiver) { - m_pReceievers.push_back(receiver); +void ConfigScopes::registerReceiver(CommonConfig *receiver) { + m_pReceivers.push_back(receiver); } -bool Config::unsavedChanges() const { +bool ConfigScopes::unsavedChanges() const { if (m_unsavedChanges) { return true; } - for (const auto &i : m_pReceievers) { + for (const auto &i : m_pReceivers) { if (i->modified()) { return true; } @@ -176,6 +180,12 @@ bool Config::unsavedChanges() const { return false; } -void Config::markUnsaved() { m_unsavedChanges = true; } +void ConfigScopes::markUnsaved() { m_unsavedChanges = true; } + +void ConfigScopes::setSetting( + const QString &name, const QVariant &value, Scope scope) { + currentSettings()->setValue(name, value); + m_unsavedChanges = true; +} } // namespace synergy::gui diff --git a/src/gui/src/Config.h b/src/lib/gui/ConfigScopes.h similarity index 80% rename from src/gui/src/Config.h rename to src/lib/gui/ConfigScopes.h index 24da15148..ecbe9438d 100644 --- a/src/gui/src/Config.h +++ b/src/lib/gui/ConfigScopes.h @@ -14,8 +14,11 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + #pragma once +#include "IConfigScopes.h" + #include #include #include @@ -25,31 +28,31 @@ namespace synergy::gui { class CommonConfig; /// @brief A general config reader and writer for user and gloabl settings -class Config : private QObject { +class ConfigScopes : public IConfigScopes { public: - enum class Scope { Current, System, User }; - - explicit Config(); - ~Config() override; + explicit ConfigScopes(); + virtual ~ConfigScopes(); /// @brief Checks if the setting exists /// @param [in] name The name of the setting to check /// @param [in] scope The scope to search in /// @return bool True if the current scope has the named setting - bool hasSetting(const QString &name, Scope scope = Scope::Current) const; + bool + hasSetting(const QString &name, Scope scope = Scope::Current) const override; /// @brief Checks if the current scope settings writable /// @return bool True if the current scope writable - bool isWritable() const; + bool isWritable() const override; /// @brief Sets the value of a setting /// @param [in] name The Setting to be saved /// @param [in] value The Value to be saved (Templated) /// @param [in] scope The scope to get the value from, default is current /// scope - template - void setSetting(const QString &name, T value, Scope scope = Scope::Current); + void setSetting( + const QString &name, const QVariant &value, + Scope scope = Scope::Current) override; /// @brief Loads a setting /// @param [in] name The setting to be loaded @@ -58,35 +61,35 @@ public: /// scope QVariant loadSetting( const QString &name, const QVariant &defaultValue = QVariant(), - Scope scope = Scope::Current) const; + Scope scope = Scope::Current) const override; /// @brief Changes the setting save and load location between System and User /// scope /// @param [in] scope The scope to set - void setScope(Scope scope = Scope::User); + void setScope(Scope scope = Scope::User) override; /// @brief Get the current scope the settings are loading and save from. /// @return Scope An enum defining the current scope - Scope getScope() const; + Scope getScope() const override; /// @brief trigger a config load across all registered classes - void loadAll(); + void loadAll() override; /// @brief trigger a config save across all registered classes - void saveAll(); + void saveAll() override; /// @brief Returns the current scopes settings object /// If more specialize control into the settings is needed this can /// provide direct access to the settings file handler /// @return QSettings The Settings object as a reference - QSettings *currentSettings() const; + QSettings *currentSettings() const override; /// @brief This marks the settings as unsaved if the settings() was used to /// directly affect the config file void markUnsaved(); /// @brief Register a class to receives requests to save and load settings - void registerReceiever(CommonConfig *receiver); + void registerReceiver(CommonConfig *receiver) override; /// @brief Checks if any registered class has any unsaved changes /// @return bool True if any registered class has unsaved changes @@ -100,16 +103,10 @@ private: std::unique_ptr m_pSystemSettings; /// @brief Receivers of load/save callbacks - std::list m_pReceievers; + std::list m_pReceivers; /// @brief Is set to true when settings are changed bool m_unsavedChanges = false; }; -template -void Config::setSetting(const QString &name, T value, Scope scope) { - currentSettings()->setValue(name, value); - m_unsavedChanges = true; -} - } // namespace synergy::gui diff --git a/src/lib/gui/IConfigScopes.h b/src/lib/gui/IConfigScopes.h new file mode 100644 index 000000000..39293dc96 --- /dev/null +++ b/src/lib/gui/IConfigScopes.h @@ -0,0 +1,51 @@ +/* + * synergy -- mouse and keyboard sharing utility + * Copyright (C) 2024 Symless Ltd. + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "gui/CommonConfig.h" + +#include +#include +#include + +namespace synergy::gui { + +class IConfigScopes { +public: + enum class Scope { Current, System, User }; + + virtual ~IConfigScopes() = default; + + virtual void registerReceiver(CommonConfig *receiver) = 0; + virtual void loadAll() = 0; + virtual bool + hasSetting(const QString &name, Scope scope = Scope::Current) const = 0; + virtual QVariant loadSetting( + const QString &name, const QVariant &defaultValue = QVariant(), + Scope scope = Scope::Current) const = 0; + virtual void setSetting( + const QString &name, const QVariant &value, + Scope scope = Scope::Current) = 0; + virtual Scope getScope() const = 0; + virtual void setScope(Scope scope = Scope::User) = 0; + virtual bool isWritable() const = 0; + virtual QSettings *currentSettings() const = 0; + virtual void saveAll() = 0; +}; + +} // namespace synergy::gui diff --git a/src/lib/gui/TlsCertificate.cpp b/src/lib/gui/TlsCertificate.cpp index f7206072c..ac67f7282 100644 --- a/src/lib/gui/TlsCertificate.cpp +++ b/src/lib/gui/TlsCertificate.cpp @@ -58,7 +58,7 @@ QString openSslWindowsDir() { // if the path still isn't found, something is seriously wrong. if (!openSslDir.exists()) { - qFatal() << "OpenSSL dir not found: " << openSslDir; + qFatal() << "openssl dir not found: " << openSslDir; } return QDir::cleanPath(openSslDir.absolutePath()); @@ -77,7 +77,7 @@ QString openSslWindowsBinary() { // if the path still isn't found, something is seriously wrong. if (!QFile::exists(path)) { - qFatal() << "OpenSSL binary not found: " << path; + qFatal() << "openssl binary not found: " << path; } return path; diff --git a/src/lib/gui/TlsUtility.h b/src/lib/gui/TlsUtility.h index c49372345..aa6d6e83e 100644 --- a/src/lib/gui/TlsUtility.h +++ b/src/lib/gui/TlsUtility.h @@ -20,7 +20,6 @@ #include "IAppConfig.h" #include "license/License.h" -#include namespace synergy::gui { diff --git a/src/lib/gui/constants.h b/src/lib/gui/constants.h index 0f175b800..f1a9a6af9 100644 --- a/src/lib/gui/constants.h +++ b/src/lib/gui/constants.h @@ -28,23 +28,39 @@ const bool kLicensingEnabled = false; const auto kColorWhite = "#ffffff"; const auto kColorPrimary = "#ff7c00"; const auto kColorSecondary = "#4285f4"; +const auto kColorTertiary = "#33b2cc"; +const auto kColorError = "#ec4c47"; +const auto kColorNotice = "#3b67d3"; -const auto kLinkStyleWhite = QString("color: %1").arg(kColorWhite); -const auto kLinkStylePrimary = QString("color: %1").arg(kColorPrimary); -const auto kLinkStyleSecondary = QString("color: %1").arg(kColorSecondary); - -const auto kLinkBuy = R"(Buy now)"; -const auto kLinkRenew = R"(Renew now)"; -const auto kLinkDownload = R"(Download now)"; +const auto kLinkBuy = R"(Buy now)"; +const auto kLinkRenew = R"(Renew now)"; +const auto kLinkDownload = R"(Download now)"; const auto kUrlSourceQuery = "source=gui"; const auto kUrlWebsite = "https://symless.com"; const auto kUrlProduct = QString("%1/synergy").arg(kUrlWebsite); const auto kUrlPurchase = - QString("%1/purchase?%2").arg(kUrlProduct).arg(kUrlSourceQuery); + QString("%1/purchase?%2").arg(kUrlProduct, kUrlSourceQuery); const auto kUrlContact = - QString("%1/contact?%2").arg(kUrlProduct).arg(kUrlSourceQuery); -const auto kUrlHelp = - QString("%1/help?%2").arg(kUrlProduct).arg(kUrlSourceQuery); + QString("%1/contact?%2").arg(kUrlProduct, kUrlSourceQuery); +const auto kUrlHelp = QString("%1/help?%2").arg(kUrlProduct, kUrlSourceQuery); const auto kUrlDownload = - QString("%1/download?%2").arg(kUrlProduct).arg(kUrlSourceQuery); + QString("%1/download?%2").arg(kUrlProduct, kUrlSourceQuery); + +const auto kStyleLineEditErrorBorder = + QString("border: 1px solid %1; border-radius: 2px; padding: 2px;") + .arg(kColorError); + +const auto kStyleErrorActiveLabel = // + QString("padding: 3px 5px; border-radius: 3px; " + "background-color: %1; color: %2") + .arg(kColorError, kColorWhite); + +const auto kStyleErrorInactiveLabel = // + QString("padding: 3px 5px; border-radius: 3px;" + "background-color: none"); + +const auto kStyleNoticeLabel = // + QString("padding: 3px 5px; border-radius: 3px;" + "background-color: %1; color: %2") + .arg(kColorNotice, kColorWhite); diff --git a/src/lib/gui/license_notices.cpp b/src/lib/gui/license_notices.cpp index a399a0d25..1e7444816 100644 --- a/src/lib/gui/license_notices.cpp +++ b/src/lib/gui/license_notices.cpp @@ -38,8 +38,7 @@ QString licenseNotice(const License &license) { } QString trialLicenseNotice(const License &license) { - const QString buyLink = - QString(kLinkBuy).arg(kUrlPurchase).arg(kLinkStyleWhite); + const QString buyLink = QString(kLinkBuy).arg(kUrlPurchase).arg(kColorWhite); if (license.isExpired()) { return QString("

Your trial has expired. %1

").arg(buyLink); } else { @@ -57,7 +56,7 @@ QString trialLicenseNotice(const License &license) { QString subscriptionLicenseNotice(const License &license) { const QString renewLink = - QString(kLinkRenew).arg(kUrlPurchase).arg(kLinkStyleWhite); + QString(kLinkRenew).arg(kUrlPurchase).arg(kColorWhite); if (license.isExpired()) { return QString("

Your license has expired. %1

").arg(renewLink); } else { diff --git a/src/test/integtests/gui/CoreInterfaceTests.cpp b/src/test/integtests/gui/CoreInterfaceTests.cpp new file mode 100644 index 000000000..55a62792b --- /dev/null +++ b/src/test/integtests/gui/CoreInterfaceTests.cpp @@ -0,0 +1,55 @@ +/* + * synergy -- mouse and keyboard sharing utility + * Copyright (C) 2024 Symless Ltd. + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/CoreInterface.h" +#include "shared/gui/QtCoreTest.h" + +#include + +class CoreInterfaceTests : public QtCoreTest {}; + +TEST_F(CoreInterfaceTests, getProfileDir_noMock_returnsNonEmpty) { + CoreInterface coreInterface; + + QString profileDir = coreInterface.getProfileDir(); + + EXPECT_FALSE(profileDir.isEmpty()); +} + +TEST_F(CoreInterfaceTests, getInstalledDir_noMock_returnsNonEmpty) { + CoreInterface coreInterface; + + QString installedDir = coreInterface.getInstalledDir(); + + EXPECT_FALSE(installedDir.isEmpty()); +} + +TEST_F(CoreInterfaceTests, getArch_noMock_returnsNonEmpty) { + CoreInterface coreInterface; + + QString arch = coreInterface.getArch(); + + EXPECT_FALSE(arch.isEmpty()); +} + +TEST_F(CoreInterfaceTests, getSerialKeyFilePath_noMock_returnsNonEmpty) { + CoreInterface coreInterface; + + QString serialKeyFilePath = coreInterface.getSerialKeyFilePath(); + + EXPECT_FALSE(serialKeyFilePath.isEmpty()); +} diff --git a/src/test/shared/TestEventQueue.cpp b/src/test/shared/TestEventQueue.cpp index 454b745c5..2915d2323 100644 --- a/src/test/shared/TestEventQueue.cpp +++ b/src/test/shared/TestEventQueue.cpp @@ -17,26 +17,24 @@ #include "test/shared/TestEventQueue.h" -#include "base/Log.h" -#include "base/SimpleEventQueueBuffer.h" #include "base/TMethodEventJob.h" #include "common/stdexcept.h" void TestEventQueue::raiseQuitEvent() { addEvent(Event(Event::kQuit)); } void TestEventQueue::initQuitTimeout(double timeout) { - assert(m_quitTimeoutTimer == nullptr); - m_quitTimeoutTimer = newOneShotTimer(timeout, NULL); + assert(m_pQuitTimeoutTimer == nullptr); + m_pQuitTimeoutTimer = newOneShotTimer(timeout, NULL); adoptHandler( - Event::kTimer, m_quitTimeoutTimer, + Event::kTimer, m_pQuitTimeoutTimer, new TMethodEventJob( this, &TestEventQueue::handleQuitTimeout)); } void TestEventQueue::cleanupQuitTimeout() { - removeHandler(Event::kTimer, m_quitTimeoutTimer); - delete m_quitTimeoutTimer; - m_quitTimeoutTimer = nullptr; + removeHandler(Event::kTimer, m_pQuitTimeoutTimer); + delete m_pQuitTimeoutTimer; + m_pQuitTimeoutTimer = nullptr; } void TestEventQueue::handleQuitTimeout(const Event &, void *vclient) { diff --git a/src/test/shared/TestEventQueue.h b/src/test/shared/TestEventQueue.h index 46fc6fb48..5f89d17bc 100644 --- a/src/test/shared/TestEventQueue.h +++ b/src/test/shared/TestEventQueue.h @@ -23,7 +23,7 @@ class EventQueueTimer; class TestEventQueue : public EventQueue { public: - TestEventQueue() : m_quitTimeoutTimer(nullptr) {} + TestEventQueue() : m_pQuitTimeoutTimer(nullptr) {} void handleQuitTimeout(const Event &, void *vclient); void raiseQuitEvent(); @@ -34,5 +34,5 @@ private: void timeoutThread(void *); private: - EventQueueTimer *m_quitTimeoutTimer; + EventQueueTimer *m_pQuitTimeoutTimer; }; diff --git a/src/test/shared/gui/QtCoreTest.h b/src/test/shared/gui/QtCoreTest.h index be17bef16..9e7a91d32 100644 --- a/src/test/shared/gui/QtCoreTest.h +++ b/src/test/shared/gui/QtCoreTest.h @@ -23,16 +23,12 @@ class QtCoreTest : public ::testing::Test { public: static void SetUpTestSuite() { - GTEST_LOG_(INFO) << "Qt core app setup"; char **argv = nullptr; int argc = 0; s_app = std::make_unique(argc, argv); } - static void TearDownTestSuite() { - s_app.reset(); - GTEST_LOG_(INFO) << "Qt core app teardown"; - } + static void TearDownTestSuite() { s_app.reset(); } static std::unique_ptr s_app; }; diff --git a/src/test/shared/gui/QtTest.h b/src/test/shared/gui/QtTest.h index 717efd16a..12f67036e 100644 --- a/src/test/shared/gui/QtTest.h +++ b/src/test/shared/gui/QtTest.h @@ -23,16 +23,12 @@ class QtTest : public ::testing::Test { public: static void SetUpTestSuite() { - GTEST_LOG_(INFO) << "Qt app setup"; char **argv = nullptr; int argc = 0; s_app = std::make_unique(argc, argv); } - static void TearDownTestSuite() { - s_app.reset(); - GTEST_LOG_(INFO) << "Qt app teardown"; - } + static void TearDownTestSuite() { s_app.reset(); } static std::unique_ptr s_app; }; diff --git a/src/test/unittests/arch/unix/ArchNetworkBSDTests.cpp b/src/test/unittests/arch/unix/ArchNetworkBSDTests.cpp index b9796f682..30a77e74a 100644 --- a/src/test/unittests/arch/unix/ArchNetworkBSDTests.cpp +++ b/src/test/unittests/arch/unix/ArchNetworkBSDTests.cpp @@ -31,6 +31,7 @@ using ::testing::NiceMock; using PollEntries = std::vector; using PollFD = struct pollfd[]; +namespace { struct MockDeps : public ArchNetworkBSD::Deps { MockDeps() { ON_CALL(*this, makePollFD(_)).WillByDefault([this](nfds_t n) { @@ -47,19 +48,7 @@ struct MockDeps : public ArchNetworkBSD::Deps { std::shared_ptr m_pollFD; }; - -#ifndef NDEBUG - -TEST(ArchNetworkBSDTests, pollSocket_negativeNum_death) { - MockDeps deps; - ArchNetworkBSD networkBSD(deps); - - PollEntries entries{{nullptr, 0, 0}}; - - EXPECT_DEATH({ networkBSD.pollSocket(entries.data(), -1, 1); }, "num > 0"); -} - -#endif // DEBUG +} // namespace TEST(ArchNetworkBSDTests, pollSocket_zeroEntries_callsSleep) { MockDeps deps; diff --git a/src/test/unittests/gui/AppConfigTests.cpp b/src/test/unittests/gui/AppConfigTests.cpp new file mode 100644 index 000000000..391c94d1a --- /dev/null +++ b/src/test/unittests/gui/AppConfigTests.cpp @@ -0,0 +1,108 @@ +/* + * synergy -- mouse and keyboard sharing utility + * Copyright (C) 2024 Symless Ltd. + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/AppConfig.h" + +#include "gmock/gmock.h" +#include +#include + +using namespace testing; + +namespace { + +class MockScopes : public synergy::gui::IConfigScopes { +public: + MOCK_METHOD( + void, registerReceiver, (synergy::gui::CommonConfig * receiver), + (override)); + MOCK_METHOD(void, loadAll, (), (override)); + MOCK_METHOD( + bool, hasSetting, (const QString &name, Scope scope), (const, override)); + MOCK_METHOD( + QVariant, loadSetting, + (const QString &name, const QVariant &defaultValue, Scope scope), + (const, override)); + MOCK_METHOD( + void, setSetting, + (const QString &name, const QVariant &value, Scope scope), (override)); + MOCK_METHOD(Scope, getScope, (), (const, override)); + MOCK_METHOD(void, setScope, (Scope scope), (override)); + MOCK_METHOD(bool, isWritable, (), (const, override)); + MOCK_METHOD(QSettings *, currentSettings, (), (const, override)); + MOCK_METHOD(void, saveAll, (), (override)); +}; + +struct MockDeps : public AppConfig::Deps { + NiceMock m_scopes; + + MockDeps() { + ON_CALL(*this, profileDir()).WillByDefault(Return("stub")); + ON_CALL(*this, scopes()).WillByDefault(ReturnRef(m_scopes)); + ON_CALL(*this, hostname()).WillByDefault(Return("stub")); + } + + MOCK_METHOD(QString, profileDir, (), (const, override)); + MOCK_METHOD(synergy::gui::IConfigScopes &, scopes, (), (override)); + MOCK_METHOD(QString, hostname, (), (const, override)); +}; + +} // namespace + +class AppConfigTests : public Test {}; + +TEST_F(AppConfigTests, ctor_byDefault_screenNameIsHostname) { + NiceMock deps; + ON_CALL(deps, hostname()).WillByDefault(Return("test")); + + AppConfig appConfig(deps); + + ASSERT_EQ(appConfig.screenName().toStdString(), "test"); +} + +TEST_F(AppConfigTests, loadAllScopes_byDefault_callsScopesLoadAll) { + NiceMock deps; + AppConfig appConfig(deps); + + EXPECT_CALL(deps.m_scopes, loadAll()); + + appConfig.loadAllScopes(); +} + +TEST_F(AppConfigTests, loadSettings_byDefault_callsScopesLoadSetting) { + NiceMock deps; + AppConfig appConfig(deps); + + ON_CALL(deps.m_scopes, hasSetting(_, _)).WillByDefault(Return(true)); + ON_CALL(deps.m_scopes, loadSetting(_, _, _)) + .WillByDefault(Return(QVariant("test"))); + EXPECT_CALL(deps.m_scopes, loadSetting(_, _, _)).Times(AnyNumber()); + + appConfig.loadSettings(); + + ASSERT_EQ(appConfig.screenName().toStdString(), "test"); +} + +TEST_F(AppConfigTests, saveSettings_byDefault_callsScopesSetSetting) { + NiceMock deps; + AppConfig appConfig(deps); + + ON_CALL(deps.m_scopes, isWritable()).WillByDefault(Return(true)); + EXPECT_CALL(deps.m_scopes, setSetting(_, _, _)).Times(AnyNumber()); + + appConfig.saveSettings(); +}