Refactor settings dialog to simplify enable/disable logic (#7428)
* Move screen config files to new GUI lib * Fixed bugs in config dialog related to service checkbox * Test status tip * Revert "Test status tip" This reverts commit d11ad5bc22dab7edcf7ef0b3baada2fce240398a. * Explain why service disabled * Corrected client error message (written by non-native English writer) to make the message easier to understand for native English speakers * Clearer logic * Improve readability * Coverage for 'add client' and client error messages * Coverage for `Screen` class * Clarify test names * Use `const QString &` for backward compatibility * Fixed lint warnings * Prevent return paths after qFatal * Use auto and abort to solve lint warnings * Remove unused fake error * Make operator hidden friend * Remove redundant access specifier * Convert int explicitly * Swap && logic for linter * Update ChangeLog
This commit is contained in:
parent
6b1e7e6f1c
commit
de21030892
52 changed files with 1188 additions and 604 deletions
|
|
@ -71,6 +71,7 @@ Enhancements:
|
|||
- #7425 Refactored core process management and IPC client
|
||||
- #7426 Fixed warnings and enable errors as warnings
|
||||
- #7427 More reliable button click detection for add client dialog
|
||||
- #7428 Refactor settings dialog to simplify enable/disable logic
|
||||
|
||||
# 1.14.6
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
"Olena",
|
||||
"outputdir",
|
||||
"Petroules",
|
||||
"Pixmap",
|
||||
"Poschta",
|
||||
"Priddy",
|
||||
"runas",
|
||||
|
|
|
|||
|
|
@ -94,8 +94,8 @@ MainWindow::MainWindow(ConfigScopes &configScopes, AppConfig &appConfig)
|
|||
m_AppConfig(appConfig),
|
||||
m_ServerConfig(appConfig, *this),
|
||||
m_CoreProcess(appConfig, m_ServerConfig),
|
||||
m_ServerConnection(*this, appConfig, m_ServerConfig),
|
||||
m_ClientConnection(*this, appConfig),
|
||||
m_ServerConnection(this, appConfig, m_ServerConfig),
|
||||
m_ClientConnection(this, appConfig),
|
||||
m_TlsUtility(appConfig, m_LicenseHandler.license()),
|
||||
m_WindowSaveTimer(this) {
|
||||
|
||||
|
|
@ -251,7 +251,9 @@ void MainWindow::connectSlots() {
|
|||
|
||||
connect(m_pActionMinimize, &QAction::triggered, this, &MainWindow::hide);
|
||||
|
||||
connect(m_pActionRestore, &QAction::triggered, this, &MainWindow::showNormal);
|
||||
connect(
|
||||
m_pActionRestore, &QAction::triggered, //
|
||||
[this]() { showAndActivate(); });
|
||||
|
||||
connect(
|
||||
m_pActionStartCore, &QAction::triggered, this,
|
||||
|
|
@ -278,6 +280,14 @@ void MainWindow::connectSlots() {
|
|||
connect(
|
||||
&m_ServerConnection, &ServerConnection::configureClient, this,
|
||||
&MainWindow::onServerConnectionConfigureClient);
|
||||
|
||||
connect(
|
||||
&m_ServerConnection, &ServerConnection::messageShowing, this,
|
||||
[this]() { showAndActivate(); });
|
||||
|
||||
connect(
|
||||
&m_ClientConnection, &ClientConnection::messageShowing, this,
|
||||
[this]() { showAndActivate(); });
|
||||
}
|
||||
|
||||
void MainWindow::onAppAboutToQuit() { m_ConfigScopes.save(); }
|
||||
|
|
@ -339,8 +349,7 @@ void MainWindow::onTrayIconActivated(QSystemTrayIcon::ActivationReason reason) {
|
|||
if (isVisible()) {
|
||||
hide();
|
||||
} else {
|
||||
showNormal();
|
||||
activateWindow();
|
||||
showAndActivate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -355,7 +364,7 @@ void MainWindow::onVersionCheckerUpdateFound(const QString &version) {
|
|||
}
|
||||
|
||||
void MainWindow::onActionStartCoreTriggered() {
|
||||
m_ClientConnection.setCheckConnection(true);
|
||||
m_ClientConnection.setShowMessage();
|
||||
m_CoreProcess.start();
|
||||
}
|
||||
|
||||
|
|
@ -408,9 +417,11 @@ void MainWindow::on_m_pActionHelp_triggered() {
|
|||
}
|
||||
|
||||
void MainWindow::on_m_pActionSettings_triggered() {
|
||||
auto result =
|
||||
SettingsDialog(this, m_AppConfig, m_LicenseHandler.license()).exec();
|
||||
if (result == QDialog::Accepted) {
|
||||
auto dialog = SettingsDialog(
|
||||
this, m_AppConfig, m_ServerConfig, m_LicenseHandler.license(),
|
||||
m_CoreProcess);
|
||||
|
||||
if (dialog.exec() == QDialog::Accepted) {
|
||||
m_ConfigScopes.save();
|
||||
|
||||
applyConfig();
|
||||
|
|
@ -445,7 +456,7 @@ void MainWindow::on_m_pLineEditClientIp_textChanged(const QString &text) {
|
|||
}
|
||||
|
||||
void MainWindow::on_m_pButtonApply_clicked() {
|
||||
m_ClientConnection.setCheckConnection(true);
|
||||
m_ClientConnection.setShowMessage();
|
||||
m_CoreProcess.restart();
|
||||
}
|
||||
|
||||
|
|
@ -516,7 +527,7 @@ void MainWindow::open() {
|
|||
if (m_AppConfig.autoHide()) {
|
||||
hide();
|
||||
} else {
|
||||
showNormal();
|
||||
showAndActivate();
|
||||
}
|
||||
|
||||
m_VersionChecker.checkLatest();
|
||||
|
|
@ -651,10 +662,10 @@ void MainWindow::updateFromLogLine(const QString &line) {
|
|||
|
||||
void MainWindow::checkConnected(const QString &line) {
|
||||
if (m_pRadioGroupServer->isChecked()) {
|
||||
m_ServerConnection.update(line);
|
||||
m_ServerConnection.handleLogLine(line);
|
||||
m_pLabelServerState->updateServerState(line);
|
||||
} else {
|
||||
m_ClientConnection.update(line);
|
||||
m_ClientConnection.handleLogLine(line);
|
||||
m_pLabelClientState->updateClientState(line);
|
||||
}
|
||||
}
|
||||
|
|
@ -1071,3 +1082,13 @@ void MainWindow::enableClient(bool enable) {
|
|||
m_CoreProcess.setMode(CoreProcess::Mode::Client);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::showAndActivate() {
|
||||
if (!isMinimized() && !isHidden()) {
|
||||
qDebug("window already visible");
|
||||
return;
|
||||
}
|
||||
|
||||
showNormal();
|
||||
activateWindow();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -171,6 +171,7 @@ private:
|
|||
void showDevThanksMessage();
|
||||
QString productName() const;
|
||||
void updateStatus();
|
||||
void showAndActivate();
|
||||
|
||||
VersionChecker m_VersionChecker;
|
||||
synergy::gui::TrayIcon m_TrayIcon;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -17,7 +17,8 @@
|
|||
*/
|
||||
|
||||
#include "ScreenSettingsDialog.h"
|
||||
#include "Screen.h"
|
||||
|
||||
#include "gui/config/Screen.h"
|
||||
#include "gui/styles.h"
|
||||
#include "validators/AliasValidator.h"
|
||||
#include "validators/ScreenNameValidator.h"
|
||||
|
|
@ -28,6 +29,9 @@
|
|||
#include <QtGui>
|
||||
|
||||
using namespace synergy::gui;
|
||||
using enum ScreenConfig::Modifier;
|
||||
using enum ScreenConfig::SwitchCorner;
|
||||
using enum ScreenConfig::Fix;
|
||||
|
||||
ScreenSettingsDialog::ScreenSettingsDialog(
|
||||
QWidget *parent, Screen *pScreen, const ScreenList *pScreens)
|
||||
|
|
@ -53,26 +57,28 @@ ScreenSettingsDialog::ScreenSettingsDialog(
|
|||
for (int i = 0; i < m_pScreen->aliases().count(); i++)
|
||||
new QListWidgetItem(m_pScreen->aliases()[i], m_pListAliases);
|
||||
|
||||
m_pComboBoxShift->setCurrentIndex(m_pScreen->modifier(Screen::Shift));
|
||||
m_pComboBoxCtrl->setCurrentIndex(m_pScreen->modifier(Screen::Ctrl));
|
||||
m_pComboBoxAlt->setCurrentIndex(m_pScreen->modifier(Screen::Alt));
|
||||
m_pComboBoxMeta->setCurrentIndex(m_pScreen->modifier(Screen::Meta));
|
||||
m_pComboBoxSuper->setCurrentIndex(m_pScreen->modifier(Screen::Super));
|
||||
m_pComboBoxShift->setCurrentIndex(
|
||||
m_pScreen->modifier(static_cast<int>(Shift)));
|
||||
m_pComboBoxCtrl->setCurrentIndex(m_pScreen->modifier(static_cast<int>(Ctrl)));
|
||||
m_pComboBoxAlt->setCurrentIndex(m_pScreen->modifier(static_cast<int>(Alt)));
|
||||
m_pComboBoxMeta->setCurrentIndex(m_pScreen->modifier(static_cast<int>(Meta)));
|
||||
m_pComboBoxSuper->setCurrentIndex(
|
||||
m_pScreen->modifier(static_cast<int>(Super)));
|
||||
|
||||
m_pCheckBoxCornerTopLeft->setChecked(
|
||||
m_pScreen->switchCorner(Screen::TopLeft));
|
||||
m_pScreen->switchCorner(static_cast<int>(TopLeft)));
|
||||
m_pCheckBoxCornerTopRight->setChecked(
|
||||
m_pScreen->switchCorner(Screen::TopRight));
|
||||
m_pScreen->switchCorner(static_cast<int>(TopRight)));
|
||||
m_pCheckBoxCornerBottomLeft->setChecked(
|
||||
m_pScreen->switchCorner(Screen::BottomLeft));
|
||||
m_pScreen->switchCorner(static_cast<int>(BottomLeft)));
|
||||
m_pCheckBoxCornerBottomRight->setChecked(
|
||||
m_pScreen->switchCorner(Screen::BottomRight));
|
||||
m_pScreen->switchCorner(static_cast<int>(BottomRight)));
|
||||
m_pSpinBoxSwitchCornerSize->setValue(m_pScreen->switchCornerSize());
|
||||
|
||||
m_pCheckBoxCapsLock->setChecked(m_pScreen->fix(Screen::CapsLock));
|
||||
m_pCheckBoxNumLock->setChecked(m_pScreen->fix(Screen::NumLock));
|
||||
m_pCheckBoxScrollLock->setChecked(m_pScreen->fix(Screen::ScrollLock));
|
||||
m_pCheckBoxXTest->setChecked(m_pScreen->fix(Screen::XTest));
|
||||
m_pCheckBoxCapsLock->setChecked(m_pScreen->fix(CapsLock));
|
||||
m_pCheckBoxNumLock->setChecked(m_pScreen->fix(NumLock));
|
||||
m_pCheckBoxScrollLock->setChecked(m_pScreen->fix(ScrollLock));
|
||||
m_pCheckBoxXTest->setChecked(m_pScreen->fix(XTest));
|
||||
}
|
||||
|
||||
void ScreenSettingsDialog::accept() {
|
||||
|
|
@ -102,26 +108,32 @@ void ScreenSettingsDialog::accept() {
|
|||
m_pScreen->addAlias(alias);
|
||||
}
|
||||
|
||||
m_pScreen->setModifier(Screen::Shift, m_pComboBoxShift->currentIndex());
|
||||
m_pScreen->setModifier(Screen::Ctrl, m_pComboBoxCtrl->currentIndex());
|
||||
m_pScreen->setModifier(Screen::Alt, m_pComboBoxAlt->currentIndex());
|
||||
m_pScreen->setModifier(Screen::Meta, m_pComboBoxMeta->currentIndex());
|
||||
m_pScreen->setModifier(Screen::Super, m_pComboBoxSuper->currentIndex());
|
||||
m_pScreen->setModifier(
|
||||
static_cast<int>(Shift), m_pComboBoxShift->currentIndex());
|
||||
m_pScreen->setModifier(
|
||||
static_cast<int>(Ctrl), m_pComboBoxCtrl->currentIndex());
|
||||
m_pScreen->setModifier(static_cast<int>(Alt), m_pComboBoxAlt->currentIndex());
|
||||
m_pScreen->setModifier(
|
||||
static_cast<int>(Meta), m_pComboBoxMeta->currentIndex());
|
||||
m_pScreen->setModifier(
|
||||
static_cast<int>(Super), m_pComboBoxSuper->currentIndex());
|
||||
|
||||
m_pScreen->setSwitchCorner(
|
||||
Screen::TopLeft, m_pCheckBoxCornerTopLeft->isChecked());
|
||||
static_cast<int>(TopLeft), m_pCheckBoxCornerTopLeft->isChecked());
|
||||
m_pScreen->setSwitchCorner(
|
||||
Screen::TopRight, m_pCheckBoxCornerTopRight->isChecked());
|
||||
static_cast<int>(TopRight), m_pCheckBoxCornerTopRight->isChecked());
|
||||
m_pScreen->setSwitchCorner(
|
||||
Screen::BottomLeft, m_pCheckBoxCornerBottomLeft->isChecked());
|
||||
static_cast<int>(BottomLeft), m_pCheckBoxCornerBottomLeft->isChecked());
|
||||
m_pScreen->setSwitchCorner(
|
||||
Screen::BottomRight, m_pCheckBoxCornerBottomRight->isChecked());
|
||||
static_cast<int>(BottomRight), m_pCheckBoxCornerBottomRight->isChecked());
|
||||
m_pScreen->setSwitchCornerSize(m_pSpinBoxSwitchCornerSize->value());
|
||||
|
||||
m_pScreen->setFix(Screen::CapsLock, m_pCheckBoxCapsLock->isChecked());
|
||||
m_pScreen->setFix(Screen::NumLock, m_pCheckBoxNumLock->isChecked());
|
||||
m_pScreen->setFix(Screen::ScrollLock, m_pCheckBoxScrollLock->isChecked());
|
||||
m_pScreen->setFix(Screen::XTest, m_pCheckBoxXTest->isChecked());
|
||||
m_pScreen->setFix(
|
||||
static_cast<int>(CapsLock), m_pCheckBoxCapsLock->isChecked());
|
||||
m_pScreen->setFix(static_cast<int>(NumLock), m_pCheckBoxNumLock->isChecked());
|
||||
m_pScreen->setFix(
|
||||
static_cast<int>(ScrollLock), m_pCheckBoxScrollLock->isChecked());
|
||||
m_pScreen->setFix(static_cast<int>(XTest), m_pCheckBoxXTest->isChecked());
|
||||
|
||||
QDialog::accept();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -17,7 +17,8 @@
|
|||
*/
|
||||
|
||||
#include "ScreenSetupModel.h"
|
||||
#include "Screen.h"
|
||||
|
||||
#include "gui/config/Screen.h"
|
||||
|
||||
#include <QtCore>
|
||||
#include <QtGui>
|
||||
|
|
@ -137,7 +138,7 @@ bool ScreenSetupModel::dropMimeData(
|
|||
Screen droppedScreen;
|
||||
stream >> droppedScreen;
|
||||
|
||||
Screen oldScreen = screen(parent.column(), parent.row());
|
||||
auto oldScreen = Screen(screen(parent.column(), parent.row()));
|
||||
if (!oldScreen.isNull() && sourceColumn != -1 && sourceRow != -1) {
|
||||
// mark the screen so it isn't deleted after the dragndrop succeeded
|
||||
// see ScreenSetupView::startDrag()
|
||||
|
|
|
|||
|
|
@ -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,16 +16,14 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if !defined(SCREENSETUPMODEL__H)
|
||||
|
||||
#define SCREENSETUPMODEL__H
|
||||
#pragma once
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
#include "ScreenList.h"
|
||||
#include "gui/config/ScreenList.h"
|
||||
|
||||
class ScreenSetupView;
|
||||
class ServerConfigDialog;
|
||||
|
|
@ -80,5 +78,3 @@ private:
|
|||
|
||||
static const QString m_MimeType;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -17,6 +17,7 @@
|
|||
*/
|
||||
|
||||
#include "ScreenSetupView.h"
|
||||
|
||||
#include "ScreenSettingsDialog.h"
|
||||
#include "ScreenSetupModel.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,14 +16,12 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if !defined(SCREENSETUPVIEW__H)
|
||||
|
||||
#define SCREENSETUPVIEW__H
|
||||
#pragma once
|
||||
|
||||
#include <QFlags>
|
||||
#include <QTableView>
|
||||
|
||||
#include "Screen.h"
|
||||
#include "gui/config/Screen.h"
|
||||
|
||||
class QWidget;
|
||||
class QMouseEvent;
|
||||
|
|
@ -51,5 +49,3 @@ protected:
|
|||
void initViewItemOption(QStyleOptionViewItem *option) const override;
|
||||
void scrollTo(const QModelIndex &, ScrollHint) override {}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -27,6 +27,11 @@
|
|||
#include <QPushButton>
|
||||
#include <QtCore>
|
||||
|
||||
using namespace synergy::gui::proxy;
|
||||
using enum ScreenConfig::Modifier;
|
||||
using enum ScreenConfig::SwitchCorner;
|
||||
using enum ScreenConfig::Fix;
|
||||
|
||||
static const struct {
|
||||
int x;
|
||||
int y;
|
||||
|
|
@ -94,7 +99,7 @@ void ServerConfig::setupScreens() {
|
|||
hotkeys().clear();
|
||||
|
||||
// m_NumSwitchCorners is used as a fixed size array. See Screen::init()
|
||||
for (int i = 0; i < NumSwitchCorners; i++)
|
||||
for (int i = 0; i < static_cast<int>(NumSwitchCorners); i++)
|
||||
switchCorners() << false;
|
||||
|
||||
// There must always be screen objects for each cell in the screens QList.
|
||||
|
|
@ -147,7 +152,7 @@ void ServerConfig::commit() {
|
|||
settings().beginWriteArray("hotkeys");
|
||||
for (int i = 0; i < hotkeys().size(); i++) {
|
||||
settings().setArrayIndex(i);
|
||||
hotkeys()[i].saveSettings(settings());
|
||||
hotkeys()[i].saveSettings(settings().get());
|
||||
}
|
||||
settings().endArray();
|
||||
|
||||
|
|
@ -189,7 +194,8 @@ void ServerConfig::recall() {
|
|||
setClientAddress(settings().value("clientAddress", "").toString());
|
||||
|
||||
readSettings(
|
||||
settings(), switchCorners(), "switchCorner", false, NumSwitchCorners);
|
||||
settings(), switchCorners(), "switchCorner", 0,
|
||||
static_cast<int>(NumSwitchCorners));
|
||||
|
||||
int numScreens = settings().beginReadArray("screens");
|
||||
Q_ASSERT(numScreens <= screens().size());
|
||||
|
|
@ -206,7 +212,7 @@ void ServerConfig::recall() {
|
|||
for (int i = 0; i < numHotkeys; i++) {
|
||||
settings().setArrayIndex(i);
|
||||
Hotkey h;
|
||||
h.loadSettings(settings());
|
||||
h.loadSettings(settings().get());
|
||||
hotkeys().append(h);
|
||||
}
|
||||
settings().endArray();
|
||||
|
|
@ -449,7 +455,7 @@ void ServerConfig::addClient(const QString &clientName) {
|
|||
fixNoServer(m_pAppConfig->screenName(), serverIndex);
|
||||
}
|
||||
|
||||
m_Screens.addScreenByPriority(clientName);
|
||||
m_Screens.addScreenByPriority(Screen(clientName));
|
||||
}
|
||||
|
||||
void ServerConfig::setConfigFile(const QString &configFile) {
|
||||
|
|
@ -542,6 +548,6 @@ QString ServerConfig::getClientAddress() const {
|
|||
return clientAddress;
|
||||
}
|
||||
|
||||
QSettings &ServerConfig::settings() {
|
||||
return *m_pAppConfig->scopes().activeSettings();
|
||||
QSettingsProxy &ServerConfig::settings() {
|
||||
return m_pAppConfig->scopes().activeSettings();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -19,9 +19,9 @@
|
|||
#pragma once
|
||||
|
||||
#include "Hotkey.h"
|
||||
#include "ScreenConfig.h"
|
||||
#include "ScreenList.h"
|
||||
#include "gui/config/IServerConfig.h"
|
||||
#include "gui/config/ScreenConfig.h"
|
||||
#include "gui/config/ScreenList.h"
|
||||
|
||||
#include <QList>
|
||||
|
||||
|
|
@ -37,6 +37,8 @@ class MainWindow;
|
|||
class AppConfig;
|
||||
|
||||
class ServerConfig : public ScreenConfig, public synergy::gui::IServerConfig {
|
||||
using QSettingsProxy = synergy::gui::proxy::QSettingsProxy;
|
||||
|
||||
friend class ServerConfigDialog;
|
||||
friend QTextStream &
|
||||
operator<<(QTextStream &outStream, const ServerConfig &config);
|
||||
|
|
@ -49,7 +51,15 @@ public:
|
|||
|
||||
bool operator==(const ServerConfig &sc) const;
|
||||
|
||||
const ScreenList &screens() const { return m_Screens; }
|
||||
//
|
||||
// Overrides
|
||||
//
|
||||
const ScreenList &screens() const override { return m_Screens; }
|
||||
bool enableDragAndDrop() const override { return m_EnableDragAndDrop; }
|
||||
|
||||
//
|
||||
// New methods
|
||||
//
|
||||
int numColumns() const { return m_Columns; }
|
||||
int numRows() const { return m_Rows; }
|
||||
bool hasHeartbeat() const { return m_HasHeartbeat; }
|
||||
|
|
@ -64,23 +74,29 @@ public:
|
|||
int switchCornerSize() const { return m_SwitchCornerSize; }
|
||||
const QList<bool> &switchCorners() const { return m_SwitchCorners; }
|
||||
const HotkeyList &hotkeys() const { return m_Hotkeys; }
|
||||
bool enableDragAndDrop() const override { return m_EnableDragAndDrop; }
|
||||
bool disableLockToScreen() const { return m_DisableLockToScreen; }
|
||||
bool clipboardSharing() const { return m_ClipboardSharing; }
|
||||
size_t clipboardSharingSize() const { return m_ClipboardSharingSize; }
|
||||
static size_t defaultClipboardSharingSize();
|
||||
|
||||
void commit();
|
||||
//
|
||||
// Overrides
|
||||
//
|
||||
bool save(const QString &fileName) const override;
|
||||
bool screenExists(const QString &screenName) const override;
|
||||
void save(QFile &file) const override;
|
||||
bool isFull() const override;
|
||||
|
||||
//
|
||||
// New methods
|
||||
//
|
||||
void commit();
|
||||
int numScreens() const;
|
||||
int autoAddScreen(const QString name);
|
||||
const QString &getServerName() const;
|
||||
void updateServerName();
|
||||
const QString &configFile() const;
|
||||
bool useExternalConfig() const;
|
||||
bool isFull() const override;
|
||||
bool screenExists(const QString &screenName) const override;
|
||||
void addClient(const QString &clientName);
|
||||
QString getClientAddress() const;
|
||||
void setClientAddress(const QString &address);
|
||||
|
|
@ -88,7 +104,7 @@ public:
|
|||
private:
|
||||
void recall();
|
||||
void setupScreens();
|
||||
QSettings &settings();
|
||||
QSettingsProxy &settings();
|
||||
ScreenList &screens() { return m_Screens; }
|
||||
void setScreens(const ScreenList &screens) { m_Screens = screens; }
|
||||
void addScreen(const Screen &screen) { m_Screens.append(screen); }
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@
|
|||
#include <QtCore>
|
||||
#include <QtGui>
|
||||
|
||||
using enum ScreenConfig::SwitchCorner;
|
||||
|
||||
ServerConfigDialog::ServerConfigDialog(
|
||||
QWidget *parent, ServerConfig &config, AppConfig &appConfig)
|
||||
: QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint),
|
||||
|
|
@ -65,13 +67,13 @@ ServerConfigDialog::ServerConfigDialog(
|
|||
m_pSpinBoxSwitchDoubleTap->setValue(serverConfig().switchDoubleTap());
|
||||
|
||||
m_pCheckBoxCornerTopLeft->setChecked(
|
||||
serverConfig().switchCorner(ScreenConfig::TopLeft));
|
||||
serverConfig().switchCorner(static_cast<int>(TopLeft)));
|
||||
m_pCheckBoxCornerTopRight->setChecked(
|
||||
serverConfig().switchCorner(ScreenConfig::TopRight));
|
||||
serverConfig().switchCorner(static_cast<int>(TopRight)));
|
||||
m_pCheckBoxCornerBottomLeft->setChecked(
|
||||
serverConfig().switchCorner(ScreenConfig::BottomLeft));
|
||||
serverConfig().switchCorner(static_cast<int>(BottomLeft)));
|
||||
m_pCheckBoxCornerBottomRight->setChecked(
|
||||
serverConfig().switchCorner(ScreenConfig::BottomRight));
|
||||
serverConfig().switchCorner(static_cast<int>(BottomRight)));
|
||||
m_pSpinBoxSwitchCornerSize->setValue(serverConfig().switchCornerSize());
|
||||
m_pCheckBoxDisableLockToScreen->setChecked(
|
||||
serverConfig().disableLockToScreen());
|
||||
|
|
@ -189,25 +191,25 @@ ServerConfigDialog::ServerConfigDialog(
|
|||
connect(
|
||||
m_pCheckBoxCornerTopLeft, &QCheckBox::stateChanged, this,
|
||||
[this](const int &v) {
|
||||
serverConfig().setSwitchCorner(ScreenConfig::TopLeft, v);
|
||||
serverConfig().setSwitchCorner(static_cast<int>(TopLeft), v);
|
||||
onChange();
|
||||
});
|
||||
connect(
|
||||
m_pCheckBoxCornerTopRight, &QCheckBox::stateChanged, this,
|
||||
[this](const int &v) {
|
||||
serverConfig().setSwitchCorner(ScreenConfig::TopRight, v);
|
||||
serverConfig().setSwitchCorner(static_cast<int>(TopRight), v);
|
||||
onChange();
|
||||
});
|
||||
connect(
|
||||
m_pCheckBoxCornerBottomLeft, &QCheckBox::stateChanged, this,
|
||||
[this](const int &v) {
|
||||
serverConfig().setSwitchCorner(ScreenConfig::BottomLeft, v);
|
||||
serverConfig().setSwitchCorner(static_cast<int>(BottomLeft), v);
|
||||
onChange();
|
||||
});
|
||||
connect(
|
||||
m_pCheckBoxCornerBottomRight, &QCheckBox::stateChanged, this,
|
||||
[this](const int &v) {
|
||||
serverConfig().setSwitchCorner(ScreenConfig::BottomRight, v);
|
||||
serverConfig().setSwitchCorner(static_cast<int>(BottomRight), v);
|
||||
onChange();
|
||||
});
|
||||
connect(
|
||||
|
|
|
|||
|
|
@ -40,12 +40,15 @@ using namespace synergy::gui;
|
|||
const char *const kProProductName = "Synergy 1 Pro";
|
||||
|
||||
SettingsDialog::SettingsDialog(
|
||||
QWidget *parent, AppConfig &config, const License &license)
|
||||
MainWindow *parent, AppConfig &appConfig, const IServerConfig &serverConfig,
|
||||
const License &license, const CoreProcess &coreProcess)
|
||||
: QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint),
|
||||
Ui::SettingsDialogBase(),
|
||||
m_appConfig(config),
|
||||
m_appConfig(appConfig),
|
||||
m_serverConfig(serverConfig),
|
||||
m_license(license),
|
||||
m_tlsUtility(config, license) {
|
||||
m_coreProcess(coreProcess),
|
||||
m_tlsUtility(appConfig, license) {
|
||||
|
||||
setupUi(this);
|
||||
|
||||
|
|
@ -53,124 +56,18 @@ SettingsDialog::SettingsDialog(
|
|||
// the developer was looking at, and it's easy to accidentally save that.
|
||||
m_pTabWidget->setCurrentIndex(0);
|
||||
|
||||
m_pMainWindow = dynamic_cast<MainWindow *>(parent);
|
||||
|
||||
loadFromConfig();
|
||||
m_wasOriginallySystemScope = appConfig().isActiveScopeSystem();
|
||||
updateControlsEnabled();
|
||||
|
||||
const auto &serveConfig = m_pMainWindow->serverConfig();
|
||||
m_wasOriginallySystemScope = m_appConfig.isActiveScopeSystem();
|
||||
updateControls();
|
||||
|
||||
m_pScreenNameError = new validators::ValidationError(this);
|
||||
m_pLineEditScreenName->setValidator(new validators::ScreenNameValidator(
|
||||
m_pLineEditScreenName, m_pScreenNameError, &serveConfig.screens()));
|
||||
m_pLineEditScreenName, m_pScreenNameError, &serverConfig.screens()));
|
||||
}
|
||||
|
||||
void SettingsDialog::accept() {
|
||||
if (!m_pLineEditScreenName->hasAcceptableInput()) {
|
||||
QMessageBox::warning(
|
||||
this, tr("Invalid screen name"), m_pScreenNameError->message());
|
||||
return;
|
||||
}
|
||||
|
||||
appConfig().setLoadFromSystemScope(m_pRadioSystemScope->isChecked());
|
||||
appConfig().setScreenName(m_pLineEditScreenName->text());
|
||||
appConfig().setPort(m_pSpinBoxPort->value());
|
||||
appConfig().setNetworkInterface(m_pLineEditInterface->text());
|
||||
appConfig().setLogLevel(m_pComboLogLevel->currentIndex());
|
||||
appConfig().setLogToFile(m_pCheckBoxLogToFile->isChecked());
|
||||
appConfig().setLogFilename(m_pLineEditLogFilename->text());
|
||||
appConfig().setElevateMode(
|
||||
static_cast<ElevateMode>(m_pComboElevate->currentIndex()));
|
||||
appConfig().setAutoHide(m_pCheckBoxAutoHide->isChecked());
|
||||
appConfig().setPreventSleep(m_pCheckBoxPreventSleep->isChecked());
|
||||
appConfig().setTlsCertPath(m_pLineEditCertificatePath->text());
|
||||
appConfig().setTlsKeyLength(m_pComboBoxKeyLength->currentText().toInt());
|
||||
appConfig().setTlsEnabled(m_pCheckBoxEnableCrypto->isChecked());
|
||||
appConfig().setLanguageSync(m_pCheckBoxLanguageSync->isChecked());
|
||||
appConfig().setInvertScrollDirection(m_pCheckBoxScrollDirection->isChecked());
|
||||
appConfig().setEnableService(m_pCheckBoxServiceEnabled->isChecked());
|
||||
appConfig().setCloseToTray(m_pCheckBoxCloseToTray->isChecked());
|
||||
appConfig().setInvertConnection(m_pInvertConnection->isChecked());
|
||||
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
void SettingsDialog::reject() {
|
||||
// restore original system scope value on reject.
|
||||
if (appConfig().isActiveScopeSystem() != m_wasOriginallySystemScope) {
|
||||
appConfig().setLoadFromSystemScope(m_wasOriginallySystemScope);
|
||||
}
|
||||
|
||||
QDialog::reject();
|
||||
}
|
||||
|
||||
void SettingsDialog::loadFromConfig() {
|
||||
|
||||
m_pLineEditScreenName->setText(appConfig().screenName());
|
||||
m_pSpinBoxPort->setValue(appConfig().port());
|
||||
m_pLineEditInterface->setText(appConfig().networkInterface());
|
||||
m_pComboLogLevel->setCurrentIndex(appConfig().logLevel());
|
||||
m_pCheckBoxLogToFile->setChecked(appConfig().logToFile());
|
||||
m_pLineEditLogFilename->setText(appConfig().logFilename());
|
||||
m_pCheckBoxAutoHide->setChecked(appConfig().autoHide());
|
||||
m_pCheckBoxPreventSleep->setChecked(appConfig().preventSleep());
|
||||
m_pLineEditCertificatePath->setText(appConfig().tlsCertPath());
|
||||
m_pCheckBoxEnableCrypto->setChecked(m_appConfig.tlsEnabled());
|
||||
m_pCheckBoxLanguageSync->setChecked(m_appConfig.languageSync());
|
||||
m_pCheckBoxScrollDirection->setChecked(m_appConfig.invertScrollDirection());
|
||||
m_pCheckBoxServiceEnabled->setChecked(m_appConfig.enableService());
|
||||
m_pCheckBoxCloseToTray->setChecked(m_appConfig.closeToTray());
|
||||
|
||||
if (m_appConfig.isActiveScopeSystem()) {
|
||||
m_pRadioSystemScope->setChecked(true);
|
||||
} else {
|
||||
m_pRadioUserScope->setChecked(true);
|
||||
}
|
||||
|
||||
m_pInvertConnection->setChecked(m_appConfig.invertConnection());
|
||||
m_pInvertConnection->setEnabled(
|
||||
m_license.productEdition() == Edition::kBusiness);
|
||||
|
||||
updateTlsControls();
|
||||
}
|
||||
|
||||
void SettingsDialog::updateTlsControls() {
|
||||
if (QFile(appConfig().tlsCertPath()).exists()) {
|
||||
updateKeyLengthOnFile(appConfig().tlsCertPath());
|
||||
} else {
|
||||
const auto keyLengthText = QString::number(appConfig().tlsKeyLength());
|
||||
m_pComboBoxKeyLength->setCurrentIndex(
|
||||
m_pComboBoxKeyLength->findText(keyLengthText));
|
||||
}
|
||||
|
||||
m_pCheckBoxEnableCrypto->setChecked(m_appConfig.tlsEnabled());
|
||||
|
||||
updateTlsControlsEnabled();
|
||||
}
|
||||
|
||||
void SettingsDialog::updateTlsControlsEnabled() {
|
||||
bool writable = appConfig().isActiveScopeWritable();
|
||||
auto clientMode = appConfig().clientGroupChecked();
|
||||
auto tlsAvailable = m_tlsUtility.isAvailableAndEnabled();
|
||||
auto tlsChecked = m_pCheckBoxEnableCrypto->isChecked();
|
||||
auto enabled = writable && !clientMode && tlsAvailable && tlsChecked;
|
||||
|
||||
qDebug(
|
||||
"tls enabled=%d, writable=%d, client=%d, available=%d, checked=%d",
|
||||
enabled, writable, clientMode, tlsAvailable, tlsChecked);
|
||||
|
||||
m_pLabelKeyLength->setEnabled(enabled);
|
||||
m_pComboBoxKeyLength->setEnabled(enabled);
|
||||
m_pLabelCertificate->setEnabled(enabled);
|
||||
m_pLineEditCertificatePath->setEnabled(enabled);
|
||||
m_pPushButtonBrowseCert->setEnabled(enabled);
|
||||
m_pPushButtonRegenCert->setEnabled(enabled);
|
||||
}
|
||||
|
||||
bool SettingsDialog::isClientMode() const {
|
||||
return m_pMainWindow->coreMode() == MainWindow::CoreMode::Client;
|
||||
}
|
||||
//
|
||||
// Auto-connect slots
|
||||
//
|
||||
|
||||
void SettingsDialog::on_m_pCheckBoxLogToFile_stateChanged(int i) {
|
||||
bool checked = i == 2;
|
||||
|
|
@ -206,9 +103,9 @@ void SettingsDialog::on_m_pCheckBoxEnableCrypto_clicked(bool) {
|
|||
|
||||
void SettingsDialog::on_m_pRadioSystemScope_toggled(bool checked) {
|
||||
// We only need to test the System scoped Radio as they are connected
|
||||
appConfig().setLoadFromSystemScope(checked);
|
||||
m_appConfig.setLoadFromSystemScope(checked);
|
||||
loadFromConfig();
|
||||
updateControlsEnabled();
|
||||
updateControls();
|
||||
}
|
||||
|
||||
void SettingsDialog::on_m_pPushButtonBrowseCert_clicked() {
|
||||
|
|
@ -233,18 +130,6 @@ void SettingsDialog::on_m_pComboBoxKeyLength_currentIndexChanged(int index) {
|
|||
updateTlsRegenerateButton();
|
||||
}
|
||||
|
||||
void SettingsDialog::updateTlsRegenerateButton() {
|
||||
const auto keyLength = m_pComboBoxKeyLength->currentText().toInt();
|
||||
auto keyChanged = appConfig().tlsKeyLength() != keyLength;
|
||||
auto pathChanged =
|
||||
appConfig().tlsCertPath() != m_pLineEditCertificatePath->text();
|
||||
// NOR the above bools, if any have changed regen should be disabled as it
|
||||
// will be done on save
|
||||
auto nor = !(keyChanged || pathChanged);
|
||||
m_pPushButtonRegenCert->setEnabled(
|
||||
nor && m_pCheckBoxEnableCrypto->isChecked());
|
||||
}
|
||||
|
||||
void SettingsDialog::on_m_pPushButtonRegenCert_clicked() {
|
||||
if (m_tlsUtility.generateCertificate()) {
|
||||
QMessageBox::information(
|
||||
|
|
@ -253,6 +138,134 @@ void SettingsDialog::on_m_pPushButtonRegenCert_clicked() {
|
|||
}
|
||||
}
|
||||
|
||||
void SettingsDialog::on_m_pCheckBoxServiceEnabled_toggled(bool) {
|
||||
updateControls();
|
||||
}
|
||||
|
||||
//
|
||||
// End of auto-connect slots
|
||||
//
|
||||
|
||||
void SettingsDialog::accept() {
|
||||
if (!m_pLineEditScreenName->hasAcceptableInput()) {
|
||||
QMessageBox::warning(
|
||||
this, tr("Invalid screen name"), m_pScreenNameError->message());
|
||||
return;
|
||||
}
|
||||
|
||||
m_appConfig.setLoadFromSystemScope(m_pRadioSystemScope->isChecked());
|
||||
m_appConfig.setScreenName(m_pLineEditScreenName->text());
|
||||
m_appConfig.setPort(m_pSpinBoxPort->value());
|
||||
m_appConfig.setNetworkInterface(m_pLineEditInterface->text());
|
||||
m_appConfig.setLogLevel(m_pComboLogLevel->currentIndex());
|
||||
m_appConfig.setLogToFile(m_pCheckBoxLogToFile->isChecked());
|
||||
m_appConfig.setLogFilename(m_pLineEditLogFilename->text());
|
||||
m_appConfig.setElevateMode(
|
||||
static_cast<ElevateMode>(m_pComboElevate->currentIndex()));
|
||||
m_appConfig.setAutoHide(m_pCheckBoxAutoHide->isChecked());
|
||||
m_appConfig.setPreventSleep(m_pCheckBoxPreventSleep->isChecked());
|
||||
m_appConfig.setTlsCertPath(m_pLineEditCertificatePath->text());
|
||||
m_appConfig.setTlsKeyLength(m_pComboBoxKeyLength->currentText().toInt());
|
||||
m_appConfig.setTlsEnabled(m_pCheckBoxEnableCrypto->isChecked());
|
||||
m_appConfig.setLanguageSync(m_pCheckBoxLanguageSync->isChecked());
|
||||
m_appConfig.setInvertScrollDirection(m_pCheckBoxScrollDirection->isChecked());
|
||||
m_appConfig.setEnableService(m_pCheckBoxServiceEnabled->isChecked());
|
||||
m_appConfig.setCloseToTray(m_pCheckBoxCloseToTray->isChecked());
|
||||
m_appConfig.setInvertConnection(m_pInvertConnection->isChecked());
|
||||
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
void SettingsDialog::reject() {
|
||||
// restore original system scope value on reject.
|
||||
if (m_appConfig.isActiveScopeSystem() != m_wasOriginallySystemScope) {
|
||||
m_appConfig.setLoadFromSystemScope(m_wasOriginallySystemScope);
|
||||
}
|
||||
|
||||
QDialog::reject();
|
||||
}
|
||||
|
||||
void SettingsDialog::loadFromConfig() {
|
||||
|
||||
m_pLineEditScreenName->setText(m_appConfig.screenName());
|
||||
m_pSpinBoxPort->setValue(m_appConfig.port());
|
||||
m_pLineEditInterface->setText(m_appConfig.networkInterface());
|
||||
m_pComboLogLevel->setCurrentIndex(m_appConfig.logLevel());
|
||||
m_pCheckBoxLogToFile->setChecked(m_appConfig.logToFile());
|
||||
m_pLineEditLogFilename->setText(m_appConfig.logFilename());
|
||||
m_pCheckBoxAutoHide->setChecked(m_appConfig.autoHide());
|
||||
m_pCheckBoxPreventSleep->setChecked(m_appConfig.preventSleep());
|
||||
m_pLineEditCertificatePath->setText(m_appConfig.tlsCertPath());
|
||||
m_pCheckBoxEnableCrypto->setChecked(m_appConfig.tlsEnabled());
|
||||
m_pCheckBoxLanguageSync->setChecked(m_appConfig.languageSync());
|
||||
m_pCheckBoxScrollDirection->setChecked(m_appConfig.invertScrollDirection());
|
||||
m_pCheckBoxServiceEnabled->setChecked(m_appConfig.enableService());
|
||||
m_pCheckBoxCloseToTray->setChecked(m_appConfig.closeToTray());
|
||||
m_pComboElevate->setCurrentIndex(static_cast<int>(m_appConfig.elevateMode()));
|
||||
|
||||
if (m_appConfig.isActiveScopeSystem()) {
|
||||
m_pRadioSystemScope->setChecked(true);
|
||||
} else {
|
||||
m_pRadioUserScope->setChecked(true);
|
||||
}
|
||||
|
||||
m_pInvertConnection->setChecked(m_appConfig.invertConnection());
|
||||
m_pInvertConnection->setEnabled(
|
||||
m_license.productEdition() == Edition::kBusiness);
|
||||
|
||||
updateTlsControls();
|
||||
}
|
||||
|
||||
void SettingsDialog::updateTlsControls() {
|
||||
if (QFile(m_appConfig.tlsCertPath()).exists()) {
|
||||
updateKeyLengthOnFile(m_appConfig.tlsCertPath());
|
||||
} else {
|
||||
const auto keyLengthText = QString::number(m_appConfig.tlsKeyLength());
|
||||
m_pComboBoxKeyLength->setCurrentIndex(
|
||||
m_pComboBoxKeyLength->findText(keyLengthText));
|
||||
}
|
||||
|
||||
m_pCheckBoxEnableCrypto->setChecked(m_appConfig.tlsEnabled());
|
||||
|
||||
updateTlsControlsEnabled();
|
||||
}
|
||||
|
||||
void SettingsDialog::updateTlsControlsEnabled() {
|
||||
const auto writable = m_appConfig.isActiveScopeWritable();
|
||||
const auto clientMode = m_appConfig.clientGroupChecked();
|
||||
const auto tlsAvailable = m_tlsUtility.isAvailableAndEnabled();
|
||||
const auto tlsChecked = m_pCheckBoxEnableCrypto->isChecked();
|
||||
|
||||
auto enabled = writable && !clientMode && tlsAvailable && tlsChecked;
|
||||
|
||||
qDebug(
|
||||
"tls enabled=%d, writable=%d, client=%d, available=%d, checked=%d",
|
||||
enabled, writable, clientMode, tlsAvailable, tlsChecked);
|
||||
|
||||
m_pLabelKeyLength->setEnabled(enabled);
|
||||
m_pComboBoxKeyLength->setEnabled(enabled);
|
||||
m_pLabelCertificate->setEnabled(enabled);
|
||||
m_pLineEditCertificatePath->setEnabled(enabled);
|
||||
m_pPushButtonBrowseCert->setEnabled(enabled);
|
||||
m_pPushButtonRegenCert->setEnabled(enabled);
|
||||
}
|
||||
|
||||
bool SettingsDialog::isClientMode() const {
|
||||
return m_coreProcess.mode() == MainWindow::CoreMode::Client;
|
||||
}
|
||||
|
||||
void SettingsDialog::updateTlsRegenerateButton() {
|
||||
const auto writable = m_appConfig.isActiveScopeWritable();
|
||||
const auto keyLength = m_pComboBoxKeyLength->currentText().toInt();
|
||||
const auto path = m_pLineEditCertificatePath->text();
|
||||
const auto keyChanged = m_appConfig.tlsKeyLength() != keyLength;
|
||||
const auto pathChanged = m_appConfig.tlsCertPath() != path;
|
||||
const auto tlsEnabled = m_pCheckBoxEnableCrypto->isChecked();
|
||||
|
||||
m_pPushButtonRegenCert->setEnabled(
|
||||
writable && tlsEnabled && (keyChanged || pathChanged));
|
||||
}
|
||||
|
||||
void SettingsDialog::updateKeyLengthOnFile(const QString &path) {
|
||||
TlsCertificate ssl;
|
||||
if (!QFile(path).exists()) {
|
||||
|
|
@ -262,52 +275,48 @@ void SettingsDialog::updateKeyLengthOnFile(const QString &path) {
|
|||
auto length = ssl.getCertKeyLength(path);
|
||||
auto index = m_pComboBoxKeyLength->findText(QString::number(length));
|
||||
m_pComboBoxKeyLength->setCurrentIndex(index);
|
||||
appConfig().setTlsKeyLength(length);
|
||||
m_appConfig.setTlsKeyLength(length);
|
||||
}
|
||||
|
||||
void SettingsDialog::updateControlsEnabled() {
|
||||
bool writable = appConfig().isActiveScopeWritable();
|
||||
void SettingsDialog::updateControls() {
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
const auto serviceAvailable = true;
|
||||
#else
|
||||
// service not supported on unix yet, so always disable.
|
||||
const auto serviceAvailable = false;
|
||||
m_pGroupService->setTitle("Service (Windows only)");
|
||||
#endif
|
||||
|
||||
const bool writable = m_appConfig.isActiveScopeWritable();
|
||||
const bool serviceChecked = m_pCheckBoxServiceEnabled->isChecked();
|
||||
const bool logToFile = m_pCheckBoxLogToFile->isChecked();
|
||||
|
||||
m_pLineEditScreenName->setEnabled(writable);
|
||||
m_pSpinBoxPort->setEnabled(writable);
|
||||
m_pLineEditInterface->setEnabled(writable);
|
||||
m_pComboLogLevel->setEnabled(writable);
|
||||
m_pCheckBoxLogToFile->setEnabled(writable);
|
||||
m_pComboElevate->setEnabled(writable);
|
||||
m_pCheckBoxAutoHide->setEnabled(writable);
|
||||
m_pCheckBoxPreventSleep->setEnabled(writable);
|
||||
m_pLineEditCertificatePath->setEnabled(writable);
|
||||
m_pComboBoxKeyLength->setEnabled(writable);
|
||||
m_pPushButtonBrowseCert->setEnabled(writable);
|
||||
m_pCheckBoxEnableCrypto->setEnabled(writable);
|
||||
m_pCheckBoxServiceEnabled->setEnabled(writable);
|
||||
m_pCheckBoxCloseToTray->setEnabled(writable);
|
||||
|
||||
m_pCheckBoxServiceEnabled->setEnabled(writable && serviceAvailable);
|
||||
m_pLabelElevate->setEnabled(writable && serviceChecked && serviceAvailable);
|
||||
m_pComboElevate->setEnabled(writable && serviceChecked && serviceAvailable);
|
||||
|
||||
m_pCheckBoxLanguageSync->setEnabled(writable && isClientMode());
|
||||
m_pCheckBoxScrollDirection->setEnabled(writable && isClientMode());
|
||||
|
||||
#if !defined(Q_OS_WIN)
|
||||
m_pCheckBoxServiceEnabled->setEnabled(false);
|
||||
#endif
|
||||
|
||||
m_pLabelLogPath->setEnabled(writable && m_pCheckBoxLogToFile->isChecked());
|
||||
m_pLineEditLogFilename->setEnabled(
|
||||
writable && m_pCheckBoxLogToFile->isChecked());
|
||||
m_pButtonBrowseLog->setEnabled(writable && m_pCheckBoxLogToFile->isChecked());
|
||||
m_pLabelLogPath->setEnabled(writable && logToFile);
|
||||
m_pLineEditLogFilename->setEnabled(writable && logToFile);
|
||||
m_pButtonBrowseLog->setEnabled(writable && logToFile);
|
||||
|
||||
updateTlsControlsEnabled();
|
||||
|
||||
if (writable) {
|
||||
updateTlsRegenerateButton();
|
||||
}
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
m_pComboElevate->setCurrentIndex(static_cast<int>(appConfig().elevateMode()));
|
||||
#else
|
||||
// elevate checkbox is only usable on ms windows.
|
||||
m_pLabelElevate->setEnabled(false);
|
||||
m_pComboElevate->setEnabled(false);
|
||||
#endif
|
||||
|
||||
updateTlsControls();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,9 @@
|
|||
|
||||
#include "ui_SettingsDialogBase.h"
|
||||
|
||||
#include "gui/config/AppConfig.h"
|
||||
#include "gui/config/IServerConfig.h"
|
||||
#include "gui/core/CoreProcess.h"
|
||||
#include "gui/core/CoreTool.h"
|
||||
#include "gui/tls/TlsUtility.h"
|
||||
#include "license/License.h"
|
||||
|
|
@ -28,15 +31,19 @@
|
|||
#include <QDialog>
|
||||
|
||||
class MainWindow;
|
||||
class AppConfig;
|
||||
|
||||
class SettingsDialog : public QDialog, public Ui::SettingsDialogBase {
|
||||
using IServerConfig = synergy::gui::IServerConfig;
|
||||
using CoreProcess = synergy::gui::CoreProcess;
|
||||
using License = synergy::license::License;
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SettingsDialog(
|
||||
QWidget *parent, AppConfig &config,
|
||||
const synergy::license::License &license);
|
||||
MainWindow *parent, AppConfig &appConfig,
|
||||
const IServerConfig &serverConfig, const License &license,
|
||||
const CoreProcess &coreProcess);
|
||||
static QString browseForSynergyc(
|
||||
QWidget *parent, const QString &programDir,
|
||||
const QString &coreClientName);
|
||||
|
|
@ -44,10 +51,19 @@ public:
|
|||
QWidget *parent, const QString &programDir,
|
||||
const QString &coreServerName);
|
||||
|
||||
protected:
|
||||
private slots:
|
||||
void on_m_pCheckBoxEnableCrypto_clicked(bool checked);
|
||||
void on_m_pCheckBoxLogToFile_stateChanged(int);
|
||||
void on_m_pButtonBrowseLog_clicked();
|
||||
void on_m_pRadioSystemScope_toggled(bool checked);
|
||||
void on_m_pPushButtonBrowseCert_clicked();
|
||||
void on_m_pComboBoxKeyLength_currentIndexChanged(int index);
|
||||
void on_m_pPushButtonRegenCert_clicked();
|
||||
void on_m_pCheckBoxServiceEnabled_toggled(bool checked);
|
||||
|
||||
private:
|
||||
void accept() override;
|
||||
void reject() override;
|
||||
AppConfig &appConfig() { return m_appConfig; }
|
||||
|
||||
/// @brief Load all settings.
|
||||
void loadFromConfig();
|
||||
|
|
@ -59,31 +75,23 @@ protected:
|
|||
void updateKeyLengthOnFile(const QString &path);
|
||||
|
||||
/// @brief Enables controls when they should be.
|
||||
void updateControlsEnabled();
|
||||
void updateControls();
|
||||
|
||||
bool isClientMode() const;
|
||||
void updateTlsControls();
|
||||
void updateTlsControlsEnabled();
|
||||
|
||||
private:
|
||||
MainWindow *m_pMainWindow;
|
||||
AppConfig &m_appConfig;
|
||||
[[no_unique_address]] CoreTool m_coreTool;
|
||||
const synergy::license::License &m_license;
|
||||
synergy::gui::TlsUtility m_tlsUtility;
|
||||
validators::ValidationError *m_pScreenNameError;
|
||||
|
||||
/// @brief Stores settings scope at start of settings dialog
|
||||
/// This is neccessary to restore state if user changes
|
||||
/// This is necessary to restore state if user changes
|
||||
/// the scope and doesn't save changes
|
||||
bool m_wasOriginallySystemScope = false;
|
||||
|
||||
private slots:
|
||||
void on_m_pCheckBoxEnableCrypto_clicked(bool checked);
|
||||
void on_m_pCheckBoxLogToFile_stateChanged(int);
|
||||
void on_m_pButtonBrowseLog_clicked();
|
||||
void on_m_pRadioSystemScope_toggled(bool checked);
|
||||
void on_m_pPushButtonBrowseCert_clicked();
|
||||
void on_m_pComboBoxKeyLength_currentIndexChanged(int index);
|
||||
void on_m_pPushButtonRegenCert_clicked();
|
||||
AppConfig &m_appConfig;
|
||||
const IServerConfig &m_serverConfig;
|
||||
const License &m_license;
|
||||
const CoreProcess &m_coreProcess;
|
||||
synergy::gui::TlsUtility m_tlsUtility;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScreenDuplicationsValidator.h"
|
||||
|
||||
namespace validators {
|
||||
|
|
|
|||
|
|
@ -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,11 +14,12 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef SCREENDUPLICATIONSVALIDATOR_H
|
||||
#define SCREENDUPLICATIONSVALIDATOR_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "IStringValidator.h"
|
||||
#include "ScreenList.h"
|
||||
|
||||
#include "gui/config/ScreenList.h"
|
||||
|
||||
namespace validators {
|
||||
|
||||
|
|
@ -35,5 +35,3 @@ public:
|
|||
};
|
||||
|
||||
} // namespace validators
|
||||
|
||||
#endif // SCREENDUPLICATIONSVALIDATOR_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
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "LineEditValidator.h"
|
||||
#include "ScreenList.h"
|
||||
#include "gui/config/ScreenList.h"
|
||||
#include "validators/ValidationError.h"
|
||||
|
||||
namespace validators {
|
||||
|
|
|
|||
|
|
@ -520,7 +520,7 @@ bool AppConfig::useInternalConfig() const { return m_UseInternalConfig; }
|
|||
|
||||
bool AppConfig::clientGroupChecked() const { return m_ClientGroupChecked; }
|
||||
|
||||
QString AppConfig::serverHostname() const { return m_ServerHostname; }
|
||||
const QString &AppConfig::serverHostname() const { return m_ServerHostname; }
|
||||
|
||||
void AppConfig::setActivationHasRun(bool value) { m_ActivationHasRun = value; }
|
||||
|
||||
|
|
|
|||
|
|
@ -136,10 +136,9 @@ public:
|
|||
*/
|
||||
void commit();
|
||||
|
||||
/**
|
||||
* Getters
|
||||
*/
|
||||
|
||||
//
|
||||
// Getters (overrides)
|
||||
//
|
||||
ProcessMode processMode() const override;
|
||||
ElevateMode elevateMode() const override;
|
||||
bool tlsEnabled() const override;
|
||||
|
|
@ -161,6 +160,12 @@ public:
|
|||
bool useExternalConfig() const override;
|
||||
const QString &configFile() const override;
|
||||
const QString &networkInterface() const override;
|
||||
const QString &serverHostname() const override;
|
||||
|
||||
//
|
||||
// Getters (new methods)
|
||||
//
|
||||
|
||||
bool isActiveScopeWritable() const;
|
||||
bool isActiveScopeSystem() const;
|
||||
int logLevel() const;
|
||||
|
|
@ -172,7 +177,6 @@ public:
|
|||
bool serverGroupChecked() const;
|
||||
bool useInternalConfig() const;
|
||||
bool clientGroupChecked() const;
|
||||
QString serverHostname() const;
|
||||
QString lastVersion() const;
|
||||
bool enableService() const;
|
||||
bool closeToTray() const;
|
||||
|
|
@ -182,9 +186,9 @@ public:
|
|||
bool showDevThanks() const;
|
||||
bool showCloseReminder() const;
|
||||
|
||||
/**
|
||||
* Setters
|
||||
*/
|
||||
//
|
||||
// Setters
|
||||
//
|
||||
|
||||
void setActivationHasRun(bool value);
|
||||
void setScreenName(const QString &s);
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@ const auto kUnixSystemConfigPath = "/usr/local/etc/symless/";
|
|||
|
||||
namespace synergy::gui {
|
||||
|
||||
using namespace proxy;
|
||||
|
||||
QString getSystemSettingPath() {
|
||||
const QString settingFilename(kSystemConfigFilename);
|
||||
#if defined(Q_OS_WIN)
|
||||
|
|
@ -92,6 +94,7 @@ ConfigScopes::ConfigScopes() {
|
|||
// if we set the scope specifically then we also have to set the application
|
||||
// name and the organisation name which breaks backwards compatibility.
|
||||
m_pUserSettings = std::make_unique<QSettings>();
|
||||
m_userSettingsProxy.set(*m_pUserSettings);
|
||||
|
||||
qDebug() << "user settings path:" << m_pUserSettings->fileName();
|
||||
|
||||
|
|
@ -104,6 +107,7 @@ ConfigScopes::ConfigScopes() {
|
|||
m_pSystemSettings = std::make_unique<QSettings>(
|
||||
QSettings::Format::IniFormat, QSettings::Scope::SystemScope, orgName,
|
||||
appName);
|
||||
m_systemSettingsProxy.set(*m_pSystemSettings);
|
||||
|
||||
qDebug() << "system settings path:" << m_pSystemSettings->fileName();
|
||||
|
||||
|
|
@ -124,7 +128,7 @@ void ConfigScopes::save() {
|
|||
}
|
||||
|
||||
bool ConfigScopes::isActiveScopeWritable() const {
|
||||
return activeSettings()->isWritable();
|
||||
return activeSettings().isWritable();
|
||||
}
|
||||
|
||||
void ConfigScopes::setActiveScope(ConfigScopes::Scope scope) {
|
||||
|
|
@ -140,15 +144,23 @@ bool ConfigScopes::scopeContains(const QString &name, Scope scope) const {
|
|||
case Scope::System:
|
||||
return m_pSystemSettings->contains(name);
|
||||
default:
|
||||
return activeSettings()->contains(name);
|
||||
return activeSettings().contains(name);
|
||||
}
|
||||
}
|
||||
|
||||
QSettings *ConfigScopes::activeSettings() const {
|
||||
QSettingsProxy &ConfigScopes::activeSettings() {
|
||||
if (m_currentScope == Scope::User) {
|
||||
return m_pUserSettings.get();
|
||||
return m_userSettingsProxy;
|
||||
} else {
|
||||
return m_pSystemSettings.get();
|
||||
return m_systemSettingsProxy;
|
||||
}
|
||||
}
|
||||
|
||||
const QSettingsProxy &ConfigScopes::activeSettings() const {
|
||||
if (m_currentScope == Scope::User) {
|
||||
return m_userSettingsProxy;
|
||||
} else {
|
||||
return m_systemSettingsProxy;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -160,7 +172,7 @@ QVariant ConfigScopes::getFromScope(
|
|||
case Scope::System:
|
||||
return m_pSystemSettings->value(name, defaultValue);
|
||||
default:
|
||||
return activeSettings()->value(name, defaultValue);
|
||||
return activeSettings().value(name, defaultValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -174,7 +186,7 @@ void ConfigScopes::setInScope(
|
|||
m_pSystemSettings->setValue(name, value);
|
||||
break;
|
||||
default:
|
||||
activeSettings()->setValue(name, value);
|
||||
activeSettings().setValue(name, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@ namespace synergy::gui {
|
|||
|
||||
/// @brief Encapsulates Qt config for both user and global scopes.
|
||||
class ConfigScopes : public QObject, public IConfigScopes {
|
||||
using QSettingsProxy = synergy::gui::proxy::QSettingsProxy;
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
|
@ -47,7 +49,8 @@ public:
|
|||
Scope scope = Scope::Current) const override;
|
||||
void setActiveScope(Scope scope = Scope::User) override;
|
||||
Scope activeScope() const override;
|
||||
QSettings *activeSettings() const override;
|
||||
QSettingsProxy &activeSettings() override;
|
||||
const QSettingsProxy &activeSettings() const override;
|
||||
|
||||
signals:
|
||||
void ready();
|
||||
|
|
@ -57,6 +60,8 @@ private:
|
|||
Scope m_currentScope = Scope::User;
|
||||
std::unique_ptr<QSettings> m_pUserSettings;
|
||||
std::unique_ptr<QSettings> m_pSystemSettings;
|
||||
QSettingsProxy m_userSettingsProxy;
|
||||
QSettingsProxy m_systemSettingsProxy;
|
||||
};
|
||||
|
||||
} // namespace synergy::gui
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ public:
|
|||
virtual bool useExternalConfig() const = 0;
|
||||
virtual const QString &configFile() const = 0;
|
||||
virtual const QString &networkInterface() const = 0;
|
||||
virtual const QString &serverHostname() const = 0;
|
||||
};
|
||||
|
||||
} // namespace synergy::gui
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "gui/proxy/QSettingsProxy.h"
|
||||
|
||||
#include <QSettings>
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
|
|
@ -24,6 +26,8 @@
|
|||
namespace synergy::gui {
|
||||
|
||||
class IConfigScopes {
|
||||
using QSettingsProxy = synergy::gui::proxy::QSettingsProxy;
|
||||
|
||||
public:
|
||||
enum class Scope { Current, System, User };
|
||||
|
||||
|
|
@ -32,7 +36,8 @@ public:
|
|||
virtual Scope activeScope() const = 0;
|
||||
virtual void setActiveScope(Scope scope = Scope::User) = 0;
|
||||
virtual bool isActiveScopeWritable() const = 0;
|
||||
virtual QSettings *activeSettings() const = 0;
|
||||
virtual QSettingsProxy &activeSettings() = 0;
|
||||
virtual const QSettingsProxy &activeSettings() const = 0;
|
||||
|
||||
/**
|
||||
* @brief Signals to listeners that the settings that they should read.
|
||||
|
|
@ -40,7 +45,7 @@ public:
|
|||
virtual void signalReady() = 0;
|
||||
|
||||
/**
|
||||
* @brief Signalls to listeners to save and calls `sync` on underlying Qt
|
||||
* @brief Signals to listeners to save and calls `sync` on underlying Qt
|
||||
* config.
|
||||
*
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@
|
|||
#include <QFile>
|
||||
#include <QString>
|
||||
|
||||
#include "ScreenList.h"
|
||||
|
||||
namespace synergy::gui {
|
||||
|
||||
class IServerConfig {
|
||||
|
|
@ -30,6 +32,7 @@ public:
|
|||
virtual bool save(const QString &fileName) const = 0;
|
||||
virtual void save(QFile &file) const = 0;
|
||||
virtual bool enableDragAndDrop() const = 0;
|
||||
virtual const ScreenList &screens() const = 0;
|
||||
};
|
||||
|
||||
} // namespace synergy::gui
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -17,19 +17,19 @@
|
|||
*/
|
||||
|
||||
#include "Screen.h"
|
||||
#include "config/ScreenConfig.h"
|
||||
|
||||
#include <QtCore>
|
||||
#include <QtGui>
|
||||
|
||||
Screen::Screen()
|
||||
: m_Pixmap(QPixmap(":res/icons/64x64/video-display.png")),
|
||||
m_Swapped(false) {
|
||||
init();
|
||||
}
|
||||
using namespace synergy::gui::proxy;
|
||||
using enum ScreenConfig::Modifier;
|
||||
using enum ScreenConfig::SwitchCorner;
|
||||
using enum ScreenConfig::Fix;
|
||||
|
||||
Screen::Screen(const QString &name)
|
||||
: m_Pixmap(QPixmap(":res/icons/64x64/video-display.png")),
|
||||
m_Swapped(false) {
|
||||
Screen::Screen() { init(); }
|
||||
|
||||
Screen::Screen(const QString &name) {
|
||||
init();
|
||||
setName(name);
|
||||
}
|
||||
|
|
@ -45,17 +45,17 @@ void Screen::init() {
|
|||
// m_Modifiers, m_SwitchCorners and m_Fixes are QLists we use like fixed-size
|
||||
// arrays, thus we need to make sure to fill them with the required number of
|
||||
// elements.
|
||||
for (int i = 0; i < NumModifiers; i++)
|
||||
for (int i = 0; i < static_cast<int>(NumModifiers); i++)
|
||||
modifiers() << i;
|
||||
|
||||
for (int i = 0; i < NumSwitchCorners; i++)
|
||||
for (int i = 0; i < static_cast<int>(NumSwitchCorners); i++)
|
||||
switchCorners() << false;
|
||||
|
||||
for (int i = 0; i < NumFixes; i++)
|
||||
for (int i = 0; i < static_cast<int>(NumFixes); i++)
|
||||
fixes() << false;
|
||||
}
|
||||
|
||||
void Screen::loadSettings(QSettings &settings) {
|
||||
void Screen::loadSettings(QSettingsProxy &settings) {
|
||||
setName(settings.value("name").toString());
|
||||
|
||||
if (name().isEmpty())
|
||||
|
|
@ -66,13 +66,14 @@ void Screen::loadSettings(QSettings &settings) {
|
|||
readSettings(settings, aliases(), "alias", QString(""));
|
||||
readSettings(
|
||||
settings, modifiers(), "modifier", static_cast<int>(DefaultMod),
|
||||
NumModifiers);
|
||||
static_cast<int>(NumModifiers));
|
||||
readSettings(
|
||||
settings, switchCorners(), "switchCorner", false, NumSwitchCorners);
|
||||
readSettings(settings, fixes(), "fix", false, NumFixes);
|
||||
settings, switchCorners(), "switchCorner", 0,
|
||||
static_cast<int>(NumSwitchCorners));
|
||||
readSettings(settings, fixes(), "fix", 0, static_cast<int>(NumFixes));
|
||||
}
|
||||
|
||||
void Screen::saveSettings(QSettings &settings) const {
|
||||
void Screen::saveSettings(QSettingsProxy &settings) const {
|
||||
settings.setValue("name", name());
|
||||
|
||||
if (name().isEmpty())
|
||||
|
|
@ -130,16 +131,3 @@ bool Screen::operator==(const Screen &screen) const {
|
|||
m_Fixes == screen.m_Fixes && m_Swapped == screen.m_Swapped &&
|
||||
m_isServer == screen.m_isServer;
|
||||
}
|
||||
|
||||
QDataStream &operator<<(QDataStream &outStream, const Screen &screen) {
|
||||
return outStream << screen.name() << screen.switchCornerSize()
|
||||
<< screen.aliases() << screen.modifiers()
|
||||
<< screen.switchCorners() << screen.fixes()
|
||||
<< screen.isServer();
|
||||
}
|
||||
|
||||
QDataStream &operator>>(QDataStream &inStream, Screen &screen) {
|
||||
return inStream >> screen.m_Name >> screen.m_SwitchCornerSize >>
|
||||
screen.m_Aliases >> screen.m_Modifiers >> screen.m_SwitchCorners >>
|
||||
screen.m_Fixes >> screen.m_isServer;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -20,6 +20,8 @@
|
|||
|
||||
#include "ScreenConfig.h"
|
||||
|
||||
#include "gui/proxy/QSettingsProxy.h"
|
||||
|
||||
#include <QList>
|
||||
#include <QPixmap>
|
||||
#include <QString>
|
||||
|
|
@ -30,34 +32,49 @@ class QTextStream;
|
|||
class ScreenSettingsDialog;
|
||||
|
||||
class Screen : public ScreenConfig {
|
||||
friend QDataStream &operator<<(QDataStream &outStream, const Screen &screen);
|
||||
friend QDataStream &operator>>(QDataStream &inStream, Screen &screen);
|
||||
using QSettingsProxy = synergy::gui::proxy::QSettingsProxy;
|
||||
|
||||
friend class ScreenSettingsDialog;
|
||||
friend class ScreenSetupModel;
|
||||
friend class ScreenSetupView;
|
||||
|
||||
public:
|
||||
Screen();
|
||||
Screen(const QString &name);
|
||||
friend QDataStream &operator<<(QDataStream &outStream, const Screen &screen) {
|
||||
return outStream << screen.name() << screen.switchCornerSize()
|
||||
<< screen.aliases() << screen.modifiers()
|
||||
<< screen.switchCorners() << screen.fixes()
|
||||
<< screen.isServer();
|
||||
}
|
||||
|
||||
friend QDataStream &operator>>(QDataStream &inStream, Screen &screen) {
|
||||
return inStream >> screen.m_Name >> screen.m_SwitchCornerSize >>
|
||||
screen.m_Aliases >> screen.m_Modifiers >> screen.m_SwitchCorners >>
|
||||
screen.m_Fixes >> screen.m_isServer;
|
||||
}
|
||||
|
||||
public:
|
||||
explicit Screen();
|
||||
explicit Screen(const QString &name);
|
||||
|
||||
const QPixmap &pixmap() const { return m_Pixmap; }
|
||||
const QString &name() const { return m_Name; }
|
||||
const QStringList &aliases() const { return m_Aliases; }
|
||||
|
||||
bool isNull() const { return m_Name.isEmpty(); }
|
||||
int modifier(int m) const {
|
||||
return m_Modifiers[m] == DefaultMod ? m : m_Modifiers[m];
|
||||
return m_Modifiers[m] ==
|
||||
static_cast<int>(ScreenConfig::Modifier::DefaultMod)
|
||||
? m
|
||||
: m_Modifiers[m];
|
||||
}
|
||||
const QList<int> &modifiers() const { return m_Modifiers; }
|
||||
bool switchCorner(int c) const { return m_SwitchCorners[c]; }
|
||||
const QList<bool> &switchCorners() const { return m_SwitchCorners; }
|
||||
int switchCornerSize() const { return m_SwitchCornerSize; }
|
||||
bool fix(Fix f) const { return m_Fixes[f]; }
|
||||
bool fix(Fix f) const { return m_Fixes[static_cast<int>(f)]; }
|
||||
const QList<bool> &fixes() const { return m_Fixes; }
|
||||
|
||||
void loadSettings(QSettings &settings);
|
||||
void saveSettings(QSettings &settings) const;
|
||||
void loadSettings(QSettingsProxy &settings);
|
||||
void saveSettings(QSettingsProxy &settings) const;
|
||||
QTextStream &writeScreensSection(QTextStream &outStream) const;
|
||||
QTextStream &writeAliasesSection(QTextStream &outStream) const;
|
||||
|
||||
|
|
@ -84,18 +101,13 @@ protected:
|
|||
void setSwapped(bool on) { m_Swapped = on; }
|
||||
|
||||
private:
|
||||
QPixmap m_Pixmap;
|
||||
QPixmap m_Pixmap = QPixmap(":res/icons/64x64/video-display.png");
|
||||
QString m_Name;
|
||||
|
||||
QStringList m_Aliases;
|
||||
QList<int> m_Modifiers;
|
||||
QList<bool> m_SwitchCorners;
|
||||
int m_SwitchCornerSize;
|
||||
QList<bool> m_Fixes;
|
||||
|
||||
bool m_Swapped;
|
||||
bool m_Swapped = false;
|
||||
bool m_isServer = false;
|
||||
};
|
||||
|
||||
QDataStream &operator<<(QDataStream &outStream, const Screen &screen);
|
||||
QDataStream &operator>>(QDataStream &inStream, Screen &screen);
|
||||
|
|
@ -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
|
||||
|
|
@ -18,14 +18,17 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <QSettings>
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
|
||||
#include "gui/proxy/QSettingsProxy.h"
|
||||
|
||||
/// @brief Screen configuration base class
|
||||
class ScreenConfig {
|
||||
using QSettingsProxy = synergy::gui::proxy::QSettingsProxy;
|
||||
|
||||
public:
|
||||
enum Modifier {
|
||||
enum class Modifier {
|
||||
DefaultMod = -1,
|
||||
Shift,
|
||||
Ctrl,
|
||||
|
|
@ -35,29 +38,28 @@ public:
|
|||
None,
|
||||
NumModifiers
|
||||
};
|
||||
enum SwitchCorner {
|
||||
enum class SwitchCorner {
|
||||
TopLeft,
|
||||
TopRight,
|
||||
BottomLeft,
|
||||
BottomRight,
|
||||
NumSwitchCorners
|
||||
};
|
||||
enum Fix { CapsLock, NumLock, ScrollLock, XTest, NumFixes };
|
||||
enum class Fix { CapsLock, NumLock, ScrollLock, XTest, NumFixes };
|
||||
|
||||
protected:
|
||||
explicit ScreenConfig() = default;
|
||||
~ScreenConfig() = default;
|
||||
|
||||
protected:
|
||||
template <typename T1, typename T2>
|
||||
void readSettings(
|
||||
QSettings &settings, T1 &array, const QString &arrayName,
|
||||
const T2 &deflt) {
|
||||
QSettingsProxy &settings, T1 &array, const QString &arrayName,
|
||||
const T2 &defaultValue) {
|
||||
int entries = settings.beginReadArray(arrayName + "Array");
|
||||
array.clear();
|
||||
for (int i = 0; i < entries; i++) {
|
||||
settings.setArrayIndex(i);
|
||||
QVariant v = settings.value(arrayName, deflt);
|
||||
QVariant v = settings.value(arrayName, defaultValue);
|
||||
array.append(v.value<T2>());
|
||||
}
|
||||
settings.endArray();
|
||||
|
|
@ -65,13 +67,13 @@ protected:
|
|||
|
||||
template <typename T1, typename T2>
|
||||
void readSettings(
|
||||
QSettings &settings, T1 &array, const QString &arrayName, const T2 &deflt,
|
||||
int entries) {
|
||||
QSettingsProxy &settings, T1 &array, const QString &arrayName,
|
||||
const T2 &defaultValue, int entries) {
|
||||
Q_ASSERT(array.size() >= entries);
|
||||
settings.beginReadArray(arrayName + "Array");
|
||||
for (int i = 0; i < entries; i++) {
|
||||
settings.setArrayIndex(i);
|
||||
QVariant v = settings.value(arrayName, deflt);
|
||||
QVariant v = settings.value(arrayName, defaultValue);
|
||||
array[i] = v.value<T2>();
|
||||
}
|
||||
settings.endArray();
|
||||
|
|
@ -79,7 +81,8 @@ protected:
|
|||
|
||||
template <typename T>
|
||||
void writeSettings(
|
||||
QSettings &settings, const T &array, const QString &arrayName) const {
|
||||
QSettingsProxy &settings, const T &array,
|
||||
const QString &arrayName) const {
|
||||
settings.beginWriteArray(arrayName + "Array");
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
settings.setArrayIndex(i);
|
||||
|
|
@ -90,7 +90,8 @@ ScreenList::ScreenList(int width) : QList<Screen>(), m_width(width) {}
|
|||
|
||||
void ScreenList::addScreenByPriority(const Screen &newScreen) {
|
||||
int serverIndex = getServerIndex(*this);
|
||||
auto indexes = getNeighborsIndexes(serverIndex, m_width, size());
|
||||
auto indexes =
|
||||
getNeighborsIndexes(serverIndex, m_width, static_cast<int>(size()));
|
||||
|
||||
bool isAdded = false;
|
||||
for (const auto &index : indexes) {
|
||||
|
|
@ -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,8 +14,8 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef SCREENLIST_H
|
||||
#define SCREENLIST_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Screen.h"
|
||||
|
||||
|
|
@ -51,5 +50,3 @@ public:
|
|||
*/
|
||||
bool operator==(const ScreenList &sc) const;
|
||||
};
|
||||
|
||||
#endif // SCREENLIST_H
|
||||
|
|
@ -17,71 +17,67 @@
|
|||
|
||||
#include "ClientConnection.h"
|
||||
|
||||
#include "messages.h"
|
||||
|
||||
#include <QHostAddress>
|
||||
#include <QMessageBox>
|
||||
|
||||
namespace synergy::gui {
|
||||
|
||||
ClientConnection::ClientConnection(QWidget &parent, AppConfig &appConfig)
|
||||
: m_parent(parent),
|
||||
m_appConfig(appConfig) {}
|
||||
//
|
||||
// ClientConnection::Deps
|
||||
//
|
||||
|
||||
void ClientConnection::update(const QString &line) {
|
||||
if (m_checkConnection && checkMainWindow()) {
|
||||
if (line.contains("failed to connect to server")) {
|
||||
m_checkConnection = false;
|
||||
if (!line.contains("server refused client with our name") &&
|
||||
!line.contains("Trying next address")) {
|
||||
showMessage(getMessage(line));
|
||||
void ClientConnection::Deps::showError(
|
||||
QWidget *parent, messages::ClientError error,
|
||||
const QString &address) const {
|
||||
messages::showClientConnectError(parent, error, address);
|
||||
}
|
||||
} else if (line.contains("connected to server")) {
|
||||
m_checkConnection = false;
|
||||
|
||||
//
|
||||
// ClientConnection
|
||||
//
|
||||
|
||||
void ClientConnection::handleLogLine(const QString &logLine) {
|
||||
if (!m_showMessage) {
|
||||
qDebug("message already shown, skipping");
|
||||
return;
|
||||
}
|
||||
|
||||
if (logLine.contains("failed to connect to server")) {
|
||||
m_showMessage = false;
|
||||
|
||||
// ignore the message if it's about the server refusing by name as
|
||||
// this will trigger the server to show an 'add client' dialog.
|
||||
if (logLine.contains("server refused client with our name")) {
|
||||
qDebug("ignoring client name refused message");
|
||||
return;
|
||||
}
|
||||
|
||||
showMessage(logLine);
|
||||
} else if (logLine.contains("connected to server")) {
|
||||
m_showMessage = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ClientConnection::checkMainWindow() {
|
||||
bool result = m_parent.isActiveWindow();
|
||||
void ClientConnection::showMessage(const QString &logLine) {
|
||||
using enum messages::ClientError;
|
||||
|
||||
if (m_parent.isMinimized() || m_parent.isHidden()) {
|
||||
m_parent.showNormal();
|
||||
m_parent.activateWindow();
|
||||
result = true;
|
||||
}
|
||||
emit messageShowing();
|
||||
|
||||
return result;
|
||||
}
|
||||
const auto address = m_appConfig.serverHostname();
|
||||
auto message =
|
||||
QString("<p>The connection to server '%1' didn't work.</p>").arg(address);
|
||||
|
||||
QString ClientConnection::getMessage(const QString &line) const {
|
||||
QString message(QObject::tr("Connection failed.\nCheck the IP address on the "
|
||||
"server, your TLS and firewall settings."));
|
||||
|
||||
if (line.contains("server already has a connected client with our name")) {
|
||||
message =
|
||||
QObject::tr("Connection failed.\nYou can’t name 2 computers the same.");
|
||||
if (logLine.contains("server already has a connected client with our name")) {
|
||||
m_deps->showError(m_pParent, AlreadyConnected, address);
|
||||
} else if (QHostAddress a(address); a.isNull()) {
|
||||
qDebug("ip not detected, showing hostname error");
|
||||
m_deps->showError(m_pParent, HostnameError, address);
|
||||
} else {
|
||||
QHostAddress address(m_appConfig.serverHostname());
|
||||
if (address.isNull()) {
|
||||
message =
|
||||
QObject::tr(
|
||||
"We can’t connect to the server \"%1\" try to connect using the "
|
||||
"server IP address and check your firewall settings.")
|
||||
.arg(m_appConfig.serverHostname());
|
||||
qDebug("ip detected, showing generic error");
|
||||
m_deps->showError(m_pParent, GenericError, address);
|
||||
}
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
void ClientConnection::showMessage(const QString &message) const {
|
||||
QMessageBox dialog(&m_parent);
|
||||
dialog.addButton(QObject::tr("Close"), QMessageBox::RejectRole);
|
||||
dialog.setText(message);
|
||||
dialog.exec();
|
||||
}
|
||||
|
||||
void ClientConnection::setCheckConnection(bool checkConnection) {
|
||||
m_checkConnection = checkConnection;
|
||||
}
|
||||
|
||||
} // namespace synergy::gui
|
||||
|
|
|
|||
|
|
@ -17,27 +17,50 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "gui/config/AppConfig.h"
|
||||
#include "gui/config/IAppConfig.h"
|
||||
|
||||
#include "gui/messages.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QWidget>
|
||||
#include <memory>
|
||||
|
||||
class QWidget;
|
||||
|
||||
namespace synergy::gui {
|
||||
|
||||
class ClientConnection {
|
||||
class ClientConnection : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ClientConnection(QWidget &parent, AppConfig &appConfig);
|
||||
void update(const QString &line);
|
||||
void setCheckConnection(bool checkConnection);
|
||||
struct Deps {
|
||||
virtual ~Deps() = default;
|
||||
virtual void showError(
|
||||
QWidget *parent, messages::ClientError error,
|
||||
const QString &address) const;
|
||||
};
|
||||
|
||||
explicit ClientConnection(
|
||||
QWidget *parent, IAppConfig &appConfig,
|
||||
std::shared_ptr<Deps> deps = std::make_shared<Deps>())
|
||||
: m_pParent(parent),
|
||||
m_appConfig(appConfig),
|
||||
m_deps(deps) {}
|
||||
|
||||
void handleLogLine(const QString &line);
|
||||
void setShowMessage() { m_showMessage = true; }
|
||||
|
||||
signals:
|
||||
void messageShowing();
|
||||
|
||||
private:
|
||||
QString getMessage(const QString &line) const;
|
||||
bool checkMainWindow();
|
||||
void showMessage(const QString &message) const;
|
||||
void showMessage(const QString &logLine);
|
||||
|
||||
QWidget &m_parent;
|
||||
AppConfig &m_appConfig;
|
||||
bool m_checkConnection = false;
|
||||
QWidget *m_pParent;
|
||||
IAppConfig &m_appConfig;
|
||||
std::shared_ptr<Deps> m_deps;
|
||||
bool m_showMessage = true;
|
||||
};
|
||||
|
||||
} // namespace synergy::gui
|
||||
|
|
|
|||
|
|
@ -18,42 +18,46 @@
|
|||
#include "ServerConnection.h"
|
||||
|
||||
#include "ServerMessage.h"
|
||||
#include "gui/config/AppConfig.h"
|
||||
#include "messages.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
|
||||
namespace synergy::gui {
|
||||
|
||||
ServerConnection::ServerConnection(
|
||||
QWidget &parent, AppConfig &appConfig, IServerConfig &serverConfig)
|
||||
: m_parent(parent),
|
||||
m_appConfig(appConfig),
|
||||
m_serverConfig(serverConfig) {}
|
||||
//
|
||||
// ServerConnection::Deps
|
||||
//
|
||||
|
||||
void ServerConnection::update(const QString &line) {
|
||||
ServerMessage message(line);
|
||||
messages::NewClientPromptResult ServerConnection::Deps::showNewClientPrompt(
|
||||
QWidget *parent, const QString &clientName) const {
|
||||
return messages::showNewClientPrompt(parent, clientName);
|
||||
}
|
||||
|
||||
//
|
||||
// ServerConnection
|
||||
//
|
||||
|
||||
ServerConnection::ServerConnection(
|
||||
QWidget *parent, IAppConfig &appConfig, IServerConfig &serverConfig,
|
||||
std::shared_ptr<Deps> deps)
|
||||
: m_pParent(parent),
|
||||
m_appConfig(appConfig),
|
||||
m_serverConfig(serverConfig),
|
||||
m_pDeps(deps) {}
|
||||
|
||||
void ServerConnection::handleLogLine(const QString &logLine) {
|
||||
ServerMessage message(logLine);
|
||||
|
||||
if (!m_appConfig.useExternalConfig() && message.isNewClientMessage() &&
|
||||
!m_ignoredClients.contains(message.getClientName())) {
|
||||
addClient(message.getClientName());
|
||||
handleNewClient(message.getClientName());
|
||||
}
|
||||
}
|
||||
|
||||
// TOOD: merge duplicated code between client and server connection
|
||||
bool ServerConnection::checkMainWindow() {
|
||||
bool result = m_parent.isActiveWindow();
|
||||
void ServerConnection::handleNewClient(const QString &clientName) {
|
||||
using enum messages::NewClientPromptResult;
|
||||
|
||||
if (m_parent.isMinimized() || m_parent.isHidden()) {
|
||||
m_parent.showNormal();
|
||||
m_parent.activateWindow();
|
||||
result = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void ServerConnection::addClient(const QString &clientName) {
|
||||
if (m_serverConfig.isFull()) {
|
||||
qDebug(
|
||||
"server config full, skipping add client prompt for: %s",
|
||||
|
|
@ -68,30 +72,17 @@ void ServerConnection::addClient(const QString &clientName) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!checkMainWindow()) {
|
||||
qDebug(
|
||||
"main window not active, skipping add client prompt for: %s",
|
||||
qPrintable(clientName));
|
||||
return;
|
||||
}
|
||||
emit messageShowing();
|
||||
|
||||
QMessageBox message(&m_parent);
|
||||
const QPushButton *ignore =
|
||||
message.addButton("Ignore", QMessageBox::RejectRole);
|
||||
const QPushButton *add =
|
||||
message.addButton("Add client", QMessageBox::AcceptRole);
|
||||
message.setText(
|
||||
QString("A new client called '%1' wants to connect").arg(clientName));
|
||||
message.exec();
|
||||
|
||||
if (message.clickedButton() == add) {
|
||||
const auto result = m_pDeps->showNewClientPrompt(m_pParent, clientName);
|
||||
if (result == Add) {
|
||||
qDebug("accepted dialog, adding client: %s", qPrintable(clientName));
|
||||
emit configureClient(clientName);
|
||||
} else if (message.clickedButton() == ignore) {
|
||||
} else if (result == Ignore) {
|
||||
qDebug("declined dialog, ignoring client: %s", qPrintable(clientName));
|
||||
m_ignoredClients.append(clientName);
|
||||
} else {
|
||||
qFatal("no expected dialog button was clicked");
|
||||
qFatal("unexpected add client result");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,8 +20,9 @@
|
|||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
#include "gui/config/AppConfig.h"
|
||||
#include "gui/config/IAppConfig.h"
|
||||
#include "gui/config/IServerConfig.h"
|
||||
#include "gui/messages.h"
|
||||
|
||||
namespace synergy::gui {
|
||||
|
||||
|
|
@ -30,20 +31,28 @@ class ServerConnection : public QObject {
|
|||
using IServerConfig = synergy::gui::IServerConfig;
|
||||
|
||||
public:
|
||||
struct Deps {
|
||||
virtual ~Deps() = default;
|
||||
virtual messages::NewClientPromptResult
|
||||
showNewClientPrompt(QWidget *parent, const QString &clientName) const;
|
||||
};
|
||||
|
||||
explicit ServerConnection(
|
||||
QWidget &parent, AppConfig &appConfig, IServerConfig &serverConfig);
|
||||
void update(const QString &line);
|
||||
QWidget *parent, IAppConfig &appConfig, IServerConfig &serverConfig,
|
||||
std::shared_ptr<Deps> deps = std::make_shared<Deps>());
|
||||
void handleLogLine(const QString &logLine);
|
||||
|
||||
signals:
|
||||
void messageShowing();
|
||||
void configureClient(const QString &clientName);
|
||||
|
||||
private:
|
||||
void addClient(const QString &clientName);
|
||||
bool checkMainWindow();
|
||||
void handleNewClient(const QString &clientName);
|
||||
|
||||
QWidget &m_parent;
|
||||
AppConfig &m_appConfig;
|
||||
QWidget *m_pParent;
|
||||
IAppConfig &m_appConfig;
|
||||
IServerConfig &m_serverConfig;
|
||||
std::shared_ptr<Deps> m_pDeps;
|
||||
QStringList m_ignoredClients;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ namespace synergy::gui {
|
|||
|
||||
ServerMessage::ServerMessage(const QString &message)
|
||||
: m_message(message),
|
||||
m_clienName(parseClientName(message)) {}
|
||||
m_clientName(parseClientName(message)) {}
|
||||
|
||||
bool ServerMessage::isNewClientMessage() const {
|
||||
return m_message.contains("unrecognised client name");
|
||||
|
|
@ -39,7 +39,7 @@ bool ServerMessage::isDisconnectedMessage() const {
|
|||
return m_message.contains("has disconnected");
|
||||
}
|
||||
|
||||
const QString &ServerMessage::getClientName() const { return m_clienName; }
|
||||
const QString &ServerMessage::getClientName() const { return m_clientName; }
|
||||
|
||||
QString ServerMessage::parseClientName(const QString &line) const {
|
||||
QString clientName("Unknown");
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ namespace synergy::gui {
|
|||
|
||||
class ServerMessage {
|
||||
QString m_message;
|
||||
QString m_clienName;
|
||||
QString m_clientName;
|
||||
|
||||
public:
|
||||
explicit ServerMessage(const QString &message);
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include <QDateTime>
|
||||
#include <QDir>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
#include <QTime>
|
||||
#include <memory>
|
||||
|
||||
|
|
@ -181,4 +182,59 @@ void showDevThanks(QWidget *parent, const QString &productName) {
|
|||
kColorSecondary));
|
||||
}
|
||||
|
||||
void showClientConnectError(
|
||||
QWidget *parent, ClientError error, const QString &address) {
|
||||
using enum ClientError;
|
||||
|
||||
auto message =
|
||||
QString("<p>The connection to server '%1' didn't work.</p>").arg(address);
|
||||
|
||||
if (error == AlreadyConnected) {
|
||||
message += //
|
||||
"<p>Two of your client computers have the same name or there are "
|
||||
"two instances of the client process running.</p>"
|
||||
"<p>Please ensure that you're using a unique name and that only a "
|
||||
"single client process is running.</p>";
|
||||
} else if (error == HostnameError) {
|
||||
message += //
|
||||
"<p>Please try to connect to the server using the server IP address "
|
||||
"instead of the hostname. </p>"
|
||||
"<p>If that doesn't work, please check your TLS and "
|
||||
"firewall settings.</p>";
|
||||
} else if (error == GenericError) {
|
||||
message += //
|
||||
"<p>Please check your TLS and firewall settings.</p>";
|
||||
} else {
|
||||
qFatal("unknown client error");
|
||||
}
|
||||
|
||||
QMessageBox dialog(parent);
|
||||
dialog.addButton(QObject::tr("Close"), QMessageBox::RejectRole);
|
||||
dialog.setText(message);
|
||||
dialog.exec();
|
||||
}
|
||||
|
||||
NewClientPromptResult
|
||||
showNewClientPrompt(QWidget *parent, const QString &clientName) {
|
||||
using enum NewClientPromptResult;
|
||||
|
||||
QMessageBox message(parent);
|
||||
const QPushButton *ignore =
|
||||
message.addButton("Ignore", QMessageBox::RejectRole);
|
||||
const QPushButton *add =
|
||||
message.addButton("Add client", QMessageBox::AcceptRole);
|
||||
message.setText(
|
||||
QString("A new client called '%1' wants to connect").arg(clientName));
|
||||
message.exec();
|
||||
|
||||
if (message.clickedButton() == add) {
|
||||
return Add;
|
||||
} else if (message.clickedButton() == ignore) {
|
||||
return Ignore;
|
||||
} else {
|
||||
qFatal("no expected dialog button was clicked");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace synergy::gui::messages
|
||||
|
|
|
|||
|
|
@ -19,10 +19,15 @@
|
|||
|
||||
#include <QMessageLogContext>
|
||||
#include <QString>
|
||||
#include <QWidget>
|
||||
|
||||
class QWidget;
|
||||
|
||||
namespace synergy::gui::messages {
|
||||
|
||||
enum class ClientError { AlreadyConnected, HostnameError, GenericError };
|
||||
|
||||
enum class NewClientPromptResult { Add, Ignore };
|
||||
|
||||
void messageHandler(
|
||||
QtMsgType type, const QMessageLogContext &context, const QString &msg);
|
||||
|
||||
|
|
@ -33,4 +38,10 @@ void showCloseReminder(QWidget *parent);
|
|||
|
||||
void showDevThanks(QWidget *parent, const QString &productName);
|
||||
|
||||
void showClientConnectError(
|
||||
QWidget *parent, ClientError error, const QString &address);
|
||||
|
||||
NewClientPromptResult
|
||||
showNewClientPrompt(QWidget *parent, const QString &clientName);
|
||||
|
||||
} // namespace synergy::gui::messages
|
||||
|
|
|
|||
61
src/lib/gui/proxy/QSettingsProxy.cpp
Normal file
61
src/lib/gui/proxy/QSettingsProxy.cpp
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "QSettingsProxy.h"
|
||||
|
||||
namespace synergy::gui::proxy {
|
||||
|
||||
int QSettingsProxy::beginReadArray(const QString &prefix) {
|
||||
return m_pSettings->beginReadArray(prefix);
|
||||
}
|
||||
|
||||
void QSettingsProxy::setArrayIndex(int i) { m_pSettings->setArrayIndex(i); }
|
||||
|
||||
QVariant QSettingsProxy::value(const QString &key) const {
|
||||
return m_pSettings->value(key);
|
||||
}
|
||||
|
||||
QVariant
|
||||
QSettingsProxy::value(const QString &key, const QVariant &defaultValue) const {
|
||||
return m_pSettings->value(key, defaultValue);
|
||||
}
|
||||
|
||||
void QSettingsProxy::endArray() { m_pSettings->endArray(); }
|
||||
|
||||
void QSettingsProxy::beginWriteArray(const QString &prefix) {
|
||||
m_pSettings->beginWriteArray(prefix);
|
||||
}
|
||||
|
||||
void QSettingsProxy::setValue(const QString &key, const QVariant &value) {
|
||||
m_pSettings->setValue(key, value);
|
||||
}
|
||||
|
||||
void QSettingsProxy::beginGroup(const QString &prefix) {
|
||||
m_pSettings->beginGroup(prefix);
|
||||
}
|
||||
|
||||
void QSettingsProxy::remove(const QString &key) { m_pSettings->remove(key); }
|
||||
|
||||
void QSettingsProxy::endGroup() { m_pSettings->endGroup(); }
|
||||
|
||||
bool QSettingsProxy::isWritable() const { return m_pSettings->isWritable(); }
|
||||
|
||||
bool QSettingsProxy::contains(const QString &key) const {
|
||||
return m_pSettings->contains(key);
|
||||
}
|
||||
|
||||
} // namespace synergy::gui::proxy
|
||||
48
src/lib/gui/proxy/QSettingsProxy.h
Normal file
48
src/lib/gui/proxy/QSettingsProxy.h
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QSettings>
|
||||
|
||||
namespace synergy::gui::proxy {
|
||||
|
||||
class QSettingsProxy {
|
||||
public:
|
||||
virtual ~QSettingsProxy() = default;
|
||||
virtual int beginReadArray(const QString &prefix);
|
||||
virtual void beginWriteArray(const QString &prefix);
|
||||
virtual void setArrayIndex(int i);
|
||||
virtual QVariant value(const QString &key) const;
|
||||
virtual QVariant
|
||||
value(const QString &key, const QVariant &defaultValue) const;
|
||||
virtual void endArray();
|
||||
virtual void setValue(const QString &key, const QVariant &value);
|
||||
virtual void beginGroup(const QString &prefix);
|
||||
virtual void endGroup();
|
||||
virtual void remove(const QString &key);
|
||||
virtual bool isWritable() const;
|
||||
virtual bool contains(const QString &key) const;
|
||||
|
||||
void set(QSettings &settings) { m_pSettings = &settings; }
|
||||
QSettings &get() const { return *m_pSettings; }
|
||||
|
||||
private:
|
||||
QSettings *m_pSettings;
|
||||
};
|
||||
|
||||
} // namespace synergy::gui::proxy
|
||||
|
|
@ -16,13 +16,12 @@
|
|||
*/
|
||||
|
||||
#include "gui/core/CoreTool.h"
|
||||
#include "shared/gui/QtCoreTest.h"
|
||||
#include "shared/gui/TestQtCoreApp.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
class CoreToolTests : public QtCoreTest {};
|
||||
|
||||
TEST_F(CoreToolTests, getProfileDir_noMock_returnsNonEmpty) {
|
||||
TEST(CoreToolTests, getProfileDir_noMock_returnsNonEmpty) {
|
||||
TestQtCoreApp app;
|
||||
CoreTool coreTool;
|
||||
|
||||
QString profileDir = coreTool.getProfileDir();
|
||||
|
|
@ -30,7 +29,8 @@ TEST_F(CoreToolTests, getProfileDir_noMock_returnsNonEmpty) {
|
|||
EXPECT_FALSE(profileDir.isEmpty());
|
||||
}
|
||||
|
||||
TEST_F(CoreToolTests, getInstalledDir_noMock_returnsNonEmpty) {
|
||||
TEST(CoreToolTests, getInstalledDir_noMock_returnsNonEmpty) {
|
||||
TestQtCoreApp app;
|
||||
CoreTool coreTool;
|
||||
|
||||
QString installedDir = coreTool.getInstalledDir();
|
||||
|
|
@ -38,7 +38,8 @@ TEST_F(CoreToolTests, getInstalledDir_noMock_returnsNonEmpty) {
|
|||
EXPECT_FALSE(installedDir.isEmpty());
|
||||
}
|
||||
|
||||
TEST_F(CoreToolTests, getArch_noMock_returnsNonEmpty) {
|
||||
TEST(CoreToolTests, getArch_noMock_returnsNonEmpty) {
|
||||
TestQtCoreApp app;
|
||||
CoreTool coreTool;
|
||||
|
||||
QString arch = coreTool.getArch();
|
||||
|
|
@ -46,7 +47,8 @@ TEST_F(CoreToolTests, getArch_noMock_returnsNonEmpty) {
|
|||
EXPECT_FALSE(arch.isEmpty());
|
||||
}
|
||||
|
||||
TEST_F(CoreToolTests, getSerialKeyFilePath_noMock_returnsNonEmpty) {
|
||||
TEST(CoreToolTests, getSerialKeyFilePath_noMock_returnsNonEmpty) {
|
||||
TestQtCoreApp app;
|
||||
CoreTool coreTool;
|
||||
|
||||
QString serialKeyFilePath = coreTool.getSerialKeyFilePath();
|
||||
|
|
|
|||
|
|
@ -1,37 +0,0 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "gui/messages.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
class QtCoreTest : public ::testing::Test {
|
||||
public:
|
||||
static void SetUpTestSuite() {
|
||||
char **argv = nullptr;
|
||||
int argc = 0;
|
||||
s_app = std::make_unique<QCoreApplication>(argc, argv);
|
||||
qInstallMessageHandler(synergy::gui::messages::messageHandler);
|
||||
}
|
||||
|
||||
static void TearDownTestSuite() { s_app.reset(); }
|
||||
|
||||
static std::unique_ptr<QCoreApplication> s_app;
|
||||
};
|
||||
|
|
@ -15,10 +15,14 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef QT_GUI_LIB
|
||||
#pragma once
|
||||
|
||||
#include "QtTest.h"
|
||||
#include <QCoreApplication>
|
||||
|
||||
std::unique_ptr<QApplication> QtTest::s_app;
|
||||
int argc = 0; // NOLINT
|
||||
char **argv = nullptr; // NOLINT
|
||||
|
||||
#endif
|
||||
class TestQtCoreApp : public QCoreApplication {
|
||||
public:
|
||||
explicit TestQtCoreApp() : QCoreApplication(argc, argv) {}
|
||||
};
|
||||
|
|
@ -15,10 +15,17 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef QT_GUI_LIB
|
||||
#pragma once
|
||||
|
||||
#include "QtCoreTest.h"
|
||||
#include <QApplication>
|
||||
|
||||
std::unique_ptr<QCoreApplication> QtCoreTest::s_app;
|
||||
int argc = 0; // NOLINT
|
||||
char **argv = nullptr; // NOLINT
|
||||
|
||||
#endif
|
||||
/**
|
||||
* Prefer using `TestQtCoreApp` instead.
|
||||
*/
|
||||
class TestQtFullApp : public QApplication {
|
||||
public:
|
||||
explicit TestQtFullApp() : QApplication(argc, argv) {}
|
||||
};
|
||||
65
src/test/shared/gui/mocks/AppConfigMock.h
Normal file
65
src/test/shared/gui/mocks/AppConfigMock.h
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "gui/config/IAppConfig.h"
|
||||
|
||||
#include "gui/config/ElevateMode.h"
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
class AppConfigMock : public synergy::gui::IAppConfig {
|
||||
using ProcessMode = synergy::gui::ProcessMode;
|
||||
|
||||
public:
|
||||
AppConfigMock() {
|
||||
ON_CALL(*this, screenName()).WillByDefault(testing::ReturnRef(m_stubName));
|
||||
ON_CALL(*this, networkInterface())
|
||||
.WillByDefault(testing::ReturnRef(m_stubInterface));
|
||||
ON_CALL(*this, logLevelText())
|
||||
.WillByDefault(testing::Return("stub log level"));
|
||||
}
|
||||
|
||||
MOCK_METHOD(QString, tlsCertPath, (), (const, override));
|
||||
MOCK_METHOD(int, tlsKeyLength, (), (const, override));
|
||||
MOCK_METHOD(bool, tlsEnabled, (), (const, override));
|
||||
MOCK_METHOD(ProcessMode, processMode, (), (const, override));
|
||||
MOCK_METHOD(ElevateMode, elevateMode, (), (const, override));
|
||||
MOCK_METHOD(QString, logLevelText, (), (const, override));
|
||||
MOCK_METHOD(const QString &, screenName, (), (const, override));
|
||||
MOCK_METHOD(bool, preventSleep, (), (const, override));
|
||||
MOCK_METHOD(bool, logToFile, (), (const, override));
|
||||
MOCK_METHOD(const QString &, logFilename, (), (const, override));
|
||||
MOCK_METHOD(QString, coreServerName, (), (const, override));
|
||||
MOCK_METHOD(QString, coreClientName, (), (const, override));
|
||||
MOCK_METHOD(bool, invertConnection, (), (const, override));
|
||||
MOCK_METHOD(void, persistLogDir, (), (const, override));
|
||||
MOCK_METHOD(QString, serialKey, (), (const, override));
|
||||
MOCK_METHOD(bool, languageSync, (), (const, override));
|
||||
MOCK_METHOD(bool, invertScrollDirection, (), (const, override));
|
||||
MOCK_METHOD(int, port, (), (const, override));
|
||||
MOCK_METHOD(bool, useExternalConfig, (), (const, override));
|
||||
MOCK_METHOD(const QString &, configFile, (), (const, override));
|
||||
MOCK_METHOD(const QString &, networkInterface, (), (const, override));
|
||||
MOCK_METHOD(const QString &, serverHostname, (), (const, override));
|
||||
|
||||
private:
|
||||
const QString m_stubName = "stub name";
|
||||
const QString m_stubInterface = "stub interface";
|
||||
const QString m_stubAddress = "stub address";
|
||||
};
|
||||
|
|
@ -17,21 +17,17 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "gui/messages.h"
|
||||
#include "gui/config/IServerConfig.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <gtest/gtest.h>
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
class QtTest : public ::testing::Test {
|
||||
class ServerConfigMock : public synergy::gui::IServerConfig {
|
||||
public:
|
||||
static void SetUpTestSuite() {
|
||||
char **argv = nullptr;
|
||||
int argc = 0;
|
||||
s_app = std::make_unique<QApplication>(argc, argv);
|
||||
qInstallMessageHandler(synergy::gui::messages::messageHandler);
|
||||
}
|
||||
|
||||
static void TearDownTestSuite() { s_app.reset(); }
|
||||
|
||||
static std::unique_ptr<QApplication> s_app;
|
||||
MOCK_METHOD(bool, isFull, (), (const, override));
|
||||
MOCK_METHOD(
|
||||
bool, screenExists, (const QString &screenName), (const, override));
|
||||
MOCK_METHOD(bool, save, (const QString &fileName), (const, override));
|
||||
MOCK_METHOD(void, save, (QFile & file), (const, override));
|
||||
MOCK_METHOD(bool, enableDragAndDrop, (), (const, override));
|
||||
MOCK_METHOD(const ScreenList &, screens, (), (const, override));
|
||||
};
|
||||
|
|
@ -17,15 +17,20 @@
|
|||
|
||||
#include "gui/config/AppConfig.h"
|
||||
|
||||
#include "gui/proxy/QSettingsProxy.h"
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using namespace testing;
|
||||
using namespace synergy::gui::proxy;
|
||||
|
||||
namespace {
|
||||
|
||||
class MockScopes : public synergy::gui::IConfigScopes {
|
||||
class ConfigScopesMock : public synergy::gui::IConfigScopes {
|
||||
using QSettingsProxy = synergy::gui::proxy::QSettingsProxy;
|
||||
|
||||
public:
|
||||
MOCK_METHOD(void, signalReady, (), (override));
|
||||
MOCK_METHOD(
|
||||
|
|
@ -41,18 +46,19 @@ public:
|
|||
MOCK_METHOD(Scope, activeScope, (), (const, override));
|
||||
MOCK_METHOD(void, setActiveScope, (Scope scope), (override));
|
||||
MOCK_METHOD(bool, isActiveScopeWritable, (), (const, override));
|
||||
MOCK_METHOD(QSettings *, activeSettings, (), (const, override));
|
||||
MOCK_METHOD(const QSettingsProxy &, activeSettings, (), (const, override));
|
||||
MOCK_METHOD(QSettingsProxy &, activeSettings, (), (override));
|
||||
MOCK_METHOD(void, save, (), (override));
|
||||
};
|
||||
|
||||
struct MockDeps : public AppConfig::Deps {
|
||||
MockDeps() {
|
||||
struct DepsMock : public AppConfig::Deps {
|
||||
DepsMock() {
|
||||
ON_CALL(*this, profileDir()).WillByDefault(Return("stub"));
|
||||
ON_CALL(*this, hostname()).WillByDefault(Return("stub"));
|
||||
}
|
||||
|
||||
static std::shared_ptr<NiceMock<MockDeps>> makeNice() {
|
||||
return std::make_shared<NiceMock<MockDeps>>();
|
||||
static std::shared_ptr<NiceMock<DepsMock>> makeNice() {
|
||||
return std::make_shared<NiceMock<DepsMock>>();
|
||||
}
|
||||
|
||||
MOCK_METHOD(QString, profileDir, (), (const, override));
|
||||
|
|
@ -64,8 +70,8 @@ struct MockDeps : public AppConfig::Deps {
|
|||
class AppConfigTests : public Test {};
|
||||
|
||||
TEST_F(AppConfigTests, ctor_byDefault_screenNameIsHostname) {
|
||||
NiceMock<MockScopes> scopes;
|
||||
auto deps = MockDeps::makeNice();
|
||||
NiceMock<ConfigScopesMock> scopes;
|
||||
auto deps = DepsMock::makeNice();
|
||||
ON_CALL(*deps, hostname()).WillByDefault(Return("test hostname"));
|
||||
|
||||
AppConfig appConfig(scopes, deps);
|
||||
|
|
@ -74,8 +80,8 @@ TEST_F(AppConfigTests, ctor_byDefault_screenNameIsHostname) {
|
|||
}
|
||||
|
||||
TEST_F(AppConfigTests, ctor_byDefault_getsFromScope) {
|
||||
NiceMock<MockScopes> scopes;
|
||||
auto deps = MockDeps::makeNice();
|
||||
NiceMock<ConfigScopesMock> scopes;
|
||||
auto deps = DepsMock::makeNice();
|
||||
|
||||
ON_CALL(scopes, scopeContains(_, _)).WillByDefault(Return(true));
|
||||
ON_CALL(scopes, getFromScope(_, _, _))
|
||||
|
|
@ -88,8 +94,8 @@ TEST_F(AppConfigTests, ctor_byDefault_getsFromScope) {
|
|||
}
|
||||
|
||||
TEST_F(AppConfigTests, commit_byDefault_setsToScope) {
|
||||
NiceMock<MockScopes> scopes;
|
||||
auto deps = MockDeps::makeNice();
|
||||
NiceMock<ConfigScopesMock> scopes;
|
||||
auto deps = DepsMock::makeNice();
|
||||
AppConfig appConfig(scopes, deps);
|
||||
|
||||
ON_CALL(scopes, isActiveScopeWritable()).WillByDefault(Return(true));
|
||||
|
|
|
|||
68
src/test/unittests/gui/config/ScreenTests.cpp
Normal file
68
src/test/unittests/gui/config/ScreenTests.cpp
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "gui/config/Screen.h"
|
||||
|
||||
#include "gui/proxy/QSettingsProxy.h"
|
||||
#include "shared/gui/TestQtCoreApp.h"
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using namespace synergy::gui::proxy;
|
||||
using namespace testing;
|
||||
|
||||
class QSettingsProxyMock : public QSettingsProxy {
|
||||
public:
|
||||
MOCK_METHOD(int, beginReadArray, (const QString &prefix), (override));
|
||||
MOCK_METHOD(void, beginWriteArray, (const QString &prefix), (override));
|
||||
MOCK_METHOD(void, setArrayIndex, (int i), (override));
|
||||
MOCK_METHOD(QVariant, value, (const QString &key), (const, override));
|
||||
MOCK_METHOD(
|
||||
QVariant, value, (const QString &key, const QVariant &defaultValue),
|
||||
(const, override));
|
||||
MOCK_METHOD(void, endArray, (), (override));
|
||||
MOCK_METHOD(
|
||||
void, setValue, (const QString &key, const QVariant &value), (override));
|
||||
MOCK_METHOD(void, beginGroup, (const QString &prefix), (override));
|
||||
MOCK_METHOD(void, endGroup, (), (override));
|
||||
MOCK_METHOD(void, remove, (const QString &key), (override));
|
||||
MOCK_METHOD(bool, isWritable, (), (const, override));
|
||||
MOCK_METHOD(bool, contains, (const QString &key), (const, override));
|
||||
};
|
||||
|
||||
TEST(ScreenTests, loadSettings_whenHasSetting_readsArray) {
|
||||
TestQtCoreApp app;
|
||||
NiceMock<QSettingsProxyMock> settings;
|
||||
Screen screen;
|
||||
ON_CALL(settings, value(_)).WillByDefault(Return("stub"));
|
||||
|
||||
EXPECT_CALL(settings, beginReadArray(_)).Times(4);
|
||||
|
||||
screen.loadSettings(settings);
|
||||
}
|
||||
|
||||
TEST(ScreenTests, saveSettings_whenNameIsSet_writesArray) {
|
||||
TestQtCoreApp app;
|
||||
NiceMock<QSettingsProxyMock> settings;
|
||||
Screen screen;
|
||||
screen.setName("stub");
|
||||
|
||||
EXPECT_CALL(settings, beginWriteArray(_)).Times(4);
|
||||
|
||||
screen.saveSettings(settings);
|
||||
}
|
||||
129
src/test/unittests/gui/core/ClientConnectionTests.cpp
Normal file
129
src/test/unittests/gui/core/ClientConnectionTests.cpp
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "gui/core/ClientConnection.h"
|
||||
|
||||
#include "shared/gui/mocks/AppConfigMock.h"
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
class QWidget;
|
||||
|
||||
using testing::_;
|
||||
using testing::NiceMock;
|
||||
using namespace synergy::gui;
|
||||
using enum messages::ClientError;
|
||||
|
||||
namespace {
|
||||
|
||||
struct DepsMock : public ClientConnection::Deps {
|
||||
MOCK_METHOD(
|
||||
void, showError,
|
||||
(QWidget * parent, messages::ClientError error, const QString &address),
|
||||
(const, override));
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
class ClientConnectionTests : public testing::Test {
|
||||
public:
|
||||
ClientConnectionTests() {
|
||||
ON_CALL(m_appConfig, serverHostname())
|
||||
.WillByDefault(testing::ReturnRef(stub));
|
||||
}
|
||||
|
||||
std::shared_ptr<DepsMock> m_pDeps = std::make_shared<NiceMock<DepsMock>>();
|
||||
NiceMock<AppConfigMock> m_appConfig;
|
||||
|
||||
private:
|
||||
const QString stub = "stub";
|
||||
};
|
||||
|
||||
TEST_F(ClientConnectionTests, handleLogLine_alreadyConnected_showError) {
|
||||
ClientConnection clientConnection(nullptr, m_appConfig, m_pDeps);
|
||||
const QString serverName = "test server";
|
||||
ON_CALL(m_appConfig, serverHostname())
|
||||
.WillByDefault(testing::ReturnRef(serverName));
|
||||
|
||||
EXPECT_CALL(*m_pDeps, showError(_, AlreadyConnected, serverName));
|
||||
|
||||
clientConnection.handleLogLine(
|
||||
"failed to connect to server\n"
|
||||
"server already has a connected client with our name");
|
||||
}
|
||||
|
||||
TEST_F(ClientConnectionTests, handleLogLine_withHostname_showError) {
|
||||
ClientConnection clientConnection(nullptr, m_appConfig, m_pDeps);
|
||||
const QString serverName = "test-hostname";
|
||||
ON_CALL(m_appConfig, serverHostname())
|
||||
.WillByDefault(testing::ReturnRef(serverName));
|
||||
|
||||
EXPECT_CALL(*m_pDeps, showError(_, HostnameError, serverName));
|
||||
|
||||
clientConnection.handleLogLine("failed to connect to server");
|
||||
}
|
||||
|
||||
TEST_F(ClientConnectionTests, handleLogLine_withIpAddress_showError) {
|
||||
ClientConnection clientConnection(nullptr, m_appConfig, m_pDeps);
|
||||
const QString serverName = "1.1.1.1";
|
||||
ON_CALL(m_appConfig, serverHostname())
|
||||
.WillByDefault(testing::ReturnRef(serverName));
|
||||
|
||||
EXPECT_CALL(*m_pDeps, showError(_, GenericError, serverName));
|
||||
|
||||
clientConnection.handleLogLine("failed to connect to server");
|
||||
}
|
||||
|
||||
TEST_F(ClientConnectionTests, handleLogLine_messageShown_shouldNotShowAgain) {
|
||||
ClientConnection clientConnection(nullptr, m_appConfig, m_pDeps);
|
||||
|
||||
clientConnection.handleLogLine("failed to connect to server");
|
||||
|
||||
EXPECT_CALL(*m_pDeps, showError(_, _, _)).Times(0);
|
||||
|
||||
clientConnection.handleLogLine("failed to connect to server");
|
||||
}
|
||||
|
||||
TEST_F(
|
||||
ClientConnectionTests,
|
||||
handleLogLine_serverRefusedClient_shouldNotShowError) {
|
||||
ClientConnection clientConnection(nullptr, m_appConfig, m_pDeps);
|
||||
|
||||
EXPECT_CALL(*m_pDeps, showError(_, _, _)).Times(0);
|
||||
|
||||
clientConnection.handleLogLine("failed to connect to server\n"
|
||||
"server refused client with our name");
|
||||
}
|
||||
|
||||
TEST_F(
|
||||
ClientConnectionTests, handleLogLine_connected_shouldPreventFutureError) {
|
||||
ClientConnection clientConnection(nullptr, m_appConfig, m_pDeps);
|
||||
clientConnection.handleLogLine("connected to server");
|
||||
|
||||
EXPECT_CALL(*m_pDeps, showError(_, _, _)).Times(0);
|
||||
|
||||
clientConnection.handleLogLine("failed to connect to server");
|
||||
}
|
||||
|
||||
TEST_F(ClientConnectionTests, handleLogLine_otherMessage_shouldNotShowError) {
|
||||
ClientConnection clientConnection(nullptr, m_appConfig, m_pDeps);
|
||||
|
||||
EXPECT_CALL(*m_pDeps, showError(_, _, _)).Times(0);
|
||||
|
||||
clientConnection.handleLogLine("hello world");
|
||||
}
|
||||
|
|
@ -19,6 +19,8 @@
|
|||
#include "gui/core/CoreProcess.h"
|
||||
#include "gui/ipc/IQIpcClient.h"
|
||||
#include "gui/proxy/QProcessProxy.h"
|
||||
#include "shared/gui/mocks/AppConfigMock.h"
|
||||
#include "shared/gui/mocks/ServerConfigMock.h"
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include <gmock/gmock.h>
|
||||
|
|
@ -30,58 +32,13 @@ using ::testing::NiceMock;
|
|||
using ::testing::Return;
|
||||
using ::testing::ReturnRef;
|
||||
|
||||
class MockAppConfig : public IAppConfig {
|
||||
public:
|
||||
MockAppConfig() {
|
||||
ON_CALL(*this, screenName()).WillByDefault(ReturnRef(m_stubName));
|
||||
ON_CALL(*this, networkInterface())
|
||||
.WillByDefault(ReturnRef(m_stubInterface));
|
||||
ON_CALL(*this, logLevelText()).WillByDefault(Return("stub log level"));
|
||||
}
|
||||
namespace {
|
||||
|
||||
MOCK_METHOD(QString, tlsCertPath, (), (const, override));
|
||||
MOCK_METHOD(int, tlsKeyLength, (), (const, override));
|
||||
MOCK_METHOD(bool, tlsEnabled, (), (const, override));
|
||||
MOCK_METHOD(ProcessMode, processMode, (), (const, override));
|
||||
MOCK_METHOD(ElevateMode, elevateMode, (), (const, override));
|
||||
MOCK_METHOD(QString, logLevelText, (), (const, override));
|
||||
MOCK_METHOD(const QString &, screenName, (), (const, override));
|
||||
MOCK_METHOD(bool, preventSleep, (), (const, override));
|
||||
MOCK_METHOD(bool, logToFile, (), (const, override));
|
||||
MOCK_METHOD(const QString &, logFilename, (), (const, override));
|
||||
MOCK_METHOD(QString, coreServerName, (), (const, override));
|
||||
MOCK_METHOD(QString, coreClientName, (), (const, override));
|
||||
MOCK_METHOD(bool, invertConnection, (), (const, override));
|
||||
MOCK_METHOD(void, persistLogDir, (), (const, override));
|
||||
MOCK_METHOD(QString, serialKey, (), (const, override));
|
||||
MOCK_METHOD(bool, languageSync, (), (const, override));
|
||||
MOCK_METHOD(bool, invertScrollDirection, (), (const, override));
|
||||
MOCK_METHOD(int, port, (), (const, override));
|
||||
MOCK_METHOD(bool, useExternalConfig, (), (const, override));
|
||||
MOCK_METHOD(const QString &, configFile, (), (const, override));
|
||||
MOCK_METHOD(const QString &, networkInterface, (), (const, override));
|
||||
|
||||
private:
|
||||
const QString m_stubName = "stub name";
|
||||
const QString m_stubInterface = "stub interface";
|
||||
const QString m_stubAddress = "stub address";
|
||||
};
|
||||
|
||||
class MockServerConfig : public IServerConfig {
|
||||
public:
|
||||
MOCK_METHOD(bool, isFull, (), (const, override));
|
||||
MOCK_METHOD(
|
||||
bool, screenExists, (const QString &screenName), (const, override));
|
||||
MOCK_METHOD(bool, save, (const QString &fileName), (const, override));
|
||||
MOCK_METHOD(void, save, (QFile & file), (const, override));
|
||||
MOCK_METHOD(bool, enableDragAndDrop, (), (const, override));
|
||||
};
|
||||
|
||||
class MockQProcessProxy : public proxy::QProcessProxy {
|
||||
class QProcessProxyMock : public proxy::QProcessProxy {
|
||||
public:
|
||||
operator bool() const override { return toBool(); }
|
||||
|
||||
MockQProcessProxy() {
|
||||
QProcessProxyMock() {
|
||||
ON_CALL(*this, toBool()).WillByDefault(Return(true));
|
||||
ON_CALL(*this, state())
|
||||
.WillByDefault(Return(QProcess::ProcessState::Running));
|
||||
|
|
@ -100,9 +57,9 @@ public:
|
|||
MOCK_METHOD(QString, readAllStandardError, (), (override));
|
||||
};
|
||||
|
||||
class MockQIpcClient : public ipc::IQIpcClient {
|
||||
class QIpcClientMock : public ipc::IQIpcClient {
|
||||
public:
|
||||
MockQIpcClient() {
|
||||
QIpcClientMock() {
|
||||
ON_CALL(*this, isConnected()).WillByDefault(Return(true));
|
||||
}
|
||||
|
||||
|
|
@ -115,9 +72,9 @@ public:
|
|||
MOCK_METHOD(bool, isConnected, (), (const, override));
|
||||
};
|
||||
|
||||
class MockDeps : public CoreProcess::Deps {
|
||||
class DepsMock : public CoreProcess::Deps {
|
||||
public:
|
||||
MockDeps() {
|
||||
DepsMock() {
|
||||
ON_CALL(*this, process()).WillByDefault(ReturnRef(m_process));
|
||||
ON_CALL(*this, ipcClient()).WillByDefault(ReturnRef(m_ipcClient));
|
||||
ON_CALL(*this, appPath(_)).WillByDefault(Return("stub app path"));
|
||||
|
|
@ -131,21 +88,23 @@ public:
|
|||
MOCK_METHOD(bool, fileExists, (const QString &path), (const, override));
|
||||
MOCK_METHOD(QString, getProfileRoot, (), (const, override));
|
||||
|
||||
NiceMock<MockQProcessProxy> m_process;
|
||||
NiceMock<MockQIpcClient> m_ipcClient;
|
||||
NiceMock<QProcessProxyMock> m_process;
|
||||
NiceMock<QIpcClientMock> m_ipcClient;
|
||||
};
|
||||
|
||||
class CoreProcessTests : public ::testing::Test {
|
||||
public:
|
||||
CoreProcessTests() : m_coreProcess(m_appConfig, m_serverConfig, m_pDeps) {}
|
||||
|
||||
NiceMock<MockAppConfig> m_appConfig;
|
||||
NiceMock<MockServerConfig> m_serverConfig;
|
||||
std::shared_ptr<NiceMock<MockDeps>> m_pDeps =
|
||||
std::make_shared<NiceMock<MockDeps>>();
|
||||
NiceMock<AppConfigMock> m_appConfig;
|
||||
NiceMock<ServerConfigMock> m_serverConfig;
|
||||
std::shared_ptr<NiceMock<DepsMock>> m_pDeps =
|
||||
std::make_shared<NiceMock<DepsMock>>();
|
||||
CoreProcess m_coreProcess;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_F(CoreProcessTests, start_serverDesktop_callsProcessStart) {
|
||||
m_coreProcess.setMode(CoreProcess::Mode::Server);
|
||||
|
||||
|
|
|
|||
91
src/test/unittests/gui/core/ServerConnectionTests.cpp
Normal file
91
src/test/unittests/gui/core/ServerConnectionTests.cpp
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "gui/core/ServerConnection.h"
|
||||
|
||||
#include "shared/gui/mocks/AppConfigMock.h"
|
||||
#include "shared/gui/mocks/ServerConfigMock.h"
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using testing::_;
|
||||
using testing::NiceMock;
|
||||
using namespace synergy::gui;
|
||||
|
||||
class QWidget;
|
||||
|
||||
namespace {
|
||||
|
||||
struct DepsMock : public ServerConnection::Deps {
|
||||
MOCK_METHOD(
|
||||
messages::NewClientPromptResult, showNewClientPrompt,
|
||||
(QWidget * parent, const QString &clientName), (const, override));
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
class ServerConnectionTests : public testing::Test {
|
||||
public:
|
||||
std::shared_ptr<DepsMock> m_pDeps = std::make_shared<NiceMock<DepsMock>>();
|
||||
NiceMock<AppConfigMock> m_appConfig;
|
||||
NiceMock<ServerConfigMock> m_serverConfig;
|
||||
};
|
||||
|
||||
TEST_F(ServerConnectionTests, handleLogLine_newClient_shouldShowPrompt) {
|
||||
ServerConnection serverConnection(
|
||||
nullptr, m_appConfig, m_serverConfig, m_pDeps);
|
||||
|
||||
QString clientName = "test client";
|
||||
EXPECT_CALL(*m_pDeps, showNewClientPrompt(_, clientName));
|
||||
|
||||
serverConnection.handleLogLine(R"(unrecognised client name "test client")");
|
||||
}
|
||||
|
||||
TEST_F(ServerConnectionTests, handleLogLine_ignoredClient_shouldNotShowPrompt) {
|
||||
ServerConnection serverConnection(
|
||||
nullptr, m_appConfig, m_serverConfig, m_pDeps);
|
||||
ON_CALL(*m_pDeps, showNewClientPrompt(_, _))
|
||||
.WillByDefault(testing::Return(messages::NewClientPromptResult::Ignore));
|
||||
serverConnection.handleLogLine(R"(unrecognised client name "stub")");
|
||||
|
||||
EXPECT_CALL(*m_pDeps, showNewClientPrompt(_, _)).Times(0);
|
||||
|
||||
serverConnection.handleLogLine(R"(unrecognised client name "stub")");
|
||||
}
|
||||
|
||||
TEST_F(
|
||||
ServerConnectionTests, handleLogLine_serverConfigFull_shouldNotShowPrompt) {
|
||||
ServerConnection serverConnection(
|
||||
nullptr, m_appConfig, m_serverConfig, m_pDeps);
|
||||
ON_CALL(m_serverConfig, isFull()).WillByDefault(testing::Return(true));
|
||||
|
||||
EXPECT_CALL(*m_pDeps, showNewClientPrompt(_, _)).Times(0);
|
||||
|
||||
serverConnection.handleLogLine(R"(unrecognised client name "test client")");
|
||||
}
|
||||
|
||||
TEST_F(ServerConnectionTests, handleLogLine_screenExists_shouldNotShowPrompt) {
|
||||
ServerConnection serverConnection(
|
||||
nullptr, m_appConfig, m_serverConfig, m_pDeps);
|
||||
ON_CALL(m_serverConfig, screenExists(_)).WillByDefault(testing::Return(true));
|
||||
|
||||
EXPECT_CALL(*m_pDeps, showNewClientPrompt(_, _)).Times(0);
|
||||
|
||||
serverConnection.handleLogLine(R"(unrecognised client name "test client")");
|
||||
}
|
||||
Loading…
Reference in a new issue