diff --git a/.ci/linux.centos.7.9/script.sh b/.ci/linux.centos.7.9/script.sh deleted file mode 100755 index 5aba99b69..000000000 --- a/.ci/linux.centos.7.9/script.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash - -source scl_source enable devtoolset-7 - -set -e - -export CMAKE_FLAGS="$CMAKE_FLAGS -DWITH_QT6=OFF -DCPACK_DIST=centos.7.9" - -$1/.ci/common/linux-build.sh $@ -$1/.ci/common/finalize-rpm.sh $1 $2 diff --git a/.ci/linux.centos.7.9/Dockerfile b/.ci/linux.rhel.8/Dockerfile similarity index 57% rename from .ci/linux.centos.7.9/Dockerfile rename to .ci/linux.rhel.8/Dockerfile index b867a0e4b..e33f6ae0e 100644 --- a/.ci/linux.centos.7.9/Dockerfile +++ b/.ci/linux.rhel.8/Dockerfile @@ -1,11 +1,10 @@ -FROM centos:7.9.2009 +FROM rockylinux:8 MAINTAINER Tobias Junghans RUN \ - yum --enablerepo=extras install -y epel-release && \ - yum install -y https://download1.rpmfusion.org/free/el/rpmfusion-free-release-7.noarch.rpm && \ - yum install -y centos-release-scl && \ - yum install -y git devtoolset-7 ninja-build cmake3 rpm-build fakeroot \ + dnf -y --enablerepo=extras install epel-release && \ + dnf -y install https://download1.rpmfusion.org/free/el/rpmfusion-free-release-8.noarch.rpm && \ + dnf -y --enablerepo=devel install git ninja-build cmake rpm-build fakeroot \ qt5-qtbase-devel qt5-qtbase qt5-linguist qt5-qttools qt5-qtquickcontrols2-devel \ libXtst-devel libXrandr-devel libXinerama-devel libXcursor-devel libXrandr-devel libXdamage-devel libXcomposite-devel libXfixes-devel \ libjpeg-turbo-devel \ @@ -18,5 +17,4 @@ RUN \ qca-qt5-devel qca-qt5-ossl \ ffmpeg-devel \ cyrus-sasl-devel \ - openldap-devel && \ - ln -s /usr/bin/cmake3 /usr/bin/cmake + openldap-devel diff --git a/.ci/linux.rhel.8/script.sh b/.ci/linux.rhel.8/script.sh new file mode 100755 index 000000000..b2516359e --- /dev/null +++ b/.ci/linux.rhel.8/script.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +set -e + +export CMAKE_FLAGS="$CMAKE_FLAGS -DWITH_QT6=OFF -DCPACK_DIST=rhel.8" + +$1/.ci/common/linux-build.sh $@ +$1/.ci/common/finalize-rpm.sh $1 $2 diff --git a/.ci/linux.rhel.9/Dockerfile b/.ci/linux.rhel.9/Dockerfile new file mode 100644 index 000000000..e57afa426 --- /dev/null +++ b/.ci/linux.rhel.9/Dockerfile @@ -0,0 +1,21 @@ +FROM rockylinux:9 +MAINTAINER Tobias Junghans + +RUN \ + dnf -y --enablerepo=extras install epel-release && \ + dnf -y install https://download1.rpmfusion.org/free/el/rpmfusion-free-release-9.noarch.rpm && \ + dnf -y --enablerepo=devel install \ + git ninja-build cmake rpm-build fakeroot \ + qt6-qtbase-devel qt6-qtbase qt6-qt5compat-devel qt6-linguist qt6-qttools-devel qt6-qtdeclarative-devel qt6-qthttpserver-devel \ + libXtst-devel libXrandr-devel libXinerama-devel libXcursor-devel libXrandr-devel libXdamage-devel libXcomposite-devel libXfixes-devel \ + libfakekey-devel \ + libjpeg-turbo-devel zlib-devel libpng-devel lzo-devel \ + libvncserver-devel \ + openssl-devel \ + pam-devel \ + procps-devel \ + lzo-devel \ + qca-qt6-devel qca-qt6-ossl \ + ffmpeg-devel \ + cyrus-sasl-devel \ + openldap-devel diff --git a/.ci/linux.rhel.9/script.sh b/.ci/linux.rhel.9/script.sh new file mode 100755 index 000000000..0f9884c1d --- /dev/null +++ b/.ci/linux.rhel.9/script.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +set -e + +export CMAKE_FLAGS="$CMAKE_FLAGS -DCPACK_DIST=rhel.9" + +$1/.ci/common/linux-build.sh $@ +$1/.ci/common/finalize-rpm.sh $1 $2 diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index fce7e69ee..6c7239589 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -10,7 +10,6 @@ build-linux: parallel: matrix: - DISTRO: - - centos.7.9 - debian.11 - debian.12 - fedora.40 @@ -18,6 +17,8 @@ build-linux: - opensuse.15.5 - opensuse.15.6 - opensuse.tumbleweed + - rhel.8 + - rhel.9 - ubuntu.20.04 - ubuntu.22.04 - ubuntu.24.04 diff --git a/CMakeLists.txt b/CMakeLists.txt index ed2e8bb4d..8f4b9dd09 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -107,7 +107,7 @@ endif() if(NOT VERSION_STRING) set(VERSION_MAJOR 4) set(VERSION_MINOR 9) - set(VERSION_PATCH 3) + set(VERSION_PATCH 4) set(VERSION_BUILD 0) set(VERSION_STRING "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}") else() diff --git a/cli/src/FeatureCommands.cpp b/cli/src/FeatureCommands.cpp index 5c8dc9167..e7d18bfa3 100644 --- a/cli/src/FeatureCommands.cpp +++ b/cli/src/FeatureCommands.cpp @@ -268,7 +268,7 @@ CommandLinePluginInterface::RunResult FeatureCommands::controlComputer( FeatureP } Computer computer; - computer.setHostAddress( host ); + computer.setHostAddress(host); auto computerControlInterface = ComputerControlInterface::Pointer::create( computer ); computerControlInterface->start(); diff --git a/configurator/src/AccessControlPage.cpp b/configurator/src/AccessControlPage.cpp index 41c5198e1..ab7ed2c35 100644 --- a/configurator/src/AccessControlPage.cpp +++ b/configurator/src/AccessControlPage.cpp @@ -63,6 +63,12 @@ void AccessControlPage::resetWidgets() { FOREACH_VEYON_ACCESS_CONTROL_CONFIG_PROPERTY(INIT_WIDGET_FROM_PROPERTY); + if (VeyonCore::config().isAccessControlRulesProcessingEnabled() == false && + VeyonCore::config().isAccessRestrictedToUserGroups() == false) + { + ui->skipAccessControl->setChecked(true); + } + m_accessGroups = VeyonCore::config().authorizedUserGroups(); auto cleanedUpAccessGroups = m_accessGroups; diff --git a/configurator/src/AccessControlRulesTestDialog.cpp b/configurator/src/AccessControlRulesTestDialog.cpp index 5f54dac2a..e144af386 100644 --- a/configurator/src/AccessControlRulesTestDialog.cpp +++ b/configurator/src/AccessControlRulesTestDialog.cpp @@ -73,7 +73,7 @@ void AccessControlRulesTestDialog::accept() ui->connectedUsersLineEdit->text().split(QLatin1Char(','))); QString resultText; - switch( result ) + switch (result ? result->action() : AccessControlRule::Action::None) { case AccessControlRule::Action::Allow: resultText = tr( "The access in the given scenario is allowed." ); diff --git a/configurator/src/GeneralConfigurationPage.cpp b/configurator/src/GeneralConfigurationPage.cpp index 5f95eb1d8..ddfe841f0 100644 --- a/configurator/src/GeneralConfigurationPage.cpp +++ b/configurator/src/GeneralConfigurationPage.cpp @@ -183,8 +183,7 @@ bool GeneralConfigurationPage::testKeyFileAuthentication() void GeneralConfigurationPage::openLogFileDirectory() { - FileSystemBrowser( FileSystemBrowser::ExistingDirectory ). - exec( ui->logFileDirectory ); + FileSystemBrowser(FileSystemBrowser::ExistingDirectory, this).exec(ui->logFileDirectory); } diff --git a/configurator/src/GeneralConfigurationPage.ui b/configurator/src/GeneralConfigurationPage.ui index 262459867..a5824c2ee 100644 --- a/configurator/src/GeneralConfigurationPage.ui +++ b/configurator/src/GeneralConfigurationPage.ui @@ -68,6 +68,32 @@ + + + + Color scheme: + + + + + + + + System + + + + + Light + + + + + Dark + + + + @@ -388,6 +414,7 @@ applicationName uiLanguage uiStyle + uiColorScheme authenticationMethod testAuthenticationButton networkObjectDirectoryPlugin diff --git a/configurator/src/MainWindow.cpp b/configurator/src/MainWindow.cpp index 31a8d2250..7b55dca2b 100644 --- a/configurator/src/MainWindow.cpp +++ b/configurator/src/MainWindow.cpp @@ -132,8 +132,23 @@ void MainWindow::reset( bool onlyUI ) void MainWindow::apply() { - if( applyConfiguration() ) + const auto showError = [this](const ConfigurationManager& configurationManager) { + vCritical() << configurationManager.errorString().toUtf8().constData(); + + QMessageBox::critical(this, + tr("%1 Configurator").arg(VeyonCore::applicationName()), + configurationManager.errorString()); + + }; + + ConfigurationManager configurationManager; + if (configurationManager.saveConfiguration()) { + if (configurationManager.applyConfiguration() == false) + { + showError(configurationManager); + } + const auto pages = findChildren(); for( auto page : pages ) { @@ -143,6 +158,10 @@ void MainWindow::apply() ui->buttonBox->setEnabled( false ); m_configChanged = false; } + else + { + showError(configurationManager); + } } @@ -325,26 +344,6 @@ void MainWindow::switchToAdvancedView() -bool MainWindow::applyConfiguration() -{ - ConfigurationManager configurationManager; - - if( configurationManager.saveConfiguration() == false || - configurationManager.applyConfiguration() == false ) - { - vCritical() << configurationManager.errorString().toUtf8().constData(); - - QMessageBox::critical( nullptr, - tr( "%1 Configurator" ).arg( VeyonCore::applicationName() ), - configurationManager.errorString() ); - return false; - } - - return true; -} - - - void MainWindow::loadConfigurationPagePlugins() { for( auto pluginObject : std::as_const( VeyonCore::pluginManager().pluginObjects() ) ) diff --git a/configurator/src/MainWindow.h b/configurator/src/MainWindow.h index b08bb7f0c..4bab96702 100644 --- a/configurator/src/MainWindow.h +++ b/configurator/src/MainWindow.h @@ -60,7 +60,6 @@ private Q_SLOTS: void switchToStandardView(); void switchToAdvancedView(); - bool applyConfiguration(); void loadConfigurationPagePlugins(); void closeEvent( QCloseEvent *closeEvent ) override; diff --git a/configurator/src/MasterConfigurationPage.cpp b/configurator/src/MasterConfigurationPage.cpp index be17c8361..4f0348b55 100644 --- a/configurator/src/MasterConfigurationPage.cpp +++ b/configurator/src/MasterConfigurationPage.cpp @@ -126,21 +126,21 @@ void MasterConfigurationPage::disableFeature() void MasterConfigurationPage::openUserConfigurationDirectory() { - FileSystemBrowser(FileSystemBrowser::ExistingDirectory).exec(ui->userConfigurationDirectory); + FileSystemBrowser(FileSystemBrowser::ExistingDirectory, this).exec(ui->userConfigurationDirectory); } void MasterConfigurationPage::openScreenshotDirectory() { - FileSystemBrowser( FileSystemBrowser::ExistingDirectory ).exec( ui->screenshotDirectory ); + FileSystemBrowser(FileSystemBrowser::ExistingDirectory, this).exec(ui->screenshotDirectory); } void MasterConfigurationPage::openConfigurationTemplatesDirectory() { - FileSystemBrowser(FileSystemBrowser::ExistingDirectory).exec(ui->configurationTemplatesDirectory); + FileSystemBrowser(FileSystemBrowser::ExistingDirectory, this).exec(ui->configurationTemplatesDirectory); } diff --git a/configurator/src/ServiceConfigurationPage.cpp b/configurator/src/ServiceConfigurationPage.cpp index 3f0d51a68..9e951936b 100644 --- a/configurator/src/ServiceConfigurationPage.cpp +++ b/configurator/src/ServiceConfigurationPage.cpp @@ -25,7 +25,6 @@ #include #include -#include "FileSystemBrowser.h" #include "VeyonConfiguration.h" #include "PluginManager.h" #include "ServiceConfigurationPage.h" @@ -84,7 +83,7 @@ void ServiceConfigurationPage::connectWidgetsToProperties() void ServiceConfigurationPage::applyConfiguration() { - VeyonServiceControl serviceControl( this ); + VeyonServiceControl serviceControl(this); if( serviceControl.isServiceRunning() && QMessageBox::question( this, tr( "Restart %1 Service" ).arg( VeyonCore::applicationName() ), @@ -93,8 +92,7 @@ void ServiceConfigurationPage::applyConfiguration() "Restart it now?" ).arg( VeyonCore::applicationName() ), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes ) == QMessageBox::Yes ) { - serviceControl.stopService(); - serviceControl.startService(); + serviceControl.restartService(); } } @@ -102,7 +100,7 @@ void ServiceConfigurationPage::applyConfiguration() void ServiceConfigurationPage::startService() { - VeyonServiceControl( this ).startService(); + VeyonServiceControl(this).startService(); updateServiceControl(); } @@ -111,7 +109,7 @@ void ServiceConfigurationPage::startService() void ServiceConfigurationPage::stopService() { - VeyonServiceControl( this ).stopService(); + VeyonServiceControl(this).stopService(); updateServiceControl(); } diff --git a/core/resources/core.qrc b/core/resources/core.qrc index 756dcb02e..3c3a6106e 100644 --- a/core/resources/core.qrc +++ b/core/resources/core.qrc @@ -5,27 +5,44 @@ application-x-pem-key.png license.png user-group-new.png + user-group-new-dark.png languages.png presentation-none.png icon16.png icon22.png icon32.png document-open.png + document-open-dark.png document-save.png + document-save-dark.png list-add.png edit-delete.png edit-find.png + edit-find-dark.png help-about.png + help-about-dark.png dialog-ok-apply.png document-edit.png default-pkey.pem go-up.png + go-up-dark.png go-down.png + go-down-dark.png go-previous.png + go-previous-dark.png go-next.png + go-next-dark.png media-playback-pause.png + media-playback-pause-dark.png media-playback-start.png + media-playback-start-dark.png media-playback-stop.png + media-playback-stop-dark.png media-record.png + toast-close.png + toast-error.png + toast-information.png + toast-success.png + toast-warning.png diff --git a/core/resources/document-open-dark.png b/core/resources/document-open-dark.png new file mode 100644 index 000000000..fa3430cb3 Binary files /dev/null and b/core/resources/document-open-dark.png differ diff --git a/core/resources/document-save-dark.png b/core/resources/document-save-dark.png new file mode 100644 index 000000000..122e9bc2d Binary files /dev/null and b/core/resources/document-save-dark.png differ diff --git a/core/resources/edit-find-dark.png b/core/resources/edit-find-dark.png new file mode 100644 index 000000000..1853cf30a Binary files /dev/null and b/core/resources/edit-find-dark.png differ diff --git a/core/resources/go-down-dark.png b/core/resources/go-down-dark.png new file mode 100644 index 000000000..36bf7a0a2 Binary files /dev/null and b/core/resources/go-down-dark.png differ diff --git a/core/resources/go-next-dark.png b/core/resources/go-next-dark.png new file mode 100644 index 000000000..7a78d72d4 Binary files /dev/null and b/core/resources/go-next-dark.png differ diff --git a/core/resources/go-previous-dark.png b/core/resources/go-previous-dark.png new file mode 100644 index 000000000..d9b316a2a Binary files /dev/null and b/core/resources/go-previous-dark.png differ diff --git a/core/resources/go-up-dark.png b/core/resources/go-up-dark.png new file mode 100644 index 000000000..2697d36f1 Binary files /dev/null and b/core/resources/go-up-dark.png differ diff --git a/core/resources/help-about-dark.png b/core/resources/help-about-dark.png new file mode 100644 index 000000000..3eafb192a Binary files /dev/null and b/core/resources/help-about-dark.png differ diff --git a/core/resources/media-playback-pause-dark.png b/core/resources/media-playback-pause-dark.png new file mode 100644 index 000000000..ede1b1bdf Binary files /dev/null and b/core/resources/media-playback-pause-dark.png differ diff --git a/core/resources/media-playback-start-dark.png b/core/resources/media-playback-start-dark.png new file mode 100644 index 000000000..5b22dc132 Binary files /dev/null and b/core/resources/media-playback-start-dark.png differ diff --git a/core/resources/media-playback-stop-dark.png b/core/resources/media-playback-stop-dark.png new file mode 100644 index 000000000..e19b08131 Binary files /dev/null and b/core/resources/media-playback-stop-dark.png differ diff --git a/core/resources/toast-close.png b/core/resources/toast-close.png new file mode 100644 index 000000000..e0a167888 Binary files /dev/null and b/core/resources/toast-close.png differ diff --git a/core/resources/toast-error.png b/core/resources/toast-error.png new file mode 100644 index 000000000..4c939933f Binary files /dev/null and b/core/resources/toast-error.png differ diff --git a/core/resources/toast-information.png b/core/resources/toast-information.png new file mode 100644 index 000000000..054da26a5 Binary files /dev/null and b/core/resources/toast-information.png differ diff --git a/core/resources/toast-success.png b/core/resources/toast-success.png new file mode 100644 index 000000000..f84f25ce2 Binary files /dev/null and b/core/resources/toast-success.png differ diff --git a/core/resources/toast-warning.png b/core/resources/toast-warning.png new file mode 100644 index 000000000..e152c0eb9 Binary files /dev/null and b/core/resources/toast-warning.png differ diff --git a/core/resources/user-group-new-dark.png b/core/resources/user-group-new-dark.png new file mode 100644 index 000000000..f66e4dd5b Binary files /dev/null and b/core/resources/user-group-new-dark.png differ diff --git a/core/src/AccessControlProvider.cpp b/core/src/AccessControlProvider.cpp index 879f601cc..cf68f6cae 100644 --- a/core/src/AccessControlProvider.cpp +++ b/core/src/AccessControlProvider.cpp @@ -37,18 +37,20 @@ AccessControlProvider::AccessControlProvider() : - m_accessControlRules(), m_userGroupsBackend(VeyonCore::userGroupsBackendManager().configuredBackend()), m_networkObjectDirectory(VeyonCore::networkObjectDirectoryManager().configuredDirectory()), - m_useDomainUserGroups(VeyonCore::config().useDomainUserGroups()) + m_useDomainUserGroups(VeyonCore::config().useDomainUserGroups()), + m_accessControlFeature(QLatin1String(staticMetaObject.className()), + Feature::Flag::Meta | Feature::Flag::Builtin, + Feature::Uid{QStringLiteral("1815941e-eaef-43ab-b9cd-5403dca3f749")}, {}, {}, {}, {}, {}) { const QJsonArray accessControlRules = VeyonCore::config().accessControlRules(); m_accessControlRules.reserve( accessControlRules.size() ); - for( const auto& accessControlRule : accessControlRules ) + for (const auto& accessControlRule : accessControlRules) { - m_accessControlRules.append( AccessControlRule( accessControlRule ) ); + m_accessControlRules.append(AccessControlRule::Pointer::create(accessControlRule)); } } @@ -118,31 +120,42 @@ QStringList AccessControlProvider::locationsOfComputer( const QString& computer -AccessControlProvider::Access AccessControlProvider::checkAccess( const QString& accessingUser, - const QString& accessingComputer, - const QStringList& connectedUsers ) +AccessControlProvider::CheckResult AccessControlProvider::checkAccess(const QString& accessingUser, + const QString& accessingComputer, + const QStringList& connectedUsers) { - if( VeyonCore::config().isAccessRestrictedToUserGroups() ) + CheckResult denyAccessCheckResult{Access::Deny}; + if (VeyonCore::config().isAccessRestrictedToUserGroups()) { - if( processAuthorizedGroups( accessingUser ) ) + if (processAuthorizedGroups(accessingUser)) { - return Access::Allow; + return {Access::Allow, Reason::UserInAuthorizedUserGroups}; } + denyAccessCheckResult.reason = Reason::UserNotInAuthorizedUserGroups; } - else if( VeyonCore::config().isAccessControlRulesProcessingEnabled() ) + else if (VeyonCore::config().isAccessControlRulesProcessingEnabled()) { - auto action = processAccessControlRules( accessingUser, - accessingComputer, - VeyonCore::platform().userFunctions().currentUser(), - HostAddress::localFQDN(), - connectedUsers ); - switch( action ) + const auto rule = processAccessControlRules(accessingUser, + accessingComputer, + VeyonCore::platform().userFunctions().currentUser(), + HostAddress::localFQDN(), + connectedUsers); + if (rule) { - case AccessControlRule::Action::Allow: - return Access::Allow; - case AccessControlRule::Action::AskForPermission: - return Access::ToBeConfirmed; - default: break; + switch(rule->action()) + { + case AccessControlRule::Action::Allow: + return {Access::Allow, Reason::AccessControlRuleMatched}; + case AccessControlRule::Action::AskForPermission: + return {Access::ToBeConfirmed}; + default: break; + } + denyAccessCheckResult.reason = Reason::AccessControlRuleMatched; + denyAccessCheckResult.matchedRule = rule; + } + else + { + denyAccessCheckResult.reason = Reason::NoAccessControlRuleMatched; } } else @@ -150,13 +163,13 @@ AccessControlProvider::Access AccessControlProvider::checkAccess( const QString& vDebug() << "no access control method configured, allowing access."; // no access control method configured, therefore grant access - return Access::Allow; + return {Access::Allow}; } vDebug() << "configured access control method did not succeed, denying access."; // configured access control method did not succeed, therefore deny access - return Access::Deny; + return denyAccessCheckResult; } @@ -175,34 +188,34 @@ bool AccessControlProvider::processAuthorizedGroups( const QString& accessingUse -AccessControlRule::Action AccessControlProvider::processAccessControlRules( const QString& accessingUser, +AccessControlRule::Pointer AccessControlProvider::processAccessControlRules(const QString& accessingUser, const QString& accessingComputer, const QString& localUser, const QString& localComputer, - const QStringList& connectedUsers ) + const QStringList& connectedUsers) { vDebug() << "processing rules for" << accessingUser << accessingComputer << localUser << localComputer << connectedUsers; - for( const auto& rule : std::as_const( m_accessControlRules ) ) + for (const auto& rule : std::as_const(m_accessControlRules)) { // rule disabled? - if( rule.action() == AccessControlRule::Action::None ) + if (rule->action() == AccessControlRule::Action::None) { // then continue with next rule continue; } - if( rule.areConditionsIgnored() || - matchConditions( rule, accessingUser, accessingComputer, localUser, localComputer, connectedUsers ) ) + if (rule->areConditionsIgnored() || + matchConditions(*rule, accessingUser, accessingComputer, localUser, localComputer, connectedUsers)) { - vDebug() << "rule" << rule.name() << "matched with action" << rule.action(); - return rule.action(); + vDebug() << "rule" << rule->name() << "matched with action" << rule->action(); + return rule; } } vDebug() << "no matching rule, denying access"; - return AccessControlRule::Action::Deny; + return nullptr; } @@ -216,12 +229,12 @@ bool AccessControlProvider::isAccessToLocalComputerDenied() const return false; } - for( const auto& rule : std::as_const( m_accessControlRules ) ) + for (const auto& rule : std::as_const(m_accessControlRules)) { - if( matchConditions( rule, {}, {}, - VeyonCore::platform().userFunctions().currentUser(), HostAddress::localFQDN(), {} ) ) + if (matchConditions(*rule, {}, {}, + VeyonCore::platform().userFunctions().currentUser(), HostAddress::localFQDN(), {})) { - switch( rule.action() ) + switch (rule->action()) { case AccessControlRule::Action::Deny: return true; @@ -239,6 +252,28 @@ bool AccessControlProvider::isAccessToLocalComputerDenied() const +bool AccessControlProvider::handleFeatureMessage(ComputerControlInterface::Pointer computerControlInterface, const FeatureMessage& message) +{ + if (message.featureUid() == m_accessControlFeature.uid()) + { + computerControlInterface->setAccessControlFailed(message.argument(Argument::Details).toString()); + return true; + } + + return false; +} + + + +void AccessControlProvider::sendDetails(QIODevice* ioDevice, const QString& details) +{ + FeatureMessage{m_accessControlFeature.uid()}.addArgument( + AccessControlProvider::Argument::Details, details) + .sendAsRfbMessage(ioDevice); +} + + + bool AccessControlProvider::isMemberOfUserGroup( const QString &user, const QString &groupName ) const { diff --git a/core/src/AccessControlProvider.h b/core/src/AccessControlProvider.h index 0b7f00a12..d744d5eb7 100644 --- a/core/src/AccessControlProvider.h +++ b/core/src/AccessControlProvider.h @@ -25,13 +25,16 @@ #pragma once #include "AccessControlRule.h" +#include "FeatureProviderInterface.h" #include "NetworkObject.h" class UserGroupsBackendInterface; class NetworkObjectDirectory; -class VEYON_CORE_EXPORT AccessControlProvider +class VEYON_CORE_EXPORT AccessControlProvider : public QObject, FeatureProviderInterface, PluginInterface { + Q_OBJECT + Q_INTERFACES(FeatureProviderInterface PluginInterface) public: enum class Access { Deny, @@ -39,25 +42,102 @@ class VEYON_CORE_EXPORT AccessControlProvider ToBeConfirmed, } ; + enum class Reason { + Unknown, + NoAccessControlRuleMatched, + AccessControlRuleMatched, + NotConfirmedByUser, + ConfirmedByUser, + UserNotInAuthorizedUserGroups, + UserInAuthorizedUserGroups, + }; + + enum class Argument + { + Details, + }; + + struct CheckResult { + Access access = Access::Deny; + Reason reason = Reason::Unknown; + AccessControlRule::Pointer matchedRule = nullptr; + }; + AccessControlProvider(); QStringList userGroups() const; QStringList locations() const; QStringList locationsOfComputer( const QString& computer ) const; - Access checkAccess( const QString& accessingUser, const QString& accessingComputer, - const QStringList& connectedUsers ); + CheckResult checkAccess(const QString& accessingUser, const QString& accessingComputer, + const QStringList& connectedUsers); bool processAuthorizedGroups( const QString& accessingUser ); - AccessControlRule::Action processAccessControlRules( const QString& accessingUser, + AccessControlRule::Pointer processAccessControlRules(const QString& accessingUser, const QString& accessingComputer, const QString& localUser, const QString& localComputer, - const QStringList& connectedUsers ); + const QStringList& connectedUsers); bool isAccessToLocalComputerDenied() const; + Plugin::Uid uid() const override + { + return Plugin::Uid{QStringLiteral("ef3f61f4-b7fa-41a1-ae09-74e022048617")}; + } + + QVersionNumber version() const override + { + return QVersionNumber(1, 0); + } + + QString name() const override + { + return QStringLiteral("AccessControlProvider"); + } + + QString description() const override + { + return tr( "Provider for access control features" ); + } + + QString vendor() const override + { + return QStringLiteral("Veyon Community"); + } + + QString copyright() const override + { + return QStringLiteral("Tobias Junghans"); + } + + const Feature& feature() const + { + return m_accessControlFeature; + } + + const FeatureList& featureList() const override + { + return m_features; + } + + bool controlFeature(Feature::Uid featureUid, Operation operation, const QVariantMap& arguments, + const ComputerControlInterfaceList& computerControlInterfaces) override + { + Q_UNUSED(featureUid) + Q_UNUSED(operation) + Q_UNUSED(arguments) + Q_UNUSED(computerControlInterfaces) + + return false; + } + + bool handleFeatureMessage(ComputerControlInterface::Pointer computerControlInterface, + const FeatureMessage& message) override; + + void sendDetails(QIODevice* ioDevice, const QString& details); + private: bool isMemberOfUserGroup( const QString& user, const QString& groupName ) const; bool isLocatedAt( const QString& computer, const QString& locationName ) const; @@ -79,9 +159,11 @@ class VEYON_CORE_EXPORT AccessControlProvider static QStringList objectNames( const NetworkObjectList& objects ); static bool matchList(const QStringList& list, const QString& pattern); - QList m_accessControlRules; + QList m_accessControlRules{}; UserGroupsBackendInterface* m_userGroupsBackend; NetworkObjectDirectory* m_networkObjectDirectory; bool m_useDomainUserGroups; + Feature m_accessControlFeature; + FeatureList m_features{m_accessControlFeature}; } ; diff --git a/core/src/AccessControlRule.cpp b/core/src/AccessControlRule.cpp index 2f7541266..ff9e6db47 100644 --- a/core/src/AccessControlRule.cpp +++ b/core/src/AccessControlRule.cpp @@ -38,19 +38,7 @@ AccessControlRule::AccessControlRule() : -AccessControlRule::AccessControlRule(const AccessControlRule &other) : - m_name( other.name() ), - m_description( other.description() ), - m_action( other.action() ), - m_parameters( other.parameters() ), - m_invertConditions( other.areConditionsInverted() ), - m_ignoreConditions( other.areConditionsIgnored() ) -{ -} - - - -AccessControlRule::AccessControlRule(const QJsonValue &jsonValue) : +AccessControlRule::AccessControlRule(const QJsonValue& jsonValue) : m_name(), m_description(), m_action( Action::None ), diff --git a/core/src/AccessControlRule.h b/core/src/AccessControlRule.h index b26747a7c..cd99cffc5 100644 --- a/core/src/AccessControlRule.h +++ b/core/src/AccessControlRule.h @@ -86,10 +86,10 @@ class VEYON_CORE_EXPORT AccessControlRule using ConditionParameterMap = QMap; + using Pointer = QSharedPointer; AccessControlRule(); - AccessControlRule( const AccessControlRule& other ); - explicit AccessControlRule( const QJsonValue& jsonValue ); + explicit AccessControlRule(const QJsonValue& jsonValue); ~AccessControlRule() = default; diff --git a/core/src/BuiltinFeatures.cpp b/core/src/BuiltinFeatures.cpp index 7ef3b7914..ef0acccca 100644 --- a/core/src/BuiltinFeatures.cpp +++ b/core/src/BuiltinFeatures.cpp @@ -22,6 +22,7 @@ * */ +#include "AccessControlProvider.h" #include "BuiltinFeatures.h" #include "MonitoringMode.h" #include "PluginManager.h" @@ -32,11 +33,13 @@ BuiltinFeatures::BuiltinFeatures() : m_systemTrayIcon( new SystemTrayIcon ), m_monitoringMode( new MonitoringMode ), - m_desktopAccessDialog( new DesktopAccessDialog ) + m_desktopAccessDialog( new DesktopAccessDialog ), + m_accessControlProvider(new AccessControlProvider) { VeyonCore::pluginManager().registerExtraPluginInterface( m_systemTrayIcon ); VeyonCore::pluginManager().registerExtraPluginInterface( m_monitoringMode ); VeyonCore::pluginManager().registerExtraPluginInterface( m_desktopAccessDialog ); + VeyonCore::pluginManager().registerExtraPluginInterface(m_accessControlProvider); } @@ -46,4 +49,5 @@ BuiltinFeatures::~BuiltinFeatures() delete m_systemTrayIcon; delete m_monitoringMode; delete m_desktopAccessDialog; + delete m_accessControlProvider; } diff --git a/core/src/BuiltinFeatures.h b/core/src/BuiltinFeatures.h index 3cc7dec6a..9058ce28d 100644 --- a/core/src/BuiltinFeatures.h +++ b/core/src/BuiltinFeatures.h @@ -26,6 +26,7 @@ #include "VeyonCore.h" +class AccessControlProvider; class DesktopAccessDialog; class MonitoringMode; class SystemTrayIcon; @@ -53,8 +54,15 @@ class VEYON_CORE_EXPORT BuiltinFeatures return *m_desktopAccessDialog; } + AccessControlProvider& accessControlProvider() + { + return *m_accessControlProvider; + } + private: SystemTrayIcon* m_systemTrayIcon; MonitoringMode* m_monitoringMode; DesktopAccessDialog* m_desktopAccessDialog; + AccessControlProvider* m_accessControlProvider; + }; diff --git a/core/src/Computer.cpp b/core/src/Computer.cpp index c170c4e05..2c1071808 100644 --- a/core/src/Computer.cpp +++ b/core/src/Computer.cpp @@ -25,13 +25,14 @@ #include "Computer.h" Computer::Computer( NetworkObject::Uid networkObjectUid, - const QString& name, + const QString& displayName, const QString& hostAddress, const QString& macAddress, const QString& location ) : m_networkObjectUid( networkObjectUid ), - m_name( name ), - m_hostAddress( hostAddress ), + m_displayName(displayName), + m_hostName(hostAddress), + m_hostAddress(hostAddress), m_macAddress( macAddress ), m_location( location ) { diff --git a/core/src/Computer.h b/core/src/Computer.h index f393e0c68..2c3897493 100644 --- a/core/src/Computer.h +++ b/core/src/Computer.h @@ -24,7 +24,7 @@ #pragma once -#include +#include #include #include "NetworkObject.h" @@ -35,7 +35,7 @@ class VEYON_CORE_EXPORT Computer { public: explicit Computer( NetworkObject::Uid networkObjectUid = NetworkObject::Uid(), - const QString& name = {}, + const QString& displayName = {}, const QString& hostAddress = {}, const QString& macAddress = {}, const QString& location = {} ); @@ -55,26 +55,32 @@ class VEYON_CORE_EXPORT Computer return m_networkObjectUid; } - void setName( const QString& name ) + void setDisplayName(const QString& displayName) { - m_name = name; + m_displayName = displayName; } - QString name() const + const QString& displayName() const { - return m_name; + return m_displayName; } - void setHostAddress( const QString& hostAddress ) + void setHostAddress(const QString& hostAddress) { - m_hostAddress = hostAddress; + m_hostName = hostAddress; + m_hostAddress = QHostAddress{hostAddress}; } - QString hostAddress() const + const QHostAddress& hostAddress() const { return m_hostAddress; } + const QString& hostName() const + { + return m_hostName; + } + void setMacAddress( const QString& macAddress ) { m_macAddress = macAddress; @@ -97,11 +103,11 @@ class VEYON_CORE_EXPORT Computer private: NetworkObject::Uid m_networkObjectUid; - QString m_name; - QString m_hostAddress; + QString m_displayName; + QString m_hostName; + QHostAddress m_hostAddress; QString m_macAddress; QString m_location; - }; using ComputerList = QVector; diff --git a/core/src/ComputerControlInterface.cpp b/core/src/ComputerControlInterface.cpp index f7124e640..36e778c17 100644 --- a/core/src/ComputerControlInterface.cpp +++ b/core/src/ComputerControlInterface.cpp @@ -22,6 +22,7 @@ * */ +#include "AccessControlProvider.h" #include "BuiltinFeatures.h" #include "ComputerControlInterface.h" #include "Computer.h" @@ -74,13 +75,13 @@ void ComputerControlInterface::start( QSize scaledFramebufferSize, UpdateMode up m_scaledFramebufferSize = scaledFramebufferSize; - if( m_computer.hostAddress().isEmpty() == false ) + if (m_computer.hostName().isEmpty() == false) { m_connection = new VeyonConnection; m_connection->setAuthenticationProxy( authenticationProxy ); auto vncConnection = m_connection->vncConnection(); - vncConnection->setHost( m_computer.hostAddress() ); + vncConnection->setHost(m_computer.hostName()); if( m_port > 0 ) { vncConnection->setPort( m_port ); @@ -186,6 +187,24 @@ QImage ComputerControlInterface::framebuffer() const +void ComputerControlInterface::setAccessControlFailed(const QString& details) +{ + lock(); + m_accessControlDetails = details; + m_state = State::AccessControlFailed; + + if (vncConnection()) + { + vncConnection()->stop(); + } + unlock(); + + Q_EMIT accessControlDetailsChanged(); + Q_EMIT stateChanged(); +} + + + void ComputerControlInterface::setServerVersion(VeyonCore::ApplicationVersion version) { m_serverVersionQueryTimer.stop(); @@ -420,7 +439,7 @@ void ComputerControlInterface::setQuality() void ComputerControlInterface::resetWatchdog() { - if( state() == State::Connected ) + if (state() == State::Connected || state() == State::AccessControlFailed) { m_pingTimer.start(); m_connectionWatchdogTimer.start(); @@ -446,17 +465,11 @@ void ComputerControlInterface::updateState() { lock(); - if( vncConnection() ) + if (vncConnection()) { - switch( vncConnection()->state() ) + if (!(m_state == State::AccessControlFailed && vncConnection()->state() == VncConnection::State::Disconnected)) { - case VncConnection::State::Disconnected: m_state = State::Disconnected; break; - case VncConnection::State::Connecting: m_state = State::Connecting; break; - case VncConnection::State::Connected: m_state = State::Connected; break; - case VncConnection::State::HostOffline: m_state = State::HostOffline; break; - case VncConnection::State::ServerNotRunning: m_state = State::ServerNotRunning; break; - case VncConnection::State::AuthenticationFailed: m_state = State::AuthenticationFailed; break; - default: m_state = VncConnection::State::Disconnected; break; + m_state = vncConnection()->state(); } } else @@ -574,7 +587,7 @@ QDebug operator<<(QDebug stream, ComputerControlInterface::Pointer computerContr { if (computerControlInterface.isNull() == false) { - stream << qUtf8Printable(computerControlInterface->computer().hostAddress()); + stream << qUtf8Printable(computerControlInterface->computer().hostName()); } return stream; } @@ -589,7 +602,7 @@ QDebug operator<<(QDebug stream, const ComputerControlInterfaceList& computerCon { if (computerControlInterface.isNull() == false) { - hostAddresses.append(computerControlInterface->computer().hostAddress()); + hostAddresses.append(computerControlInterface->computer().hostName()); } } diff --git a/core/src/ComputerControlInterface.h b/core/src/ComputerControlInterface.h index 456425bc2..075e3463f 100644 --- a/core/src/ComputerControlInterface.h +++ b/core/src/ComputerControlInterface.h @@ -101,6 +101,13 @@ class VEYON_CORE_EXPORT ComputerControlInterface : public QObject, public Lockab QImage framebuffer() const; + const QString& accessControlDetails() const + { + return m_accessControlDetails; + } + + void setAccessControlFailed(const QString& details); + VeyonCore::ApplicationVersion serverVersion() const { return m_serverVersion; @@ -221,11 +228,13 @@ class VEYON_CORE_EXPORT ComputerControlInterface : public QObject, public Lockab VeyonCore::ApplicationVersion m_serverVersion{VeyonCore::ApplicationVersion::Unknown}; QTimer m_serverVersionQueryTimer{this}; + QString m_accessControlDetails{}; QTimer m_statePollingTimer{this}; QMap m_properties; Q_SIGNALS: + void accessControlDetailsChanged(); void framebufferSizeChanged(); void framebufferUpdated(); void userChanged(); diff --git a/core/src/FeatureMessage.cpp b/core/src/FeatureMessage.cpp index 462f82214..e57c4a9d2 100644 --- a/core/src/FeatureMessage.cpp +++ b/core/src/FeatureMessage.cpp @@ -27,11 +27,11 @@ #include "VariantArrayMessage.h" -bool FeatureMessage::send( QIODevice* ioDevice ) const +bool FeatureMessage::sendPlain(QIODevice* ioDevice) const { - if( ioDevice ) + if (ioDevice) { - VariantArrayMessage message( ioDevice ); + VariantArrayMessage message(ioDevice); message.write( m_featureUid ); message.write( m_command ); @@ -47,6 +47,23 @@ bool FeatureMessage::send( QIODevice* ioDevice ) const +bool FeatureMessage::sendAsRfbMessage(QIODevice* ioDevice) const +{ + if (ioDevice) + { + const char rfbMessageType = FeatureMessage::RfbMessageType; + ioDevice->write(&rfbMessageType, sizeof(rfbMessageType)); + + return sendPlain(ioDevice); + } + + vCritical() << "no IO device!"; + + return false; +} + + + bool FeatureMessage::isReadyForReceive( QIODevice* ioDevice ) { return ioDevice != nullptr && diff --git a/core/src/FeatureMessage.h b/core/src/FeatureMessage.h index afcd17a19..43085562d 100644 --- a/core/src/FeatureMessage.h +++ b/core/src/FeatureMessage.h @@ -109,7 +109,8 @@ class VEYON_CORE_EXPORT FeatureMessage return m_arguments.contains( QString::number( static_cast( index ) ) ); } - bool send( QIODevice* ioDevice ) const; + bool sendPlain(QIODevice* ioDevice) const; + bool sendAsRfbMessage(QIODevice* ioDevice) const; bool isReadyForReceive( QIODevice* ioDevice ); diff --git a/core/src/FeatureWorkerManager.cpp b/core/src/FeatureWorkerManager.cpp index 64d490bdf..5663e08b1 100644 --- a/core/src/FeatureWorkerManager.cpp +++ b/core/src/FeatureWorkerManager.cpp @@ -336,7 +336,7 @@ void FeatureWorkerManager::sendPendingMessages() while( worker.socket && worker.pendingMessages.isEmpty() == false ) { - worker.pendingMessages.first().send( worker.socket ); + worker.pendingMessages.first().sendPlain(worker.socket); worker.pendingMessages.removeFirst(); } } diff --git a/core/src/FileSystemBrowser.cpp b/core/src/FileSystemBrowser.cpp index 3c4f9f8d1..bf128440f 100644 --- a/core/src/FileSystemBrowser.cpp +++ b/core/src/FileSystemBrowser.cpp @@ -66,18 +66,16 @@ QString FileSystemBrowser::exec( const QString &path, switch( m_browseMode ) { case ExistingDirectory: - chosenPath = QFileDialog::getExistingDirectory( nullptr, title, + chosenPath = QFileDialog::getExistingDirectory(m_parent, title, browsePath, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks ); break; case ExistingFile: - chosenPath = QFileDialog::getOpenFileName( nullptr, title, - browsePath, filter ); + chosenPath = QFileDialog::getOpenFileName(m_parent, title, browsePath, filter); break; case SaveFile: - chosenPath = QFileDialog::getSaveFileName( nullptr, title, - browsePath, filter ); + chosenPath = QFileDialog::getSaveFileName(m_parent, title, browsePath, filter); break; default: break; diff --git a/core/src/FileSystemBrowser.h b/core/src/FileSystemBrowser.h index 8117f437e..28a359df7 100644 --- a/core/src/FileSystemBrowser.h +++ b/core/src/FileSystemBrowser.h @@ -40,7 +40,8 @@ class VEYON_CORE_EXPORT FileSystemBrowser } ; using BrowseMode = BrowseModes; - explicit FileSystemBrowser( BrowseMode m ) : + explicit FileSystemBrowser(BrowseMode m, QWidget* parent) : + m_parent(parent), m_browseMode( m ), m_expandPath( true ), m_shrinkPath( true ) @@ -64,6 +65,7 @@ class VEYON_CORE_EXPORT FileSystemBrowser private: + QWidget* m_parent; BrowseMode m_browseMode; bool m_expandPath; bool m_shrinkPath; diff --git a/core/src/PlatformNetworkFunctions.h b/core/src/PlatformNetworkFunctions.h index da2dce008..b92f9531f 100644 --- a/core/src/PlatformNetworkFunctions.h +++ b/core/src/PlatformNetworkFunctions.h @@ -33,14 +33,19 @@ class PlatformNetworkFunctions public: using Socket = uintptr_t; - enum { - PingTimeout = 1000, - PingProcessTimeout = PingTimeout*2 + static constexpr int PingTimeout = 1000; + static constexpr int PingProcessTimeout = 5000; + + enum class PingResult { + Unknown, + ReplyReceived, + TimedOut, + NameResolutionFailed }; virtual ~PlatformNetworkFunctions() = default; - virtual bool ping( const QString& hostAddress ) = 0; + virtual PingResult ping(const QString& hostAddress) = 0; virtual bool configureFirewallException( const QString& applicationPath, const QString& description, bool enabled ) = 0; virtual bool configureSocketKeepalive( Socket socket, bool enabled, int idleTime, int interval, int probes ) = 0; diff --git a/core/src/PlatformSessionFunctions.h b/core/src/PlatformSessionFunctions.h index 2cf211557..94a7b5ac2 100644 --- a/core/src/PlatformSessionFunctions.h +++ b/core/src/PlatformSessionFunctions.h @@ -38,7 +38,7 @@ class VEYON_CORE_EXPORT PlatformSessionFunctions struct SessionInfo { SessionId id = InvalidSessionId; - SessionUptime uptime; + SessionUptime uptime = 0; QString clientAddress; QString clientName; QString hostName; diff --git a/core/src/Screenshot.cpp b/core/src/Screenshot.cpp index 7172eae53..0ec513403 100644 --- a/core/src/Screenshot.cpp +++ b/core/src/Screenshot.cpp @@ -74,7 +74,7 @@ void Screenshot::take( const ComputerControlInterface::Pointer& computerControlI } // construct filename - m_fileName = dir + QDir::separator() + constructFileName( userLogin, computerControlInterface->computer().hostAddress() ); + m_fileName = dir + QDir::separator() + constructFileName(userLogin, computerControlInterface->computer().hostName()); QFile outputFile( m_fileName ); if( VeyonCore::platform().filesystemFunctions().openFileSafely( @@ -99,7 +99,7 @@ void Screenshot::take( const ComputerControlInterface::Pointer& computerControlI user = QStringLiteral( "%1 (%2)" ).arg( userLogin, computerControlInterface->userFullName() ); } - const auto host = computerControlInterface->computer().hostAddress(); + const auto host = computerControlInterface->computer().hostName(); const auto date = QDate::currentDate().toString( Qt::ISODate ); const auto time = QTime::currentTime().toString( Qt::ISODate ); diff --git a/core/src/ServiceControl.cpp b/core/src/ServiceControl.cpp index 0b255c25c..d82723e5f 100644 --- a/core/src/ServiceControl.cpp +++ b/core/src/ServiceControl.cpp @@ -23,12 +23,11 @@ */ #include -#include -#include -#include +#include #include "PlatformServiceFunctions.h" #include "ServiceControl.h" +#include "Toast.h" ServiceControl::ServiceControl( const QString& name, @@ -61,8 +60,8 @@ bool ServiceControl::isServiceRunning() void ServiceControl::startService() { - serviceControl( tr( "Starting service %1" ).arg( m_name ), - QtConcurrent::run( [=]() { VeyonCore::platform().serviceFunctions().start( m_name ); } ) ); + serviceControl(tr("Starting %1").arg(m_displayName), + QtConcurrent::run([=]() { VeyonCore::platform().serviceFunctions().start(m_name); })); } @@ -70,71 +69,78 @@ void ServiceControl::startService() void ServiceControl::stopService() { - serviceControl( tr( "Stopping service %1" ).arg( m_name ), - QtConcurrent::run( [=]() { VeyonCore::platform().serviceFunctions().stop( m_name ); } ) ); + serviceControl(tr("Stopping %1").arg(m_displayName), + QtConcurrent::run([=]() { VeyonCore::platform().serviceFunctions().stop(m_name); })); +} + + + +void ServiceControl::restartService() +{ + serviceControl(tr("Restarting %1").arg(m_displayName), + QtConcurrent::run([=]() { + VeyonCore::platform().serviceFunctions().stop(m_name); + VeyonCore::platform().serviceFunctions().start(m_name); + })); } void ServiceControl::registerService() { - serviceControl( tr( "Registering service %1" ).arg( m_name ), - QtConcurrent::run( [=]() { VeyonCore::platform().serviceFunctions().install( m_name, - m_filePath, - PlatformServiceFunctions::StartMode::Auto, - m_displayName ); } ) ); + serviceControl(tr("Registering %1").arg(m_displayName), + QtConcurrent::run([=]() { VeyonCore::platform().serviceFunctions().install(m_name, + m_filePath, + PlatformServiceFunctions::StartMode::Auto, + m_displayName ); })); } void ServiceControl::unregisterService() { - serviceControl( tr( "Unregistering service %1" ).arg( m_name ), - QtConcurrent::run( [=]() { VeyonCore::platform().serviceFunctions().uninstall( m_name ); } ) ); + serviceControl(tr("Unregistering %1").arg(m_displayName), + QtConcurrent::run([=]() { VeyonCore::platform().serviceFunctions().uninstall( m_name ); })); } -void ServiceControl::serviceControl( const QString& title, const Operation& operation ) +void ServiceControl::serviceControl(const QString& title, const Operation& operation) { - if( m_parent ) + if (m_parent) { - graphicalFeedback( title, operation ); + graphicalFeedback(title, operation); } else { - textFeedback( title, operation ); + textFeedback(title, operation); } } -void ServiceControl::graphicalFeedback( const QString& title, const Operation& operation ) +void ServiceControl::graphicalFeedback(const QString& title, const Operation& operation) { - QProgressDialog pd( title, {}, 0, 0, m_parent ); - pd.setWindowTitle( tr( "Service control" ) ); - - auto b = new QProgressBar( &pd ); - b->setMaximum( 100 ); - b->setTextVisible( false ); - pd.setBar( b ); - b->show(); - pd.setWindowModality( Qt::WindowModal ); - pd.show(); - - int j = 0; - while( operation.isFinished() == false ) + auto toast = new Toast(m_parent); + toast->setTitle(tr("Service control")); + toast->setText(title); + toast->applyPreset(Toast::Preset::Information); + toast->setDuration(0); + toast->show(); + + while (operation.isRunning()) { QCoreApplication::processEvents(); - b->setValue( ++j % 100 ); - QThread::msleep( 10 ); + QThread::msleep(10); } + + toast->hide(); } -void ServiceControl::textFeedback( const QString& title, const Operation& operation ) +void ServiceControl::textFeedback(const QString& title, const Operation& operation) { printf( "%s", qUtf8Printable( title ) ); diff --git a/core/src/ServiceControl.h b/core/src/ServiceControl.h index b8aaa5c62..bbd9f31e7 100644 --- a/core/src/ServiceControl.h +++ b/core/src/ServiceControl.h @@ -49,13 +49,13 @@ class VEYON_CORE_EXPORT ServiceControl : public QObject void startService(); void stopService(); - + void restartService(); private: using Operation = QFuture; - void serviceControl( const QString& title, const Operation& operation ); - void graphicalFeedback( const QString &title, const Operation& operation ); - void textFeedback( const QString &title, const Operation& operation ); + void serviceControl(const QString& title, const Operation& operation); + void graphicalFeedback(const QString &title, const Operation& operation); + void textFeedback(const QString &title, const Operation& operation); const QString m_name; const QString m_filePath; diff --git a/core/src/Toast.cpp b/core/src/Toast.cpp new file mode 100644 index 000000000..08144790b --- /dev/null +++ b/core/src/Toast.cpp @@ -0,0 +1,2015 @@ +/* + * File based on https://github.com/niklashenning/qt-toast/blob/master/src/Toast.cpp + * + * MIT License + + * Copyright (c) 2024 Niklas Henning + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Toast.h" +#include "VeyonCore.h" + +// Static +int Toast::s_maximumOnScreen = 3; +int Toast::s_spacing = 10; +int Toast::s_offsetX = 20; +int Toast::s_offsetY = 45; +bool Toast::s_alwaysOnMainScreen = false; +QScreen* Toast::s_fixedScreen = nullptr; +Toast::Position Toast::s_position = Toast::Position::BottomRight; +std::deque Toast::s_currentlyShown = std::deque(); +std::deque Toast::s_queue = std::deque(); + +// Static constants +const int Toast::sc_updatePositionDuration = 200; +const int Toast::sc_durationBarUpdateInterval = 5; +const int Toast::sc_dropShadowSize = 5; +const QColor Toast::sc_successAccentColor = QColor("#3E9141"); +const QColor Toast::sc_warningAccentColor = QColor("#E8B849"); +const QColor Toast::sc_errorAccentColor = QColor("#BA2626"); +const QColor Toast::sc_informationAccentColor = QColor("#007FFF"); +const QColor Toast::sc_defaultAccentColor = QColor("#5C5C5C"); +const QColor Toast::sc_defaultBackgroundColor = QColor("#E7F4F9"); +const QColor Toast::sc_defaultTitleColor = QColor("#000000"); +const QColor Toast::sc_defaultTextColor = QColor("#5C5C5C"); +const QColor Toast::sc_defaultIconSeparatorColor = QColor("#D9D9D9"); +const QColor Toast::sc_defaultCloseButtonIconColor = QColor("#000000"); +const QColor Toast::sc_defaultBackgroundColorDark = QColor("#292929"); +const QColor Toast::sc_defaultTitleColorDark = QColor("#FFFFFF"); +const QColor Toast::sc_defaultTextColorDark = QColor("#D0D0D0"); +const QColor Toast::sc_defaultIconSeparatorColorDark = QColor("#585858"); +const QColor Toast::sc_defaultCloseButtonIconColorDark = QColor("#C9C9C9"); + + +Toast::Toast(QWidget* parent) + : QDialog(parent) +{ + // Init attributes + m_duration = 5000; + m_showDurationBar = true; + m_icon = getIconFromEnum(Icon::Information); + m_showIcon = false; + m_iconSize = QSize(18, 18); + m_showIconSeparator = true; + m_iconSeparatorWidth = 2; + m_closeButtonIcon = getIconFromEnum(Icon::Close); + m_showCloseButton = true; + m_closeButtonIconSize = QSize(10, 10); + m_closeButtonSize = QSize(24, 24); + m_closeButtonAlignment = ButtonAlignment::Top; + m_fadeInDuration = 250; + m_fadeOutDuration = 250; + m_resetDurationOnHover = true; + m_stayOnTop = true; + m_borderRadius = 0; + m_backgroundColor = sc_defaultBackgroundColor; + m_titleColor = sc_defaultTitleColor; + m_textColor = sc_defaultTextColor; + m_iconColor = sc_defaultAccentColor; + m_iconSeparatorColor = sc_defaultIconSeparatorColor; + m_closeButtonIconColor = sc_defaultCloseButtonIconColor; + m_durationBarColor = sc_defaultAccentColor; + m_titleFont = font(); + m_titleFont.setBold(true); + m_textFont = font(); + m_margins = QMargins(20, 18, 10, 18); + m_iconMargins = QMargins(0, 0, 15, 0); + m_iconSectionMargins = QMargins(0, 0, 15, 0); + m_textSectionMargins = QMargins(0, 0, 15, 0); + m_closeButtonMargins = QMargins(0, -8, 0, -8); + m_textSectionSpacing = 8; + + m_elapsedTime = 0; + m_fadingOut = false; + m_used = false; + m_parent = parent; + + // Window settings + setAttribute(Qt::WidgetAttribute::WA_TranslucentBackground); + setFocusPolicy(Qt::FocusPolicy::NoFocus); + + // Notification widget (QLabel because QWidget has weird behaviour with stylesheets) + m_notification = new QLabel(this); + + // Drop shadow (has to be drawn manually since only one graphics effect can be applied) + m_dropShadowLayer1 = new QWidget(this); + m_dropShadowLayer2 = new QWidget(this); + m_dropShadowLayer3 = new QWidget(this); + m_dropShadowLayer4 = new QWidget(this); + m_dropShadowLayer5 = new QWidget(this); + m_dropShadowLayer1->setObjectName(QStringLiteral("toast-drop-shadow-layer-1")); + m_dropShadowLayer2->setObjectName(QStringLiteral("toast-drop-shadow-layer-2")); + m_dropShadowLayer3->setObjectName(QStringLiteral("toast-drop-shadow-layer-3")); + m_dropShadowLayer4->setObjectName(QStringLiteral("toast-drop-shadow-layer-4")); + m_dropShadowLayer5->setObjectName(QStringLiteral("toast-drop-shadow-layer-5")); + + // Opacity effect for fading animations + m_opacityEffect = new QGraphicsOpacityEffect(); + m_opacityEffect->setOpacity(1); + setGraphicsEffect(m_opacityEffect); + + // Close button + m_closeButton = new QPushButton(m_notification); + m_closeButton->setCursor(Qt::CursorShape::PointingHandCursor); + m_closeButton->setObjectName(QStringLiteral("toast-close-button")); + connect(m_closeButton, &QPushButton::clicked, this, &Toast::hide); + + // Text and title labels + m_titleLabel = new QLabel(m_notification); + m_textLabel = new QLabel(m_notification); + + // Icon (QPushButton instead of QLabel to get better icon quality) + m_iconWidget = new QPushButton(m_notification); + m_iconWidget->setObjectName(QStringLiteral("toast-icon-widget")); + + // Icon separator + m_iconSeparator = new QWidget(m_notification); + m_iconSeparator->setFixedWidth(2); + + // Duration bar container (used to make border radius possible on 4 px high widget) + m_durationBarContainer = new QWidget(m_notification); + m_durationBarContainer->setFixedHeight(4); + m_durationBarContainer->setStyleSheet(QStringLiteral("background: transparent;")); + + // Duration bar + m_durationBar = new QWidget(m_durationBarContainer); + m_durationBar->setFixedHeight(20); + m_durationBar->move(0, -16); + + // Duration bar chunk + m_durationBarChunk = new QWidget(m_durationBarContainer); + m_durationBarChunk->setFixedHeight(20); + m_durationBarChunk->move(0, -16); + + // Set defaults + setIcon(m_icon); + setIconSize(m_iconSize); + setIconColor(m_iconColor); + setIconSeparatorWidth(m_iconSeparatorWidth); + setCloseButtonIcon(m_closeButtonIcon); + setCloseButtonIconSize(m_closeButtonIconSize); + setCloseButtonSize(m_closeButtonSize); + setCloseButtonAlignment(m_closeButtonAlignment); + setStayOnTop(m_stayOnTop); + setBackgroundColor(m_backgroundColor); + setTitleColor(m_titleColor); + setTextColor(m_textColor); + setBorderRadius(m_borderRadius); + setIconSeparatorColor(m_iconSeparatorColor); + setCloseButtonIconColor(m_closeButtonIconColor); + setDurationBarColor(m_durationBarColor); + setTitleFont(m_titleFont); + setTextFont(m_textFont); + + // Timer for hiding the notification after set duration + m_durationTimer = new QTimer(this); + m_durationTimer->setSingleShot(true); + connect(m_durationTimer, &QTimer::timeout, this, &Toast::fadeOut); + + // Timer for updating the duration bar + m_durationBarTimer = new QTimer(this); + connect(m_durationBarTimer, &QTimer::timeout, this, &Toast::updateDurationBar); + + // Apply stylesheet + setStyleSheet(QStringLiteral( + "#toast-drop-shadow-layer-1 { background: rgba(0, 0, 0, 3); border-radius: 8px; }" + "#toast-drop-shadow-layer-2 { background: rgba(0, 0, 0, 5); border-radius: 8px; }" + "#toast-drop-shadow-layer-3 { background: rgba(0, 0, 0, 6); border-radius: 8px; }" + "#toast-drop-shadow-layer-4 { background: rgba(0, 0, 0, 9); border-radius: 8px; }" + "#toast-drop-shadow-layer-5 { background: rgba(0, 0, 0, 10); border-radius: 8px; }" + "#toast-close-button { background: transparent; }" + "#toast-icon-widget { background: transparent; }" + )); +} + +Toast::~Toast() +{ +} + +int Toast::getMaximumOnScreen() +{ + return s_maximumOnScreen; +} + +int Toast::getSpacing() +{ + return s_spacing; +} + +QPoint Toast::getOffset() +{ + return QPoint(s_offsetX, s_offsetY); +} + +int Toast::getOffsetX() +{ + return s_offsetX; +} + +int Toast::getOffsetY() +{ + return s_offsetY; +} + +bool Toast::isAlwaysOnMainScreen() +{ + return s_alwaysOnMainScreen; +} + +QScreen* Toast::getFixedScreen() +{ + return s_fixedScreen; +} + +Toast::Position Toast::getPosition() +{ + return s_position; +} + +int Toast::getCount() +{ + return s_currentlyShown.size() + s_queue.size(); +} + +int Toast::getVisibleCount() +{ + return s_currentlyShown.size(); +} + +int Toast::getQueuedCount() +{ + return s_queue.size(); +} + +int Toast::getDuration() +{ + return m_duration; +} + +bool Toast::isShowDurationBar() +{ + return m_showDurationBar; +} + +QString Toast::getTitle() +{ + return m_title; +} + +QString Toast::getText() +{ + return m_text; +} + +QPixmap Toast::getIcon() +{ + return m_icon; +} + +bool Toast::isShowIcon() +{ + return m_showIcon; +} + +QSize Toast::getIconSize() +{ + return m_iconSize; +} + +bool Toast::isShowIconSeparator() +{ + return m_showIconSeparator; +} + +int Toast::getIconSeparatorWidth() +{ + return m_iconSeparatorWidth; +} + +QPixmap Toast::getCloseButtonIcon() +{ + return m_closeButtonIcon; +} + +bool Toast::isShowCloseButton() +{ + return m_showCloseButton; +} + +QSize Toast::getCloseButtonIconSize() +{ + return m_closeButtonIconSize; +} + +int Toast::getCloseButtonWidth() +{ + return m_closeButtonSize.width(); +} + +int Toast::getCloseButtonHeight() +{ + return m_closeButtonSize.height(); +} + +QSize Toast::getCloseButtonSize() +{ + return m_closeButtonSize; +} + +Toast::ButtonAlignment Toast::getCloseButtonAlignment() +{ + return m_closeButtonAlignment; +} + +int Toast::getFadeInDuration() +{ + return m_fadeInDuration; +} + +int Toast::getFadeOutDuration() +{ + return m_fadeOutDuration; +} + +bool Toast::isResetDurationOnHover() +{ + return m_resetDurationOnHover; +} + +bool Toast::isStayOnTop() +{ + return m_stayOnTop; +} + +int Toast::getBorderRadius() +{ + return m_borderRadius; +} + +QColor Toast::getBackgroundColor() +{ + return m_backgroundColor; +} + +QColor Toast::getTitleColor() +{ + return m_titleColor; +} + +QColor Toast::getTextColor() +{ + return m_textColor; +} + +QColor Toast::getIconColor() +{ + return m_iconColor; +} + +QColor Toast::getIconSeparatorColor() +{ + return m_iconSeparatorColor; +} + +QColor Toast::getCloseButtonIconColor() +{ + return m_closeButtonIconColor; +} + +QColor Toast::getDurationBarColor() +{ + return m_durationBarColor; +} + +QFont Toast::getTitleFont() +{ + return m_titleFont; +} + +QFont Toast::getTextFont() +{ + return m_textFont; +} + +QMargins Toast::getMargins() +{ + return m_margins; +} + +QMargins Toast::getIconMargins() +{ + return m_iconMargins; +} + +QMargins Toast::getIconSectionMargins() +{ + return m_iconSectionMargins; +} + +QMargins Toast::getTextSectionMargins() +{ + return m_textSectionMargins; +} + +QMargins Toast::getCloseButtonMargins() +{ + return m_closeButtonMargins; +} + +int Toast::getTextSectionSpacing() +{ + return m_textSectionSpacing; +} + +void Toast::setMaximumOnScreen(int maximum) +{ + int freedSpaces = maximum - s_maximumOnScreen; + s_maximumOnScreen = maximum; + + if (freedSpaces > 0) + { + for (int i = 0; i < freedSpaces; i++) + { + showNextInQueue(); + } + } +} + +void Toast::setSpacing(int spacing) +{ + s_spacing = spacing; + updateCurrentlyShowingPositionY(); +} + +void Toast::setOffset(int x, int y) +{ + s_offsetX = x; + s_offsetY = y; + updateCurrentlyShowingPositionXY(); +} + +void Toast::setOffsetX(int offsetX) +{ + s_offsetX = offsetX; + updateCurrentlyShowingPositionX(); +} + +void Toast::setOffsetY(int offsetY) +{ + s_offsetY = offsetY; + updateCurrentlyShowingPositionY(); +} + +void Toast::setAlwaysOnMainScreen(bool enabled) +{ + s_alwaysOnMainScreen = enabled; + updateCurrentlyShowingPositionXY(); +} + +void Toast::setFixedScreen(QScreen* screen) +{ + s_fixedScreen = screen; + updateCurrentlyShowingPositionXY(); +} + +void Toast::setPosition(Position position) +{ + s_position = position; + updateCurrentlyShowingPositionXY(); +} + +void Toast::reset() +{ + // Reset static attributes + s_maximumOnScreen = 3; + s_spacing = 10; + s_offsetX = 20; + s_offsetY = 45; + s_alwaysOnMainScreen = false; + s_fixedScreen = nullptr; + s_position = Position::BottomRight; + + // Hide currently showing toasts and clear queue + for (Toast* toast : s_currentlyShown) + { + toast->setVisible(false); + toast->deleteLater(); + } + + s_currentlyShown.clear(); + s_queue.clear(); +} + +void Toast::setDuration(int duration) +{ + if (m_used) + { + return; + } + m_duration = duration; +} + +void Toast::setShowDurationBar(bool enabled) +{ + if (m_used) + { + return; + } + m_showDurationBar = enabled; +} + +void Toast::setTitle(QString title) +{ + if (m_used) + { + return; + } + m_title = title; + m_titleLabel->setText(title); +} + +void Toast::setText(QString text) +{ + if (m_used) + { + return; + } + m_text = text; + m_textLabel->setText(text); +} + +void Toast::setIcon(QPixmap icon) +{ + if (m_used) + { + return; + } + m_icon = icon; + m_iconWidget->setIcon(QIcon(icon)); + setIconColor(m_iconColor); +} + +void Toast::setIcon(Icon icon) +{ + if (m_used) + { + return; + } + m_icon = getIconFromEnum(icon); + m_iconWidget->setIcon(QIcon(m_icon)); + setIconColor(m_iconColor); +} + +void Toast::setShowIcon(bool enabled) +{ + if (m_used) + { + return; + } + m_showIcon = enabled; +} + +void Toast::setIconSize(QSize size) +{ + if (m_used) + { + return; + } + m_iconSize = size; + m_iconWidget->setFixedSize(size); + m_iconWidget->setIconSize(size); + setIcon(m_icon); +} + +void Toast::setShowIconSeparator(bool enabled) +{ + if (m_used) + { + return; + } + m_showIconSeparator = enabled; + + if (enabled) + { + m_iconSeparator->setFixedWidth(m_iconSeparatorWidth); + } + else { + m_iconSeparator->setFixedWidth(0); + } +} + +void Toast::setIconSeparatorWidth(int width) +{ + if (m_used) + { + return; + } + m_iconSeparatorWidth = width; + + if (m_showIconSeparator) + { + m_iconSeparator->setFixedWidth(width); + } +} + +void Toast::setCloseButtonIcon(QPixmap icon) +{ + if (m_used) + { + return; + } + m_closeButtonIcon = icon; + m_closeButton->setIcon(QIcon(icon)); + setCloseButtonIconColor(m_closeButtonIconColor); +} + +void Toast::setCloseButtonIcon(Icon icon) +{ + if (m_used) + { + return; + } + m_closeButtonIcon = getIconFromEnum(icon); + m_closeButton->setIcon(QIcon(m_closeButtonIcon)); + setCloseButtonIconColor(m_closeButtonIconColor); +} + +void Toast::setShowCloseButton(bool enabled) +{ + if (m_used) + { + return; + } + m_showCloseButton = enabled; +} + +void Toast::setCloseButtonIconSize(QSize size) +{ + if (m_used) + { + return; + } + m_closeButtonIconSize = size; + m_closeButton->setIconSize(size); + setCloseButtonIcon(m_closeButtonIcon); +} + +void Toast::setCloseButtonSize(QSize size) +{ + if (m_used) + { + return; + } + m_closeButtonSize = size; + m_closeButton->setFixedSize(size); +} + +void Toast::setCloseButtonWidth(int width) +{ + if (m_used) + { + return; + } + m_closeButtonSize.setWidth(width); + m_closeButton->setFixedSize(m_closeButtonSize); +} + +void Toast::setCloseButtonHeight(int height) +{ + if (m_used) + { + return; + } + m_closeButtonSize.setHeight(height); + m_closeButton->setFixedSize(m_closeButtonSize); +} + +void Toast::setCloseButtonAlignment(ButtonAlignment alignment) +{ + if (m_used) + { + return; + } + m_closeButtonAlignment = alignment; +} + +void Toast::setFadeInDuration(int duration) +{ + if (m_used) + { + return; + } + m_fadeInDuration = duration; +} + +void Toast::setFadeOutDuration(int duration) +{ + if (m_used) + { + return; + } + m_fadeOutDuration = duration; +} + +void Toast::setResetDurationOnHover(bool enabled) +{ + if (m_used) + { + return; + } + m_resetDurationOnHover = enabled; +} + +void Toast::setStayOnTop(bool enabled) +{ + if (m_used) + { + return; + } + m_stayOnTop = enabled; + + if (enabled) + { + setWindowFlags(Qt::WindowType::Tool + | Qt::WindowType::CustomizeWindowHint + | Qt::WindowType::FramelessWindowHint + | Qt::WindowType::WindowStaysOnTopHint); + } + else + { + setWindowFlags(Qt::WindowType::Tool + | Qt::WindowType::CustomizeWindowHint + | Qt::WindowType::FramelessWindowHint); + } +} + +void Toast::setBorderRadius(int borderRadius) +{ + if (m_used) + { + return; + } + m_borderRadius = borderRadius; +} + +void Toast::setBackgroundColor(QColor color) +{ + if (m_used) + { + return; + } + m_backgroundColor = color; +} + +void Toast::setTitleColor(QColor color) +{ + if (m_used) + { + return; + } + m_titleColor = color; +} + +void Toast::setTextColor(QColor color) +{ + if (m_used) + { + return; + } + m_textColor = color; +} + +void Toast::setIconColor(QColor color) +{ + if (m_used) + { + return; + } + m_iconColor = color; + + QImage recoloredImage = recolorImage(m_iconWidget->icon() + .pixmap(m_iconWidget->iconSize()).toImage(), color); + m_iconWidget->setIcon(QIcon(QPixmap::fromImage(recoloredImage))); +} + +void Toast::setIconSeparatorColor(QColor color) +{ + if (m_used) + { + return; + } + m_iconSeparatorColor = color; +} + +void Toast::setCloseButtonIconColor(QColor color) +{ + if (m_used) + { + return; + } + m_closeButtonIconColor = color; + + QImage recoloredImage = recolorImage(m_closeButton->icon() + .pixmap(m_closeButton->iconSize()).toImage(), color); + m_closeButton->setIcon(QIcon(QPixmap::fromImage(recoloredImage))); +} + +void Toast::setDurationBarColor(QColor color) +{ + if (m_used) + { + return; + } + m_durationBarColor = color; +} + +void Toast::setTitleFont(QFont font) +{ + if (m_used) + { + return; + } + m_titleFont = font; + m_titleLabel->setFont(font); +} + +void Toast::setTextFont(QFont font) +{ + if (m_used) + { + return; + } + m_textFont = font; + m_textLabel->setFont(font); +} + +void Toast::setMargins(QMargins margins) +{ + if (m_used) + { + return; + } + m_margins = margins; +} + +void Toast::setMarginLeft(int margin) +{ + if (m_used) + { + return; + } + m_margins.setLeft(margin); +} + +void Toast::setMarginTop(int margin) +{ + if (m_used) + { + return; + } + m_margins.setTop(margin); +} + +void Toast::setMarginRight(int margin) +{ + if (m_used) + { + return; + } + m_margins.setRight(margin); +} + + +void Toast::setMarginBottom(int margin) +{ + if (m_used) + { + return; + } + m_margins.setBottom(margin); +} + + +void Toast::setIconMargins(QMargins margins) +{ + if (m_used) + { + return; + } + m_iconMargins = margins; +} + + +void Toast::setIconMarginLeft(int margin) +{ + if (m_used) + { + return; + } + m_iconMargins.setLeft(margin); +} + + +void Toast::setIconMarginTop(int margin) +{ + if (m_used) + { + return; + } + m_iconMargins.setTop(margin); +} + + +void Toast::setIconMarginRight(int margin) +{ + if (m_used) + { + return; + } + m_iconMargins.setRight(margin); +} + + +void Toast::setIconMarginBottom(int margin) +{ + if (m_used) + { + return; + } + m_iconMargins.setBottom(margin); +} + + +void Toast::setIconSectionMargins(QMargins margins) +{ + if (m_used) + { + return; + } + m_iconSectionMargins = margins; +} + + +void Toast::setIconSectionMarginLeft(int margin) +{ + if (m_used) + { + return; + } + m_iconSectionMargins.setLeft(margin); +} + + +void Toast::setIconSectionMarginTop(int margin) +{ + if (m_used) + { + return; + } + m_iconSectionMargins.setTop(margin); +} + + +void Toast::setIconSectionMarginRight(int margin) +{ + if (m_used) + { + return; + } + m_iconSectionMargins.setRight(margin); +} + + +void Toast::setIconSectionMarginBottom(int margin) +{ + if (m_used) + { + return; + } + m_iconSectionMargins.setBottom(margin); +} + + +void Toast::setTextSectionMargins(QMargins margins) +{ + if (m_used) + { + return; + } + m_textSectionMargins = margins; +} + + +void Toast::setTextSectionMarginLeft(int margin) +{ + if (m_used) + { + return; + } + m_textSectionMargins.setLeft(margin); +} + + +void Toast::setTextSectionMarginTop(int margin) +{ + if (m_used) + { + return; + } + m_textSectionMargins.setTop(margin); +} + + +void Toast::setTextSectionMarginRight(int margin) +{ + if (m_used) + { + return; + } + m_textSectionMargins.setRight(margin); +} + + +void Toast::setTextSectionMarginBottom(int margin) +{ + if (m_used) + { + return; + } + m_textSectionMargins.setBottom(margin); +} + + +void Toast::setCloseButtonMargins(QMargins margins) +{ + if (m_used) + { + return; + } + m_closeButtonMargins = margins; +} + + +void Toast::setCloseButtonMarginLeft(int margin) +{ + if (m_used) + { + return; + } + m_closeButtonMargins.setLeft(margin); +} + + +void Toast::setCloseButtonMarginTop(int margin) +{ + if (m_used) + { + return; + } + m_closeButtonMargins.setTop(margin); +} + + +void Toast::setCloseButtonMarginRight(int margin) +{ + if (m_used) + { + return; + } + m_closeButtonMargins.setRight(margin); +} + + +void Toast::setCloseButtonMarginBottom(int margin) +{ + if (m_used) + { + return; + } + m_closeButtonMargins.setBottom(margin); +} + + +void Toast::setTextSectionSpacing(int spacing) +{ + if (m_used) + { + return; + } + m_textSectionSpacing = spacing; +} + + +void Toast::setFixedSize(QSize size) +{ + setMinimumSize(size); + setMaximumSize(size); +} + + +void Toast::setFixedSize(int width, int height) +{ + setMinimumSize(width, height); + setMaximumSize(width, height); +} + + +void Toast::setFixedWidth(int width) +{ + setMinimumWidth(width); + setMaximumWidth(width); +} + +void Toast::setFixedHeight(int height) +{ + setMinimumHeight(height); + setMaximumHeight(height); +} + +void Toast::applyPreset(Preset preset) +{ + if (m_used) + { + return; + } + + if (preset == Preset::Success) + { + setIcon(Icon::Success); + setIconColor(sc_successAccentColor); + setDurationBarColor(sc_successAccentColor); + } + else if (preset == Preset::Warning) + { + setIcon(Icon::Warning); + setIconColor(sc_warningAccentColor); + setDurationBarColor(sc_warningAccentColor); + } + else if (preset == Preset::Error) + { + setIcon(Icon::Error); + setIconColor(sc_errorAccentColor); + setDurationBarColor(sc_errorAccentColor); + } + else if (preset == Preset::Information) + { + setIcon(Icon::Information); + setIconColor(sc_informationAccentColor); + setDurationBarColor(sc_informationAccentColor); + } + + if ( +#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) + (QGuiApplication::styleHints() && + QGuiApplication::styleHints()->colorScheme() == Qt::ColorScheme::Dark) || +#endif + VeyonCore::useDarkMode()) + { + setBackgroundColor(sc_defaultBackgroundColorDark); + setCloseButtonIconColor(sc_defaultCloseButtonIconColorDark); + setIconSeparatorColor(sc_defaultIconSeparatorColorDark); + setTitleColor(sc_defaultTitleColorDark); + setTextColor(sc_defaultTextColorDark); + } + else + { + setBackgroundColor(sc_defaultBackgroundColor); + setCloseButtonIconColor(sc_defaultCloseButtonIconColor); + setIconSeparatorColor(sc_defaultIconSeparatorColor); + setTitleColor(sc_defaultTitleColor); + setTextColor(sc_defaultTextColor); + } + + setShowDurationBar(true); + setShowIcon(true); + setShowIconSeparator(true); + setIconSeparatorWidth(2); +} + + +void Toast::show() +{ + // Check if already used + if (m_used) + { + return; + } + + // If max notifications on screen not reached, show notification + if (s_maximumOnScreen > int(s_currentlyShown.size())) + { + m_used = true; + s_currentlyShown.push_back(this); + + // Setup UI + setupUI(); + + // Start duration timer + if (m_duration != 0) + { + m_durationTimer->start(m_duration); + } + + // Start duration bar update timer + if (m_duration != 0 && m_showDurationBar) + { + m_durationBarTimer->start(sc_durationBarUpdateInterval); + } + + // Calculate position and show + QPoint position = calculatePosition(); + + // If not first toast on screen, also do a fade down / up animation + if (s_currentlyShown.size() > 1) + { + // Calculate offset if predecessor toast is still in fade down / up animation + Toast* predecessorToast = getPredecessorToast(); + QPoint predecessorTarget = predecessorToast->calculatePosition(); + int predecessorTargetDifferenceY = abs(predecessorToast->y() - predecessorTarget.y()); + + // Calculate start position of fade down / up animation based on position + if (s_position == Position::BottomRight + || s_position == Position::BottomLeft + || s_position == Position::BottomMiddle) + { + move(position.x(), + position.y() - (int)(height() / 1.5) - predecessorTargetDifferenceY); + } + else if (s_position == Position::TopRight + || s_position == Position::TopLeft + || s_position == Position::TopMiddle + || s_position == Position::Center) + { + move(position.x(), + position.y() + (int)(height() / 1.5) + predecessorTargetDifferenceY); + } + + // Start fade down / up animation + QPropertyAnimation* posAnimation = new QPropertyAnimation(this, "pos"); + posAnimation->setEndValue(QPoint(position.x(), position.y())); + posAnimation->setDuration(m_fadeInDuration); + posAnimation->start(QAbstractAnimation::DeleteWhenStopped); + } + else + { + move(position.x(), position.y()); + } + + // Fade in + QDialog::show(); + QPropertyAnimation* fadeInAnimation = new QPropertyAnimation(m_opacityEffect, "opacity"); + fadeInAnimation->setDuration(m_fadeInDuration); + fadeInAnimation->setStartValue(0); + fadeInAnimation->setEndValue(1); + fadeInAnimation->start(QAbstractAnimation::DeleteWhenStopped); + + // Make sure title bar of parent is not grayed out + if (m_parent) + { + m_parent->activateWindow(); + } + + // Update every other currently shown notification + for (Toast* toast : s_currentlyShown) + { + toast->updatePositionXY(); + } + } + else + { + // Add notification to queue instead + s_queue.push_back(this); + } +} + +void Toast::hide() +{ + if (!m_fadingOut) + { + if (m_duration != 0) + { + m_durationTimer->stop(); + } + fadeOut(); + } +} + +void Toast::hide_() +{ + close(); + + int index = 0; + for (Toast* toast : s_currentlyShown) + { + if (toast == this) + { + s_currentlyShown.erase(s_currentlyShown.begin() + index); + m_elapsedTime = 0; + m_fadingOut = false; + + // Emit signal + Q_EMIT closed(); + + // Update every other currently shown notification + for (Toast* toast : s_currentlyShown) + { + toast->updatePositionY(); + } + + // Show next item from queue after updating + QTimer::singleShot(m_fadeInDuration, this, &Toast::deleteAndShowNextInQueue); + + break; + }; + index++; + } +} + +void Toast::enterEvent(EnterEvent* event) +{ + Q_UNUSED(event) + + // Reset timer if hovered and resetting is enabled + if (m_duration != 0 && m_durationTimer->isActive() && m_resetDurationOnHover) + { + m_durationTimer->stop(); + + // Reset duration bar if enabled + if (m_showDurationBar) + { + m_durationBarTimer->stop(); + m_durationBarChunk->setFixedWidth(m_notification->width()); + m_elapsedTime = 0; + } + } +} + +void Toast::leaveEvent(QEvent* event) +{ + Q_UNUSED(event) + + // Start timer again when leaving notification and reset is enabled + if (m_duration != 0 && !m_durationTimer->isActive() && m_resetDurationOnHover) + { + m_durationTimer->start(m_duration); + + // Restart duration bar animation if enabled + if (m_showDurationBar) + { + m_durationBarTimer->start(sc_durationBarUpdateInterval); + } + } +} + +void Toast::fadeOut() +{ + m_fadingOut = true; + QPropertyAnimation* fadeOutAnimation = new QPropertyAnimation(m_opacityEffect, "opacity"); + fadeOutAnimation->setDuration(m_fadeOutDuration); + fadeOutAnimation->setStartValue(1); + fadeOutAnimation->setEndValue(0); + connect(fadeOutAnimation, &QPropertyAnimation::finished, this, &Toast::hide_); + fadeOutAnimation->start(QAbstractAnimation::DeleteWhenStopped); +} + +void Toast::updateDurationBar() +{ + m_elapsedTime += sc_durationBarUpdateInterval; + + if (m_elapsedTime >= m_duration) + { + m_durationBarTimer->stop(); + return; + } + double newChunkWidth = floor(m_durationBarContainer->width() + - (double)m_elapsedTime / (double)m_duration * m_durationBarContainer->width()); + m_durationBarChunk->setFixedWidth(newChunkWidth); +} + +void Toast::showNextInQueue() +{ + if (s_queue.size() > 0) + { + Toast* nextToast = s_queue.front(); + s_queue.pop_front(); + nextToast->show(); + } +} + +void Toast::setupUI() +{ + // Update stylesheet + updateStylesheet(); + + // Calculate title and text width and height + QFontMetrics* titleFontMetrics = new QFontMetrics(m_titleFont); + int titleWidth = titleFontMetrics->boundingRect(m_title).width() + 1; + int titleHeight = titleFontMetrics->boundingRect(m_title).height(); + delete titleFontMetrics; + + QFontMetrics* textFontMetrics = new QFontMetrics(m_textFont); + int textWidth = textFontMetrics->boundingRect(m_text).width() + 1; + int textHeight = textFontMetrics->boundingRect(m_text).height(); + delete textFontMetrics; + + int textSectionSpacing = m_title.isEmpty() || m_text.isEmpty() ? 0 : m_textSectionSpacing; + + int textSectionHeight = m_textSectionMargins.top() + titleHeight + + textSectionSpacing + textHeight + m_textSectionMargins.bottom(); + + // Calculate duration bar height + int durationBarHeight = m_showDurationBar ? m_durationBarContainer->height() : 0; + + // Calculate icon section width and height + int iconSectionWidth = 0; + int iconSectionHeight = 0; + + if (m_showIcon) + { + iconSectionWidth = m_iconSectionMargins.left() + m_iconMargins.left() + + m_iconWidget->width() + m_iconMargins.right() + + m_iconSeparator->width() + m_iconSectionMargins.right(); + iconSectionHeight = m_iconSectionMargins.top() + m_iconMargins.top() + + m_iconWidget->height() + m_iconMargins.bottom() + m_iconSectionMargins.bottom(); + } + + // Calculate close button section size + int closeButtonWidth = m_showCloseButton ? m_closeButton->width() : 0; + int closeButtonHeight = m_showCloseButton ? m_closeButton->height() : 0; + QMargins closeButtonMargins = m_showCloseButton ? m_closeButtonMargins : QMargins(0, 0, 0, 0); + + int closeButtonSectionHeight = m_closeButtonMargins.top() + + closeButtonHeight + m_closeButtonMargins.bottom(); + + // Calculate needed width and height + int width = m_margins.left() + iconSectionWidth + m_textSectionMargins.left() + + std::max(titleWidth, textWidth) + m_textSectionMargins.right() + + closeButtonMargins.left() + closeButtonWidth + + closeButtonMargins.right() + m_margins.right(); + + int height = m_margins.top() + std::max({iconSectionHeight, textSectionHeight, + closeButtonSectionHeight}) + m_margins.bottom() + durationBarHeight; + + int forcedAdditionalHeight = 0; + int forcedReducedHeight = 0; + + // Handle width greater than maximum width + if (width > maximumWidth()) + { + // Enable line break for title and text and recalculate size + int newTitleWidth = std::max(titleWidth, textWidth) - (width - maximumWidth()); + if (newTitleWidth > 0) + { + titleWidth = newTitleWidth; + } + + int newTextWidth = std::max(titleWidth, textWidth) - (width - maximumWidth()); + if (newTextWidth > 0) + { + textWidth = newTextWidth; + } + + m_titleLabel->setMinimumWidth(titleWidth); + m_titleLabel->setWordWrap(true); + if (m_title.isEmpty() == false) + { + titleHeight = m_titleLabel->sizeHint().height(); + } + m_titleLabel->setFixedSize(titleWidth, titleHeight); + + m_textLabel->setMinimumWidth(textWidth); + m_textLabel->setWordWrap(true); + if (m_text.isEmpty() == false) + { + textHeight = m_textLabel->sizeHint().height(); + } + m_textLabel->setFixedSize(textWidth, textHeight); + + // Recalculate width and height + width = maximumWidth(); + + textSectionHeight = m_textSectionMargins.top() + titleHeight + + textSectionSpacing + textHeight + m_textSectionMargins.bottom(); + + height = m_margins.top() + std::max({iconSectionHeight, textSectionHeight, + closeButtonSectionHeight}) + m_margins.bottom() + durationBarHeight; + } + + // Handle height less than minimum height + if (height < minimumHeight()) + { + // Enable word wrap for title and text labels + m_titleLabel->setWordWrap(true); + m_textLabel->setWordWrap(true); + + // Calculate height with initial label width + titleWidth = m_titleLabel->fontMetrics().boundingRect(QRect(0, 0, 0, 0), + Qt::TextFlag::TextWordWrap, m_titleLabel->text()).width(); + + textWidth = m_textLabel->fontMetrics().boundingRect(QRect(0, 0, 0, 0), + Qt::TextFlag::TextWordWrap, m_textLabel->text()).width(); + + int tempWidth = std::max(titleWidth, textWidth); + + titleWidth = m_titleLabel->fontMetrics().boundingRect(QRect(0, 0, tempWidth, 0), + Qt::TextFlag::TextWordWrap, m_titleLabel->text()).width(); + if (m_title.isEmpty() == false) + { + titleHeight = m_titleLabel->fontMetrics().boundingRect(QRect(0, 0, tempWidth, 0), + Qt::TextFlag::TextWordWrap, m_titleLabel->text()).height(); + } + + textWidth = m_textLabel->fontMetrics().boundingRect(QRect(0, 0, tempWidth, 0), + Qt::TextFlag::TextWordWrap, m_textLabel->text()).width(); + if (m_text.isEmpty() == false) + { + textHeight = m_textLabel->fontMetrics().boundingRect(QRect(0, 0, tempWidth, 0), + Qt::TextFlag::TextWordWrap, m_textLabel->text()).height(); + } + + textSectionHeight = m_textSectionMargins.top() + titleHeight + + textSectionSpacing + textHeight + m_textSectionMargins.bottom(); + + height = m_margins.top() + std::max({ iconSectionHeight, textSectionHeight, + closeButtonSectionHeight }) + m_margins.bottom() + durationBarHeight; + + while (tempWidth <= width) + { + // Recalculate height with different text widths to find optimal value + int tempTitleWidth = m_titleLabel->fontMetrics().boundingRect(QRect(0, 0, tempWidth, 0), + Qt::TextFlag::TextWordWrap, m_titleLabel->text()).width(); + + int tempTitleHeight = m_titleLabel->fontMetrics().boundingRect(QRect(0, 0, tempWidth, 0), + Qt::TextFlag::TextWordWrap, m_titleLabel->text()).height(); + + int tempTextWidth = m_textLabel->fontMetrics().boundingRect(QRect(0, 0, tempWidth, 0), + Qt::TextFlag::TextWordWrap, m_textLabel->text()).width(); + + int tempTextHeight = m_textLabel->fontMetrics().boundingRect(QRect(0, 0, tempWidth, 0), + Qt::TextFlag::TextWordWrap, m_textLabel->text()).height(); + + if (m_title.isEmpty()) + { + tempTitleHeight = 0; + } + + if (m_text.isEmpty()) + { + tempTextHeight = 0; + } + + int tempTextSectionHeight = m_textSectionMargins.top() + tempTitleHeight + + textSectionSpacing + tempTextHeight + m_textSectionMargins.bottom(); + + int tempHeight = m_margins.top() + std::max({ iconSectionHeight, tempTextSectionHeight, + closeButtonSectionHeight }) + m_margins.bottom() + durationBarHeight; + + // Store values if calculated height is greater than or equal to min height + if (tempHeight >= minimumHeight()) + { + titleWidth = tempTitleWidth; + titleHeight = tempTitleHeight; + textWidth = tempTextWidth; + textHeight = tempTextHeight; + textSectionHeight = tempTextSectionHeight; + height = tempHeight; + tempWidth += 1; + } + else + { + // Exit loop if calculated height is less than min height + break; + } + } + + // Recalculate width + width = m_margins.left() + iconSectionWidth + m_textSectionMargins.left() + + std::max(titleWidth, textWidth) + m_textSectionMargins.right() + + closeButtonMargins.left() + closeButtonWidth + + closeButtonMargins.right() + m_margins.right(); + + // If min height not met, set height to min height + if (height < minimumHeight()) + { + forcedAdditionalHeight = minimumHeight() - height; + height = minimumHeight(); + } + } + + // Handle width less than minimum width + if (width < minimumWidth()) + { + width = minimumWidth(); + } + + // Handle height greater than maximum height + if (height > maximumHeight()) + { + forcedReducedHeight = height - maximumHeight(); + height = maximumHeight(); + } + + // Calculate width and height including space for drop shadow + int totalWidth = width + sc_dropShadowSize * 2; + int totalHeight = height + sc_dropShadowSize * 2; + + // Resize drop shadow + m_dropShadowLayer1->resize(totalWidth, totalHeight); + m_dropShadowLayer1->move(0, 0); + m_dropShadowLayer2->resize(totalWidth - 2, totalHeight - 2); + m_dropShadowLayer2->move(1, 1); + m_dropShadowLayer3->resize(totalWidth - 4, totalHeight - 4); + m_dropShadowLayer3->move(2, 2); + m_dropShadowLayer4->resize(totalWidth - 6, totalHeight - 6); + m_dropShadowLayer4->move(3, 3); + m_dropShadowLayer5->resize(totalWidth - 8, totalHeight - 8); + m_dropShadowLayer5->move(4, 4); + + // Resize window + QDialog::setFixedSize(totalWidth, totalHeight); + m_notification->setFixedSize(width, height); + m_notification->move(sc_dropShadowSize, sc_dropShadowSize); + m_notification->raise(); + + // Calculate difference between height and height of icon section + int heightIconSectionHeightDifference = std::max({ iconSectionHeight, + textSectionHeight, closeButtonSectionHeight }) - iconSectionHeight; + + if (m_showIcon) + { + // Move icon + m_iconWidget->move(m_margins.left() + m_iconSectionMargins.left()+ m_iconMargins.left(), + m_margins.top() + m_iconSectionMargins.top() + m_iconMargins.top() + + ceil(heightIconSectionHeightDifference / 2) - floor(forcedReducedHeight / 2)); + + // Move and resize icon separator + m_iconSeparator->setFixedHeight(textSectionHeight); + m_iconSeparator->move(m_margins.left() + m_iconSectionMargins.left() + m_iconMargins.left() + + m_iconWidget->width() + m_iconMargins.right(), m_margins.top() + m_iconSectionMargins.top() + + ceil(forcedAdditionalHeight / 2) - floor(forcedReducedHeight / 2)); + } + else + { + // Hide icon section + m_iconWidget->setVisible(false); + m_iconSeparator->setVisible(false); + } + + // Calculate difference between height and height of text section + int heightTextSectionHeightDifference = std::max({iconSectionHeight, + textSectionHeight, closeButtonSectionHeight}) - textSectionHeight; + + // Resize title and text labels + m_titleLabel->setFixedSize(std::max(titleWidth, textWidth), titleHeight); + m_textLabel->setFixedSize(std::max(titleWidth, textWidth), textHeight); + + // Move title and text labels + if (m_showIcon) + { + m_titleLabel->move(m_margins.left() + m_iconSectionMargins.left() + + m_iconMargins.left() + m_iconWidget->width() + m_iconMargins.right() + + m_iconSeparator->width() + m_iconSectionMargins.right() + m_textSectionMargins.left(), + m_margins.top() + m_textSectionMargins.top() + ceil(heightTextSectionHeightDifference / 2) + + ceil(forcedAdditionalHeight / 2) - floor(forcedReducedHeight / 2)); + + m_textLabel->move(m_margins.left() + m_iconSectionMargins.left() + + m_iconMargins.left() + m_iconWidget->width() + m_iconMargins.right() + + m_iconSeparator->width() + m_iconSectionMargins.right() + m_textSectionMargins.left(), + m_margins.top() + m_textSectionMargins.top() + titleHeight + + textSectionSpacing + ceil(heightTextSectionHeightDifference / 2) + + ceil(forcedAdditionalHeight / 2) - floor(forcedReducedHeight / 2)); + } + else { + // Position is different if icon hidden + m_titleLabel->move(m_margins.left() + m_textSectionMargins.left(), + m_margins.top() + m_textSectionMargins.top() + ceil(heightTextSectionHeightDifference / 2) + + ceil(forcedAdditionalHeight / 2) - floor(forcedReducedHeight / 2)); + + m_textLabel->move(m_margins.left() + m_textSectionMargins.left(), + m_margins.top() + m_textSectionMargins.top() + titleHeight + + textSectionSpacing + ceil(heightTextSectionHeightDifference / 2) + + ceil(forcedAdditionalHeight / 2) - floor(forcedReducedHeight / 2)); + } + + // Adjust label position if either title or text is empty + if (m_title.isEmpty() && m_text.isEmpty() == false) + { + m_textLabel->move(m_textLabel->x(), + (int)((height - textHeight - durationBarHeight) / 2)); + } + else if (m_title.isEmpty() == false && m_text.isEmpty()) + { + m_titleLabel->move(m_titleLabel->x(), + (int)((height - titleHeight - durationBarHeight) / 2)); + } + + // Move close button to top, middle, or bottom position + if (m_closeButtonAlignment == ButtonAlignment::Top) + { + m_closeButton->move(width - closeButtonWidth - closeButtonMargins.right() + - m_margins.right(), m_margins.top() + closeButtonMargins.top()); + } + else if (m_closeButtonAlignment == ButtonAlignment::Middle) + { + m_closeButton->move(width - closeButtonWidth - closeButtonMargins.right() + - m_margins.right(), ceil((height - closeButtonHeight - durationBarHeight) / 2)); + } + else if (m_closeButtonAlignment == ButtonAlignment::Bottom) + { + m_closeButton->move(width - closeButtonWidth - closeButtonMargins.right() + - m_margins.right(), height - closeButtonHeight - m_margins.bottom() + - closeButtonMargins.bottom() - durationBarHeight); + } + + // Hide close button if disabled + if (!m_showCloseButton) + { + m_closeButton->setVisible(false); + } + + // Resize, move, and show duration bar if enabled + if (m_showDurationBar) + { + m_durationBarContainer->setFixedWidth(width); + m_durationBarContainer->move(0, height - durationBarHeight); + m_durationBar->setFixedWidth(width); + m_durationBarChunk->setFixedWidth(width); + } + else { + m_durationBarContainer->setVisible(false); + } +} + +QPoint Toast::calculatePosition() +{ + // Calculate vertical space taken up by all the currently showing notifications + int offsetY = 0; + + for (Toast* toast : s_currentlyShown) + { + if (toast == this) + { + break; + } + offsetY += toast->m_notification->height() + s_spacing; + } + + // Get screen + QScreen* primaryScreen = QGuiApplication::primaryScreen(); + QScreen* currentScreen = nullptr; + + if (s_fixedScreen) + { + currentScreen = s_fixedScreen; + } + else if (s_alwaysOnMainScreen || !m_parent) + { + currentScreen = primaryScreen; + } + else + { + QList screens = QGuiApplication::screens(); + + for (QScreen* screen : screens) + { + if (m_parent->geometry().intersects(screen->geometry())) + { + if (!currentScreen) + { + currentScreen = screen; + } + else + { + currentScreen = primaryScreen; + break; + } + } + } + } + + // Calculate x and y position of notification + int x = 0; + int y = 0; + + if (s_position == Position::BottomRight) + { + x = currentScreen->geometry().width() - m_notification->width() + - s_offsetX + currentScreen->geometry().x(); + y = currentScreen->geometry().height() - m_notification->height() + - s_offsetY + currentScreen->geometry().y() - offsetY; + } + else if (s_position == Position::BottomLeft) + { + x = currentScreen->geometry().x() + s_offsetX; + y = currentScreen->geometry().height() - m_notification->height() + - s_offsetY + currentScreen->geometry().y() - offsetY; + } + else if (s_position == Position::BottomMiddle) + { + x = (int)(currentScreen->geometry().x() + + currentScreen->geometry().width() / 2 - m_notification->width() / 2); + y = currentScreen->geometry().height() - m_notification->height() + - s_offsetY + currentScreen->geometry().y() - offsetY; + } + else if (s_position == Position::TopRight) + { + x = currentScreen->geometry().width() - m_notification->width() + - s_offsetX + currentScreen->geometry().x(); + y = currentScreen->geometry().y() + s_offsetY + offsetY; + } + else if (s_position == Position::TopLeft) + { + x = currentScreen->geometry().x() + s_offsetX; + y = currentScreen->geometry().y() + s_offsetY + offsetY; + } + else if (s_position == Position::TopMiddle) + { + x = (int)(currentScreen->geometry().x() + + currentScreen->geometry().width() / 2 - m_notification->width() / 2); + y = currentScreen->geometry().y() + s_offsetY + offsetY; + } + else if (s_position == Position::Center) + { + x = (int)(currentScreen->geometry().x() + + currentScreen->geometry().width() / 2 - m_notification->width() / 2); + y = (int)(currentScreen->geometry().y() + currentScreen->geometry().height() / 2 + - m_notification->height() / 2 + offsetY); + } + + x -= sc_dropShadowSize; + y -= sc_dropShadowSize; + + return QPoint(x, y); +} + +void Toast::updatePositionXY() +{ + QPoint position = calculatePosition(); + + // Animate position change + QPropertyAnimation* posAnimation = new QPropertyAnimation(this, "pos"); + posAnimation->setEndValue(position); + posAnimation->setDuration(sc_updatePositionDuration); + posAnimation->start(QAbstractAnimation::DeleteWhenStopped); +} + +void Toast::updatePositionX() +{ + QPoint position = calculatePosition(); + + // Animate position change + QPropertyAnimation* posAnimation = new QPropertyAnimation(this, "pos"); + posAnimation->setEndValue(QPoint(position.x(), y())); + posAnimation->setDuration(sc_updatePositionDuration); + posAnimation->start(); +} + +void Toast::updatePositionY() +{ + QPoint position = calculatePosition(); + + // Animate position change + QPropertyAnimation* posAnimation = new QPropertyAnimation(this, "pos"); + posAnimation->setEndValue(QPoint(x(), position.y())); + posAnimation->setDuration(sc_updatePositionDuration); + posAnimation->start(QAbstractAnimation::DeleteWhenStopped); +} + +void Toast::updateStylesheet() +{ + m_notification->setStyleSheet(QStringLiteral("background: %1;" + "border-radius: %2px; ").arg(m_backgroundColor.name()).arg(m_borderRadius)); + + m_durationBar->setStyleSheet(QStringLiteral("background: rgba(%1, %2, %3, 100);" + "border-radius: %4px;").arg(m_durationBarColor.red()) + .arg(m_durationBarColor.green()).arg(m_durationBarColor.blue()).arg(m_borderRadius)); + + m_durationBarChunk->setStyleSheet(QStringLiteral("background: rgba(%1, %2, %3, 255);" + "border-bottom-left-radius: %4px; border-bottom-right-radius: %5px;") + .arg(m_durationBarColor.red()).arg(m_durationBarColor.green()) + .arg(m_durationBarColor.blue()).arg(m_borderRadius) + .arg(m_duration == 0 ? m_borderRadius : 0)); + + m_iconSeparator->setStyleSheet(QStringLiteral("background: %1;").arg(m_iconSeparatorColor.name())); + + m_titleLabel->setStyleSheet(QStringLiteral("color: %1;").arg(m_titleColor.name())); + m_textLabel->setStyleSheet(QStringLiteral("color: %1;").arg(m_textColor.name())); +} + +Toast* Toast::getPredecessorToast() +{ + Toast* predecessorToast = nullptr; + + for (Toast* toast : s_currentlyShown) + { + if (toast == this) + { + return predecessorToast; + } + predecessorToast = toast; + } + + return predecessorToast; +} + +QImage Toast::recolorImage(QImage image, QColor color) +{ + // Loop through every pixel + for (int x = 0; x < image.width(); x++) { + for (int y = 0; y < image.height(); y++) { + // Get current color of the pixel + QColor currentColor = image.pixelColor(x, y); + + // Replace the rgb values with rgb of new color and keep alpha the same + QColor newColor = QColor::fromRgba(qRgba(color.red(), color.green(), + color.blue(), currentColor.alpha())); + image.setPixelColor(x, y, newColor); + } + } + return image; +} + +QPixmap Toast::getIconFromEnum(Icon enumIcon) +{ + auto base = QStringLiteral(":/core/toast-%1"); + + if (enumIcon == Icon::Success) + { + return QPixmap(base.arg(QStringLiteral("success.png"))); + } + else if (enumIcon == Icon::Warning) + { + return QPixmap(base.arg(QStringLiteral("warning.png"))); + } + else if (enumIcon == Icon::Error) + { + return QPixmap(base.arg(QStringLiteral("error.png"))); + } + else if (enumIcon == Icon::Information) + { + return QPixmap(base.arg(QStringLiteral("information.png"))); + } + else if (enumIcon == Icon::Close) + { + return QPixmap(base.arg(QStringLiteral("close.png"))); + } + return QPixmap(); +} + +void Toast::updateCurrentlyShowingPositionXY() +{ + for (Toast* toast : s_currentlyShown) + { + toast->updatePositionXY(); + } +} + +void Toast::updateCurrentlyShowingPositionX() +{ + for (Toast* toast : s_currentlyShown) + { + toast->updatePositionX(); + } +} + +void Toast::updateCurrentlyShowingPositionY() +{ + for (Toast* toast : s_currentlyShown) + { + toast->updatePositionY(); + } +} + +void Toast::deleteAndShowNextInQueue() +{ + showNextInQueue(); + deleteLater(); +} diff --git a/core/src/Toast.h b/core/src/Toast.h new file mode 100644 index 000000000..badd0b6be --- /dev/null +++ b/core/src/Toast.h @@ -0,0 +1,319 @@ +/* + * File based on https://github.com/niklashenning/qt-toast/blob/master/src/Toast.h + * + * MIT License + + * Copyright (c) 2024 Niklas Henning + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#include +#include + +class QGraphicsOpacityEffect; +class QLabel; + +class Toast : public QDialog +{ + Q_OBJECT +public: + enum class Preset + { + Success, + Warning, + Error, + Information, + }; + + enum class Icon + { + Success, + Warning, + Error, + Information, + Close + }; + + enum class Position + { + BottomLeft, + BottomMiddle, + BottomRight, + TopLeft, + TopMiddle, + TopRight, + Center + }; + + enum class ButtonAlignment + { + Top, + Middle, + Bottom + }; + + Toast(QWidget* parent = nullptr); + ~Toast(); + + static int getMaximumOnScreen(); + static int getSpacing(); + static QPoint getOffset(); + static int getOffsetX(); + static int getOffsetY(); + static bool isAlwaysOnMainScreen(); + static QScreen* getFixedScreen(); + static Position getPosition(); + static int getCount(); + static int getVisibleCount(); + static int getQueuedCount(); + int getDuration(); + bool isShowDurationBar(); + QString getTitle(); + QString getText(); + QPixmap getIcon(); + bool isShowIcon(); + QSize getIconSize(); + bool isShowIconSeparator(); + int getIconSeparatorWidth(); + QPixmap getCloseButtonIcon(); + bool isShowCloseButton(); + QSize getCloseButtonIconSize(); + int getCloseButtonWidth(); + int getCloseButtonHeight(); + QSize getCloseButtonSize(); + ButtonAlignment getCloseButtonAlignment(); + int getFadeInDuration(); + int getFadeOutDuration(); + bool isResetDurationOnHover(); + bool isStayOnTop(); + int getBorderRadius(); + QColor getBackgroundColor(); + QColor getTitleColor(); + QColor getTextColor(); + QColor getIconColor(); + QColor getIconSeparatorColor(); + QColor getCloseButtonIconColor(); + QColor getDurationBarColor(); + QFont getTitleFont(); + QFont getTextFont(); + QMargins getMargins(); + QMargins getIconMargins(); + QMargins getIconSectionMargins(); + QMargins getTextSectionMargins(); + QMargins getCloseButtonMargins(); + int getTextSectionSpacing(); + + static void setMaximumOnScreen(int maximum); + static void setSpacing(int spacing); + static void setOffset(int x, int y); + static void setOffsetX(int offsetX); + static void setOffsetY(int offsetY); + static void setAlwaysOnMainScreen(bool enabled); + static void setFixedScreen(QScreen* screen); + static void setPosition(Position position); + static void reset(); + void setDuration(int duration); + void setShowDurationBar(bool enabled); + void setTitle(QString title); + void setText(QString text); + void setIcon(QPixmap icon); + void setIcon(Icon icon); + void setShowIcon(bool enabled); + void setIconSize(QSize size); + void setShowIconSeparator(bool enabled); + void setIconSeparatorWidth(int width); + void setCloseButtonIcon(QPixmap icon); + void setCloseButtonIcon(Icon icon); + void setShowCloseButton(bool enabled); + void setCloseButtonIconSize(QSize size); + void setCloseButtonSize(QSize size); + void setCloseButtonWidth(int width); + void setCloseButtonHeight(int height); + void setCloseButtonAlignment(ButtonAlignment alignment); + void setFadeInDuration(int duration); + void setFadeOutDuration(int duration); + void setResetDurationOnHover(bool enabled); + void setStayOnTop(bool enabled); + void setBorderRadius(int borderRadius); + void setBackgroundColor(QColor color); + void setTitleColor(QColor color); + void setTextColor(QColor color); + void setIconColor(QColor color); + void setIconSeparatorColor(QColor color); + void setCloseButtonIconColor(QColor color); + void setDurationBarColor(QColor color); + void setTitleFont(QFont font); + void setTextFont(QFont font); + void setMargins(QMargins margins); + void setMarginLeft(int margin); + void setMarginTop(int margin); + void setMarginRight(int margin); + void setMarginBottom(int margin); + void setIconMargins(QMargins margins); + void setIconMarginLeft(int margin); + void setIconMarginTop(int margin); + void setIconMarginRight(int margin); + void setIconMarginBottom(int margin); + void setIconSectionMargins(QMargins margins); + void setIconSectionMarginLeft(int margin); + void setIconSectionMarginTop(int margin); + void setIconSectionMarginRight(int margin); + void setIconSectionMarginBottom(int margin); + void setTextSectionMargins(QMargins margins); + void setTextSectionMarginLeft(int margin); + void setTextSectionMarginTop(int margin); + void setTextSectionMarginRight(int margin); + void setTextSectionMarginBottom(int margin); + void setCloseButtonMargins(QMargins margins); + void setCloseButtonMarginLeft(int margin); + void setCloseButtonMarginTop(int margin); + void setCloseButtonMarginRight(int margin); + void setCloseButtonMarginBottom(int margin); + void setTextSectionSpacing(int spacing); + void setFixedSize(QSize size); + void setFixedSize(int width, int height); + void setFixedWidth(int width); + void setFixedHeight(int height); + void applyPreset(Preset preset); + + +public Q_SLOTS: + void show(); + void hide(); + +Q_SIGNALS: + void closed(); + +protected: +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + using EnterEvent = QEnterEvent; +#else + using EnterEvent = QEvent; +#endif + void enterEvent(EnterEvent* event) override; + void leaveEvent(QEvent* event) override; + +private Q_SLOTS: + void hide_(); + void fadeOut(); + void updateDurationBar(); + void deleteAndShowNextInQueue(); + +private: + static int s_maximumOnScreen; + static int s_spacing; + static int s_offsetX; + static int s_offsetY; + static bool s_alwaysOnMainScreen; + static QScreen* s_fixedScreen; + static Position s_position; + static std::deque s_currentlyShown; + static std::deque s_queue; + int m_duration; + bool m_showDurationBar; + QString m_title; + QString m_text; + QPixmap m_icon; + bool m_showIcon; + QSize m_iconSize; + bool m_showIconSeparator; + int m_iconSeparatorWidth; + QPixmap m_closeButtonIcon; + bool m_showCloseButton; + QSize m_closeButtonIconSize; + QSize m_closeButtonSize; + ButtonAlignment m_closeButtonAlignment; + int m_fadeInDuration; + int m_fadeOutDuration; + bool m_resetDurationOnHover; + bool m_stayOnTop; + int m_borderRadius; + QColor m_backgroundColor; + QColor m_titleColor; + QColor m_textColor; + QColor m_iconColor; + QColor m_iconSeparatorColor; + QColor m_closeButtonIconColor; + QColor m_durationBarColor; + QFont m_titleFont; + QFont m_textFont; + QMargins m_margins; + QMargins m_iconMargins; + QMargins m_iconSectionMargins; + QMargins m_textSectionMargins; + QMargins m_closeButtonMargins; + int m_textSectionSpacing; + int m_elapsedTime; + bool m_fadingOut; + bool m_used; + QWidget* m_parent; + QLabel* m_notification; + QWidget* m_dropShadowLayer1; + QWidget* m_dropShadowLayer2; + QWidget* m_dropShadowLayer3; + QWidget* m_dropShadowLayer4; + QWidget* m_dropShadowLayer5; + QGraphicsOpacityEffect* m_opacityEffect; + QPushButton* m_closeButton; + QLabel* m_titleLabel; + QLabel* m_textLabel; + QPushButton* m_iconWidget; + QWidget* m_iconSeparator; + QWidget* m_durationBarContainer; + QWidget* m_durationBar; + QWidget* m_durationBarChunk; + QTimer* m_durationTimer; + QTimer* m_durationBarTimer; + + void setupUI(); + void updatePositionXY(); + void updatePositionX(); + void updatePositionY(); + void updateStylesheet(); + QPoint calculatePosition(); + Toast* getPredecessorToast(); + static QImage recolorImage(QImage image, QColor color); + static QPixmap getIconFromEnum(Icon enumIcon); + static void updateCurrentlyShowingPositionXY(); + static void updateCurrentlyShowingPositionX(); + static void updateCurrentlyShowingPositionY(); + static void showNextInQueue(); + + static const int sc_updatePositionDuration; + static const int sc_durationBarUpdateInterval; + static const int sc_dropShadowSize; + static const QColor sc_successAccentColor; + static const QColor sc_warningAccentColor; + static const QColor sc_errorAccentColor; + static const QColor sc_informationAccentColor; + static const QColor sc_defaultAccentColor; + static const QColor sc_defaultBackgroundColor; + static const QColor sc_defaultTitleColor; + static const QColor sc_defaultTextColor; + static const QColor sc_defaultIconSeparatorColor; + static const QColor sc_defaultCloseButtonIconColor; + static const QColor sc_defaultBackgroundColorDark; + static const QColor sc_defaultTitleColorDark; + static const QColor sc_defaultTextColorDark; + static const QColor sc_defaultIconSeparatorColorDark; + static const QColor sc_defaultCloseButtonIconColorDark; +}; diff --git a/core/src/VariantStream.cpp b/core/src/VariantStream.cpp index 3f39895dd..6e4f05df7 100644 --- a/core/src/VariantStream.cpp +++ b/core/src/VariantStream.cpp @@ -22,7 +22,9 @@ * */ +#include #include +#include #include "VariantStream.h" diff --git a/core/src/VeyonConfigurationProperties.h b/core/src/VeyonConfigurationProperties.h index f043f3412..7bb4a6c9d 100644 --- a/core/src/VeyonConfigurationProperties.h +++ b/core/src/VeyonConfigurationProperties.h @@ -50,7 +50,8 @@ OP( VeyonConfiguration, VeyonCore::config(), int, vncConnectionRetryInterval, setVncConnectionRetryInterval, "ConnectionRetryInterval", "VncConnection", VncConnectionConfiguration::DefaultConnectionRetryInterval, Configuration::Property::Flag::Hidden ) \ OP( VeyonConfiguration, VeyonCore::config(), int, vncConnectionMessageWaitTimeout, setVncConnectionMessageWaitTimeout, "MessageWaitTimeout", "VncConnection", VncConnectionConfiguration::DefaultMessageWaitTimeout, Configuration::Property::Flag::Hidden ) \ OP( VeyonConfiguration, VeyonCore::config(), int, vncConnectionFastFramebufferUpdateInterval, setVncConnectionFastFramebufferUpdateInterval, "FastFramebufferUpdateInterval", "VncConnection", VncConnectionConfiguration::DefaultFastFramebufferUpdateInterval, Configuration::Property::Flag::Hidden ) \ - OP( VeyonConfiguration, VeyonCore::config(), int, vncConnectionFramebufferUpdateWatchdogTimeout, setVncConnectionFramebufferUpdateWatchdogTimeout, "FramebufferUpdateWatchdogTimeout", "VncConnection", VncConnectionConfiguration::DefaultFramebufferUpdateWatchdogTimeout, Configuration::Property::Flag::Hidden ) \ + OP( VeyonConfiguration, VeyonCore::config(), int, vncConnectionInitialFramebufferUpdateTimeout, setVncConnectionInitialFramebufferUpdateTimeout, "InitialFramebufferUpdateTimeout", "VncConnection", VncConnectionConfiguration::DefaultInitialFramebufferUpdateTimeout, Configuration::Property::Flag::Hidden ) \ + OP( VeyonConfiguration, VeyonCore::config(), int, vncConnectionFramebufferUpdateTimeout, setVncConnectionFramebufferUpdateTimeout, "FramebufferUpdateTimeout", "VncConnection", VncConnectionConfiguration::DefaultFramebufferUpdateTimeout, Configuration::Property::Flag::Hidden ) \ OP( VeyonConfiguration, VeyonCore::config(), int, vncConnectionSocketKeepaliveIdleTime, setVncConnectionSocketKeepaliveIdleTime, "SocketKeepaliveIdleTime", "VncConnection", VncConnectionConfiguration::DefaultSocketKeepaliveIdleTime, Configuration::Property::Flag::Hidden ) \ OP( VeyonConfiguration, VeyonCore::config(), int, vncConnectionSocketKeepaliveInterval, setVncConnectionSocketKeepaliveInterval, "SocketKeepaliveInterval", "VncConnection", VncConnectionConfiguration::DefaultSocketKeepaliveInterval, Configuration::Property::Flag::Hidden ) \ OP( VeyonConfiguration, VeyonCore::config(), int, vncConnectionSocketKeepaliveCount, setVncConnectionSocketKeepaliveCount, "SocketKeepaliveCount", "VncConnection", VncConnectionConfiguration::DefaultSocketKeepaliveCount, Configuration::Property::Flag::Hidden ) \ @@ -58,7 +59,8 @@ #define FOREACH_VEYON_UI_CONFIG_PROPERTY(OP) \ OP( VeyonConfiguration, VeyonCore::config(), QString, applicationName, setApplicationName, "ApplicationName", "UI", QStringLiteral("Veyon"), Configuration::Property::Flag::Hidden ) \ OP( VeyonConfiguration, VeyonCore::config(), QString, uiLanguage, setUiLanguage, "Language", "UI", QString(), Configuration::Property::Flag::Standard ) \ - OP( VeyonConfiguration, VeyonCore::config(), VeyonCore::UiStyle, uiStyle, setUiStyle, "Style", "UI", QVariant::fromValue(VeyonCore::UiStyle::Fusion), Configuration::Property::Flag::Standard ) + OP( VeyonConfiguration, VeyonCore::config(), VeyonCore::UiStyle, uiStyle, setUiStyle, "Style", "UI", QVariant::fromValue(VeyonCore::UiStyle::Fusion), Configuration::Property::Flag::Standard ) \ + OP( VeyonConfiguration, VeyonCore::config(), VeyonCore::UiColorScheme, uiColorScheme, setUiColorScheme, "ColorScheme", "UI", QVariant::fromValue(VeyonCore::UiColorScheme::System), Configuration::Property::Flag::Standard ) #define FOREACH_VEYON_SERVICE_CONFIG_PROPERTY(OP) \ OP( VeyonConfiguration, VeyonCore::config(), bool, isTrayIconHidden, setTrayIconHidden, "HideTrayIcon", "Service", false, Configuration::Property::Flag::Advanced ) \ diff --git a/core/src/VeyonConnection.h b/core/src/VeyonConnection.h index cb608160f..2183b771f 100644 --- a/core/src/VeyonConnection.h +++ b/core/src/VeyonConnection.h @@ -36,6 +36,11 @@ class VEYON_CORE_EXPORT VeyonConnection : public QObject { Q_OBJECT public: + using Instances = struct { + QMutex mutex; + QHash connections; + }; + VeyonConnection(); void stopAndDeleteLater(); @@ -97,5 +102,6 @@ class VEYON_CORE_EXPORT VeyonConnection : public QObject RfbVeyonAuth::Type m_veyonAuthType; AuthenticationProxy* m_authenticationProxy{nullptr}; + QString m_accessControlMessage; } ; diff --git a/core/src/VeyonCore.cpp b/core/src/VeyonCore.cpp index af2b25810..ba6c13fb8 100644 --- a/core/src/VeyonCore.cpp +++ b/core/src/VeyonCore.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -99,6 +100,8 @@ VeyonCore::VeyonCore( QCoreApplication* application, Component component, const initManagers(); + initFeatures(); + initSystemInfo(); Q_EMIT initialized(); // clazy:exclude=incorrect-emit @@ -113,15 +116,15 @@ VeyonCore::~VeyonCore() delete m_featureManager; m_featureManager = nullptr; + delete m_builtinFeatures; + m_builtinFeatures = nullptr; + delete m_userGroupsBackendManager; m_userGroupsBackendManager = nullptr; delete m_authenticationCredentials; m_authenticationCredentials = nullptr; - delete m_builtinFeatures; - m_builtinFeatures = nullptr; - delete m_logger; m_logger = nullptr; @@ -285,6 +288,29 @@ void VeyonCore::enforceBranding( QWidget *topLevelWidget ) +bool VeyonCore::useDarkMode() +{ + const auto colorScheme = config().uiColorScheme(); + +#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) + if (colorScheme == UiColorScheme::System && + QGuiApplication::styleHints() && + QGuiApplication::styleHints()->colorScheme() == Qt::ColorScheme::Dark) + { + return true; + } +#endif + + if (colorScheme == UiColorScheme::Dark) + { + return true; + } + + return false; +} + + + bool VeyonCore::isDebugging() { return s_instance && s_instance->m_debugging; @@ -650,6 +676,20 @@ void VeyonCore::initUi() toolTipPalette.setColor(QPalette::ToolTipBase, toolTipBackgroundColor); toolTipPalette.setColor(QPalette::ToolTipText, Qt::white); QToolTip::setPalette(toolTipPalette); + +#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) + switch (config().uiColorScheme()) + { + case UiColorScheme::Dark: + QGuiApplication::styleHints()->setColorScheme(Qt::ColorScheme::Dark); + break; + case UiColorScheme::Light: + QGuiApplication::styleHints()->setColorScheme(Qt::ColorScheme::Light); + break; + default: + break; + } +#endif } } @@ -680,21 +720,26 @@ void VeyonCore::initPlugins() // load all other (non-platform) plugins m_pluginManager->loadPlugins(); m_pluginManager->upgradePlugins(); - - m_builtinFeatures = new BuiltinFeatures(); } void VeyonCore::initManagers() { - m_featureManager = new FeatureManager(this); m_userGroupsBackendManager = new UserGroupsBackendManager( this ); m_networkObjectDirectoryManager = new NetworkObjectDirectoryManager( this ); } +void VeyonCore::initFeatures() +{ + m_builtinFeatures = new BuiltinFeatures(); + m_featureManager = new FeatureManager(this); +} + + + bool VeyonCore::initLogonAuthentication() { if( qobject_cast( QCoreApplication::instance() ) ) diff --git a/core/src/VeyonCore.h b/core/src/VeyonCore.h index bcdcf90d7..352657b57 100644 --- a/core/src/VeyonCore.h +++ b/core/src/VeyonCore.h @@ -26,8 +26,6 @@ #include #include -#include -#include #include #include @@ -96,6 +94,13 @@ class VEYON_CORE_EXPORT VeyonCore : public QObject }; Q_ENUM(UiStyle) + enum class UiColorScheme { + System, + Light, + Dark + }; + Q_ENUM(UiColorScheme) + VeyonCore( QCoreApplication* application, Component component, const QString& appComponentName ); ~VeyonCore() override; @@ -175,6 +180,7 @@ class VEYON_CORE_EXPORT VeyonCore : public QObject static QString applicationName(); static void enforceBranding( QWidget* topLevelWidget ); + static bool useDarkMode(); static bool isDebugging(); @@ -209,6 +215,7 @@ class VEYON_CORE_EXPORT VeyonCore : public QObject void initAuthenticationCredentials(); void initPlugins(); void initManagers(); + void initFeatures(); void initLocalComputerControlInterface(); bool initLogonAuthentication(); bool initKeyFileAuthentication(); diff --git a/core/src/VncClientProtocol.cpp b/core/src/VncClientProtocol.cpp index abe09f91b..d6b782993 100644 --- a/core/src/VncClientProtocol.cpp +++ b/core/src/VncClientProtocol.cpp @@ -72,7 +72,6 @@ VncClientProtocol::VncClientProtocol( QIODevice* socket, const Password& vncPass m_state( Disconnected ), m_vncPassword( vncPassword ), m_serverInitMessage(), - m_pixelFormat( { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } ), m_framebufferWidth( 0 ), m_framebufferHeight( 0 ) { @@ -115,26 +114,40 @@ bool VncClientProtocol::read() // Flawfinder: ignore -bool VncClientProtocol::setPixelFormat( rfbPixelFormat pixelFormat ) +void VncClientProtocol::setPixelFormat(rfbPixelFormat pixelFormat) { - rfbSetPixelFormatMsg spf; + m_pixelFormat = pixelFormat; +} + + + +void VncClientProtocol::setEncodings(const QVector& encodings) +{ + m_encodings = encodings; +} + + + +bool VncClientProtocol::sendPixelFormat() +{ + rfbSetPixelFormatMsg spf{}; spf.type = rfbSetPixelFormat; spf.pad1 = 0; spf.pad2 = 0; - spf.format = pixelFormat; - spf.format.redMax = qFromBigEndian(pixelFormat.redMax); - spf.format.greenMax = qFromBigEndian(pixelFormat.greenMax); - spf.format.blueMax = qFromBigEndian(pixelFormat.blueMax); + spf.format = m_pixelFormat; + spf.format.redMax = qToBigEndian(spf.format.redMax); + spf.format.greenMax = qToBigEndian(spf.format.greenMax); + spf.format.blueMax = qToBigEndian(spf.format.blueMax); - return m_socket->write( reinterpret_cast( &spf ), sz_rfbSetPixelFormatMsg ) == sz_rfbSetPixelFormatMsg; + return m_socket->write(reinterpret_cast(&spf), sz_rfbSetPixelFormatMsg) == sz_rfbSetPixelFormatMsg; } -bool VncClientProtocol::setEncodings( const QVector& encodings ) +bool VncClientProtocol::sendEncodings() { - if( encodings.size() > MAX_ENCODINGS ) + if (m_encodings.size() > MAX_ENCODINGS) { return false; } @@ -148,16 +161,16 @@ bool VncClientProtocol::setEncodings( const QVector& encodings ) setEncodingsMsg->pad = 0; setEncodingsMsg->nEncodings = 0; - for( auto encoding : encodings ) + for (const auto encoding : std::as_const(m_encodings)) { - encs[setEncodingsMsg->nEncodings++] = qFromBigEndian( encoding ); + encs[setEncodingsMsg->nEncodings++] = qToBigEndian(encoding); } const auto len = sz_rfbSetEncodingsMsg + setEncodingsMsg->nEncodings * 4; - setEncodingsMsg->nEncodings = qFromBigEndian(setEncodingsMsg->nEncodings); + setEncodingsMsg->nEncodings = qToBigEndian(setEncodingsMsg->nEncodings); - return m_socket->write( buf, len ) == len; + return m_socket->write(buf, len) == len; } @@ -378,8 +391,8 @@ bool VncClientProtocol::receiveServerInitMessage() { rfbServerInitMsg message; - if( m_socket->bytesAvailable() >= sz_rfbServerInitMsg && - m_socket->peek( reinterpret_cast( &message ), sz_rfbServerInitMsg ) == sz_rfbServerInitMsg ) + if (m_socket->bytesAvailable() >= sz_rfbServerInitMsg && + m_socket->peek(reinterpret_cast(&message), sz_rfbServerInitMsg) == sz_rfbServerInitMsg) { const auto nameLength = qFromBigEndian( message.nameLength ); @@ -622,7 +635,11 @@ bool VncClientProtocol::handleRect( QBuffer& buffer, rfbFramebufferUpdateRectHea return true; default: - vCritical() << "Unsupported rect encoding" << rectHeader.encoding; + vCritical() << "Unsupported rect encoding" << +#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) + Qt::hex << +#endif + rectHeader.encoding; m_socket->close(); break; } @@ -668,8 +685,8 @@ bool VncClientProtocol::handleRectEncodingCoRRE( QBuffer& buffer, uint bytesPerP bool VncClientProtocol::handleRectEncodingHextile( QBuffer& buffer, - const rfbFramebufferUpdateRectHeader rectHeader, - uint bytesPerPixel ) + const rfbFramebufferUpdateRectHeader rectHeader, + uint bytesPerPixel ) { const uint rx = rectHeader.r.x; const uint ry = rectHeader.r.y; @@ -848,7 +865,7 @@ bool VncClientProtocol::handleRectEncodingTight(QBuffer& buffer, if ((compCtl & rfbTightNoZlib) == rfbTightNoZlib) { - compCtl &= ~(rfbTightNoZlib); + compCtl &= ~(rfbTightNoZlib); } if (compCtl == rfbTightFill) diff --git a/core/src/VncClientProtocol.h b/core/src/VncClientProtocol.h index 6abf0317f..e3883be53 100644 --- a/core/src/VncClientProtocol.h +++ b/core/src/VncClientProtocol.h @@ -74,8 +74,11 @@ class VEYON_CORE_EXPORT VncClientProtocol return m_framebufferHeight; } - bool setPixelFormat( rfbPixelFormat pixelFormat ); - bool setEncodings( const QVector& encodings ); + void setPixelFormat(rfbPixelFormat pixelFormat); + void setEncodings(const QVector& encodings); + + bool sendPixelFormat(); + bool sendEncodings(); void requestFramebufferUpdate( bool incremental ); @@ -143,7 +146,8 @@ class VEYON_CORE_EXPORT VncClientProtocol QByteArray m_serverInitMessage; - rfbPixelFormat m_pixelFormat; + rfbPixelFormat m_pixelFormat{}; + QVector m_encodings{}; quint16 m_framebufferWidth; quint16 m_framebufferHeight; diff --git a/core/src/VncConnection.cpp b/core/src/VncConnection.cpp index f7c57a293..786b863f5 100644 --- a/core/src/VncConnection.cpp +++ b/core/src/VncConnection.cpp @@ -185,7 +185,8 @@ VncConnection::VncConnection( QObject* parent ) : m_connectionRetryInterval = VeyonCore::config().vncConnectionRetryInterval(); m_messageWaitTimeout = VeyonCore::config().vncConnectionMessageWaitTimeout(); m_fastFramebufferUpdateInterval = VeyonCore::config().vncConnectionFastFramebufferUpdateInterval(); - m_framebufferUpdateWatchdogTimeout = VeyonCore::config().vncConnectionFramebufferUpdateWatchdogTimeout(); + m_initialFramebufferUpdateTimeout = VeyonCore::config().vncConnectionInitialFramebufferUpdateTimeout(); + m_framebufferUpdateTimeout = VeyonCore::config().vncConnectionFramebufferUpdateTimeout(); m_socketKeepaliveIdleTime = VeyonCore::config().vncConnectionSocketKeepaliveIdleTime(); m_socketKeepaliveInterval = VeyonCore::config().vncConnectionSocketKeepaliveInterval(); m_socketKeepaliveCount = VeyonCore::config().vncConnectionSocketKeepaliveCount(); @@ -239,7 +240,15 @@ QImage VncConnection::image() void VncConnection::restart() { - setControlFlag( ControlFlag::RestartConnection, true ); + if (isRunning()) + { + setControlFlag(ControlFlag::RestartConnection, true); + } + else + { + setControlFlag(ControlFlag::TerminateThread, false); + start(); + } } @@ -384,12 +393,15 @@ void VncConnection::setFramebufferUpdateInterval( int interval ) { m_framebufferUpdateInterval = interval; - if (m_framebufferUpdateInterval <= 0) + if (state() == State::Connected) { - setControlFlag(ControlFlag::TriggerFramebufferUpdate, true); - } + if (m_framebufferUpdateInterval <= 0) + { + setControlFlag(ControlFlag::TriggerFramebufferUpdate, true); + } - m_updateIntervalSleeper.wakeAll(); + m_updateIntervalSleeper.wakeAll(); + } } @@ -409,7 +421,7 @@ void VncConnection::rescaleFramebuffer() QReadLocker locker( &m_imgLock ); - if( m_image.size().isValid() == false ) + if (m_image.isNull() || m_image.size().isValid() == false) { return; } @@ -449,9 +461,17 @@ void VncConnection::run() { while( isControlFlagSet( ControlFlag::TerminateThread ) == false ) { + QElapsedTimer connectionTimer; + connectionTimer.start(); + establishConnection(); handleConnection(); closeConnection(); + + const auto minimumConnectionTime = m_framebufferUpdateInterval > 0 ? + int(m_framebufferUpdateInterval) : + m_connectionRetryInterval; + QThread::msleep(std::max(0, minimumConnectionTime - connectionTimer.elapsed())); } if( isControlFlagSet( ControlFlag::DeleteAfterFinished ) ) @@ -524,7 +544,8 @@ void VncConnection::establishConnection() if( clientInitialized ) { - m_framebufferUpdateWatchdog.restart(); + m_fullFramebufferUpdateTimer.restart(); + m_incrementalFramebufferUpdateTimer.restart(); VeyonCore::platform().networkFunctions(). configureSocketKeepalive( static_cast( m_client->sock ), true, @@ -537,15 +558,26 @@ void VncConnection::establishConnection() // guess reason why connection failed if( isControlFlagSet( ControlFlag::ServerReachable ) == false ) { - if( isControlFlagSet( ControlFlag::SkipHostPing ) || - VeyonCore::platform().networkFunctions().ping( m_host ) == false ) + if (isControlFlagSet(ControlFlag::SkipHostPing)) { - setState( State::HostOffline ); + setState(State::HostOffline); } else { - setState( State::ServerNotRunning ); + const auto pingResult = VeyonCore::platform().networkFunctions().ping(m_host); + switch (pingResult) + { + case PlatformNetworkFunctions::PingResult::ReplyReceived: + setState(State::ServerNotRunning); + break; + case PlatformNetworkFunctions::PingResult::NameResolutionFailed: + setState(State::HostNameResolutionFailed); + break; + default: + setState(State::HostOffline); + } } + } else if( m_framebufferState == FramebufferState::Invalid ) { @@ -610,16 +642,16 @@ void VncConnection::handleConnection() break; } } - else if (m_framebufferUpdateWatchdog.elapsed() >= - qMax(2*m_framebufferUpdateInterval, m_framebufferUpdateWatchdogTimeout)) + else if (m_fullFramebufferUpdateTimer.elapsed() >= fullFramebufferUpdateTimeout()) { requestFrameufferUpdate(FramebufferUpdateType::Full); - m_framebufferUpdateWatchdog.restart(); + m_fullFramebufferUpdateTimer.restart(); } - else if (m_framebufferUpdateInterval > 0 && m_framebufferUpdateWatchdog.elapsed() > m_framebufferUpdateInterval) + else if (m_framebufferUpdateInterval > 0 && + m_incrementalFramebufferUpdateTimer.elapsed() > incrementalFramebufferUpdateTimeout()) { requestFrameufferUpdate(FramebufferUpdateType::Incremental); - m_framebufferUpdateWatchdog.restart(); + m_incrementalFramebufferUpdateTimer.restart(); } else if (isControlFlagSet(ControlFlag::TriggerFramebufferUpdate)) { @@ -753,7 +785,8 @@ void VncConnection::requestFrameufferUpdate(FramebufferUpdateType updateType) void VncConnection::finishFrameBufferUpdate() { - m_framebufferUpdateWatchdog.restart(); + m_incrementalFramebufferUpdateTimer.restart(); + m_fullFramebufferUpdateTimer.restart(); m_framebufferState = FramebufferState::Valid; setControlFlag( ControlFlag::ScaledFramebufferNeedsUpdate, true ); @@ -763,6 +796,26 @@ void VncConnection::finishFrameBufferUpdate() +int VncConnection::fullFramebufferUpdateTimeout() const +{ + return m_framebufferState == FramebufferState::Valid ? + m_framebufferUpdateTimeout + : + std::max(int(m_framebufferUpdateInterval), m_initialFramebufferUpdateTimeout); +} + + + +int VncConnection::incrementalFramebufferUpdateTimeout() const +{ + return m_framebufferState == FramebufferState::Valid ? + int(m_framebufferUpdateInterval) + : + std::min(int(m_framebufferUpdateInterval), m_initialFramebufferUpdateTimeout); +} + + + void VncConnection::updateEncodingSettingsFromQuality() { m_client->appData.encodingsString = m_quality == VncConnectionConfiguration::Quality::Highest ? diff --git a/core/src/VncConnection.h b/core/src/VncConnection.h index 4ebf30b54..11aa05947 100644 --- a/core/src/VncConnection.h +++ b/core/src/VncConnection.h @@ -67,8 +67,10 @@ class VEYON_CORE_EXPORT VncConnection : public QThread Disconnected, Connecting, HostOffline, + HostNameResolutionFailed, ServerNotRunning, AuthenticationFailed, + AccessControlFailed, ConnectionFailed, Connected } ; @@ -199,6 +201,9 @@ class VEYON_CORE_EXPORT VncConnection : public QThread void requestFrameufferUpdate(FramebufferUpdateType updateType); void finishFrameBufferUpdate(); + int fullFramebufferUpdateTimeout() const; + int incrementalFramebufferUpdateTimeout() const; + void updateEncodingSettingsFromQuality(); void sendEvents(); @@ -223,7 +228,8 @@ class VEYON_CORE_EXPORT VncConnection : public QThread int m_connectionRetryInterval{VncConnectionConfiguration::DefaultConnectionRetryInterval}; int m_messageWaitTimeout{VncConnectionConfiguration::DefaultMessageWaitTimeout}; int m_fastFramebufferUpdateInterval{VncConnectionConfiguration::DefaultFastFramebufferUpdateInterval}; - int m_framebufferUpdateWatchdogTimeout{VncConnectionConfiguration::DefaultFramebufferUpdateWatchdogTimeout}; + int m_initialFramebufferUpdateTimeout{VncConnectionConfiguration::DefaultInitialFramebufferUpdateTimeout}; + int m_framebufferUpdateTimeout{VncConnectionConfiguration::DefaultFramebufferUpdateTimeout}; int m_socketKeepaliveIdleTime{VncConnectionConfiguration::DefaultSocketKeepaliveIdleTime}; int m_socketKeepaliveInterval{VncConnectionConfiguration::DefaultSocketKeepaliveInterval}; int m_socketKeepaliveCount{VncConnectionConfiguration::DefaultSocketKeepaliveCount}; @@ -246,7 +252,8 @@ class VEYON_CORE_EXPORT VncConnection : public QThread QMutex m_eventQueueMutex; QWaitCondition m_updateIntervalSleeper; QAtomicInt m_framebufferUpdateInterval; - QElapsedTimer m_framebufferUpdateWatchdog; + QElapsedTimer m_fullFramebufferUpdateTimer{}; + QElapsedTimer m_incrementalFramebufferUpdateTimer{}; // queue for RFB and custom events QQueue m_eventQueue; diff --git a/core/src/VncConnectionConfiguration.h b/core/src/VncConnectionConfiguration.h index c8bf8b025..0a925c563 100644 --- a/core/src/VncConnectionConfiguration.h +++ b/core/src/VncConnectionConfiguration.h @@ -47,7 +47,8 @@ class VEYON_CORE_EXPORT VncConnectionConfiguration static constexpr int DefaultConnectionRetryInterval = 1000; static constexpr int DefaultMessageWaitTimeout = 500; static constexpr int DefaultFastFramebufferUpdateInterval = 100; - static constexpr int DefaultFramebufferUpdateWatchdogTimeout = 10000; + static constexpr int DefaultInitialFramebufferUpdateTimeout = 10000; + static constexpr int DefaultFramebufferUpdateTimeout = 60000; static constexpr int DefaultSocketKeepaliveIdleTime = 1000; static constexpr int DefaultSocketKeepaliveInterval = 500; static constexpr int DefaultSocketKeepaliveCount = 5; diff --git a/core/src/VncFeatureMessageEvent.cpp b/core/src/VncFeatureMessageEvent.cpp index c090c3b9d..ee566b8ef 100644 --- a/core/src/VncFeatureMessageEvent.cpp +++ b/core/src/VncFeatureMessageEvent.cpp @@ -42,8 +42,6 @@ void VncFeatureMessageEvent::fire( rfbClient* client ) << m_featureMessage; SocketDevice socketDevice( VncConnection::libvncClientDispatcher, client ); - const char messageType = FeatureMessage::RfbMessageType; - socketDevice.write( &messageType, sizeof(messageType) ); - m_featureMessage.send( &socketDevice ); + m_featureMessage.sendAsRfbMessage(&socketDevice); } diff --git a/core/src/VncServerClient.h b/core/src/VncServerClient.h index 8f27b624d..5d83da253 100644 --- a/core/src/VncServerClient.h +++ b/core/src/VncServerClient.h @@ -54,7 +54,7 @@ class VEYON_CORE_EXPORT VncServerClient : public QObject explicit VncServerClient( QObject* parent = nullptr ) : QObject( parent ), - m_protocolState( VncServerProtocol::Disconnected ), + m_protocolState( VncServerProtocol::State::Disconnected ), m_authState( AuthState::Init ), m_authType( RfbVeyonAuth::Invalid ), m_accessControlState( AccessControlState::Init ), @@ -104,6 +104,16 @@ class VEYON_CORE_EXPORT VncServerClient : public QObject m_accessControlState = accessControlState; } + const QString& accessControlDetails() const + { + return m_accessControlDetails; + } + + void setAccessControlDetails(const QString& details) + { + m_accessControlDetails = details; + } + QElapsedTimer& accessControlTimer() { return m_accessControlTimer; @@ -163,6 +173,7 @@ public Q_SLOTS: AuthState m_authState; RfbVeyonAuth::Type m_authType; AccessControlState m_accessControlState; + QString m_accessControlDetails; QElapsedTimer m_accessControlTimer; QString m_username; QString m_hostAddress; diff --git a/core/src/VncServerProtocol.cpp b/core/src/VncServerProtocol.cpp index 1298fb159..e01f64caf 100644 --- a/core/src/VncServerProtocol.cpp +++ b/core/src/VncServerProtocol.cpp @@ -28,24 +28,20 @@ #include #include -#include "AuthenticationCredentials.h" +#include "AccessControlProvider.h" +#include "BuiltinFeatures.h" #include "VariantArrayMessage.h" #include "VncServerClient.h" #include "VncServerProtocol.h" -VncServerProtocol::VncServerProtocol( QIODevice* socket, - VncServerClient* client ) : +VncServerProtocol::VncServerProtocol(QTcpSocket* socket, VncServerClient* client) : m_socket( socket ), m_client( client ), m_serverInitMessage() { - auto qtcpSocket = qobject_cast(socket); - if (qtcpSocket) - { - m_client->setHostAddress(qtcpSocket->peerAddress().toString()); - } + m_client->setHostAddress(m_socket->peerAddress().toString()); m_client->setAccessControlState( VncServerClient::AccessControlState::Init ); } @@ -60,7 +56,7 @@ VncServerProtocol::State VncServerProtocol::state() const void VncServerProtocol::start() { - if( state() == Disconnected ) + if( state() == State::Disconnected ) { rfbProtocolVersionMsg protocol; // Flawfinder: ignore @@ -68,7 +64,7 @@ void VncServerProtocol::start() m_socket->write( protocol, sz_rfbProtocolVersionMsg ); - setState( Protocol ); + setState( State::Protocol ); } } @@ -78,29 +74,40 @@ bool VncServerProtocol::read() { switch( state() ) { - case Protocol: + case State::Protocol: return readProtocol(); - case SecurityInit: + case State::SecurityInit: return receiveSecurityTypeResponse(); - case AuthenticationTypes: + case State::AuthenticationTypes: return receiveAuthenticationTypeResponse(); - case Authenticating: + case State::Authenticating: return receiveAuthenticationMessage(); - case AccessControl: + case State::AccessControl: return processAccessControl(); - case FramebufferInit: + case State::FramebufferInit: return processFramebufferInit(); - case Close: + case State::Close: vDebug() << "closing connection per protocol state"; m_socket->close(); break; + case State::Closing: + if (m_socket->isOpen()) + { + m_socket->readAll(); + } + else + { + setState(State::Close); + } + return false; + default: break; } @@ -138,7 +145,7 @@ bool VncServerProtocol::readProtocol() return false; } - setState( SecurityInit ); + setState( State::SecurityInit ); return sendSecurityTypes(); } @@ -174,7 +181,7 @@ bool VncServerProtocol::receiveSecurityTypeResponse() return false; } - setState( AuthenticationTypes ); + setState(State::AuthenticationTypes); return sendAuthenticationTypes(); } @@ -222,7 +229,7 @@ bool VncServerProtocol::receiveAuthenticationTypeResponse() m_client->setAuthType( chosenAuthType ); m_client->setUsername( username ); - setState( Authenticating ); + setState( State::Authenticating ); // send auth ack message VariantArrayMessage( m_socket ).send(); @@ -262,7 +269,7 @@ bool VncServerProtocol::processAuthentication( VariantArrayMessage& message ) const auto authResult = qToBigEndian(rfbVncAuthOK); m_socket->write( reinterpret_cast( &authResult ), sizeof(authResult) ); - setState( AccessControl ); + setState( State::AccessControl ); return true; } @@ -288,7 +295,7 @@ bool VncServerProtocol::processAccessControl() switch( m_client->accessControlState() ) { case VncServerClient::AccessControlState::Successful: - setState( FramebufferInit ); + setState( State::FramebufferInit ); return true; case VncServerClient::AccessControlState::Pending: @@ -297,8 +304,10 @@ bool VncServerProtocol::processAccessControl() default: vCritical() << "access control failed - closing connection"; - m_socket->close(); - break; + m_socket->read(sz_rfbClientInitMsg); + sendEmptyServerInitMessage(); + sendFailedAccessControlDetails(); + return true; } return false; @@ -306,6 +315,29 @@ bool VncServerProtocol::processAccessControl() +void VncServerProtocol::sendFailedAccessControlDetails() +{ + VeyonCore::builtinFeatures().accessControlProvider().sendDetails(m_socket, client()->accessControlDetails()); + + QObject::connect (&m_accessControlDetailsSendTimer, &QTimer::timeout, m_socket, [this]() { + VeyonCore::builtinFeatures().accessControlProvider().sendDetails(m_socket, client()->accessControlDetails()); + }); + QTimer::singleShot(AccessControlCloseDelay, m_socket, &QAbstractSocket::close); + m_accessControlDetailsSendTimer.start(AccessControlDetailsSendInterval); + + setState(State::Closing); +} + + + +void VncServerProtocol::sendEmptyServerInitMessage() +{ + rfbServerInitMsg message{}; + m_socket->write(reinterpret_cast(&message), sizeof(message)); +} + + + bool VncServerProtocol::processFramebufferInit() { if( m_socket->bytesAvailable() >= sz_rfbClientInitMsg && @@ -316,7 +348,7 @@ bool VncServerProtocol::processFramebufferInit() m_socket->write( m_serverInitMessage ); - setState( Running ); + setState( State::Running ); return true; } diff --git a/core/src/VncServerProtocol.h b/core/src/VncServerProtocol.h index b2ed77c7c..fd9ddff82 100644 --- a/core/src/VncServerProtocol.h +++ b/core/src/VncServerProtocol.h @@ -24,9 +24,11 @@ #pragma once +#include + #include "RfbVeyonAuth.h" -class QIODevice; +class QTcpSocket; class VariantArrayMessage; class VncServerClient; @@ -36,7 +38,8 @@ class VncServerClient; class VEYON_CORE_EXPORT VncServerProtocol { public: - enum State { + enum class State + { Disconnected, Protocol, SecurityInit, @@ -46,11 +49,11 @@ class VEYON_CORE_EXPORT VncServerProtocol FramebufferInit, Running, Close, + Closing, StateCount } ; - VncServerProtocol( QIODevice* socket, - VncServerClient* client ); + VncServerProtocol(QTcpSocket* socket, VncServerClient* client); virtual ~VncServerProtocol() = default; State state() const; @@ -68,7 +71,7 @@ class VEYON_CORE_EXPORT VncServerProtocol virtual void processAuthenticationMessage( VariantArrayMessage& message ) = 0; virtual void performAccessControl() = 0; - QIODevice* socket() + QTcpSocket* socket() { return m_socket; } @@ -91,12 +94,21 @@ class VEYON_CORE_EXPORT VncServerProtocol bool processAuthentication( VariantArrayMessage& message ); bool processAccessControl(); + void sendFailedAccessControlDetails(); + + void sendEmptyServerInitMessage(); + bool processFramebufferInit(); private: - QIODevice* m_socket; + static constexpr auto AccessControlCloseDelay = 10000; + static constexpr auto AccessControlDetailsSendInterval = 100; + + QTcpSocket* m_socket; VncServerClient* m_client; QByteArray m_serverInitMessage; + QTimer m_accessControlDetailsSendTimer; + } ; diff --git a/master/resources/align-grid-dark.png b/master/resources/align-grid-dark.png new file mode 100644 index 000000000..0ba4f08b5 Binary files /dev/null and b/master/resources/align-grid-dark.png differ diff --git a/master/resources/exchange-positions-zorder-dark.png b/master/resources/exchange-positions-zorder-dark.png new file mode 100644 index 000000000..59d1dc0fc Binary files /dev/null and b/master/resources/exchange-positions-zorder-dark.png differ diff --git a/master/resources/host-access-denied.png b/master/resources/host-access-denied.png new file mode 100644 index 000000000..bcddd3785 Binary files /dev/null and b/master/resources/host-access-denied.png differ diff --git a/master/resources/host-dns-error.png b/master/resources/host-dns-error.png new file mode 100644 index 000000000..28e0a7197 Binary files /dev/null and b/master/resources/host-dns-error.png differ diff --git a/master/resources/host-offline.png b/master/resources/host-offline.png new file mode 100644 index 000000000..11d4e72a7 Binary files /dev/null and b/master/resources/host-offline.png differ diff --git a/master/resources/host-online.png b/master/resources/host-online.png new file mode 100644 index 000000000..fff4f82de Binary files /dev/null and b/master/resources/host-online.png differ diff --git a/master/resources/host-service-error.png b/master/resources/host-service-error.png new file mode 100644 index 000000000..f76310cd8 Binary files /dev/null and b/master/resources/host-service-error.png differ diff --git a/master/resources/master.qrc b/master/resources/master.qrc index c8550669a..2ca49ad84 100644 --- a/master/resources/master.qrc +++ b/master/resources/master.qrc @@ -1,20 +1,26 @@ zoom-fit-best.png + zoom-fit-best-dark.png camera-photo.png - preferences-desktop-display.png - preferences-desktop-display-blue.png - preferences-desktop-display-orange.png - preferences-desktop-display-gray.png - preferences-desktop-display-red.png + host-offline.png + host-online.png + host-dns-error.png + host-service-error.png + host-access-denied.png splash.png computers.png align-grid.png + align-grid-dark.png exchange-positions-zorder.png + exchange-positions-zorder-dark.png powered-on.png + powered-on-dark.png computer-slideshow.png spotlight.png update-realtime-enabled.png + update-realtime-enabled-dark.png update-realtime-disabled.png + update-realtime-disabled-dark.png diff --git a/master/resources/powered-on-dark.png b/master/resources/powered-on-dark.png new file mode 100644 index 000000000..7cea1b6f7 Binary files /dev/null and b/master/resources/powered-on-dark.png differ diff --git a/master/resources/preferences-desktop-display-blue.png b/master/resources/preferences-desktop-display-blue.png deleted file mode 100644 index 5668baf1a..000000000 Binary files a/master/resources/preferences-desktop-display-blue.png and /dev/null differ diff --git a/master/resources/preferences-desktop-display-gray.png b/master/resources/preferences-desktop-display-gray.png deleted file mode 100644 index ac58363e5..000000000 Binary files a/master/resources/preferences-desktop-display-gray.png and /dev/null differ diff --git a/master/resources/preferences-desktop-display-orange.png b/master/resources/preferences-desktop-display-orange.png deleted file mode 100644 index 2d1f1ea07..000000000 Binary files a/master/resources/preferences-desktop-display-orange.png and /dev/null differ diff --git a/master/resources/preferences-desktop-display-red.png b/master/resources/preferences-desktop-display-red.png deleted file mode 100644 index c4db932c6..000000000 Binary files a/master/resources/preferences-desktop-display-red.png and /dev/null differ diff --git a/master/resources/preferences-desktop-display.png b/master/resources/preferences-desktop-display.png deleted file mode 100644 index af00f3434..000000000 Binary files a/master/resources/preferences-desktop-display.png and /dev/null differ diff --git a/master/resources/update-realtime-disabled-dark.png b/master/resources/update-realtime-disabled-dark.png new file mode 100644 index 000000000..7d6d1d266 Binary files /dev/null and b/master/resources/update-realtime-disabled-dark.png differ diff --git a/master/resources/update-realtime-enabled-dark.png b/master/resources/update-realtime-enabled-dark.png new file mode 100644 index 000000000..eab99b9ca Binary files /dev/null and b/master/resources/update-realtime-enabled-dark.png differ diff --git a/master/resources/zoom-fit-best-dark.png b/master/resources/zoom-fit-best-dark.png new file mode 100644 index 000000000..31a3feb69 Binary files /dev/null and b/master/resources/zoom-fit-best-dark.png differ diff --git a/master/src/ComputerControlListModel.cpp b/master/src/ComputerControlListModel.cpp index 8e1a2f2f4..f23e69e61 100644 --- a/master/src/ComputerControlListModel.cpp +++ b/master/src/ComputerControlListModel.cpp @@ -39,9 +39,11 @@ ComputerControlListModel::ComputerControlListModel( VeyonMaster* masterCore, QObject* parent ) : ComputerListModel( parent ), m_master( masterCore ), - m_iconDefault( QStringLiteral(":/master/preferences-desktop-display-gray.png") ), - m_iconConnectionProblem( QStringLiteral(":/master/preferences-desktop-display-red.png") ), - m_iconServerNotRunning( QStringLiteral(":/master/preferences-desktop-display-orange.png") ) + m_iconHostOffline(QStringLiteral(":/master/host-offline.png")), + m_iconHostOnline(QStringLiteral(":/master/host-online.png")), + m_iconHostNameResolutionFailed(QStringLiteral(":/master/host-dns-error.png")), + m_iconHostAccessDenied(QStringLiteral(":/master/host-access-denied.png")), + m_iconHostServiceError(QStringLiteral(":/master/host-service-error.png")) { #if defined(QT_TESTLIB_LIB) && QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) new QAbstractItemModelTester( this, QAbstractItemModelTester::FailureReportingMode::Warning, this ); @@ -262,6 +264,10 @@ QVariant ComputerControlListModel::uidRoleData(const ComputerControlInterface::P case UidRoleContent::NetworkObjectUid: return controlInterface->computer().networkObjectUid(); case UidRoleContent::SessionMetaDataHash: + if (controlInterface->sessionInfo().metaData.isEmpty()) + { + return controlInterface->computer().networkObjectUid(); + } return QUuid::createUuidV5(uidRoleNamespace, controlInterface->sessionInfo().metaData); } @@ -277,6 +283,13 @@ void ComputerControlListModel::updateState( const QModelIndex& index ) +void ComputerControlListModel::updateAccessControlDetails(const QModelIndex& index) +{ + Q_EMIT dataChanged(index, index, { Qt::ToolTipRole }); +} + + + void ComputerControlListModel::updateScreen( const QModelIndex& index ) { Q_EMIT dataChanged( index, index, { Qt::DecorationRole, FramebufferRole } ); @@ -339,6 +352,9 @@ void ComputerControlListModel::startComputerControlInterface( ComputerControlInt connect(controlInterface, &ComputerControlInterface::sessionInfoChanged, this, [=]() { updateSessionInfo(interfaceIndex(controlInterface)); }); + + connect(controlInterface, &ComputerControlInterface::accessControlDetailsChanged, + this, [=] () { updateAccessControlDetails(interfaceIndex(controlInterface)); }); } @@ -375,7 +391,7 @@ double ComputerControlListModel::averageAspectRatio() const QImage ComputerControlListModel::scaleAndAlignIcon( const QImage& icon, QSize size ) const { - const auto scaledIcon = icon.scaled( size.width(), size.height(), Qt::KeepAspectRatio ); + const auto scaledIcon = icon.scaled(size.width(), size.height(), Qt::KeepAspectRatio, Qt::SmoothTransformation); QImage scaledAndAlignedIcon( size, QImage::Format_ARGB32 ); scaledAndAlignedIcon.fill( Qt::transparent ); @@ -402,20 +418,26 @@ QImage ComputerControlListModel::computerDecorationRole( const ComputerControlIn return image; } - return scaleAndAlignIcon( m_iconDefault, controlInterface->scaledFramebufferSize() ); + return scaleAndAlignIcon(m_iconHostOnline, controlInterface->scaledFramebufferSize()); } + case ComputerControlInterface::State::HostNameResolutionFailed: + return scaleAndAlignIcon(m_iconHostNameResolutionFailed, controlInterface->scaledFramebufferSize()); + case ComputerControlInterface::State::ServerNotRunning: - return scaleAndAlignIcon( m_iconServerNotRunning, controlInterface->scaledFramebufferSize() ); + return scaleAndAlignIcon(m_iconHostServiceError, controlInterface->scaledFramebufferSize()); case ComputerControlInterface::State::AuthenticationFailed: - return scaleAndAlignIcon( m_iconConnectionProblem, controlInterface->scaledFramebufferSize() ); + return scaleAndAlignIcon(m_iconHostAccessDenied, controlInterface->scaledFramebufferSize()); + + case ComputerControlInterface::State::AccessControlFailed: + return scaleAndAlignIcon(m_iconHostAccessDenied, controlInterface->scaledFramebufferSize()); default: break; } - return scaleAndAlignIcon( m_iconDefault, controlInterface->scaledFramebufferSize() ); + return scaleAndAlignIcon(m_iconHostOffline, controlInterface->scaledFramebufferSize()); } @@ -423,20 +445,25 @@ QImage ComputerControlListModel::computerDecorationRole( const ComputerControlIn QString ComputerControlListModel::computerToolTipRole( const ComputerControlInterface::Pointer& controlInterface ) const { const QString state( computerStateDescription( controlInterface ) ); - const QString name( tr( "Name: %1" ).arg( controlInterface->computer().name() ) ); + const QString displayName(tr("Name: %1").arg(controlInterface->computer().displayName())); const QString location( tr( "Location: %1" ).arg( controlInterface->computer().location() ) ); - const QString host( tr( "Host/IP address: %1" ).arg( controlInterface->computer().hostAddress().isEmpty() - ? QStringLiteral("<%1>").arg( tr("invalid") ) - : controlInterface->computer().hostAddress() ) ); - const QString user( userInformation( controlInterface ) ); - const QString features( tr( "Active features: %1" ).arg( activeFeatures( controlInterface ) ) ); - - if( user.isEmpty() ) + const QString host = + controlInterface->computer().hostAddress().isNull() ? + tr("Hostname: %1").arg(controlInterface->computer().hostName().isEmpty() ? + QStringLiteral("<%1>").arg(tr("unknown")) + : + controlInterface->computer().hostName()) + : + tr("IP address: %1").arg(controlInterface->computer().hostAddress().toString()); + const QString user(userInformation(controlInterface)); + const QString features = activeFeaturesInformation(controlInterface); + + if (controlInterface->state() != ComputerControlInterface::State::Connected) { - return QStringLiteral("%1
%2
%3
%4
%5").arg(state, name, location, host, features); + return QStringLiteral("%1
%2
%3
%4").arg(state, displayName, location, host); } - return QStringLiteral("%1
%2
%3
%4
%5
%6").arg(state, name, location, host, features, user); + return QStringLiteral("%1
%2
%3
%4
%5
%6").arg(state, displayName, location, host, features, user); } @@ -457,15 +484,13 @@ QString ComputerControlListModel::computerDisplayRole( const ComputerControlInte { return user; } - else - { - return QStringLiteral("%1 - %2").arg( user, controlInterface->computer().name() ); - } + + return QStringLiteral("%1 - %2").arg(user, controlInterface->computer().displayName()); } if( displayRoleContent() != DisplayRoleContent::UserName ) { - return controlInterface->computer().name(); + return controlInterface->computer().displayName(); } return tr("[no user]"); @@ -478,12 +503,12 @@ QString ComputerControlListModel::computerSortRole( const ComputerControlInterfa switch( sortOrder() ) { case SortOrder::ComputerAndUserName: - return controlInterface->computer().location() + controlInterface->computer().name() + - controlInterface->computer().hostAddress() + controlInterface->userLoginName(); + return controlInterface->computer().location() + controlInterface->computer().displayName() + + controlInterface->computer().hostName() + controlInterface->userLoginName(); case SortOrder::ComputerName: - return controlInterface->computer().location() + controlInterface->computer().name() + - controlInterface->computer().hostAddress(); + return controlInterface->computer().location() + controlInterface->computer().displayName() + + controlInterface->computer().hostName(); case SortOrder::UserName: if( controlInterface->userFullName().isEmpty() == false ) @@ -504,7 +529,11 @@ QString ComputerControlListModel::computerStateDescription( const ComputerContro switch( controlInterface->state() ) { case ComputerControlInterface::State::Connected: - return tr( "Online and connected" ); + if (controlInterface->hasValidFramebuffer()) + { + return tr("Online and connected"); + } + [[fallthrough]]; case ComputerControlInterface::State::Connecting: return tr( "Establishing connection" ); @@ -512,12 +541,18 @@ QString ComputerControlListModel::computerStateDescription( const ComputerContro case ComputerControlInterface::State::HostOffline: return tr( "Computer offline or switched off" ); + case ComputerControlInterface::State::HostNameResolutionFailed: + return tr("Hostname could not be resolved"); + case ComputerControlInterface::State::ServerNotRunning: return tr( "Veyon Server unreachable or not running" ); case ComputerControlInterface::State::AuthenticationFailed: return tr( "Authentication failed or access denied" ); + case ComputerControlInterface::State::AccessControlFailed: + return controlInterface->accessControlDetails(); + default: break; } @@ -529,47 +564,41 @@ QString ComputerControlListModel::computerStateDescription( const ComputerContro QString ComputerControlListModel::userInformation(const ComputerControlInterface::Pointer& controlInterface) { - if( controlInterface->state() == ComputerControlInterface::State::Connected ) + if (controlInterface->userLoginName().isEmpty()) { - if( controlInterface->userLoginName().isEmpty() ) - { - return tr( "No user logged on" ); - } - - auto user = controlInterface->userLoginName(); - if( controlInterface->userFullName().isEmpty() == false ) - { - user = QStringLiteral("%1 (%2)").arg(controlInterface->userFullName(), user); - } + return tr("No user logged on"); + } - return tr( "Logged on user: %1" ).arg( user ); + auto user = controlInterface->userLoginName(); + if (controlInterface->userFullName().isEmpty() == false) + { + user = QStringLiteral("%1 (%2)").arg(controlInterface->userFullName(), user); } - return {}; + return tr("Logged on user: %1").arg(user); } -QString ComputerControlListModel::activeFeatures( const ComputerControlInterface::Pointer& controlInterface ) const +QString ComputerControlListModel::activeFeaturesInformation(const ComputerControlInterface::Pointer& controlInterface) { QStringList featureNames; - featureNames.reserve( controlInterface->activeFeatures().size() ); + featureNames.reserve(controlInterface->activeFeatures().size()); - for( const auto& feature : VeyonCore::featureManager().features() ) + for (const auto& feature : VeyonCore::featureManager().features()) { - if( feature.testFlag( Feature::Flag::Master ) && - controlInterface->activeFeatures().contains( feature.uid() ) ) + if (feature.testFlag(Feature::Flag::Master) && + feature.displayName().isEmpty() == false && + controlInterface->activeFeatures().contains(feature.uid())) { - featureNames.append( feature.displayName() ); + featureNames.append(feature.displayName()); } } - featureNames.removeAll( {} ); - - if( featureNames.isEmpty() ) + if (featureNames.isEmpty()) { - return tr("[none]"); + return tr("No features active"); } - return featureNames.join( QStringLiteral(", ") ); + return tr("Active features: %1").arg(featureNames.join(QStringLiteral(", "))); } diff --git a/master/src/ComputerControlListModel.h b/master/src/ComputerControlListModel.h index 6294f6b06..2a80882e1 100644 --- a/master/src/ComputerControlListModel.h +++ b/master/src/ComputerControlListModel.h @@ -69,6 +69,7 @@ class ComputerControlListModel : public ComputerListModel QVariant uidRoleData(const ComputerControlInterface::Pointer& controlInterface) const; void updateState( const QModelIndex& index ); + void updateAccessControlDetails(const QModelIndex& index); void updateScreen( const QModelIndex& index ); void updateActiveFeatures( const QModelIndex& index ); void updateUser( const QModelIndex& index ); @@ -86,13 +87,15 @@ class ComputerControlListModel : public ComputerListModel QString computerSortRole( const ComputerControlInterface::Pointer& controlInterface ) const; static QString computerStateDescription( const ComputerControlInterface::Pointer& controlInterface ); static QString userInformation(const ComputerControlInterface::Pointer& controlInterface); - QString activeFeatures( const ComputerControlInterface::Pointer& controlInterface ) const; + static QString activeFeaturesInformation(const ComputerControlInterface::Pointer& controlInterface); VeyonMaster* m_master; - QImage m_iconDefault; - QImage m_iconConnectionProblem; - QImage m_iconServerNotRunning; + QImage m_iconHostOffline; + QImage m_iconHostOnline; + QImage m_iconHostNameResolutionFailed; + QImage m_iconHostAccessDenied; + QImage m_iconHostServiceError; QSize m_computerScreenSize{}; diff --git a/master/src/ComputerItemDelegate.cpp b/master/src/ComputerItemDelegate.cpp new file mode 100644 index 000000000..5b299e7fc --- /dev/null +++ b/master/src/ComputerItemDelegate.cpp @@ -0,0 +1,105 @@ +/* + * ComputerItemDelegate.cpp - implementation of ComputerItemDelegate + + * Copyright (c) 2025 Tobias Junghans + * + * This file is part of Veyon - https://veyon.io + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program 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 (see COPYING); if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#include + +#include "ComputerControlListModel.h" +#include "ComputerItemDelegate.h" +#include "FeatureManager.h" + + +ComputerItemDelegate::ComputerItemDelegate(QObject* parent) : + QStyledItemDelegate(parent) +{ + initFeaturePixmaps(); +} + + + +void ComputerItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const +{ + QStyledItemDelegate::paint(painter, option, index); + + if (index.isValid() && index.model()) + { + drawFeatureIcons(painter, option.rect.topLeft(), + index.model()->data(index, ComputerControlListModel::ControlInterfaceRole).value()); + } +} + + + +void ComputerItemDelegate::initFeaturePixmaps() +{ + for (const auto& feature : VeyonCore::featureManager().features() ) + { + if (feature.testFlag(Feature::Flag::Master) && !feature.iconUrl().isEmpty()) + { + m_featurePixmaps[feature.uid()] = QIcon(feature.iconUrl()).pixmap(QSize(OverlayIconSize, OverlayIconSize)); + } + } +} + + + +void ComputerItemDelegate::drawFeatureIcons(QPainter* painter, const QPoint& pos, ComputerControlInterface::Pointer controlInterface) const +{ + if (painter && + controlInterface && + controlInterface->state() == ComputerControlInterface::State::Connected) + { + auto count = 0; + for (const auto& feature : controlInterface->activeFeatures()) + { + if (m_featurePixmaps.contains(feature)) + { + count++; + } + } + + if (count == 0) + { + return; + } + + int x = pos.x() + OverlayIconsPadding; + const int y = pos.y() + OverlayIconsPadding; + + painter->setRenderHint(QPainter::Antialiasing); + painter->setBrush(QColor(255, 255, 255, 192)); + painter->setPen(QColor(25, 140, 179)); + painter->drawRoundedRect(QRect(x, y, count * (OverlayIconSize + OverlayIconSpacing), OverlayIconSize), + OverlayIconsRadius, OverlayIconsRadius); + + for (const auto& feature : controlInterface->activeFeatures()) + { + const auto it = m_featurePixmaps.find(feature); + if (it != m_featurePixmaps.constEnd()) + { + painter->drawPixmap(QPoint(x, y), *it); + x += OverlayIconSize + OverlayIconSpacing; + } + } + } +} diff --git a/master/src/ComputerItemDelegate.h b/master/src/ComputerItemDelegate.h new file mode 100644 index 000000000..96835bd35 --- /dev/null +++ b/master/src/ComputerItemDelegate.h @@ -0,0 +1,51 @@ +/* + * ComputerItemDelegate.h - header file for ComputerItemDelegate + * + * Copyright (c) 2025 Tobias Junghans + * + * This file is part of Veyon - https://veyon.io + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program 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 (see COPYING); if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#pragma once + +#include +#include + +#include "ComputerControlInterface.h" + +class ComputerItemDelegate : public QStyledItemDelegate +{ + Q_OBJECT +public: + ComputerItemDelegate(QObject* parent = nullptr); + + virtual void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override; + +private: + void initFeaturePixmaps(); + void drawFeatureIcons(QPainter* painter, const QPoint& pos, ComputerControlInterface::Pointer controlInterface) const; + + static constexpr int OverlayIconSize = 32; + static constexpr int OverlayIconSpacing = 4; + static constexpr int OverlayIconsPadding = 8; + static constexpr int OverlayIconsRadius = 6; + + QMap m_featurePixmaps; + +}; diff --git a/master/src/ComputerManager.cpp b/master/src/ComputerManager.cpp index d7f716a02..9098302ba 100644 --- a/master/src/ComputerManager.cpp +++ b/master/src/ComputerManager.cpp @@ -120,7 +120,7 @@ bool ComputerManager::saveComputerAndUsersList( const QString& fileName ) // fetch user const auto user = m_networkObjectOverlayDataModel->data( mapToUserNameModelIndex( networkObjectIndex ) ).toString(); // create new line with computer and user - lines += computer.name() + QLatin1Char(';') + computer.hostAddress() + QLatin1Char(';') + user; // clazy:exclude=reserve-candidates + lines += computer.displayName() + QLatin1Char(';') + computer.hostName() + QLatin1Char(';') + user; // clazy:exclude=reserve-candidates } } @@ -199,7 +199,7 @@ void ComputerManager::updateSessionInfo(const ComputerControlInterface::Pointer& switch (m_computerNameSource) { case NetworkObjectDirectory::ComputerNameSource::HostAddress: - computerName = controlInterface->computer().hostAddress(); + computerName = controlInterface->computer().hostName(); break; case NetworkObjectDirectory::ComputerNameSource::SessionClientName: computerName = controlInterface->sessionInfo().clientName; diff --git a/master/src/ComputerMonitoringWidget.cpp b/master/src/ComputerMonitoringWidget.cpp index 9768758bd..42062627a 100644 --- a/master/src/ComputerMonitoringWidget.cpp +++ b/master/src/ComputerMonitoringWidget.cpp @@ -28,6 +28,7 @@ #include #include "ComputerControlListModel.h" +#include "ComputerItemDelegate.h" #include "ComputerMonitoringModel.h" #include "ComputerMonitoringWidget.h" #include "VeyonMaster.h" @@ -55,6 +56,8 @@ ComputerMonitoringWidget::ComputerMonitoringWidget( QWidget *parent ) : setUniformItemSizes( true ); setSelectionRectVisible( true ); + setItemDelegate(new ComputerItemDelegate(this)); + setUidRole( ComputerControlListModel::UidRole ); connect( this, &QListView::doubleClicked, this, &ComputerMonitoringWidget::runDoubleClickFeature ); @@ -161,8 +164,16 @@ void ComputerMonitoringWidget::setIconSize( const QSize& size ) void ComputerMonitoringWidget::setColors( const QColor& backgroundColor, const QColor& textColor ) { auto pal = palette(); - pal.setColor( QPalette::Base, backgroundColor ); - pal.setColor( QPalette::Text, textColor ); + if (VeyonCore::useDarkMode()) + { + pal.setColor(QPalette::Base, textColor); + pal.setColor(QPalette::Text, backgroundColor); + } + else + { + pal.setColor(QPalette::Base, backgroundColor); + pal.setColor(QPalette::Text, textColor); + } setPalette( pal ); } diff --git a/master/src/ComputerZoomWidget.cpp b/master/src/ComputerZoomWidget.cpp index cbd98ece8..6c581bdb7 100644 --- a/master/src/ComputerZoomWidget.cpp +++ b/master/src/ComputerZoomWidget.cpp @@ -139,13 +139,13 @@ void ComputerZoomWidget::updateComputerZoomWidgetTitle() if (username.isEmpty()) { - setWindowTitle( QStringLiteral( "%1 - %2" ).arg( m_vncView->computerControlInterface()->computer().name(), + setWindowTitle( QStringLiteral( "%1 - %2" ).arg( m_vncView->computerControlInterface()->computer().displayName(), VeyonCore::applicationName() ) ); } else { setWindowTitle( QStringLiteral( "%1 - %2 - %3" ).arg( username, - m_vncView->computerControlInterface()->computer().name(), + m_vncView->computerControlInterface()->computer().displayName(), VeyonCore::applicationName() ) ); } } diff --git a/master/src/MainToolBar.cpp b/master/src/MainToolBar.cpp index f599245d5..7e7e78cf0 100644 --- a/master/src/MainToolBar.cpp +++ b/master/src/MainToolBar.cpp @@ -21,7 +21,6 @@ * USA. */ -#include #include #include @@ -36,7 +35,7 @@ MainToolBar::MainToolBar( QWidget* parent ) : QToolBar( tr( "Configuration" ), parent ), m_mainWindow( dynamic_cast( parent ) ) { - setIconSize(QSize(48, 48) / qGuiApp->devicePixelRatio()); + setIconSize(QSize(32, 32)); ToolButton::setToolTipsDisabled( m_mainWindow->masterCore().userConfig().noToolTips() ); ToolButton::setIconOnlyMode( m_mainWindow, m_mainWindow->masterCore().userConfig().toolButtonIconOnlyMode() ); diff --git a/master/src/MainWindow.cpp b/master/src/MainWindow.cpp index 2ffd11c99..3dda66b8c 100644 --- a/master/src/MainWindow.cpp +++ b/master/src/MainWindow.cpp @@ -44,6 +44,7 @@ #include "MonitoringMode.h" #include "NetworkObjectDirectory.h" #include "NetworkObjectDirectoryManager.h" +#include "PlatformUserFunctions.h" #include "SlideshowPanel.h" #include "SpotlightPanel.h" #include "ToolButton.h" @@ -234,10 +235,11 @@ MainWindow::MainWindow( VeyonMaster &masterCore, QWidget* parent ) : // initialize computer placement controls auto customComputerPositionsControlMenu = new QMenu; - customComputerPositionsControlMenu->addAction(QIcon(QStringLiteral(":/core/document-open.png")), + const auto darkSuffix = VeyonCore::useDarkMode() ? QStringLiteral("-dark") : QString(); + customComputerPositionsControlMenu->addAction(QIcon(QStringLiteral(":/core/document-open%1.png").arg(darkSuffix)), tr("Load computer positions"), this, &MainWindow::loadComputerPositions); - customComputerPositionsControlMenu->addAction(QIcon(QStringLiteral(":/core/document-save.png")), + customComputerPositionsControlMenu->addAction(QIcon(QStringLiteral(":/core/document-save%1.png").arg(darkSuffix)), tr("Save computer positions"), this, &MainWindow::saveComputerPositions); ui->useCustomComputerPositionsButton->setMenu(customComputerPositionsControlMenu); @@ -252,7 +254,17 @@ MainWindow::MainWindow( VeyonMaster &masterCore, QWidget* parent ) : const auto toolButtons = findChildren(); for(auto* btn : toolButtons) { - btn->setIconSize(QSize(32, 32) / qGuiApp->devicePixelRatio()); + btn->setIconSize(QSize(20, 20)); + } + + if (VeyonCore::useDarkMode()) + { + ui->aboutButton->setIcon(QIcon(QStringLiteral(":/core/help-about-dark.png"))); + ui->filterComputersWithLoggedOnUsersButton->setIcon(QIcon(QStringLiteral(":/core/user-group-new-dark.png"))); + ui->autoAdjustComputerIconSizeButton->setIcon(QIcon(QStringLiteral(":/master/zoom-fit-best-dark.png"))); + ui->alignComputersButton->setIcon(QIcon(QStringLiteral(":/master/align-grid-dark.png"))); + ui->useCustomComputerPositionsButton->setIcon(QIcon(QStringLiteral(":/master/exchange-positions-zorder-dark.png"))); + ui->filterPoweredOnComputersButton->setIcon(QIcon(QStringLiteral(":/master/powered-on-dark.png"))); } // create the main toolbar @@ -306,14 +318,16 @@ bool MainWindow::initAuthentication() bool MainWindow::initAccessControl() { - if( VeyonCore::config().accessControlForMasterEnabled() && - VeyonCore::authenticationCredentials().hasCredentials( AuthenticationCredentials::Type::UserLogon ) ) + if (VeyonCore::config().accessControlForMasterEnabled()) { - const auto accessControlResult = - AccessControlProvider().checkAccess( VeyonCore::authenticationCredentials().logonUsername(), - QHostAddress( QHostAddress::LocalHost ).toString(), - QStringList() ); - if( accessControlResult == AccessControlProvider::Access::Deny ) + const auto accessingUser = VeyonCore::authenticationCredentials().hasCredentials(AuthenticationCredentials::Type::UserLogon) ? + VeyonCore::authenticationCredentials().logonUsername() : + VeyonCore::platform().userFunctions().currentUser(); + const auto accessControlResult = VeyonCore::builtinFeatures().accessControlProvider() + .checkAccess(accessingUser, + QHostAddress(QHostAddress::LocalHost).toString(), + {}); + if( accessControlResult.access == AccessControlProvider::Access::Deny ) { vWarning() << "user" << VeyonCore::authenticationCredentials().logonUsername() << "is not allowed to access computers"; diff --git a/master/src/ScreenshotManagementPanel.cpp b/master/src/ScreenshotManagementPanel.cpp index 6e3aa90f6..725df1773 100644 --- a/master/src/ScreenshotManagementPanel.cpp +++ b/master/src/ScreenshotManagementPanel.cpp @@ -62,6 +62,11 @@ ScreenshotManagementPanel::ScreenshotManagementPanel( QWidget *parent ) : connect( ui->showBtn, &QPushButton::clicked, this, &ScreenshotManagementPanel::showScreenshot ); connect( ui->deleteBtn, &QPushButton::clicked, this, &ScreenshotManagementPanel::deleteScreenshot ); + if (VeyonCore::useDarkMode()) + { + ui->showBtn->setIcon(QIcon(QStringLiteral(":/core/edit-find-dark.png"))); + } + updateModel(); } diff --git a/master/src/SlideshowPanel.cpp b/master/src/SlideshowPanel.cpp index bc5b1e0d4..9048a2561 100644 --- a/master/src/SlideshowPanel.cpp +++ b/master/src/SlideshowPanel.cpp @@ -47,6 +47,16 @@ SlideshowPanel::SlideshowPanel( UserConfig& config, ComputerMonitoringWidget* co ui->monitoringWidget->setSelectionMode( QListView::SingleSelection ); ui->monitoringWidget->setModel( m_model ); + if (VeyonCore::useDarkMode()) + { + QIcon startStopIcon; + startStopIcon.addPixmap(QPixmap(QStringLiteral(":/core/media-playback-pause-dark.png")), QIcon::Mode::Normal, QIcon::State::On); + startStopIcon.addPixmap(QPixmap(QStringLiteral(":/core/media-playback-start-dark.png")), QIcon::Mode::Normal, QIcon::State::Off); + ui->startStopButton->setIcon(startStopIcon); + ui->showPreviousButton->setIcon(QIcon(QStringLiteral(":/core/go-previous-dark.png"))); + ui->showNextButton->setIcon(QIcon(QStringLiteral(":/core/go-next-dark.png"))); + } + connect( ui->startStopButton, &QAbstractButton::toggled, this, &SlideshowPanel::updateDuration ); connect( ui->durationSlider, &QSlider::valueChanged, this, &SlideshowPanel::updateDuration ); diff --git a/master/src/SpotlightPanel.cpp b/master/src/SpotlightPanel.cpp index 07fe59b80..51f39ca43 100644 --- a/master/src/SpotlightPanel.cpp +++ b/master/src/SpotlightPanel.cpp @@ -50,6 +50,16 @@ SpotlightPanel::SpotlightPanel( UserConfig& config, ComputerMonitoringWidget* co ui->monitoringWidget->setIgnoreWheelEvent( true ); ui->monitoringWidget->setModel( m_model ); + if (VeyonCore::useDarkMode()) + { + QIcon realtimeViewIcon; + realtimeViewIcon.addPixmap(QPixmap(QStringLiteral(":/master/update-realtime-enabled-dark.png")), QIcon::Mode::Normal, QIcon::State::On); + realtimeViewIcon.addPixmap(QPixmap(QStringLiteral(":/master/update-realtime-disabled-dark.png")), QIcon::Mode::Normal, QIcon::State::Off); + ui->realtimeViewButton->setIcon(realtimeViewIcon); + ui->addButton->setIcon(QIcon(QStringLiteral(":/core/go-up-dark.png"))); + ui->removeButton->setIcon(QIcon(QStringLiteral(":/core/go-down-dark.png"))); + } + connect( ui->addButton, &QAbstractButton::clicked, this, &SpotlightPanel::add ); connect( ui->removeButton, &QAbstractButton::clicked, this, &SpotlightPanel::remove ); connect( ui->realtimeViewButton, &QAbstractButton::toggled, this, &SpotlightPanel::setRealtimeView ); diff --git a/plugins/authkeys/AuthKeysConfigurationPage.cpp b/plugins/authkeys/AuthKeysConfigurationPage.cpp index e5a997cd9..e53902109 100644 --- a/plugins/authkeys/AuthKeysConfigurationPage.cpp +++ b/plugins/authkeys/AuthKeysConfigurationPage.cpp @@ -94,16 +94,14 @@ void AuthKeysConfigurationPage::applyConfiguration() void AuthKeysConfigurationPage::openPublicKeyBaseDir() { - FileSystemBrowser( FileSystemBrowser::ExistingDirectory ). - exec( ui->publicKeyBaseDir ); + FileSystemBrowser(FileSystemBrowser::ExistingDirectory, this).exec(ui->publicKeyBaseDir); } void AuthKeysConfigurationPage::openPrivateKeyBaseDir() { - FileSystemBrowser( FileSystemBrowser::ExistingDirectory ). - exec( ui->privateKeyBaseDir ); + FileSystemBrowser(FileSystemBrowser::ExistingDirectory, this).exec(ui->privateKeyBaseDir); } diff --git a/plugins/demo/DemoFeaturePlugin.cpp b/plugins/demo/DemoFeaturePlugin.cpp index a0a5314f5..5ed1719fc 100644 --- a/plugins/demo/DemoFeaturePlugin.cpp +++ b/plugins/demo/DemoFeaturePlugin.cpp @@ -215,7 +215,7 @@ bool DemoFeaturePlugin::startFeature( VeyonMasterInterface& master, const Featur auto demoServerPort = VeyonCore::config().demoServerPort(); const auto& demoServerInterface = selectedComputerControlInterfaces.constFirst(); - const auto demoServerHost = demoServerInterface->computer().hostAddress(); + const auto demoServerHost = demoServerInterface->computer().hostName(); const auto primaryServerPort = HostAddress::parsePortNumber( demoServerHost ); if( primaryServerPort > 0 ) diff --git a/plugins/demo/DemoServer.cpp b/plugins/demo/DemoServer.cpp index 7efb078f8..d2ae9808e 100644 --- a/plugins/demo/DemoServer.cpp +++ b/plugins/demo/DemoServer.cpp @@ -348,7 +348,9 @@ bool DemoServer::setVncServerPixelFormat() format.pad1 = 0; format.pad2 = 0; - return m_vncClientProtocol->setPixelFormat( format ); + m_vncClientProtocol->setPixelFormat(format); + + return m_vncClientProtocol->sendPixelFormat(); } @@ -357,20 +359,21 @@ bool DemoServer::setVncServerEncodings(int quality) { m_quality = quality; - return m_vncClientProtocol-> - setEncodings( { - rfbEncodingTight, - rfbEncodingZYWRLE, - rfbEncodingZRLE, - rfbEncodingUltra, - rfbEncodingCopyRect, - rfbEncodingHextile, - rfbEncodingCoRRE, - rfbEncodingRRE, - rfbEncodingRaw, - rfbEncodingCompressLevel9, - rfbEncodingQualityLevel0 + quality, - rfbEncodingNewFBSize, - rfbEncodingLastRect - } ); + m_vncClientProtocol->setEncodings({ + rfbEncodingTight, + rfbEncodingZYWRLE, + rfbEncodingZRLE, + rfbEncodingUltra, + rfbEncodingCopyRect, + rfbEncodingHextile, + rfbEncodingCoRRE, + rfbEncodingRRE, + rfbEncodingRaw, + rfbEncodingCompressLevel9, + rfbEncodingQualityLevel0 + quality, + rfbEncodingNewFBSize, + rfbEncodingLastRect + }); + + return m_vncClientProtocol->sendEncodings(); } diff --git a/plugins/filetransfer/FileTransferConfigurationPage.cpp b/plugins/filetransfer/FileTransferConfigurationPage.cpp index 2faab7d7d..4fca328ea 100644 --- a/plugins/filetransfer/FileTransferConfigurationPage.cpp +++ b/plugins/filetransfer/FileTransferConfigurationPage.cpp @@ -75,12 +75,12 @@ void FileTransferConfigurationPage::applyConfiguration() void FileTransferConfigurationPage::browseDefaultSourceDirectory() { - FileSystemBrowser( FileSystemBrowser::ExistingDirectory ).exec( ui->fileTransferDefaultSourceDirectory ); + FileSystemBrowser(FileSystemBrowser::ExistingDirectory, this).exec(ui->fileTransferDefaultSourceDirectory); } void FileTransferConfigurationPage::browseDestinationDirectory() { - FileSystemBrowser( FileSystemBrowser::ExistingDirectory ).exec( ui->fileTransferDestinationDirectory ); + FileSystemBrowser(FileSystemBrowser::ExistingDirectory, this).exec(ui->fileTransferDestinationDirectory); } diff --git a/plugins/platform/linux/LinuxNetworkFunctions.cpp b/plugins/platform/linux/LinuxNetworkFunctions.cpp index 98f5f3b3a..7e91da43c 100644 --- a/plugins/platform/linux/LinuxNetworkFunctions.cpp +++ b/plugins/platform/linux/LinuxNetworkFunctions.cpp @@ -29,13 +29,23 @@ #include "LinuxNetworkFunctions.h" -bool LinuxNetworkFunctions::ping( const QString& hostAddress ) +LinuxNetworkFunctions::PingResult LinuxNetworkFunctions::ping(const QString& hostAddress) { QProcess pingProcess; pingProcess.start( QStringLiteral("ping"), { QStringLiteral("-c"), QStringLiteral("1"), QStringLiteral("-w"), QString::number( PingTimeout / 1000 ), hostAddress } ); - pingProcess.waitForFinished( PingProcessTimeout ); + if (pingProcess.waitForFinished(PingProcessTimeout)) + { + switch (pingProcess.exitCode()) + { + case 0: return PingResult::ReplyReceived; + case 1: return PingResult::TimedOut; + case 2: return PingResult::NameResolutionFailed; + default: + break; + } + } - return pingProcess.exitCode() == 0; + return PingResult::Unknown; } diff --git a/plugins/platform/linux/LinuxNetworkFunctions.h b/plugins/platform/linux/LinuxNetworkFunctions.h index 73f9750e9..d0d41548a 100644 --- a/plugins/platform/linux/LinuxNetworkFunctions.h +++ b/plugins/platform/linux/LinuxNetworkFunctions.h @@ -31,7 +31,7 @@ class LinuxNetworkFunctions : public PlatformNetworkFunctions { public: - bool ping( const QString& hostAddress ) override; + PingResult ping(const QString& hostAddress) override; bool configureFirewallException( const QString& applicationPath, const QString& description, bool enabled ) override; bool configureSocketKeepalive( Socket socket, bool enabled, int idleTime, int interval, int probes ) override; diff --git a/plugins/platform/windows/WindowsNetworkFunctions.cpp b/plugins/platform/windows/WindowsNetworkFunctions.cpp index 218aab410..07b30b40f 100644 --- a/plugins/platform/windows/WindowsNetworkFunctions.cpp +++ b/plugins/platform/windows/WindowsNetworkFunctions.cpp @@ -224,24 +224,32 @@ WindowsNetworkFunctions::WindowsNetworkFunctions() : PlatformNetworkFunctions() -bool WindowsNetworkFunctions::ping( const QString& hostAddress ) +WindowsNetworkFunctions::PingResult WindowsNetworkFunctions::ping(const QString& hostAddress) { - bool result; + auto result = PingResult::Unknown; - const auto convertedAddress = HostAddress(hostAddress).tryConvert(HostAddress::Type::IpAddress); - const auto addressProtocol = QHostAddress(convertedAddress).protocol(); - - if( addressProtocol == QAbstractSocket::IPv4Protocol && pingIPv4Address(convertedAddress, &result) ) + const auto ipAddress = HostAddress(hostAddress).convert(HostAddress::Type::IpAddress); + if (ipAddress.isEmpty() == false) { - return result; + const auto addressProtocol = QHostAddress(ipAddress).protocol(); + + if (addressProtocol == QAbstractSocket::IPv4Protocol && pingIPv4Address(ipAddress, &result)) + { + return result; + } + + if (addressProtocol == QAbstractSocket::IPv6Protocol && pingIPv6Address(ipAddress, &result)) + { + return result; + } } - if( addressProtocol == QAbstractSocket::IPv6Protocol && pingIPv6Address(convertedAddress, &result) ) + if (pingViaUtility(hostAddress, &result)) { return result; } - return pingViaUtility(hostAddress); + return PingResult::Unknown; } @@ -328,14 +336,14 @@ bool WindowsNetworkFunctions::configureSocketKeepalive( Socket socket, bool enab -bool WindowsNetworkFunctions::pingIPv4Address( const QString& hostAddress, bool* result ) +bool WindowsNetworkFunctions::pingIPv4Address(const QString& hostAddress, PingResult* result) { if( result == nullptr ) { return false; } - *result = false; + *result = PingResult::Unknown; const IPAddr ipAddress = inet_addr(hostAddress.toLatin1().constData()); if( ipAddress == INADDR_NONE ) @@ -363,23 +371,29 @@ bool WindowsNetworkFunctions::pingIPv4Address( const QString& hostAddress, bool* if( success ) { - *result = true; + *result = PingResult::ReplyReceived; + return true; + } + + if (error == IP_REQ_TIMED_OUT) + { + *result = PingResult::TimedOut; return true; } - return error == IP_REQ_TIMED_OUT; + return false; } -bool WindowsNetworkFunctions::pingIPv6Address( const QString& hostAddress, bool* result ) +bool WindowsNetworkFunctions::pingIPv6Address(const QString& hostAddress, PingResult* result) { if( result == nullptr ) { return false; } - *result = false; + *result = PingResult::Unknown; SOCKADDR_IN6 icmp6LocalAddr{}; icmp6LocalAddr.sin6_addr = in6addr_any; @@ -446,20 +460,61 @@ bool WindowsNetworkFunctions::pingIPv6Address( const QString& hostAddress, bool* if( success ) { - *result = true; + *result = PingResult::ReplyReceived; return true; } - return error == IP_REQ_TIMED_OUT; + if (error == IP_REQ_TIMED_OUT) + { + *result = PingResult::TimedOut; + return true; + } + + return false; } -bool WindowsNetworkFunctions::pingViaUtility( const QString& hostAddress ) +bool WindowsNetworkFunctions::pingViaUtility(const QString& hostAddress, PingResult* result) { + if (result == nullptr) + { + return false; + } + + *result = PingResult::Unknown; + + const QStringList pingArguments = { + QStringLiteral("-n"), QStringLiteral("1"), + QStringLiteral("-w"), QString::number(PingTimeout), + hostAddress + }; + QProcess pingProcess; - pingProcess.start( QStringLiteral("ping"), { QStringLiteral("-n"), QStringLiteral("1"), QStringLiteral("-w"), QString::number( PingTimeout ), hostAddress } ); - pingProcess.waitForFinished( PingProcessTimeout ); + pingProcess.start(QStringLiteral("ping"), pingArguments); + if (pingProcess.waitForStarted(PingProcessTimeout)) + { + if (pingProcess.waitForFinished(PingProcessTimeout)) + { + if (QString::fromUtf8(pingProcess.readAll()).split(QLatin1Char('\n')).filter(QStringLiteral("=")).size() >= 2) + { + *result = PingResult::ReplyReceived; + } + else if (pingProcess.exitCode() == 1) + { + *result = PingResult::NameResolutionFailed; + } + else + { + *result = PingResult::TimedOut; + } + } + else + { + *result = PingResult::NameResolutionFailed; + } + return true; + } - return pingProcess.exitCode() == 0; + return false; } diff --git a/plugins/platform/windows/WindowsNetworkFunctions.h b/plugins/platform/windows/WindowsNetworkFunctions.h index 99a4cdb0c..d86144c40 100644 --- a/plugins/platform/windows/WindowsNetworkFunctions.h +++ b/plugins/platform/windows/WindowsNetworkFunctions.h @@ -35,7 +35,7 @@ class WindowsNetworkFunctions : public PlatformNetworkFunctions public: WindowsNetworkFunctions(); - bool ping( const QString& hostAddress ) override; + PingResult ping(const QString& hostAddress) override; bool configureFirewallException( const QString& applicationPath, const QString& description, bool enabled ) override; bool configureSocketKeepalive( Socket socket, bool enabled, int idleTime, int interval, int probes ) override; @@ -43,8 +43,8 @@ class WindowsNetworkFunctions : public PlatformNetworkFunctions static constexpr auto WindowsFirewallServiceError = HRESULT(0x800706D9); private: - bool pingIPv4Address( const QString& hostAddress, bool* result ); - bool pingIPv6Address( const QString& hostAddress, bool* result ); - bool pingViaUtility( const QString& hostAddress ); + bool pingIPv4Address(const QString& hostAddress, PingResult* result); + bool pingIPv6Address(const QString& hostAddress, PingResult* result); + bool pingViaUtility(const QString& hostAddress, PingResult* result); }; diff --git a/plugins/remoteaccess/RemoteAccessFeaturePlugin.cpp b/plugins/remoteaccess/RemoteAccessFeaturePlugin.cpp index ecdc3b6ed..0b2b84d50 100644 --- a/plugins/remoteaccess/RemoteAccessFeaturePlugin.cpp +++ b/plugins/remoteaccess/RemoteAccessFeaturePlugin.cpp @@ -123,18 +123,18 @@ bool RemoteAccessFeaturePlugin::startFeature( VeyonMasterInterface& master, cons } else { - const auto hostName = QInputDialog::getText( master.mainWindow(), - tr( "Remote access" ), - tr( "No computer has been selected so you can enter a hostname " - "or IP address of a computer for manual access:" ) ); - if( hostName.isEmpty() ) + const auto hostAddress = QInputDialog::getText(master.mainWindow(), + tr("Remote access"), + tr("No computer has been selected so you can enter a hostname " + "or IP address of a computer for manual access:")); + if (hostAddress.isEmpty()) { return false; } Computer customComputer; - customComputer.setHostAddress( hostName ); - customComputer.setName( hostName ); + customComputer.setHostAddress(hostAddress); + customComputer.setDisplayName(hostAddress); createRemoteAccessWindow(ComputerControlInterface::Pointer::create(customComputer), viewOnly); } @@ -345,8 +345,8 @@ bool RemoteAccessFeaturePlugin::remoteAccess( const QString& hostAddress, bool v } Computer remoteComputer; - remoteComputer.setName( hostAddress ); - remoteComputer.setHostAddress( hostAddress ); + remoteComputer.setDisplayName(hostAddress); + remoteComputer.setHostAddress(hostAddress); if( remoteControlEnabled() == false ) { diff --git a/plugins/remoteaccess/RemoteAccessWidget.cpp b/plugins/remoteaccess/RemoteAccessWidget.cpp index 7fbae456e..8d418879a 100644 --- a/plugins/remoteaccess/RemoteAccessWidget.cpp +++ b/plugins/remoteaccess/RemoteAccessWidget.cpp @@ -523,13 +523,13 @@ void RemoteAccessWidget::updateRemoteAccessTitle() if (username.isEmpty() ) { - setWindowTitle( tr( "%1 - %2 Remote Access" ).arg( m_computerControlInterface->computer().name(), - VeyonCore::applicationName() ) ); + setWindowTitle(tr("%1 - %2 Remote Access").arg(m_computerControlInterface->computer().displayName(), + VeyonCore::applicationName())); } else { - setWindowTitle( tr( "%1 - %2 - %3 Remote Access" ).arg( username, - m_computerControlInterface->computer().name(), - VeyonCore::applicationName() ) ); + setWindowTitle(tr("%1 - %2 - %3 Remote Access").arg(username, + m_computerControlInterface->computer().displayName(), + VeyonCore::applicationName())); } } diff --git a/plugins/testing/TestingCommandLinePlugin.cpp b/plugins/testing/TestingCommandLinePlugin.cpp index bdf1f7da9..ff034909d 100644 --- a/plugins/testing/TestingCommandLinePlugin.cpp +++ b/plugins/testing/TestingCommandLinePlugin.cpp @@ -58,7 +58,7 @@ QString TestingCommandLinePlugin::commandHelp( const QString& command ) const CommandLinePluginInterface::RunResult TestingCommandLinePlugin::handle_checkaccess( const QStringList& arguments ) { - switch( AccessControlProvider().checkAccess( arguments.value( 0 ), arguments.value( 1 ), { arguments.value( 2 ) } ) ) + switch (AccessControlProvider().checkAccess(arguments.value(0), arguments.value(1), {arguments.value(2)}).access) { case AccessControlProvider::Access::Allow: printf( "[TEST]: CheckAccess: ALLOW\n" ); return Successful; case AccessControlProvider::Access::Deny: printf( "[TEST]: CheckAccess: DENY\n" ); return Successful; @@ -88,9 +88,11 @@ CommandLinePluginInterface::RunResult TestingCommandLinePlugin::handle_authorize CommandLinePluginInterface::RunResult TestingCommandLinePlugin::handle_accesscontrolrules( const QStringList& arguments ) { - switch( AccessControlProvider().processAccessControlRules( arguments.value( 0 ), arguments.value( 1 ), - arguments.value( 2 ), arguments.value( 3 ), - QStringList( arguments.value( 4 ) ) ) ) + AccessControlProvider provider; + const auto rule = provider.processAccessControlRules(arguments.value(0), arguments.value(1), + arguments.value(2), arguments.value(3), + QStringList(arguments.value(4))); + switch(rule ? rule->action() : AccessControlRule::Action::None) { case AccessControlRule::Action::Allow: printf( "[TEST]: AccessControlRules: ALLOW\n" ); return Successful; case AccessControlRule::Action::Deny: printf( "[TEST]: AccessControlRules: DENY\n" ); return Successful; @@ -129,5 +131,5 @@ CommandLinePluginInterface::RunResult TestingCommandLinePlugin::handle_ping( con return NotEnoughArguments; } - return VeyonCore::platform().networkFunctions().ping( arguments.first() ) ? Successful : Failed; + return VeyonCore::platform().networkFunctions().ping( arguments.first() ) == PlatformNetworkFunctions::PingResult::ReplyReceived ? Successful : Failed; } diff --git a/plugins/vncserver/headless/HeadlessVncServer.cpp b/plugins/vncserver/headless/HeadlessVncServer.cpp index 51ca50383..5cdc23a4d 100644 --- a/plugins/vncserver/headless/HeadlessVncServer.cpp +++ b/plugins/vncserver/headless/HeadlessVncServer.cpp @@ -64,6 +64,17 @@ void HeadlessVncServer::prepareServer() bool HeadlessVncServer::runServer( int serverPort, const Password& password ) { + if (VeyonCore::isDebugging()) + { + rfbLog = rfbLogDebug; + rfbErr = rfbLogDebug; + } + else + { + rfbLog = rfbLogNone; + rfbErr = rfbLogNone; + } + HeadlessVncScreen screen; if( initScreen( &screen ) == false || @@ -148,4 +159,29 @@ bool HeadlessVncServer::initVncServer( int serverPort, const VncServerPluginInte } + +void HeadlessVncServer::rfbLogDebug(const char* format, ...) +{ + va_list args; + va_start(args, format); + + static constexpr int MaxMessageLength = 256; + char message[MaxMessageLength]; + + vsnprintf(message, sizeof(message), format, args); + message[MaxMessageLength-1] = 0; + + va_end(args); + + vDebug() << message; +} + + + +void HeadlessVncServer::rfbLogNone(const char* format, ...) +{ + Q_UNUSED(format); +} + + IMPLEMENT_CONFIG_PROXY(HeadlessVncConfiguration) diff --git a/plugins/vncserver/headless/HeadlessVncServer.h b/plugins/vncserver/headless/HeadlessVncServer.h index 8c0b80811..59d70bb9b 100644 --- a/plugins/vncserver/headless/HeadlessVncServer.h +++ b/plugins/vncserver/headless/HeadlessVncServer.h @@ -108,6 +108,9 @@ class HeadlessVncServer : public QObject, VncServerPluginInterface, PluginInterf bool handleScreenChanges( HeadlessVncScreen* screen ); + static void rfbLogDebug(const char* format, ...); + static void rfbLogNone(const char* format, ...); + HeadlessVncConfiguration m_configuration; }; diff --git a/plugins/webapi/WebApiConfigurationPage.cpp b/plugins/webapi/WebApiConfigurationPage.cpp index 9b2e74983..8eae7b761 100644 --- a/plugins/webapi/WebApiConfigurationPage.cpp +++ b/plugins/webapi/WebApiConfigurationPage.cpp @@ -37,11 +37,11 @@ WebApiConfigurationPage::WebApiConfigurationPage( WebApiConfiguration& configura ui->setupUi(this); connect( ui->browseTlsCertificateFile, &QAbstractButton::clicked, this, [this]() { - FileSystemBrowser( FileSystemBrowser::ExistingFile ).exec( ui->tlsCertificateFile ); + FileSystemBrowser(FileSystemBrowser::ExistingFile, this).exec(ui->tlsCertificateFile); } ); connect( ui->browseTlsPrivateKeyFile, &QAbstractButton::clicked, this, [this]() { - FileSystemBrowser( FileSystemBrowser::ExistingFile ).exec( ui->tlsPrivateKeyFile ); + FileSystemBrowser(FileSystemBrowser::ExistingFile, this ).exec(ui->tlsPrivateKeyFile); } ); Configuration::UiMapping::setFlags( this, Configuration::Property::Flag::Advanced ); diff --git a/plugins/webapi/WebApiController.cpp b/plugins/webapi/WebApiController.cpp index 55e35af94..4d6b7db6f 100644 --- a/plugins/webapi/WebApiController.cpp +++ b/plugins/webapi/WebApiController.cpp @@ -85,7 +85,7 @@ WebApiController::Response WebApiController::getHostState(const Request& request return QVariantMap{{k2s(Key::State), QByteArrayLiteral("online")}}; } - if (VeyonCore::platform().networkFunctions().ping(host)) + if (VeyonCore::platform().networkFunctions().ping(host) == PlatformNetworkFunctions::PingResult::ReplyReceived) { return QByteArrayLiteral("up"); } @@ -501,7 +501,7 @@ QString WebApiController::getConnectionDetails() rows.append({uuidToString(it.key()), EnumHelper::toString(connection->controlInterface()->state()), - connection->controlInterface()->computer().hostAddress(), + connection->controlInterface()->computer().hostName(), connection->controlInterface()->userLoginName(), EnumHelper::toString(connection->controlInterface()->serverVersion()), }); diff --git a/project.yml b/project.yml index 3d69df563..20dd0835e 100644 --- a/project.yml +++ b/project.yml @@ -1,6 +1,6 @@ project: name: Veyon - version: 4.9.3 + version: 4.9.4 copyright: 2004-2025 author: Tobias Junghans contact: Tobias Junghans diff --git a/server/src/ComputerControlServer.cpp b/server/src/ComputerControlServer.cpp index b051ab855..8cae76843 100644 --- a/server/src/ComputerControlServer.cpp +++ b/server/src/ComputerControlServer.cpp @@ -44,7 +44,7 @@ ComputerControlServer::ComputerControlServer( QObject* parent ) : m_serverAuthenticationManager( this ), m_serverAccessControlManager( m_featureWorkerManager, VeyonCore::builtinFeatures().desktopAccessDialog(), this ), m_vncServer(), - m_vncProxyServer( VeyonCore::config().localConnectOnly() || AccessControlProvider().isAccessToLocalComputerDenied() ? + m_vncProxyServer( VeyonCore::config().localConnectOnly() || VeyonCore::builtinFeatures().accessControlProvider().isAccessToLocalComputerDenied() ? QHostAddress::LocalHost : QHostAddress::Any, VeyonCore::config().veyonServerPort() + VeyonCore::sessionId(), this, @@ -143,12 +143,9 @@ bool ComputerControlServer::sendFeatureMessageReply( const MessageContext& conte { vDebug() << reply; - if( context.ioDevice() ) + if (context.ioDevice()) { - char rfbMessageType = FeatureMessage::RfbMessageType; - context.ioDevice()->write( &rfbMessageType, sizeof(rfbMessageType) ); - - return reply.send( context.ioDevice() ); + return reply.sendAsRfbMessage(context.ioDevice()); } return false; @@ -170,8 +167,8 @@ void ComputerControlServer::setMinimumFramebufferUpdateInterval(const MessageCon void ComputerControlServer::checkForIncompleteAuthentication( VncServerClient* client ) { // connection to client closed during authentication? - if( client->protocolState() == VncServerProtocol::AuthenticationTypes || - client->protocolState() == VncServerProtocol::Authenticating ) + if( client->protocolState() == VncServerProtocol::State::AuthenticationTypes || + client->protocolState() == VncServerProtocol::State::Authenticating ) { // then mark as failed authentication and report it client->setAuthState( VncServerClient::AuthState::Failed ); diff --git a/server/src/ServerAccessControlManager.cpp b/server/src/ServerAccessControlManager.cpp index 12d6384e2..0a37c3a0f 100644 --- a/server/src/ServerAccessControlManager.cpp +++ b/server/src/ServerAccessControlManager.cpp @@ -24,11 +24,10 @@ #include "VeyonCore.h" +#include "BuiltinFeatures.h" #include "ServerAccessControlManager.h" #include "AccessControlProvider.h" #include "DesktopAccessDialog.h" -#include "VeyonConfiguration.h" -#include "VariantArrayMessage.h" ServerAccessControlManager::ServerAccessControlManager( FeatureWorkerManager& featureWorkerManager, @@ -60,6 +59,7 @@ void ServerAccessControlManager::addClient( VncServerClient* client ) default: // reject unknown auth type client->setAccessControlState( VncServerClient::AccessControlState::Failed ); + client->setAccessControlDetails(tr("Requested authentication method not available")); break; } @@ -90,7 +90,7 @@ void ServerAccessControlManager::removeClient( VncServerClient* client ) prevClient->accessControlState() != VncServerClient::AccessControlState::Pending ) { vDebug() << "closing connection as client does not pass access control any longer"; - prevClient->setProtocolState( VncServerProtocol::Close ); + prevClient->setProtocolState( VncServerProtocol::State::Close ); } } } @@ -117,15 +117,19 @@ void ServerAccessControlManager::performAccessControl( VncServerClient* client ) break; } - const auto accessResult = - AccessControlProvider().checkAccess( client->username(), - client->hostAddress(), - connectedUsers() ); + const auto checkResult = VeyonCore::builtinFeatures().accessControlProvider() + .checkAccess(client->username(), + client->hostAddress(), + connectedUsers()); - switch( accessResult ) + switch (checkResult.access) { case AccessControlProvider::Access::Allow: client->setAccessControlState( VncServerClient::AccessControlState::Successful ); + if (checkResult.matchedRule) + { + client->setAccessControlDetails(tr("Access allowed by rule \"%1\"").arg(checkResult.matchedRule->name())); + } break; case AccessControlProvider::Access::ToBeConfirmed: @@ -134,7 +138,19 @@ void ServerAccessControlManager::performAccessControl( VncServerClient* client ) default: client->setAccessControlState( VncServerClient::AccessControlState::Failed ); - client->setProtocolState( VncServerProtocol::Close ); + client->setProtocolState( VncServerProtocol::State::Close ); + if (checkResult.reason == AccessControlProvider::Reason::AccessControlRuleMatched && checkResult.matchedRule) + { + client->setAccessControlDetails(tr("Access denied by rule \"%1\"").arg(checkResult.matchedRule->name())); + } + else if (checkResult.reason == AccessControlProvider::Reason::NoAccessControlRuleMatched) + { + client->setAccessControlDetails(tr("No rule allowed access")); + } + else if (checkResult.reason == AccessControlProvider::Reason::UserNotInAuthorizedUserGroups) + { + client->setAccessControlDetails(tr("Accessing user not member of an authorized user group")); + } break; } @@ -155,6 +171,7 @@ VncServerClient::AccessControlState ServerAccessControlManager::confirmDesktopAc return VncServerClient::AccessControlState::Successful; } + client->setAccessControlDetails(tr("User has denied access")); return VncServerClient::AccessControlState::Failed; } @@ -205,12 +222,13 @@ void ServerAccessControlManager::finishDesktopAccessConfirmation( VncServerClien if( choice == DesktopAccessDialog::ChoiceYes || choice == DesktopAccessDialog::ChoiceAlways ) { client->setAccessControlState( VncServerClient::AccessControlState::Successful ); + client->setAccessControlDetails(tr("User confirmed access")); m_clients.append( client ); } else { client->setAccessControlState( VncServerClient::AccessControlState::Failed ); - client->setProtocolState( VncServerProtocol::Close ); + client->setAccessControlDetails(tr("User has denied access")); } } diff --git a/server/src/ServerAccessControlManager.h b/server/src/ServerAccessControlManager.h index 2f54de3f8..dc4453713 100644 --- a/server/src/ServerAccessControlManager.h +++ b/server/src/ServerAccessControlManager.h @@ -25,7 +25,6 @@ #pragma once #include "DesktopAccessDialog.h" -#include "RfbVeyonAuth.h" #include "VncServerClient.h" class VariantArrayMessage; diff --git a/server/src/VncProxyConnection.cpp b/server/src/VncProxyConnection.cpp index c5a68e90d..c62a1ba48 100644 --- a/server/src/VncProxyConnection.cpp +++ b/server/src/VncProxyConnection.cpp @@ -39,7 +39,6 @@ VncProxyConnection::VncProxyConnection( QTcpSocket* clientSocket, m_proxyClientSocket( clientSocket ), m_vncServerSocket( new QTcpSocket( this ) ), m_rfbClientToServerMessageSizes( { - { rfbSetPixelFormat, sz_rfbSetPixelFormatMsg }, { rfbFramebufferUpdateRequest, sz_rfbFramebufferUpdateRequestMsg }, { rfbKeyEvent, sz_rfbKeyEventMsg }, { rfbPointerEvent, sz_rfbPointerEventMsg }, @@ -76,7 +75,7 @@ void VncProxyConnection::start() void VncProxyConnection::readFromClient() { - if( serverProtocol().state() != VncServerProtocol::Running ) + if( serverProtocol().state() != VncServerProtocol::State::Running ) { while( serverProtocol().read() ) // Flawfinder: ignore { @@ -99,7 +98,7 @@ void VncProxyConnection::readFromClient() readFromClientLater(); } - if( serverProtocol().state() == VncServerProtocol::FramebufferInit && + if( serverProtocol().state() == VncServerProtocol::State::FramebufferInit && clientProtocol().state() == VncClientProtocol::Disconnected ) { m_vncServerSocket->connectToHost( QHostAddress::LocalHost, quint16(m_vncServerPort) ); @@ -130,7 +129,7 @@ void VncProxyConnection::readFromServer() readFromServerLater(); } } - else if( serverProtocol().state() == VncServerProtocol::Running ) + else if( serverProtocol().state() == VncServerProtocol::State::Running ) { while( receiveServerMessage() ) { @@ -222,6 +221,23 @@ bool VncProxyConnection::receiveClientMessage() } break; + case rfbSetPixelFormat: + if (socket->bytesAvailable() >= sz_rfbSetPixelFormatMsg) + { + rfbSetPixelFormatMsg setPixelFormatMessage; + if (socket->peek(reinterpret_cast(&setPixelFormatMessage), sz_rfbSetPixelFormatMsg) == sz_rfbSetPixelFormatMsg) + { + auto format = setPixelFormatMessage.format; + format.redMax = qFromBigEndian(format.redMax); + format.greenMax = qFromBigEndian(format.greenMax); + format.blueMax = qFromBigEndian(format.blueMax); + clientProtocol().setPixelFormat(format); + + return forwardDataToServer(sz_rfbSetPixelFormatMsg); + } + } + break; + default: if( m_rfbClientToServerMessageSizes.contains( messageType ) == false ) { diff --git a/server/src/VncProxyConnection.h b/server/src/VncProxyConnection.h index 95f01fdd4..fef6f09ef 100644 --- a/server/src/VncProxyConnection.h +++ b/server/src/VncProxyConnection.h @@ -24,7 +24,7 @@ #pragma once -#include "VeyonCore.h" +#include class QBuffer; class QTcpSocket; diff --git a/translations/veyon.ts b/translations/veyon.ts index abe6f940f..415e24c4a 100644 --- a/translations/veyon.ts +++ b/translations/veyon.ts @@ -133,6 +133,13 @@ If you're interested in translating Veyon into your local or another langua + + AccessControlProvider + + Provider for access control features + + + AccessControlRuleEditDialog @@ -1002,14 +1009,6 @@ Make sure that the names of the keys belonging to each other are identical on al Location: %1 - - Host/IP address: %1 - - - - invalid - - Active features: %1 @@ -1051,7 +1050,23 @@ Make sure that the names of the keys belonging to each other are identical on al - [none] + Hostname: %1 + + + + unknown + + + + IP address: %1 + + + + Hostname could not be resolved + + + + No features active @@ -1978,6 +1993,18 @@ Make sure that the names of the keys belonging to each other are identical on al No user groups plugin was found. Please check your installation! + + Color scheme: + + + + Light + + + + Dark + + HeadlessVncServer @@ -3713,6 +3740,37 @@ Please save your work and close all programs. + + ServerAccessControlManager + + Requested authentication method not available + + + + Access allowed by rule "%1" + + + + Access denied by rule "%1" + + + + No rule allowed access + + + + Accessing user not member of an authorized user group + + + + User has denied access + + + + User confirmed access + + + ServiceConfigurationPage @@ -3874,23 +3932,27 @@ Example: [^-]*-(PC[0-9]*) ServiceControl - Starting service %1 + Service control - Stopping service %1 + Starting %1 - Registering service %1 + Stopping %1 - Unregistering service %1 + Restarting %1 - Service control + Registering %1 + + + + Unregistering %1 diff --git a/translations/veyon_ar.ts b/translations/veyon_ar.ts index 1b2b4cf8e..777124373 100644 --- a/translations/veyon_ar.ts +++ b/translations/veyon_ar.ts @@ -131,6 +131,13 @@ If you're interested in translating Veyon into your local or another langua + + AccessControlProvider + + Provider for access control features + + + AccessControlRuleEditDialog @@ -1000,14 +1007,6 @@ Make sure that the names of the keys belonging to each other are identical on al Location: %1 - - Host/IP address: %1 - - - - invalid - - Active features: %1 @@ -1049,7 +1048,23 @@ Make sure that the names of the keys belonging to each other are identical on al - [none] + Hostname: %1 + + + + unknown + غير معروف + + + IP address: %1 + + + + Hostname could not be resolved + + + + No features active @@ -1976,6 +1991,18 @@ Make sure that the names of the keys belonging to each other are identical on al No user groups plugin was found. Please check your installation! + + Color scheme: + + + + Light + + + + Dark + + HeadlessVncServer @@ -3711,6 +3738,37 @@ Please save your work and close all programs. + + ServerAccessControlManager + + Requested authentication method not available + + + + Access allowed by rule "%1" + + + + Access denied by rule "%1" + + + + No rule allowed access + + + + Accessing user not member of an authorized user group + + + + User has denied access + + + + User confirmed access + + + ServiceConfigurationPage @@ -3872,23 +3930,27 @@ Example: [^-]*-(PC[0-9]*) ServiceControl - Starting service %1 + Service control - Stopping service %1 + Starting %1 - Registering service %1 + Stopping %1 - Unregistering service %1 + Restarting %1 - Service control + Registering %1 + + + + Unregistering %1 diff --git a/translations/veyon_bg.ts b/translations/veyon_bg.ts index b3c6bd6ae..447836409 100644 --- a/translations/veyon_bg.ts +++ b/translations/veyon_bg.ts @@ -133,6 +133,13 @@ If you're interested in translating Veyon into your local or another langua Посоченият потребител няма право да получава достъп до компютри с тази конфигурация. + + AccessControlProvider + + Provider for access control features + + + AccessControlRuleEditDialog @@ -1005,14 +1012,6 @@ Make sure that the names of the keys belonging to each other are identical on al Location: %1 Location: %1 - - Host/IP address: %1 - Host/IP address: %1 - - - invalid - - Active features: %1 Active features: %1 @@ -1054,7 +1053,23 @@ Make sure that the names of the keys belonging to each other are identical on al Logged on user: %1 - [none] + Hostname: %1 + + + + unknown + unknown + + + IP address: %1 + + + + Hostname could not be resolved + + + + No features active @@ -1981,6 +1996,18 @@ Make sure that the names of the keys belonging to each other are identical on al No user groups plugin was found. Please check your installation! + + Color scheme: + + + + Light + + + + Dark + + HeadlessVncServer @@ -3737,6 +3764,37 @@ Please save your work and close all programs. + + ServerAccessControlManager + + Requested authentication method not available + + + + Access allowed by rule "%1" + + + + Access denied by rule "%1" + + + + No rule allowed access + + + + Accessing user not member of an authorized user group + + + + User has denied access + + + + User confirmed access + + + ServiceConfigurationPage @@ -3899,24 +3957,28 @@ Example: [^-]*-(PC[0-9]*) ServiceControl - Starting service %1 - Starting service %1 + Service control + Service control + + + Starting %1 + - Stopping service %1 - Stopping service %1 + Stopping %1 + - Registering service %1 - Registering service %1 + Restarting %1 + - Unregistering service %1 - Unregistering service %1 + Registering %1 + - Service control - Service control + Unregistering %1 + diff --git a/translations/veyon_ca_ES.ts b/translations/veyon_ca_ES.ts index 884809816..4f9fc68ea 100644 --- a/translations/veyon_ca_ES.ts +++ b/translations/veyon_ca_ES.ts @@ -133,6 +133,13 @@ Si esteu interessat a traduir el Veyon al vostre idioma local o a un altre o vol L'usuari especificat no té permís per a accedir als ordinadors amb aquesta configuració. + + AccessControlProvider + + Provider for access control features + + + AccessControlRuleEditDialog @@ -1005,14 +1012,6 @@ Make sure that the names of the keys belonging to each other are identical on al Location: %1 Ubicació: %1 - - Host/IP address: %1 - Adreça IP/amfitrió: %1 - - - invalid - no vàlid - Active features: %1 Característiques actives: %1 @@ -1054,8 +1053,24 @@ Make sure that the names of the keys belonging to each other are identical on al Usuari connectat: %1 - [none] - [cap] + Hostname: %1 + + + + unknown + desconegut + + + IP address: %1 + + + + Hostname could not be resolved + + + + No features active + @@ -1981,6 +1996,18 @@ Make sure that the names of the keys belonging to each other are identical on al No user groups plugin was found. Please check your installation! + + Color scheme: + + + + Light + + + + Dark + + HeadlessVncServer @@ -3737,6 +3764,37 @@ Deseu el vostre treball i tanqueu tots els programes. Esteu segur que voleu suprimir totes les captures de pantalla seleccionades? + + ServerAccessControlManager + + Requested authentication method not available + + + + Access allowed by rule "%1" + + + + Access denied by rule "%1" + + + + No rule allowed access + + + + Accessing user not member of an authorized user group + + + + User has denied access + + + + User confirmed access + + + ServiceConfigurationPage @@ -3899,24 +3957,28 @@ Example: [^-]*-(PC[0-9]*) ServiceControl - Starting service %1 - Iniciant el servei %1 + Service control + Control del servei + + + Starting %1 + - Stopping service %1 - Aturant el servei %1 + Stopping %1 + - Registering service %1 - Servei de registre %1 + Restarting %1 + - Unregistering service %1 - S'està cancel·lant el registre del servei %1 + Registering %1 + - Service control - Control del servei + Unregistering %1 + diff --git a/translations/veyon_cs.ts b/translations/veyon_cs.ts index 3f3b9ced3..19a53ebd5 100644 --- a/translations/veyon_cs.ts +++ b/translations/veyon_cs.ts @@ -133,6 +133,13 @@ Pokud ale překlad není kompletní a nebo by potřeboval vylepšit, případně Zadanému uživateli není umožněn přístup k počítačům s tímto nastavením. + + AccessControlProvider + + Provider for access control features + + + AccessControlRuleEditDialog @@ -1005,14 +1012,6 @@ Make sure that the names of the keys belonging to each other are identical on al Location: %1 Umístění: %1 - - Host/IP address: %1 - Stroj / IP adresa: %1 - - - invalid - - Active features: %1 Aktivní funkce: %1 @@ -1054,7 +1053,23 @@ Make sure that the names of the keys belonging to each other are identical on al Přihlášený uživatel: %1 - [none] + Hostname: %1 + + + + unknown + Neznámé + + + IP address: %1 + + + + Hostname could not be resolved + + + + No features active @@ -1981,6 +1996,18 @@ Make sure that the names of the keys belonging to each other are identical on al No user groups plugin was found. Please check your installation! + + Color scheme: + + + + Light + + + + Dark + + HeadlessVncServer @@ -3733,6 +3760,37 @@ Uložte si rozdělanou práci a ukončete všechny aplikace. + + ServerAccessControlManager + + Requested authentication method not available + + + + Access allowed by rule "%1" + + + + Access denied by rule "%1" + + + + No rule allowed access + + + + Accessing user not member of an authorized user group + + + + User has denied access + + + + User confirmed access + + + ServiceConfigurationPage @@ -3895,24 +3953,28 @@ Example: [^-]*-(PC[0-9]*) ServiceControl - Starting service %1 - Spouštění služby %1 + Service control + Řízení služby + + + Starting %1 + - Stopping service %1 - Zastavování služby %1 + Stopping %1 + - Registering service %1 - Registrace služby %1 + Restarting %1 + - Unregistering service %1 - Rušení registrace služby %1 + Registering %1 + - Service control - Řízení služby + Unregistering %1 + diff --git a/translations/veyon_de.ts b/translations/veyon_de.ts index aab0b12ce..e12017622 100644 --- a/translations/veyon_de.ts +++ b/translations/veyon_de.ts @@ -131,6 +131,13 @@ If you're interested in translating Veyon into your local or another langua Der angegebene Benutzer darf mit dieser Konfiguration nicht auf Computer zugreifen. + + AccessControlProvider + + Provider for access control features + Anbieter für Zugriffskontrollfunktionen + + AccessControlRuleEditDialog @@ -1004,14 +1011,6 @@ Achten Sie darauf, dass die Namen der zueinander gehörenden Schlüssel auf alle Location: %1 Standort: %1 - - Host/IP address: %1 - Host-/IP-Adresse: %1 - - - invalid - ungültig - Active features: %1 Aktive Funktionen: %1 @@ -1053,8 +1052,24 @@ Achten Sie darauf, dass die Namen der zueinander gehörenden Schlüssel auf alle Angemeldeter Benutzer: %1 - [none] - [keine] + Hostname: %1 + Hostname: %1 + + + unknown + unbekannt + + + IP address: %1 + IP-Adresse: %1 + + + Hostname could not be resolved + Hostname konnte nicht aufgelöst werden + + + No features active + Keine Funktionen aktiv @@ -1980,6 +1995,18 @@ Achten Sie darauf, dass die Namen der zueinander gehörenden Schlüssel auf alle No user groups plugin was found. Please check your installation! Es wurde kein Benutzergruppen-Plugin gefunden. Bitte überprüfen Sie Ihre Installation! + + Color scheme: + Farbschema: + + + Light + Hell + + + Dark + Dunkel + HeadlessVncServer @@ -3738,6 +3765,37 @@ Bitte speichern Sie Ihre Arbeiten und schließen alle Programme. Möchten Sie wirklich alle ausgewählten Screenshots löschen? + + ServerAccessControlManager + + Requested authentication method not available + Angeforderte Authentifizierungsmethode nicht verfügbar + + + Access allowed by rule "%1" + Zugriff erlaubt durch Regel "%1" + + + Access denied by rule "%1" + Zugriff verweigert durch Regel "%1" + + + No rule allowed access + Keine Regel erlaubt Zugriff + + + Accessing user not member of an authorized user group + Zugreifender Benutzer ist nicht Mitglied einer autorisierten Benutzergruppe + + + User has denied access + Benutzer hat den Zugriff abgelehnt + + + User confirmed access + Benutzer hat den Zugriff bestätigt + + ServiceConfigurationPage @@ -3902,24 +3960,28 @@ Beispiel: [^-]*-(PC[0-9]*) ServiceControl - Starting service %1 - Starte Dienst %1 + Service control + Dienststeuerung - Stopping service %1 - Beende Dienst %1 + Starting %1 + Starte %1 - Registering service %1 - Registriere Dienst %1 + Stopping %1 + Beende %1 - Unregistering service %1 - Deregistriere Dienst %1 + Restarting %1 + Starte %1 neu - Service control - Dienststeuerung + Registering %1 + Registriere %1 + + + Unregistering %1 + Deregistriere %1 diff --git a/translations/veyon_el.ts b/translations/veyon_el.ts index 5f3ee3706..ae5ef75e0 100644 --- a/translations/veyon_el.ts +++ b/translations/veyon_el.ts @@ -133,6 +133,13 @@ If you're interested in translating Veyon into your local or another langua Ο συγκεκριμένος χρήστης δεν έχει δικαίωμα πρόσβασης σε υπολογιστές με αυτή τη διαμόρφωση. + + AccessControlProvider + + Provider for access control features + + + AccessControlRuleEditDialog @@ -1002,14 +1009,6 @@ Make sure that the names of the keys belonging to each other are identical on al Location: %1 - - Host/IP address: %1 - - - - invalid - - Active features: %1 @@ -1051,7 +1050,23 @@ Make sure that the names of the keys belonging to each other are identical on al - [none] + Hostname: %1 + + + + unknown + άγνωστο + + + IP address: %1 + + + + Hostname could not be resolved + + + + No features active @@ -1978,6 +1993,18 @@ Make sure that the names of the keys belonging to each other are identical on al No user groups plugin was found. Please check your installation! + + Color scheme: + + + + Light + + + + Dark + + HeadlessVncServer @@ -3713,6 +3740,37 @@ Please save your work and close all programs. + + ServerAccessControlManager + + Requested authentication method not available + + + + Access allowed by rule "%1" + + + + Access denied by rule "%1" + + + + No rule allowed access + + + + Accessing user not member of an authorized user group + + + + User has denied access + + + + User confirmed access + + + ServiceConfigurationPage @@ -3874,23 +3932,27 @@ Example: [^-]*-(PC[0-9]*) ServiceControl - Starting service %1 - Εκκίνηση της υπηρεσίας %1 + Service control + - Stopping service %1 - Τερματισμός της υπηρεσίας %1 + Starting %1 + - Registering service %1 + Stopping %1 - Unregistering service %1 + Restarting %1 - Service control + Registering %1 + + + + Unregistering %1 diff --git a/translations/veyon_es_ES.ts b/translations/veyon_es_ES.ts index 30d363b2c..e6369df5c 100644 --- a/translations/veyon_es_ES.ts +++ b/translations/veyon_es_ES.ts @@ -135,6 +135,13 @@ Si deseas mejorar la traducción actual, por favor, ¡contacta con un desarrolla El usuario especificado no puede acceder a los equipos con esta configuración. + + AccessControlProvider + + Provider for access control features + + + AccessControlRuleEditDialog @@ -1007,14 +1014,6 @@ Make sure that the names of the keys belonging to each other are identical on al Location: %1 Ubicación: %1 - - Host/IP address: %1 - Equipo/Dirección IP: %1 - - - invalid - invalido - Active features: %1 Características activas: %1 @@ -1056,8 +1055,24 @@ Make sure that the names of the keys belonging to each other are identical on al Usuario conectado: %1 - [none] - [ninguno/a] + Hostname: %1 + + + + unknown + desconocido + + + IP address: %1 + + + + Hostname could not be resolved + + + + No features active + @@ -1983,6 +1998,18 @@ Make sure that the names of the keys belonging to each other are identical on al No user groups plugin was found. Please check your installation! + + Color scheme: + + + + Light + + + + Dark + + HeadlessVncServer @@ -3739,6 +3766,37 @@ Por favor guarde su trabajo y cierre todos los programas. ¿Realmente desea eliminar todas las capturas de pantalla seleccionadas? + + ServerAccessControlManager + + Requested authentication method not available + + + + Access allowed by rule "%1" + + + + Access denied by rule "%1" + + + + No rule allowed access + + + + Accessing user not member of an authorized user group + + + + User has denied access + + + + User confirmed access + + + ServiceConfigurationPage @@ -3901,24 +3959,28 @@ Example: [^-]*-(PC[0-9]*) ServiceControl - Starting service %1 - Iniciando servicio %1 + Service control + Control de servicio + + + Starting %1 + - Stopping service %1 - Deteniendo servicio %1 + Stopping %1 + - Registering service %1 - Registrando servicio %1 + Restarting %1 + - Unregistering service %1 - Eliminando registro de servicio %1 + Registering %1 + - Service control - Control de servicio + Unregistering %1 + diff --git a/translations/veyon_et.ts b/translations/veyon_et.ts index a8d19e669..ad7a16ca7 100644 --- a/translations/veyon_et.ts +++ b/translations/veyon_et.ts @@ -133,6 +133,13 @@ Kui olete huvitatud Veyoni tõlkimisest oma kohalikku või mõnda muusse keelde Määratud kasutajal pole lubatud selle konfiguratsiooniga arvutitele juurde pääseda. + + AccessControlProvider + + Provider for access control features + + + AccessControlRuleEditDialog @@ -1007,14 +1014,6 @@ Veenduge, et üksteisele kuuluvate võtmete nimed oleksid kõikides arvutites id Location: %1 Asukoht: %1 - - Host/IP address: %1 - Host/IP aadress: %1 - - - invalid - kehtetu - Active features: %1 Aktiivsed funktsioonid: %1 @@ -1056,8 +1055,24 @@ Veenduge, et üksteisele kuuluvate võtmete nimed oleksid kõikides arvutites id Sisseloginud kasutaja: %1 - [none] - [pole] + Hostname: %1 + + + + unknown + tundmatu + + + IP address: %1 + + + + Hostname could not be resolved + + + + No features active + @@ -1983,6 +1998,18 @@ Veenduge, et üksteisele kuuluvate võtmete nimed oleksid kõikides arvutites id No user groups plugin was found. Please check your installation! Ühtegi kasutajarühmade pistikprogrammi ei leitud. Palun kontrolli oma paigaldust! + + Color scheme: + + + + Light + + + + Dark + + HeadlessVncServer @@ -3739,6 +3766,37 @@ Salvestage oma töö ja sulgege kõik programmid. Kas soovite tõesti kõik valitud ekraanipildid kustutada? + + ServerAccessControlManager + + Requested authentication method not available + + + + Access allowed by rule "%1" + + + + Access denied by rule "%1" + + + + No rule allowed access + + + + Accessing user not member of an authorized user group + + + + User has denied access + + + + User confirmed access + + + ServiceConfigurationPage @@ -3903,24 +3961,28 @@ Näide: [^-]*-(PC[0-9]*) ServiceControl - Starting service %1 - Käivita teenus %1 + Service control + Teenuse juhtimine + + + Starting %1 + - Stopping service %1 - Teenuse peatamine %1 + Stopping %1 + - Registering service %1 - Teenuse registreerimine %1 + Restarting %1 + - Unregistering service %1 - Teenuse registreerimise tühistamine %1 + Registering %1 + - Service control - Teenuse juhtimine + Unregistering %1 + diff --git a/translations/veyon_eu.ts b/translations/veyon_eu.ts index 773fc78f6..658adf335 100644 --- a/translations/veyon_eu.ts +++ b/translations/veyon_eu.ts @@ -133,6 +133,13 @@ Veyon zure tokiko hizkuntzara edo beste hizkuntza batera itzultzeko interesa bad Zehaztutako erabiltzaileak konfigurazio honekin ez du baimenik ordenagailuetara sartzeko. + + AccessControlProvider + + Provider for access control features + + + AccessControlRuleEditDialog @@ -245,7 +252,7 @@ Veyon zure tokiko hizkuntzara edo beste hizkuntza batera itzultzeko interesa bad Local computer is already being accessed - + Tokiko ordenagailua sartzen ari da dagoeneko @@ -411,7 +418,9 @@ Gako publikoa ordenagailu bezeroetan erabiltzen da sarrerako konexio eskaera aut Please enter the name of the user group or role for which to import the authentication key. Make sure that the names of the keys belonging to each other are identical on all computers. - + Idatzi autentifikazio gakoa inportatzeko erabiltzaile taldearen edo rolaren izena. + +Ziurtatu gakoen izenak ordenagailu guztietan berdinak direla. @@ -1005,14 +1014,6 @@ Make sure that the names of the keys belonging to each other are identical on al Location: %1 Kokalekua: %1 - - Host/IP address: %1 - Ostalaria/IP helbidea: %1 - - - invalid - baliogabea - Active features: %1 Funtzio aktiboak: %1 @@ -1054,8 +1055,24 @@ Make sure that the names of the keys belonging to each other are identical on al Saioa hasi duen erabiltzailea: %1 - [none] - [none] + Hostname: %1 + + + + unknown + ezezaguna + + + IP address: %1 + + + + Hostname could not be resolved + + + + No features active + @@ -1981,6 +1998,18 @@ Make sure that the names of the keys belonging to each other are identical on al No user groups plugin was found. Please check your installation! Ez da aurkitu erabiltzaile taldeen pluginik. Mesedez, egiaztatu zure instalazioa! + + Color scheme: + + + + Light + + + + Dark + + HeadlessVncServer @@ -2979,15 +3008,17 @@ Make sure that the names of the keys belonging to each other are identical on al Use custom computer arrangement. Press and hold to load arrangement from a file or save current arrangement to a file. - + Ordenagailuaren antolamendu pertsonalizatua erabili. + +Luze sakatu fitxategi batetik kargatzeko edo uneko antolamendua fitxategi batera gordetzeko. Load computer positions - + Kargatu ordenagailuen kokapenak Save computer positions - + Gorde ordenagailuen kokapenak @@ -3190,23 +3221,23 @@ Press and hold to load arrangement from a file or save current arrangement to a Always expand all locations - + Zabaldu beti kokapen guztiak Configuration templates - + Konfigurazio txantiloiak Advanced - + Aurreratuak Computer name source - + Ordenagailuen izenen iturria Default - + Lehenetsia Host address @@ -3214,31 +3245,31 @@ Press and hold to load arrangement from a file or save current arrangement to a Session client address - + Saioaren bezeroen helbideak Session client name - + Saioaren bezeroen izenak Session host name - + Saioaren ostatu-izena Session metadata - + Saioaren metadatuak Full name of user - + Erabiltzailearen izen osoa User login name - + Erabiltzailearen saioa hasteko izena Computer UID role - + Ordenagailuen UID rola Session meta data hash @@ -3735,6 +3766,37 @@ Mesedez, gorde zure lana eta itxi programa guztiak. Aukeratutako pantaila-argazki guztiak ezabatu nahi dituzu? + + ServerAccessControlManager + + Requested authentication method not available + + + + Access allowed by rule "%1" + + + + Access denied by rule "%1" + + + + No rule allowed access + + + + Accessing user not member of an authorized user group + + + + User has denied access + + + + User confirmed access + + + ServiceConfigurationPage @@ -3857,11 +3919,11 @@ Normalean hori beharrezkoa da terminal zerbitzariak onartzeko. Session metadata - + Saioaren metadatuak Content - + Edukia None @@ -3869,52 +3931,58 @@ Normalean hori beharrezkoa da terminal zerbitzariak onartzeko. Value of an environment variable - + Inguruko aldagai baten balioa Value of a registry key - + Erregistro gako baten balioa Environment variable name: - + Inguruko aldagaiaren izena: Registry key name: - + Erregistro gakoaren izena: Optionally enter a regular expression with a capture to extract a part of the computer name and use it as the display name for the computer. Example: [^-]*-(PC[0-9]*) - + Aukeran, sartu adierazpen erregular bat ordenagailuaren izenaren zati batekin eta erabili ordenagailuaren bistaratzeko izen gisa. + +Adibidea: [^ -] * - (PC [0-9] *) Enable if a single Veyon Server instance should be launched for the currently active session, no matter if local or remote. - + Gaitu Veyon Zerbitzari instantzia bat abiarazi behar bada une honetan aktibo dagoen saiorako, ez dio axola tokiko edo urruneko. ServiceControl - Starting service %1 - % 1 zerbitzua abiarazten + Service control + Zerbitzuaren kontrola - Stopping service %1 - % 1 zerbitzua gelditzen + Starting %1 + - Registering service %1 - %1 zerbitzua erregistratzen + Stopping %1 + - Unregistering service %1 - %1 zerbitzuaren erregistroa kentzen + Restarting %1 + - Service control - Zerbitzuaren kontrola + Registering %1 + + + + Unregistering %1 + diff --git a/translations/veyon_fa.ts b/translations/veyon_fa.ts index 0cf11258b..711d05f86 100644 --- a/translations/veyon_fa.ts +++ b/translations/veyon_fa.ts @@ -132,6 +132,13 @@ If you're interested in translating Veyon into your local or another langua کاربر مورد نظر مجاز نیست به این پیکربندی دسترسی پیدا کند. + + AccessControlProvider + + Provider for access control features + + + AccessControlRuleEditDialog @@ -1001,14 +1008,6 @@ Make sure that the names of the keys belonging to each other are identical on al Location: %1 - - Host/IP address: %1 - میزبان / آدرس آی پی :٪ 1 - - - invalid - - Active features: %1 ویژگی های فعال:٪ 1 @@ -1050,7 +1049,23 @@ Make sure that the names of the keys belonging to each other are identical on al کاربر وارد شده:٪ 1 - [none] + Hostname: %1 + + + + unknown + + + + IP address: %1 + + + + Hostname could not be resolved + + + + No features active @@ -1977,6 +1992,18 @@ Make sure that the names of the keys belonging to each other are identical on al No user groups plugin was found. Please check your installation! + + Color scheme: + + + + Light + + + + Dark + + HeadlessVncServer @@ -3712,6 +3739,37 @@ Please save your work and close all programs. + + ServerAccessControlManager + + Requested authentication method not available + + + + Access allowed by rule "%1" + + + + Access denied by rule "%1" + + + + No rule allowed access + + + + Accessing user not member of an authorized user group + + + + User has denied access + + + + User confirmed access + + + ServiceConfigurationPage @@ -3873,23 +3931,27 @@ Example: [^-]*-(PC[0-9]*) ServiceControl - Starting service %1 + Service control - Stopping service %1 + Starting %1 - Registering service %1 + Stopping %1 - Unregistering service %1 + Restarting %1 - Service control + Registering %1 + + + + Unregistering %1 diff --git a/translations/veyon_fr.ts b/translations/veyon_fr.ts index 6f6ba5a2d..9ba7908a7 100644 --- a/translations/veyon_fr.ts +++ b/translations/veyon_fr.ts @@ -133,6 +133,13 @@ Cependant, si vous êtes intéressé pour traduire Veyon dans une autre langue, Avec cette configuration, l'utilisateur spécifié n'est pas autorisé à accéder aux ordinateurs. + + AccessControlProvider + + Provider for access control features + + + AccessControlRuleEditDialog @@ -1005,14 +1012,6 @@ Make sure that the names of the keys belonging to each other are identical on al Location: %1 Emplacement : %1 - - Host/IP address: %1 - Adresse de l'hôte / IP : %1 - - - invalid - invalide - Active features: %1 Fonctionnalités activées : %1 @@ -1054,8 +1053,24 @@ Make sure that the names of the keys belonging to each other are identical on al Connecté sur l'utilisateur : %1 - [none] - [Aucun] + Hostname: %1 + + + + unknown + inconnu + + + IP address: %1 + + + + Hostname could not be resolved + + + + No features active + @@ -1981,6 +1996,18 @@ Make sure that the names of the keys belonging to each other are identical on al No user groups plugin was found. Please check your installation! + + Color scheme: + + + + Light + + + + Dark + + HeadlessVncServer @@ -3737,6 +3764,37 @@ Veuillez sauvegarder votre travail et fermer tous les programmes. Souhaitez-vous vraiment supprimer toutes les captures d'écran sélectionnées? + + ServerAccessControlManager + + Requested authentication method not available + + + + Access allowed by rule "%1" + + + + Access denied by rule "%1" + + + + No rule allowed access + + + + Accessing user not member of an authorized user group + + + + User has denied access + + + + User confirmed access + + + ServiceConfigurationPage @@ -3899,24 +3957,28 @@ Example: [^-]*-(PC[0-9]*) ServiceControl - Starting service %1 - Démarrage du service %1 + Service control + Contrôle du service + + + Starting %1 + - Stopping service %1 - Arrêt du service %1 + Stopping %1 + - Registering service %1 - Inscription du service %1 + Restarting %1 + - Unregistering service %1 - Déinscription du service %1 + Registering %1 + - Service control - Contrôle du service + Unregistering %1 + diff --git a/translations/veyon_he.ts b/translations/veyon_he.ts index 4dd7489c5..27edfb7b5 100644 --- a/translations/veyon_he.ts +++ b/translations/veyon_he.ts @@ -131,6 +131,13 @@ If you're interested in translating Veyon into your local or another langua המשתמש הזה אינו רשאי לבצע גישה למחשבים עם הגדרה נוכחית + + AccessControlProvider + + Provider for access control features + + + AccessControlRuleEditDialog @@ -1003,14 +1010,6 @@ Make sure that the names of the keys belonging to each other are identical on al Location: %1 מיקום: %1 - - Host/IP address: %1 - - - - invalid - לא בתוקף - Active features: %1 @@ -1052,7 +1051,23 @@ Make sure that the names of the keys belonging to each other are identical on al מחובר בתור: %1 - [none] + Hostname: %1 + + + + unknown + לא ידוע + + + IP address: %1 + + + + Hostname could not be resolved + + + + No features active @@ -1979,6 +1994,18 @@ Make sure that the names of the keys belonging to each other are identical on al No user groups plugin was found. Please check your installation! + + Color scheme: + + + + Light + + + + Dark + + HeadlessVncServer @@ -3714,6 +3741,37 @@ Please save your work and close all programs. + + ServerAccessControlManager + + Requested authentication method not available + + + + Access allowed by rule "%1" + + + + Access denied by rule "%1" + + + + No rule allowed access + + + + Accessing user not member of an authorized user group + + + + User has denied access + + + + User confirmed access + + + ServiceConfigurationPage @@ -3875,24 +3933,28 @@ Example: [^-]*-(PC[0-9]*) ServiceControl - Starting service %1 + Service control + שליטה בשירות + + + Starting %1 - Stopping service %1 + Stopping %1 - Registering service %1 + Restarting %1 - Unregistering service %1 + Registering %1 - Service control - שליטה בשירות + Unregistering %1 + diff --git a/translations/veyon_hu.ts b/translations/veyon_hu.ts index fab3a7c51..c108801d1 100644 --- a/translations/veyon_hu.ts +++ b/translations/veyon_hu.ts @@ -133,6 +133,13 @@ Ha érdekel a Veyon fordítása (saját vagy egyéb nyelvre), esetleg meglévő A kijelölt felhasználó nem férhet hozzá a számítógéphez a jelenlegi konfiguráció alapján. + + AccessControlProvider + + Provider for access control features + + + AccessControlRuleEditDialog @@ -1005,14 +1012,6 @@ Make sure that the names of the keys belonging to each other are identical on al Location: %1 Helyszín: %1 - - Host/IP address: %1 - Kiszolgáló/IP cím: %1 - - - invalid - érvénytelen - Active features: %1 Aktív szolgáltatások: %1 @@ -1054,8 +1053,24 @@ Make sure that the names of the keys belonging to each other are identical on al Bejelentkezett felhasználó: %1 - [none] - [nincs] + Hostname: %1 + + + + unknown + ismeretlen + + + IP address: %1 + + + + Hostname could not be resolved + + + + No features active + @@ -1981,6 +1996,18 @@ Make sure that the names of the keys belonging to each other are identical on al No user groups plugin was found. Please check your installation! + + Color scheme: + + + + Light + + + + Dark + + HeadlessVncServer @@ -3735,6 +3762,37 @@ Please save your work and close all programs. Biztos, hogy eltávolítod a kiválasztott képernyőképeket? + + ServerAccessControlManager + + Requested authentication method not available + + + + Access allowed by rule "%1" + + + + Access denied by rule "%1" + + + + No rule allowed access + + + + Accessing user not member of an authorized user group + + + + User has denied access + + + + User confirmed access + + + ServiceConfigurationPage @@ -3898,24 +3956,28 @@ Példa: [^-]*-(PC[0-9]*) ServiceControl - Starting service %1 - %1 szolgáltatás indítása + Service control + Szolgáltatásvezérlés + + + Starting %1 + - Stopping service %1 - %1 szolgáltatás leállítása + Stopping %1 + - Registering service %1 - %1 szolgáltatás nyilvántartásban vétele + Restarting %1 + - Unregistering service %1 - %1 szolgáltatás törlése a nyilvántartásból + Registering %1 + - Service control - Szolgáltatásvezérlés + Unregistering %1 + diff --git a/translations/veyon_id.ts b/translations/veyon_id.ts index 0a7b45e2c..2a3f9f94d 100644 --- a/translations/veyon_id.ts +++ b/translations/veyon_id.ts @@ -133,6 +133,13 @@ Jika anda tertarik menerjemahkan Veyon pada bahasa lokal Anda atau bahasa lain a Pengguna yang ditentukan tidak diizinkan mengakses komputer dengan konfigurasi ini. + + AccessControlProvider + + Provider for access control features + + + AccessControlRuleEditDialog @@ -1005,14 +1012,6 @@ Make sure that the names of the keys belonging to each other are identical on al Location: %1 - - Host/IP address: %1 - Host/Alamat IP: %1 - - - invalid - - Active features: %1 Fitur aktif: %1 @@ -1054,7 +1053,23 @@ Make sure that the names of the keys belonging to each other are identical on al - [none] + Hostname: %1 + + + + unknown + + + + IP address: %1 + + + + Hostname could not be resolved + + + + No features active @@ -1981,6 +1996,18 @@ Make sure that the names of the keys belonging to each other are identical on al No user groups plugin was found. Please check your installation! + + Color scheme: + + + + Light + + + + Dark + + HeadlessVncServer @@ -3716,6 +3743,37 @@ Please save your work and close all programs. + + ServerAccessControlManager + + Requested authentication method not available + + + + Access allowed by rule "%1" + + + + Access denied by rule "%1" + + + + No rule allowed access + + + + Accessing user not member of an authorized user group + + + + User has denied access + + + + User confirmed access + + + ServiceConfigurationPage @@ -3877,24 +3935,28 @@ Example: [^-]*-(PC[0-9]*) ServiceControl - Starting service %1 - Mulai layanan %1 + Service control + Kontrol Layanan + + + Starting %1 + - Stopping service %1 - Matikan layanan %1 + Stopping %1 + - Registering service %1 - Daftarkan layanan %1 + Restarting %1 + - Unregistering service %1 - Batalkan pendaftaran layanan %1 + Registering %1 + - Service control - Kontrol Layanan + Unregistering %1 + diff --git a/translations/veyon_it.ts b/translations/veyon_it.ts index 66f6a537f..57f8634e8 100644 --- a/translations/veyon_it.ts +++ b/translations/veyon_it.ts @@ -133,6 +133,13 @@ Se sei interessato alla traduzione di Veyon nella tua lingua locale o in qualche L'utente indicato non è abilitato ad accedere a computer con questa confiugurazione. + + AccessControlProvider + + Provider for access control features + Fornitore di funzionalità di controllo degli accessi + + AccessControlRuleEditDialog @@ -1004,14 +1011,6 @@ Assicurati che i nomi delle chiavi che appartengono l'una all'altra si Location: %1 Posizione: %1 - - Host/IP address: %1 - Host/indirizzo IP: %1 - - - invalid - non valido - Active features: %1 Funzioni attive: %1 @@ -1053,8 +1052,24 @@ Assicurati che i nomi delle chiavi che appartengono l'una all'altra si Utente connesso: %1 - [none] - [nessuno] + Hostname: %1 + Nome host: %1 + + + unknown + sconosciuto + + + IP address: %1 + Indirizzo IP: %1 + + + Hostname could not be resolved + Il nome host non può essere risolto + + + No features active + Nessuna funzione attiva @@ -1980,6 +1995,18 @@ Assicurati che i nomi delle chiavi che appartengono l'una all'altra si No user groups plugin was found. Please check your installation! Nessun plugin per gruppi di utenti è stato trovato. Controlla la tua installazione! + + Color scheme: + Schema di colori: + + + Light + + + + Dark + Scuro + HeadlessVncServer @@ -3728,6 +3755,37 @@ Si prega di salvare il lavoro e chiudere tutti i programmi. Vuoi davvero eliminare tutti gli screenshot selezionati? + + ServerAccessControlManager + + Requested authentication method not available + Metodo di autenticazione richiesto non disponibile + + + Access allowed by rule "%1" + Accesso consentito dalla regola "%1" + + + Access denied by rule "%1" + Accesso negato dalla regola "%1" + + + No rule allowed access + Nessuna regola ha consentito l'accesso + + + Accessing user not member of an authorized user group + L'utente che accede non è membro di un gruppo di utenti autorizzati + + + User has denied access + L'utente ha rifiutato l'accesso + + + User confirmed access + L'utente ha confermato l'accesso + + ServiceConfigurationPage @@ -3891,24 +3949,28 @@ Esempio: [^-]*-(PC[0-9]*) ServiceControl - Starting service %1 - Avvio del servizio%1 + Service control + Controllo del servizio - Stopping service %1 - Arresto del servizio%1 + Starting %1 + Avvio %1 - Registering service %1 - Registrazione del servizio%1 + Stopping %1 + Arresto %1 - Unregistering service %1 - Servizio di annullamento della registrazione%1 + Restarting %1 + Riavvio %1 - Service control - Controllo del servizio + Registering %1 + Registrazione di %1 + + + Unregistering %1 + Disregistrazione di %1 diff --git a/translations/veyon_ja.ts b/translations/veyon_ja.ts index f59b4cd2e..1c930d50b 100644 --- a/translations/veyon_ja.ts +++ b/translations/veyon_ja.ts @@ -133,6 +133,13 @@ If you're interested in translating Veyon into your local or another langua このユーザーは設定によりコンピューターへのアクセスが拒否されました。 + + AccessControlProvider + + Provider for access control features + + + AccessControlRuleEditDialog @@ -1005,14 +1012,6 @@ Make sure that the names of the keys belonging to each other are identical on al Location: %1 場所: %1 - - Host/IP address: %1 - ホスト/IPアドレス: %1 - - - invalid - 無効 - Active features: %1 アクティブな機能: %1 @@ -1054,8 +1053,24 @@ Make sure that the names of the keys belonging to each other are identical on al ログインしたユーザー: %1 - [none] - [なし] + Hostname: %1 + + + + unknown + + + + IP address: %1 + + + + Hostname could not be resolved + + + + No features active + @@ -1981,6 +1996,18 @@ Make sure that the names of the keys belonging to each other are identical on al No user groups plugin was found. Please check your installation! + + Color scheme: + + + + Light + + + + Dark + + HeadlessVncServer @@ -3719,6 +3746,37 @@ Please save your work and close all programs. 選択したスクリーンショットを削除しても良いですか? + + ServerAccessControlManager + + Requested authentication method not available + + + + Access allowed by rule "%1" + + + + Access denied by rule "%1" + + + + No rule allowed access + + + + Accessing user not member of an authorized user group + + + + User has denied access + + + + User confirmed access + + + ServiceConfigurationPage @@ -3880,24 +3938,28 @@ Example: [^-]*-(PC[0-9]*) ServiceControl - Starting service %1 - サービス %1 を開始 + Service control + サービス制御 + + + Starting %1 + - Stopping service %1 - サービス %1 を停止 + Stopping %1 + - Registering service %1 - サービス %1 を登録 + Restarting %1 + - Unregistering service %1 - サービス %1 の登録を解除 + Registering %1 + - Service control - サービス制御 + Unregistering %1 + diff --git a/translations/veyon_ko.ts b/translations/veyon_ko.ts index b17b9a38d..e63038c4f 100644 --- a/translations/veyon_ko.ts +++ b/translations/veyon_ko.ts @@ -133,6 +133,13 @@ Veyon 번역에 관심이 있거나 번역을 개선하실 의향이 있으신 선택된 사용자는 이 설정으로 컴퓨터 접근이 거부 됨. + + AccessControlProvider + + Provider for access control features + + + AccessControlRuleEditDialog @@ -1005,14 +1012,6 @@ Make sure that the names of the keys belonging to each other are identical on al Location: %1 장소: %1 - - Host/IP address: %1 - 호스트/IP 주소: %1 - - - invalid - - Active features: %1 활성화된 기능들: %1 @@ -1054,7 +1053,23 @@ Make sure that the names of the keys belonging to each other are identical on al 로그온된 사용자 : %1 - [none] + Hostname: %1 + + + + unknown + 알수없음 + + + IP address: %1 + + + + Hostname could not be resolved + + + + No features active @@ -1981,6 +1996,18 @@ Make sure that the names of the keys belonging to each other are identical on al No user groups plugin was found. Please check your installation! + + Color scheme: + + + + Light + + + + Dark + + HeadlessVncServer @@ -3735,6 +3762,37 @@ Please save your work and close all programs. + + ServerAccessControlManager + + Requested authentication method not available + + + + Access allowed by rule "%1" + + + + Access denied by rule "%1" + + + + No rule allowed access + + + + Accessing user not member of an authorized user group + + + + User has denied access + + + + User confirmed access + + + ServiceConfigurationPage @@ -3897,24 +3955,28 @@ Example: [^-]*-(PC[0-9]*) ServiceControl - Starting service %1 - 서비스 %1 시작중 + Service control + 서비스 제어 + + + Starting %1 + - Stopping service %1 - 서비스 %1 중지중 + Stopping %1 + - Registering service %1 - 서비스 %1 를 등록중 + Restarting %1 + - Unregistering service %1 - 서비스 %1 를 등록 해제중 + Registering %1 + - Service control - 서비스 제어 + Unregistering %1 + diff --git a/translations/veyon_lt.ts b/translations/veyon_lt.ts index 3232c9df5..83344f9dd 100644 --- a/translations/veyon_lt.ts +++ b/translations/veyon_lt.ts @@ -132,6 +132,13 @@ Jeigu domina Veyon programos vertimas į vietinę ar kitą kalbą, arba norite p Pasirinktam naudotojui neleidžiama prieiga prie kompiuterių su šia konfigūracija. + + AccessControlProvider + + Provider for access control features + + + AccessControlRuleEditDialog @@ -1004,14 +1011,6 @@ Make sure that the names of the keys belonging to each other are identical on al Location: %1 Vieta: %1 - - Host/IP address: %1 - Serverio/IP adresas: %1 - - - invalid - - Active features: %1 Aktyvios funkcijos: %1 @@ -1053,7 +1052,23 @@ Make sure that the names of the keys belonging to each other are identical on al Prisijungęs naudotojas: %1 - [none] + Hostname: %1 + + + + unknown + Nežinomas + + + IP address: %1 + + + + Hostname could not be resolved + + + + No features active @@ -1980,6 +1995,18 @@ Make sure that the names of the keys belonging to each other are identical on al No user groups plugin was found. Please check your installation! + + Color scheme: + + + + Light + + + + Dark + + HeadlessVncServer @@ -3716,6 +3743,37 @@ Please save your work and close all programs. + + ServerAccessControlManager + + Requested authentication method not available + + + + Access allowed by rule "%1" + + + + Access denied by rule "%1" + + + + No rule allowed access + + + + Accessing user not member of an authorized user group + + + + User has denied access + + + + User confirmed access + + + ServiceConfigurationPage @@ -3877,24 +3935,28 @@ Example: [^-]*-(PC[0-9]*) ServiceControl - Starting service %1 - Paleidžiama tarnyba %1 + Service control + Serviso valdymas + + + Starting %1 + - Stopping service %1 - Stabdoma tarnyba %1 + Stopping %1 + - Registering service %1 - Užregistruojama tarnyba %1 + Restarting %1 + - Unregistering service %1 - Išregistruojama tarnyba %1 + Registering %1 + - Service control - Serviso valdymas + Unregistering %1 + diff --git a/translations/veyon_lv.ts b/translations/veyon_lv.ts index 49a740886..32fe665a3 100644 --- a/translations/veyon_lv.ts +++ b/translations/veyon_lv.ts @@ -133,6 +133,13 @@ Ja esat ieinteresēti tulkot Veyon citā valodā vai uzlabot esošo tulkojumu, l Norādītajam lietotājam nav piekļuve datoriem ar šo konfigurāciju. + + AccessControlProvider + + Provider for access control features + + + AccessControlRuleEditDialog @@ -1005,14 +1012,6 @@ Make sure that the names of the keys belonging to each other are identical on al Location: %1 Vieta: %1 - - Host/IP address: %1 - Dalībnieku adreses/IP: %1 - - - invalid - nederīgs - Active features: %1 Aktīvās iespējas: %1 @@ -1054,8 +1053,24 @@ Make sure that the names of the keys belonging to each other are identical on al Ielogojies lietotajā: %1 - [none] - [neviens] + Hostname: %1 + + + + unknown + nezināms + + + IP address: %1 + + + + Hostname could not be resolved + + + + No features active + @@ -1981,6 +1996,18 @@ Make sure that the names of the keys belonging to each other are identical on al No user groups plugin was found. Please check your installation! + + Color scheme: + + + + Light + + + + Dark + + HeadlessVncServer @@ -3718,6 +3745,37 @@ Lūdzu, saglabājiet savu darbu un aizveriet visas programmas. + + ServerAccessControlManager + + Requested authentication method not available + + + + Access allowed by rule "%1" + + + + Access denied by rule "%1" + + + + No rule allowed access + + + + Accessing user not member of an authorized user group + + + + User has denied access + + + + User confirmed access + + + ServiceConfigurationPage @@ -3879,24 +3937,28 @@ Example: [^-]*-(PC[0-9]*) ServiceControl - Starting service %1 - Palaižas pakalpojums %1 + Service control + Pakalpojuma kontrole + + + Starting %1 + - Stopping service %1 - Apstājas pakalpojums %1 + Stopping %1 + - Registering service %1 - Reģistrēt pakalpojumu %1 + Restarting %1 + - Unregistering service %1 - Atcelt reģistrāciju pakalpojumam %1 + Registering %1 + - Service control - Pakalpojuma kontrole + Unregistering %1 + diff --git a/translations/veyon_mn.ts b/translations/veyon_mn.ts index 7af23703d..b366eaa5b 100644 --- a/translations/veyon_mn.ts +++ b/translations/veyon_mn.ts @@ -131,6 +131,13 @@ If you're interested in translating Veyon into your local or another langua + + AccessControlProvider + + Provider for access control features + + + AccessControlRuleEditDialog @@ -1000,14 +1007,6 @@ Make sure that the names of the keys belonging to each other are identical on al Location: %1 - - Host/IP address: %1 - - - - invalid - - Active features: %1 @@ -1049,7 +1048,23 @@ Make sure that the names of the keys belonging to each other are identical on al - [none] + Hostname: %1 + + + + unknown + үл мэдэгдэх + + + IP address: %1 + + + + Hostname could not be resolved + + + + No features active @@ -1976,6 +1991,18 @@ Make sure that the names of the keys belonging to each other are identical on al No user groups plugin was found. Please check your installation! + + Color scheme: + + + + Light + + + + Dark + + HeadlessVncServer @@ -3711,6 +3738,37 @@ Please save your work and close all programs. + + ServerAccessControlManager + + Requested authentication method not available + + + + Access allowed by rule "%1" + + + + Access denied by rule "%1" + + + + No rule allowed access + + + + Accessing user not member of an authorized user group + + + + User has denied access + + + + User confirmed access + + + ServiceConfigurationPage @@ -3872,23 +3930,27 @@ Example: [^-]*-(PC[0-9]*) ServiceControl - Starting service %1 + Service control - Stopping service %1 + Starting %1 - Registering service %1 + Stopping %1 - Unregistering service %1 + Restarting %1 - Service control + Registering %1 + + + + Unregistering %1 diff --git a/translations/veyon_nl.ts b/translations/veyon_nl.ts index 85bee2e38..777a1967f 100644 --- a/translations/veyon_nl.ts +++ b/translations/veyon_nl.ts @@ -133,6 +133,13 @@ Als je geïnteresseerd bent in het vertalen van Veyon in je eigen taal of een an De opgegeven gebruiker is niet toegestaan om toegang tot computers te krijgen met deze configuratie. + + AccessControlProvider + + Provider for access control features + + + AccessControlRuleEditDialog @@ -1007,14 +1014,6 @@ Zorg ervoor dat de namen van de sleutels die bij elkaar horen identiek zijn op a Location: %1 Locatie: %1 - - Host/IP address: %1 - Host/IP adres: %1 - - - invalid - ongeldig - Active features: %1 Actieve functies: %1 @@ -1056,8 +1055,24 @@ Zorg ervoor dat de namen van de sleutels die bij elkaar horen identiek zijn op a Ingelogde gebruiker: %1 - [none] - [geen] + Hostname: %1 + + + + unknown + onbekend + + + IP address: %1 + + + + Hostname could not be resolved + + + + No features active + @@ -1985,6 +2000,18 @@ Translated with DeepL No user groups plugin was found. Please check your installation! Er is geen plugin voor gebruikersgroepen gevonden. Controleer je installatie! + + Color scheme: + + + + Light + + + + Dark + + HeadlessVncServer @@ -3741,6 +3768,37 @@ Sla je werk op en sluit alle programma's af. Wil je echt alle geselecteerde schermafbeeldingen verwijderen? + + ServerAccessControlManager + + Requested authentication method not available + + + + Access allowed by rule "%1" + + + + Access denied by rule "%1" + + + + No rule allowed access + + + + Accessing user not member of an authorized user group + + + + User has denied access + + + + User confirmed access + + + ServiceConfigurationPage @@ -3905,24 +3963,28 @@ Voorbeeld: [^-]*-(PC[0-9]*) ServiceControl - Starting service %1 - Service %1 wordt gestart + Service control + Servicecontrole + + + Starting %1 + - Stopping service %1 - Service %1 wordt gestopt + Stopping %1 + - Registering service %1 - Service %1 wordt geregistreerd + Restarting %1 + - Unregistering service %1 - Dienst %1 afmelden + Registering %1 + - Service control - Servicecontrole + Unregistering %1 + diff --git a/translations/veyon_no_NO.ts b/translations/veyon_no_NO.ts index ce1046b48..4f0f67122 100644 --- a/translations/veyon_no_NO.ts +++ b/translations/veyon_no_NO.ts @@ -131,6 +131,13 @@ If you're interested in translating Veyon into your local or another langua + + AccessControlProvider + + Provider for access control features + + + AccessControlRuleEditDialog @@ -1000,14 +1007,6 @@ Make sure that the names of the keys belonging to each other are identical on al Location: %1 - - Host/IP address: %1 - - - - invalid - - Active features: %1 @@ -1049,7 +1048,23 @@ Make sure that the names of the keys belonging to each other are identical on al Pålogget bruker: %1 - [none] + Hostname: %1 + + + + unknown + + + + IP address: %1 + + + + Hostname could not be resolved + + + + No features active @@ -1976,6 +1991,18 @@ Make sure that the names of the keys belonging to each other are identical on al No user groups plugin was found. Please check your installation! + + Color scheme: + + + + Light + + + + Dark + + HeadlessVncServer @@ -3711,6 +3738,37 @@ Please save your work and close all programs. + + ServerAccessControlManager + + Requested authentication method not available + + + + Access allowed by rule "%1" + + + + Access denied by rule "%1" + + + + No rule allowed access + + + + Accessing user not member of an authorized user group + + + + User has denied access + + + + User confirmed access + + + ServiceConfigurationPage @@ -3872,23 +3930,27 @@ Example: [^-]*-(PC[0-9]*) ServiceControl - Starting service %1 + Service control - Stopping service %1 + Starting %1 - Registering service %1 + Stopping %1 - Unregistering service %1 + Restarting %1 - Service control + Registering %1 + + + + Unregistering %1 diff --git a/translations/veyon_pl.ts b/translations/veyon_pl.ts index 9913598f6..5d726ccc5 100644 --- a/translations/veyon_pl.ts +++ b/translations/veyon_pl.ts @@ -133,6 +133,13 @@ Jeśli chcesz przetłumaczyć Veyon na swój język lub chcesz poprawić obecne Użytkownik nie ma dostępu do komputerów przy tej konfiguracji. + + AccessControlProvider + + Provider for access control features + + + AccessControlRuleEditDialog @@ -1005,14 +1012,6 @@ Make sure that the names of the keys belonging to each other are identical on al Location: %1 Lokalizacja: %1 - - Host/IP address: %1 - Host/adres IP: %1 - - - invalid - nieprawidłowy - Active features: %1 Aktywne funkcje: %1 @@ -1054,7 +1053,23 @@ Make sure that the names of the keys belonging to each other are identical on al Zalogowano użytkownika: %1 - [none] + Hostname: %1 + + + + unknown + nieznane + + + IP address: %1 + + + + Hostname could not be resolved + + + + No features active @@ -1981,6 +1996,18 @@ Make sure that the names of the keys belonging to each other are identical on al No user groups plugin was found. Please check your installation! + + Color scheme: + + + + Light + + + + Dark + + HeadlessVncServer @@ -3732,6 +3759,37 @@ Zapisz swoją pracę i zamknij wszystkie programy. Czy na pewno chcesz usunąć wszystkie zaznaczone zrzuty ekranu? + + ServerAccessControlManager + + Requested authentication method not available + + + + Access allowed by rule "%1" + + + + Access denied by rule "%1" + + + + No rule allowed access + + + + Accessing user not member of an authorized user group + + + + User has denied access + + + + User confirmed access + + + ServiceConfigurationPage @@ -3894,24 +3952,28 @@ Example: [^-]*-(PC[0-9]*) ServiceControl - Starting service %1 - Uruchamianie usługi %1 + Service control + Zarządzenie usługą + + + Starting %1 + - Stopping service %1 - Zatrzymywanie usługi %1 + Stopping %1 + - Registering service %1 - Rejestrowanie usługi %1 + Restarting %1 + - Unregistering service %1 - Wyrejestrowywanie usługi %1 + Registering %1 + - Service control - Zarządzenie usługą + Unregistering %1 + diff --git a/translations/veyon_pt_BR.ts b/translations/veyon_pt_BR.ts index e2f1e7daf..6d4a776d5 100644 --- a/translations/veyon_pt_BR.ts +++ b/translations/veyon_pt_BR.ts @@ -133,6 +133,13 @@ Se você tem interesse em traduzir o Veyon para o seu idioma local, ou outro idi O usuário especificado não pode acessar computadores com esta configuração. + + AccessControlProvider + + Provider for access control features + + + AccessControlRuleEditDialog @@ -1005,14 +1012,6 @@ Make sure that the names of the keys belonging to each other are identical on al Location: %1 - - Host/IP address: %1 - Servidor/endereço IP: %1 - - - invalid - - Active features: %1 Funcionalidades ativas: %1 @@ -1054,7 +1053,23 @@ Make sure that the names of the keys belonging to each other are identical on al Usuário logado: %1 - [none] + Hostname: %1 + + + + unknown + desconhecido + + + IP address: %1 + + + + Hostname could not be resolved + + + + No features active @@ -1981,6 +1996,18 @@ Make sure that the names of the keys belonging to each other are identical on al No user groups plugin was found. Please check your installation! + + Color scheme: + + + + Light + + + + Dark + + HeadlessVncServer @@ -3721,6 +3748,37 @@ Please save your work and close all programs. + + ServerAccessControlManager + + Requested authentication method not available + + + + Access allowed by rule "%1" + + + + Access denied by rule "%1" + + + + No rule allowed access + + + + Accessing user not member of an authorized user group + + + + User has denied access + + + + User confirmed access + + + ServiceConfigurationPage @@ -3884,23 +3942,27 @@ Exemplo: [^-]*-(PC[0-9]*) ServiceControl - Starting service %1 + Service control - Stopping service %1 + Starting %1 - Registering service %1 + Stopping %1 - Unregistering service %1 + Restarting %1 - Service control + Registering %1 + + + + Unregistering %1 diff --git a/translations/veyon_pt_PT.ts b/translations/veyon_pt_PT.ts index 4ba19abc0..a84bc0a2e 100644 --- a/translations/veyon_pt_PT.ts +++ b/translations/veyon_pt_PT.ts @@ -133,6 +133,13 @@ Se está interessado em traduzir o Veyon para o seu idioma ou quer melhorar uma O utilizador especificado não pode aceder a computadores com esta configuração. + + AccessControlProvider + + Provider for access control features + + + AccessControlRuleEditDialog @@ -1005,14 +1012,6 @@ Make sure that the names of the keys belonging to each other are identical on al Location: %1 - - Host/IP address: %1 - - - - invalid - - Active features: %1 @@ -1054,7 +1053,23 @@ Make sure that the names of the keys belonging to each other are identical on al - [none] + Hostname: %1 + + + + unknown + + + + IP address: %1 + + + + Hostname could not be resolved + + + + No features active @@ -1981,6 +1996,18 @@ Make sure that the names of the keys belonging to each other are identical on al No user groups plugin was found. Please check your installation! + + Color scheme: + + + + Light + + + + Dark + + HeadlessVncServer @@ -3716,6 +3743,37 @@ Please save your work and close all programs. + + ServerAccessControlManager + + Requested authentication method not available + + + + Access allowed by rule "%1" + + + + Access denied by rule "%1" + + + + No rule allowed access + + + + Accessing user not member of an authorized user group + + + + User has denied access + + + + User confirmed access + + + ServiceConfigurationPage @@ -3877,23 +3935,27 @@ Example: [^-]*-(PC[0-9]*) ServiceControl - Starting service %1 + Service control - Stopping service %1 + Starting %1 - Registering service %1 + Stopping %1 - Unregistering service %1 + Restarting %1 - Service control + Registering %1 + + + + Unregistering %1 diff --git a/translations/veyon_ru.ts b/translations/veyon_ru.ts index db2e2b89e..6a69da050 100644 --- a/translations/veyon_ru.ts +++ b/translations/veyon_ru.ts @@ -133,6 +133,13 @@ If you're interested in translating Veyon into your local or another langua Указанному пользователю не разрешается обращаться к компьютерам с этой конфигурацией. + + AccessControlProvider + + Provider for access control features + + + AccessControlRuleEditDialog @@ -1007,14 +1014,6 @@ Make sure that the names of the keys belonging to each other are identical on al Location: %1 Место: %1 - - Host/IP address: %1 - Хост/IP-адрес: %1 - - - invalid - некорректно - Active features: %1 Задействованные возможности: %1 @@ -1056,8 +1055,24 @@ Make sure that the names of the keys belonging to each other are identical on al Вход в систему под пользователем: %1 - [none] - [нет] + Hostname: %1 + + + + unknown + неизвестный + + + IP address: %1 + + + + Hostname could not be resolved + + + + No features active + @@ -1983,6 +1998,18 @@ Make sure that the names of the keys belonging to each other are identical on al No user groups plugin was found. Please check your installation! Плагин групп пользователей не найден. Проверьте установку! + + Color scheme: + + + + Light + + + + Dark + + HeadlessVncServer @@ -3741,6 +3768,37 @@ Please save your work and close all programs. Действительно удалить выбранные снимки экрана? + + ServerAccessControlManager + + Requested authentication method not available + + + + Access allowed by rule "%1" + + + + Access denied by rule "%1" + + + + No rule allowed access + + + + Accessing user not member of an authorized user group + + + + User has denied access + + + + User confirmed access + + + ServiceConfigurationPage @@ -3905,24 +3963,28 @@ Example: [^-]*-(PC[0-9]*) ServiceControl - Starting service %1 - Запускаем сервис %1 + Service control + Управление сервисам + + + Starting %1 + - Stopping service %1 - Останавливаем сервис %1 + Stopping %1 + - Registering service %1 - Регистрируем сервис %1 + Restarting %1 + - Unregistering service %1 - Отменяем регистрацию сервиса %1 + Registering %1 + - Service control - Управление сервисам + Unregistering %1 + diff --git a/translations/veyon_sl.ts b/translations/veyon_sl.ts index 992f6370c..e8638c94c 100644 --- a/translations/veyon_sl.ts +++ b/translations/veyon_sl.ts @@ -133,6 +133,13 @@ If you're interested in translating Veyon into your local or another langua Navedeni uporabnik ne sme dostopati do računalnikov s to konfiguracijo. + + AccessControlProvider + + Provider for access control features + + + AccessControlRuleEditDialog @@ -1005,14 +1012,6 @@ Make sure that the names of the keys belonging to each other are identical on al Location: %1 Lokacija: %1 - - Host/IP address: %1 - Gostitelj/IP naslov: %1 - - - invalid - - Active features: %1 Aktivne funkcije: %1 @@ -1054,7 +1053,23 @@ Make sure that the names of the keys belonging to each other are identical on al Prijavljen uporabnik: %1 - [none] + Hostname: %1 + + + + unknown + neznano + + + IP address: %1 + + + + Hostname could not be resolved + + + + No features active @@ -1981,6 +1996,18 @@ Make sure that the names of the keys belonging to each other are identical on al No user groups plugin was found. Please check your installation! + + Color scheme: + + + + Light + + + + Dark + + HeadlessVncServer @@ -3735,6 +3762,37 @@ Please save your work and close all programs. + + ServerAccessControlManager + + Requested authentication method not available + + + + Access allowed by rule "%1" + + + + Access denied by rule "%1" + + + + No rule allowed access + + + + Accessing user not member of an authorized user group + + + + User has denied access + + + + User confirmed access + + + ServiceConfigurationPage @@ -3897,24 +3955,28 @@ Example: [^-]*-(PC[0-9]*) ServiceControl - Starting service %1 - Zagon storitve %1 + Service control + Nadzor storitve + + + Starting %1 + - Stopping service %1 - Zaustavitev storitve %1 + Stopping %1 + - Registering service %1 - Registracija storitve %1 + Restarting %1 + - Unregistering service %1 - Odregistracija storitve %1 + Registering %1 + - Service control - Nadzor storitve + Unregistering %1 + diff --git a/translations/veyon_sr.ts b/translations/veyon_sr.ts index 526d90762..99f8fb96a 100644 --- a/translations/veyon_sr.ts +++ b/translations/veyon_sr.ts @@ -133,6 +133,13 @@ Ako ste zainteresovani za prevodjenje Veyon na vaš lokalni ili drugi jezik ili Navedenom korisniku nije dozvoljen pristup računarima sa ovom konfiguracijom. + + AccessControlProvider + + Provider for access control features + + + AccessControlRuleEditDialog @@ -1005,14 +1012,6 @@ Make sure that the names of the keys belonging to each other are identical on al Location: %1 Lokacija: %1 - - Host/IP address: %1 - Domaćin/IP adresa: %1 - - - invalid - - Active features: %1 Aktivne karakteristike: %1 @@ -1054,7 +1053,23 @@ Make sure that the names of the keys belonging to each other are identical on al Prijavljeni korisnik: %1 - [none] + Hostname: %1 + + + + unknown + nepoznato + + + IP address: %1 + + + + Hostname could not be resolved + + + + No features active @@ -1981,6 +1996,18 @@ Make sure that the names of the keys belonging to each other are identical on al No user groups plugin was found. Please check your installation! + + Color scheme: + + + + Light + + + + Dark + + HeadlessVncServer @@ -3737,6 +3764,37 @@ Molimo snimite/spasite Vaš rad i zatvorite sve programe. + + ServerAccessControlManager + + Requested authentication method not available + + + + Access allowed by rule "%1" + + + + Access denied by rule "%1" + + + + No rule allowed access + + + + Accessing user not member of an authorized user group + + + + User has denied access + + + + User confirmed access + + + ServiceConfigurationPage @@ -3899,24 +3957,28 @@ Example: [^-]*-(PC[0-9]*) ServiceControl - Starting service %1 - Startanje servisa %1 + Service control + Kontrola servisa + + + Starting %1 + - Stopping service %1 - Zaustavljanje servisa %1 + Stopping %1 + - Registering service %1 - Registrovanje servisa %1 + Restarting %1 + - Unregistering service %1 - Deregistrovanje servisa %1 + Registering %1 + - Service control - Kontrola servisa + Unregistering %1 + diff --git a/translations/veyon_sv.ts b/translations/veyon_sv.ts index e2292445f..fac8319bb 100644 --- a/translations/veyon_sv.ts +++ b/translations/veyon_sv.ts @@ -15,7 +15,7 @@ Website: - Hemsida + Webbsida: Support Veyon project with a donation @@ -54,11 +54,11 @@ Om du är intresserad av att översätta Veyon till ditt lokala eller ett ett an Restrict access to members of specific user groups - + Begränsa åtkomsten till medlemmar i specifika användargrupper Test - Test + Testa Process access control rules @@ -133,6 +133,13 @@ Om du är intresserad av att översätta Veyon till ditt lokala eller ett ett an Den specificerade användaren är inte tillåten att komma åt datorer med den här konfigurationen. + + AccessControlProvider + + Provider for access control features + + + AccessControlRuleEditDialog @@ -181,7 +188,7 @@ Om du är intresserad av att översätta Veyon till ditt lokala eller ett ett an Accessing computer and local computer are at the same location - + Åtkomstdatorn och den lokala datorn befinner sig på samma plats No user logged on @@ -189,7 +196,7 @@ Om du är intresserad av att översätta Veyon till ditt lokala eller ett ett an is located at - + är belägen på Accessing computer is localhost @@ -245,7 +252,7 @@ Om du är intresserad av att översätta Veyon till ditt lokala eller ett ett an Local computer is already being accessed - + Den lokala datorn är redan tillgänglig @@ -256,791 +263,788 @@ Om du är intresserad av att översätta Veyon till ditt lokala eller ett ett an Accessing user: - + Tillgång till användare: Local computer: - + Lokal dator: Accessing computer: - + Åtkomst till dator: Please enter the following user and computer information in order to test the configured ruleset. - + Ange följande användar- och datorinformation för att testa den konfigurerade regeluppsättningen. Local user: - + Lokal användare: Connected users: - + Anslutna användare: The access in the given scenario is allowed. - + Åtkomsten i det givna scenariot är tillåten. The access in the given scenario is denied. - + Tillträde i det givna scenariot nekas. The access in the given scenario needs permission of the logged on user. - + Åtkomsten i det givna scenariot kräver tillstånd från den inloggade användaren. ERROR: Unknown action - + ERROR: Okänd åtgärd Test result - + Testresultat AuthKeysConfigurationPage Authentication keys - + Autentiseringsnycklar Introduction - + Introduktion Please perform the following steps to set up key file authentication: - + Utför följande steg för att konfigurera autentisering av nyckelfiler: 1) Create a key pair on the master computer. - + 1) Skapa ett nyckelpar på huvuddatorn. 2) Set an access group whose members should be allowed to access other computers. - + 2) Ange en åtkomstgrupp vars medlemmar ska ha åtkomst till andra datorer. 3) Export the public key and import it on all client computers with the same name. - + 3) Exportera den publika nyckeln och importera den på alla klientdatorer med samma namn. Please refer to the <a href="https://veyon.readthedocs.io/en/latest/admin/index.html">Veyon Administrator Manual</a> for more information. - + Mer information finns i <a href="https://veyon.readthedocs.io/en/latest/admin/index.html">Veyons administratörshandbok</a>. Key file directories - + Kataloger med nyckelfiler Public key file base directory - + Baskatalog för fil med offentlig nyckel Private key file base directory - + Baskatalog för fil med privat nyckel Available authentication keys - + Tillgängliga autentiseringsnycklar An authentication key pair consist of two coupled cryptographic keys, a private and a public key. A private key allows users on the master computer to access client computers. It is important that only authorized users have read access to the private key file. The public key is used on client computers to authenticate incoming connection request. - + Ett nyckelpar för autentisering består av två kopplade kryptografiska nycklar, en privat och en offentlig nyckel. +En privat nyckel ger användare på huvuddatorn åtkomst till klientdatorer. +Det är viktigt att endast behöriga användare har läsbehörighet till den privata nyckelfilen. +Den publika nyckeln används på klientdatorer för att autentisera inkommande anslutningsbegäran. Create key pair - + Skapa nyckelpar Delete key - + Radera tangent Import key - + Importera nyckel Export key - + Exportknapp Set access group - + Ställ in åtkomstgrupp Key files (*.pem) - + Nyckelfiler (*.pem) Authentication key name - + Namn på autentiseringsnyckel Please enter the name of the user group or role for which to create an authentication key pair: - + Ange namnet på den användargrupp eller roll för vilken du vill skapa ett nyckelpar för autentisering: Do you really want to delete authentication key "%1/%2"? - + Vill du verkligen ta bort autentiseringsnyckeln "%1/%2"? Please select a key to delete! - + Välj en nyckel som ska raderas! Please select a key to export! - + Vänligen välj en nyckel för export! Please select a user group which to grant access to key "%1": - + Välj en användargrupp som ska få tillgång till nyckeln "%1": Please select a key which to set the access group for! - + Välj en nyckel som du vill ställa in åtkomstgruppen för! Please enter the name of the user group or role for which to import the authentication key. Make sure that the names of the keys belonging to each other are identical on all computers. - + Ange namnet på den användargrupp eller roll som autentiseringsnyckeln ska importeras för. + +Se till att namnen på de nycklar som tillhör varandra är identiska på alla datorer. AuthKeysManager Please check your permissions. - + Vänligen kontrollera dina behörigheter. Key name contains invalid characters! - + Nyckelns namn innehåller ogiltiga tecken! Invalid key type specified! Please specify "%1" or "%2". - + Ogiltig nyckeltyp angiven! Vänligen ange "%1" eller "%2". Specified key does not exist! Please use the "list" command to list all installed keys. - + Angiven nyckel finns inte! Använd kommandot "list" för att lista alla installerade nycklar. One or more key files already exist! Please delete them using the "delete" command. - + En eller flera nyckelfiler finns redan! Ta bort dem med hjälp av kommandot "delete". Creating new key pair for "%1" - + Skapar nytt nyckelpar för "%1" Failed to create public or private key! - + Misslyckades med att skapa offentlig eller privat nyckel! Newly created key pair has been saved to "%1" and "%2". - + Det nyskapade nyckelparet har sparats till "%1" och "%2". Could not remove key file "%1"! - + Det gick inte att ta bort nyckelfilen "%1"! Could not remove key file directory "%1"! - + Det gick inte att ta bort nyckelfilskatalogen "%1"! Failed to create directory for output file. - + Misslyckades med att skapa katalog för utdatafil. File "%1" already exists. - + Filen "%1" finns redan. Failed to write output file. - + Misslyckades med att skriva utdatafilen. Key "%1/%2" has been exported to "%3" successfully. - + Nyckel "%1/%2" har exporterats till "%3" framgångsrikt. Failed read input file. - + Misslyckades med att läsa inmatningsfilen. File "%1" does not contain a valid private key! - + Filen "%1" innehåller inte en giltig privat nyckel! File "%1" does not contain a valid public key! - + Filen "%1" innehåller inte en giltig offentlig nyckel! Failed to create directory for key file. - + Misslyckades med att skapa katalog för nyckelfilen. Failed to write key file "%1". - + Misslyckades med att skriva nyckelfilen "%1". Failed to set permissions for key file "%1"! - + Misslyckades med att ange behörigheter för nyckelfilen "%1"! Key "%1/%2" has been imported successfully. Please check file permissions of "%3" in order to prevent unauthorized accesses. - + Nyckel "%1/%2" har importerats framgångsrikt. Kontrollera filbehörigheterna för "%3" för att förhindra obehörig åtkomst. Failed to convert private key to public key - + Misslyckades med att konvertera privat nyckel till offentlig nyckel Failed to create directory for private key file "%1". - + Det gick inte att skapa en katalog för den privata nyckelfilen "%1". Failed to save private key in file "%1"! - + Misslyckades med att spara privat nyckel i filen "%1"! Failed to set permissions for private key file "%1"! - + Misslyckades med att ange behörigheter för privat nyckelfil "%1"! Failed to create directory for public key file "%1". - + Det gick inte att skapa en katalog för den offentliga nyckelfilen "%1". Failed to save public key in file "%1"! - + Misslyckades med att spara offentlig nyckel i filen "%1"! Failed to set permissions for public key file "%1"! - + Misslyckades med att ange behörigheter för den offentliga nyckelfilen "%1"! Failed to set owner of key file "%1" to "%2". - + Misslyckades med att ange ägare för nyckelfilen "%1" till "%2". Failed to set permissions for key file "%1". - + Misslyckades med att ange behörigheter för nyckelfilen "%1". Key "%1" is now accessible by user group "%2". - + Nyckel "%1" är nu tillgänglig för användargrupp "%2". <N/A> - + <N/A> Failed to read key file. - + Misslyckades med att läsa nyckelfilen. AuthKeysPlugin Create new authentication key pair - + Skapa ett nytt nyckelpar för autentisering Delete authentication key - + Ta bort autentiseringsnyckel List authentication keys - + Lista autentiseringsnycklar Import public or private key - + Importera offentlig eller privat nyckel Export public or private key - + Exportera offentlig eller privat nyckel Extract public key from existing private key - + Extrahera offentlig nyckel från befintlig privat nyckel Set user group allowed to access a key - + Ange vilken användargrupp som ska ha åtkomst till en nyckel Please specify the command to display help for. - + Ange det kommando som du vill visa hjälp för. NAME - + NAMN This command creates a new authentication key pair with name <NAME> and saves private and public key to the configured key directories. The parameter must be a name for the key, which may only contain letters. - + Det här kommandot skapar ett nytt nyckelpar för autentisering med namnet <NAME> och sparar den privata och offentliga nyckeln i de konfigurerade nyckelkatalogerna. Parametern måste vara ett namn för nyckeln, som endast får innehålla bokstäver. KEY - + Nyckel This command deletes the authentication key <KEY> from the configured key directory. Please note that a key can't be recovered once it has been deleted. - + Detta kommando raderar autentiseringsnyckeln <KEY> från den konfigurerade nyckelkatalogen. Observera att en nyckel inte kan återställas när den har tagits bort. FILE - + ORDER This command exports the authentication key <KEY> to <FILE>. If <FILE> is not specified a name will be constructed from name and type of <KEY>. - + Detta kommando exporterar autentiseringsnyckeln <KEY> till <FILE>. Om <FILE> inte anges kommer ett namn att konstrueras utifrån namn och typ för <KEY>. This command extracts the public key part from the private key <KEY> and saves it as the corresponding public key. When setting up another master computer, it is therefore sufficient to transfer the private key only. The public key can then be extracted. - + Detta kommando extraherar den offentliga nyckeldelen från den privata nyckeln <KEY> och sparar den som motsvarande offentliga nyckel. När du installerar en annan huvuddator räcker det därför med att endast överföra den privata nyckeln. Den publika nyckeln kan sedan extraheras. This command imports the authentication key <KEY> from <FILE>. If <FILE> is not specified a name will be constructed from name and type of <KEY>. - + Detta kommando importerar autentiseringsnyckeln <KEY> från <FILE>. Om <FILE> inte anges kommer ett namn att konstrueras utifrån namn och typ i <KEY>. This command lists all available authentication keys in the configured key directory. If the option "%1" is specified a table with key details will be displayed instead. Some details might be missing if a key is not accessible e.g. due to the lack of read permissions. - + Detta kommando listar alla tillgängliga autentiseringsnycklar i den konfigurerade nyckelkatalogen. Om alternativet "%1" anges visas i stället en tabell med nyckelinformation. Vissa detaljer kan saknas om en nyckel inte är tillgänglig, t.ex. på grund av att läsbehörighet saknas. ACCESS GROUP - + TILLGÅNGSGRUPP This command adjusts file access permissions to <KEY> such that only the user group <ACCESS GROUP> has read access to it. - + Detta kommando justerar filåtkomstbehörigheterna för <KEY> så att endast användargruppen <ACCESS GROUP> har läsåtkomst till den. The specified command does not exist or no help is available for it. - + Det angivna kommandot finns inte eller så finns det ingen hjälp tillgänglig för det. Please specify the key name (e.g. "teacher/public") as the first argument. - + Ange nyckelns namn (t.ex. "teacher/public") som första argument. TYPE - + TYP PAIR ID - + PAIR ID Command line support for managing authentication keys - + Kommandoradsstöd för hantering av autentiseringsnycklar Commands for managing authentication keys - + Kommandon för hantering av autentiseringsnycklar AuthKeysTableModel Name - + Namn Type - + Typ Access group - + Behörighetsgrupp Pair ID - + Par-ID BuiltinDirectoryConfigurationPage Locations & computers - + Platser och datorer Builtin directory - + Inbyggd katalog Computers - + Datorer Locations - + Platser Add new computer - + Lägg till ny dator Remove selected computer - + Ta bort vald dator Name - + Namn Host address/IP - + Värdadress/IP MAC address - + MAC-adress Add new location - + Skapa ny plats Remove selected location - + Ta bort vald plats The import of CSV files is possible through the command line interface. For more information, see the <a href="https://docs.veyon.io/en/latest/admin/cli.html#network-object-directory">online documentation</a>. - + Import av CSV-filer är möjlig genom kommandoradsgränssnittet. För mer information, se <a href="https://docs.veyon.io/en/latest/admin/cli.html#network-object-directory">dokumentation online</a>. New location - + Ny plats New computer - + Ny dator BuiltinDirectoryPlugin Show help for specific command - + Visa hjälp för ett specifikt kommando Add a location or computer - + Lägg till en plats eller dator Clear all locations and computers - + Rensa alla platser och datorer Dump all or individual locations and computers - + Dumpa alla eller enskilda platser och datorer List all locations and computers - + Lista alla platser och datorer Remove a location or computer - + Ta bort en plats eller dator Import objects from given file - + Importera objekt från en given fil Export objects to given file - + Exportera objekt till en given fil FILE - + ORDER LOCATION - + PLATS FORMAT-STRING-WITH-PLACEHOLDERS - + FORMAT-STRÄNG-MED-PLATSHÅLLARE REGULAR-EXPRESSION-WITH-PLACEHOLDER - + REGULJÄRT UTTRYCK-MED-PLATSHÅLLARE Imports objects from the specified text file using the given format string or regular expression containing one or multiple placeholders. Valid placeholders are: %1 - + Importerar objekt från den angivna textfilen med hjälp av den angivna formatsträngen eller det reguljära uttrycket som innehåller en eller flera platshållare. Giltiga platshållare är: %1 Import simple CSV file to a single room - + Importera enkel CSV-fil till ett enda rum Import CSV file with location name in first column - + Importera CSV-fil med platsnamn i första kolumnen Import text file with with key/value pairs using regular expressions - + Importera textfil med nyckel/värde-par med hjälp av reguljära uttryck Import arbitrarily formatted data - + Importera godtyckligt formaterad data Exports objects to the specified text file using the given format string containing one or multiple placeholders. Valid placeholders are: %1 - + Exporterar objekt till den angivna textfilen med hjälp av den angivna formatsträngen som innehåller en eller flera platshållare. Giltiga platshållare är: %1 Export all objects to a CSV file - + Exportera alla objekt till en CSV-fil Export all computers in a specific location to a CSV file - + Exportera alla datorer på en viss plats till en CSV-fil TYPE - + TYP NAME - + NAMN HOST ADDRESS - + VÄRDENS ADRESS MAC ADDRESS - + MAC-ADRESS PARENT - + FÖRÄLDRAR Adds an object where %1 can be one of "%2" or "%3". %4 can be specified by name or UUID. - + Lägger till ett objekt där %1 ckan vara en av "%2" eller "%3". %4 ckan specificeras med namn eller UUID. Add a room - + Lägg till ett rum Add a computer to room %1 - + Lägg till en dator i rum %1 OBJECT - + OBJECT Removes the specified object from the directory. %1 can be specified by name or UUID. Removing a location will also remove all related computers. - + Tar bort det angivna objektet från katalogen. %1 c kan anges med namn eller UUID. Om du tar bort en plats tas även alla relaterade datorer bort. Remove a computer by name - + Ta bort en dator med namn Remove an object by UUID - + Ta bort ett objekt med UUID The specified command does not exist or no help is available for it. - + Det angivna kommandot finns inte eller så finns det ingen hjälp tillgänglig för det. Invalid type specified. Valid values are "%1" or "%2". - + Ogiltig typ angiven. Giltiga värden är "%1" eller "%2". Object UUID - + Objektets UUID Parent UUID - + Förälder UUID Type - + Typ Name - + Namn Host address - + Värdadress MAC address - + MAC-adress Specified object not found. - + Angivet objekt hittades inte. File "%1" does not exist! - + Filen "%1" finns inte! Can't open file "%1" for reading! - + Kan inte öppna filen "%1" för läsning! Unknown argument "%1". - + Okänt argument "%1". No format string or regular expression specified! - + Ingen formatsträng eller reguljärt uttryck har angetts! Can't open file "%1" for writing! - + Kan inte öppna filen "%1" för skrivning! No format string specified! - + Ingen formatsträng specificerad! Location "%1" - + Plats "%1" Computer "%1" (host address: "%2" MAC address: "%3") - + Dator "%1" (värdadress: "%2" MAC-adress: "%3") Unclassified object "%1" with ID "%2" - + Oklassificerat objekt "%1" med ID "%2" None - + Ingen Invalid - + Ogiltig Error while parsing line %1. - + Fel vid parsning av rad %1. Network object directory which stores objects in local configuration - + Nätverksobjektkatalog som lagrar objekt i lokal konfiguration Builtin (computers and locations in local configuration) - + Inbyggd (datorer och platser i lokal konfiguration) Commands for managing the builtin network object directory - + Kommandon för att hantera den inbyggda katalogen för nätverksobjekt Location - + Plats Computer - + Dator Root - + Rot "Room 01" - + "Rum 01" "Computer 01" - + "Dator 01" Location "%1" not found. - + Platsen "%1" hittades inte. BuiltinUltraVncServer Builtin VNC server (UltraVNC) - + Inbyggd VNC-server (UltraVNC) BuiltinX11VncServer Builtin VNC server (x11vnc) - + Inbyggd VNC-server (x11vnc) ComputerControlListModel Name: %1 - + Namn: %1 Location: %1 - - - - Host/IP address: %1 - - - - invalid - + Plats: %1 Active features: %1 - + Aktiva funktioner: %1 [no user] - + [ingen användare] Online and connected - + Online och uppkopplad Establishing connection - + Upprättande av anslutning Computer offline or switched off - + Dator offline eller avstängd Veyon Server unreachable or not running - + Veyon Server går inte att nå eller körs inte Authentication failed or access denied - + Autentiseringen misslyckades eller åtkomst nekades Disconnected - + Urkopplad No user logged on @@ -1048,10 +1052,26 @@ Make sure that the names of the keys belonging to each other are identical on al Logged on user: %1 + Inloggad användare: %1 + + + Hostname: %1 + + + + unknown + okänd + + + IP address: %1 - [none] + Hostname could not be resolved + + + + No features active @@ -1063,206 +1083,206 @@ Make sure that the names of the keys belonging to each other are identical on al User "%1" at host "%2" attempted to access this computer but could not authenticate successfully. - + Användaren "%1" på värden "%2" försökte komma åt den här datorn men kunde inte autentisera sig. Remote access - + Fjärråtkomst User "%1" at host "%2" is now accessing this computer. - + Användaren "%1" på värden "%2" har nu tillgång till den här datorn. Access control error - + Fel i åtkomstkontroll User "%1" at host "%2" attempted to access this computer but has been blocked due to access control settings. - + Användaren "%1" på värden "%2" försökte komma åt den här datorn men blockerades på grund av inställningar för åtkomstkontroll. %1 Service %2 at %3:%4 - + %1 Service %2 vid %3:%4 Active connections: - + Aktiva anslutningar: ComputerManager User - + Användare Logged in since - + Inloggad sedan Missing network object directory plugin - + Saknar plugin för nätverksobjektkatalog No default network object directory plugin was found. Please check your installation or configure a different network object directory backend via %1 Configurator. - + Inget standardinsticksprogram för nätverksobjektkatalog hittades. Kontrollera din installation eller konfigurera en annan backend för nätverksobjektkatalog via %1 Configurator. Computer name;Hostname;User - + Datornamn;Värdnamn;Användare %1 days - + %1 days 1 day - + 1 dag Location detection failed - + Platsdetektering misslyckades Could not determine the location of this computer. This indicates a problem with the system configuration. All locations will be shown in the computer select panel instead. - + Det gick inte att fastställa platsen för den här datorn. Detta indikerar ett problem med systemkonfigurationen. Alla platser visas i stället i panelen för val av dator. ComputerSelectPanel Search computers - + Sök datorer Add location - + Lägg till plats Save computer/user list - + Spara dator/användarlista Select output filename - + Välj filnamn för utdata CSV files (*.csv) - + CSV-filer (*.csv) File error - + Fel i filen Could not write the computer and users list to %1! Please check the file access permissions. - + Det gick inte att skriva dator- och användarlistan till %1! Kontrollera filåtkomstbehörigheterna. ConfigCommands Clear system-wide Veyon configuration - + Rensa systemomfattande Veyon-konfiguration List all configuration keys and values - + Lista alla konfigurationsnycklar och värden Import configuration from given file - + Importera konfiguration från given fil Export configuration to given file - + Exportera konfiguration till angiven fil Read and output configuration value for given key - + Läser och matar ut konfigurationsvärde för given nyckel Write given value to given configuration key - + Skriv ett givet värde till en given konfigurationsnyckel Unset (remove) given configuration key - + Ta bort (unset) en given konfigurationsnyckel Upgrade and save configuration of program and plugins - + Uppgradera och spara konfiguration av program och plugins Please specify an existing configuration file to import. - + Ange en befintlig konfigurationsfil som ska importeras. Configuration file is not readable! - + Konfigurationsfilen är inte läsbar! Please specify a valid filename for the configuration export. - + Ange ett giltigt filnamn för konfigurationsexporten. Output file is not writable! - + Utdatafilen är inte skrivbar! Output directory is not writable! - + Utdatakatalogen är inte skrivbar! Please specify a valid key. - + Vänligen ange en giltig nyckel. Specified key does not exist in current configuration! - + Angiven nyckel finns inte i aktuell konfiguration! Please specify a valid value. - + Vänligen ange ett giltigt värde. Configure Veyon at command line - + Konfigurera Veyon på kommandoraden Commands for managing the configuration of Veyon - + Kommandon för att hantera konfigurationen av Veyon ConfigurationManager Could not modify the autostart property for the %1 Service. - + Det gick inte att ändra egenskapen autostart för tjänsten %1. Could not configure the firewall configuration for the %1 Server. - + Det gick inte att konfigurera brandväggskonfigurationen för servern %1. Could not configure the firewall configuration for the %1 Worker. - + Det gick inte att konfigurera brandväggskonfigurationen för %1 Worker. Could not apply platform-specific configuration settings. - + Det gick inte att tillämpa plattformsspecifika konfigurationsinställningar. Configuration is not writable. Please check your permissions! - + Konfigurationen är inte skrivbar. Vänligen kontrollera dina behörigheter! DemoClient %1 Demo - + %1 Demo @@ -1273,62 +1293,62 @@ Make sure that the names of the keys belonging to each other are identical on al Tunables - + Avstämbara instrument s - + s Update interval - + Uppdateringsintervall MB - + MB ms - + ms Slow down thumbnail updates while demo is running - + Långsammare uppdatering av miniatyrbilder när demo körs Memory limit - + Minnesgräns Key frame interval - + Intervall för nyckelram Bandwidth limit - + Begränsning av bandbredd MB/s - + MB/s DemoFeaturePlugin Demo - + Demo Stop demo - + Stoppa demo Share your screen or allow a user to share his screen with other users. - + Dela din skärm eller låt en användare dela sin skärm med andra användare. Full screen demo - + Demo i fullskärm Window demo @@ -1336,66 +1356,66 @@ Make sure that the names of the keys belonging to each other are identical on al Share your own screen in fullscreen mode - + Dela din egen skärm i helskärmsläge In this mode your screen is being displayed in full screen mode on all computers while the input devices of the users are locked. - + I det här läget visas din skärm i helskärmsläge på alla datorer medan användarnas inmatningsenheter är låsta. Share your own screen in a window - + Dela din egen skärm i ett fönster In this mode your screen being displayed in a window on all computers. The users are able to switch to other windows as needed. - + I det här läget visas din skärm i ett fönster på alla datorer. Användarna kan växla till andra fönster efter behov. Share selected user's screen in fullscreen mode - + Dela den valda användarens skärm i helskärmsläge In this mode the screen of the selected user is being displayed in full screen mode on all computers while the input devices of the users are locked. - + I detta läge visas skärmen för den valda användaren i helskärmsläge på alla datorer medan användarnas inmatningsenheter är låsta. Share selected user's screen in a window - + Dela den valda användarens skärm i ett fönster In this mode the screen of the selected user being displayed in a window on all computers. The users are able to switch to other windows as needed. - + I det här läget visas skärmen för den valda användaren i ett fönster på alla datorer. Användarna kan växla till andra fönster efter behov. Please select a user screen to share. - + Välj en användarskärm som du vill dela med dig av. Please select only one user screen to share. - + Välj bara en användarskärm att dela med dig av. All screens - + Alla skärmar Give a demonstration by screen broadcasting - + Ge en demonstration genom skärmutsändning DesktopAccessDialog Desktop access dialog - + Dialog för åtkomst till skrivbord Confirm desktop access - + Bekräfta åtkomst till skrivbordet The user %1 at computer %2 wants to access your desktop. Do you want to grant access? - + Användaren %1 på datorn %2 vill komma åt ditt skrivbord. Vill du bevilja åtkomst? Never for this session @@ -1410,90 +1430,90 @@ Make sure that the names of the keys belonging to each other are identical on al DesktopServicesConfigurationPage Applications & websites - + Applikationer & webbplatser Predefined applications - + Fördefinierade applikationer Name - + Namn Path - + Sökväg Add new application - + Lägg till ny applikation Remove selected application - + Ta bort vald applikation Predefined websites - + Fördefinierade webbplatser Add new website - + Lägg till ny webbplats Remove selected website - + Ta bort vald webbplats URL - + URL New application - + Ny application New website - + Ny webbplats DesktopServicesFeaturePlugin Start application - + Starta ansökan Click this button to start an application on all computers. - + Klicka på den här knappen för att starta ett program på alla datorer. Open website - + Öppna webbplats Click this button to open a website on all computers. - + Klicka på den här knappen för att öppna en webbplats på alla datorer. Start application "%1" - + Starta applikationen "%1" Custom application - + Anpassad applikation Open website "%1" - + Öppna webbplatsen "%1" Custom website - + Anpassad webbplats Start apps and open websites in user sessions - + Starta appar och öppna webbplatser i användarsessioner @@ -1504,300 +1524,300 @@ Make sure that the names of the keys belonging to each other are identical on al Room %1 - + Rum %1 generic-student-user - + generisk-student-användare Please complete all tasks within the next 5 minutes. - + Vänligen slutför alla uppgifter inom de närmaste 5 minuterna. Custom website - + Anpassad webbplats Open file manager - + Öppna filhanteraren Start learning tool - + Starta inlärningsverktyget Play tutorial video - + Spela upp instruktionsvideo Custom application - + Anpassad applikation Handout - + Handout Texts to read - + Texter att läsa ExternalVncServer External VNC server - + Extern VNC-server ExternalVncServerConfigurationWidget External VNC server configuration - + Konfiguration av extern VNC-server Port: - + Hamn: Password: - + Lösenord: FeatureCommands List names of all available features - + Lista namn på alla tillgängliga funktioner Show table with details of all available features - + Visa tabell med detaljer om alla tillgängliga funktioner Start a feature on a remote host - + Starta en funktion på en avlägsen värd Stop a feature on a remote host - + Stoppa en funktion på en fjärrvärd Please specify the command to display help for. - + Ange det kommando som du vill visa hjälp för. Displays a list with the names of all available features. - + Visar en lista med namnen på alla tillgängliga funktioner. Displays a table with detailed information about all available features. This information include a description, the UID, the name of the plugin providing the respective feature and some other implementation-related details. - + Visar en tabell med detaljerad information om alla tillgängliga funktioner. Informationen omfattar en beskrivning, UID, namnet på det plugin som tillhandahåller respektive funktion och vissa andra implementeringsrelaterade detaljer. HOST ADDRESS - + VÄRDENS ADRESS FEATURE - + Funktion ARGUMENTS - + Aktivera extra videoargument Starts the specified feature on the specified host by connecting to the Veyon Server running remotely. The feature can be specified by name or UID. Use the ``show`` command to see all available features. Depending on the feature, additional arguments (such as the text message to display) encoded as a single JSON string have to be specified. Please refer to the developer documentation for more information - + Startar den angivna funktionen på den angivna värden genom att ansluta till Veyon Server som körs på distans. Funktionen kan anges med namn eller UID. Använd kommandot ``show`` för att se alla tillgängliga funktioner. Beroende på funktionen måste ytterligare argument (t.ex. textmeddelandet som ska visas) kodade som en enda JSON-sträng anges. Se utvecklarens dokumentation för mer information Lock the screen - + Lås skärmen Display a text message - + Visa ett textmeddelande Test message - + Test meddelande Start an application - + Starta en ansökan Stops the specified feature on the specified host by connecting to the Veyon Server running remotely. The feature can be specified by name or UID. Use the ``show`` command to see all available features. - + Stoppar den angivna funktionen på den angivna värden genom att ansluta till Veyon-servern som körs på distans. Funktionen kan anges med namn eller UID. Använd kommandot ``show`` för att se alla tillgängliga funktioner. Unlock the screen - + Lås upp skärmen The specified command does not exist or no help is available for it. - + Det angivna kommandot finns inte eller så finns det ingen hjälp tillgänglig för det. Name - + Namn Description - + Beskrivning Master - + Säkerhetsansvarig Service - + Tjänst Worker - + Vägledare UID - + UID Plugin - + Tillägg Invalid feature name or UID specified - + Ogiltigt funktionsnamn eller UID angivet Error parsing the JSON-encoded arguments: %1 - + Fel vid analys av JSON-kodade argument: %1 Failed to initialize credentials - + Initialisering av autentiseringsuppgifter misslyckades Could not establish a connection to host %1 - + Det gick inte att upprätta en anslutning till värden %1 Failed to send feature control message to host %1 - + Misslyckades med att skicka feature control-meddelande till host %1 Feature-related CLI operations - + Funktionsrelaterade CLI-åtgärder Commands for controlling features - + Kommandon för styrning av funktioner FileTransferConfigurationPage File transfer - + Filöverföring Directories - + Kataloger Destination directory - + Destinationskatalog Default source directory - + Standard källkatalog Options - + Alternativ Remember last source directory - + Kom ihåg den senaste källkatalogen Create destination directory if it does not exist - + Skapa destinationskatalog om den inte finns FileTransferController Could not open file "%1" for reading! Please check your permissions! - + Filen "%1" kunde inte öppnas för läsning! Vänligen kontrollera dina behörigheter! FileTransferDialog File transfer - + Filöverföring Options - + Alternativ Overwrite existing files - + Skriv över befintliga filer Transfer only - + Endast överföring Transfer and open file(s) with associated program - + Överför och öppna fil(er) med tillhörande program Transfer and open destination folder - + Överför och öppna målmappen Files - + Filer Start - + Starta FileTransferPlugin File transfer - + Filöverföring Click this button to transfer files from your computer to all computers. - + Klicka på den här knappen för att överföra filer från din dator till alla datorer. Select one or more files to transfer - + Välj en eller flera filer som ska överföras Received file "%1". - + Mottagen fil "%1". Could not receive file "%1" as it already exists. - + Kunde inte ta emot filen "%1" eftersom den redan finns. Could not receive file "%1" as it could not be opened for writing! - + Kunde inte ta emot filen "%1" eftersom den inte kunde öppnas för skrivning! Transfer files to remote computer - + Överför filer till fjärrdatorn @@ -1808,23 +1828,23 @@ Make sure that the names of the keys belonging to each other are identical on al Use system language setting - + Använd systemets språkinställning Language: - + Språk: Veyon - + Veyon Style: - + Stil: Native - + Inbyggd Authentication @@ -1832,31 +1852,31 @@ Make sure that the names of the keys belonging to each other are identical on al Method: - + Metod: Logon authentication - + Autentisering av inloggning Key file authentication - + Autentisering av nyckelfiler Test - Test + Testa Network object directory - + Katalog över nätverksobjekt Backend: - + Bakände: Update interval: - + Uppdateringsintervall: seconds @@ -1900,15 +1920,15 @@ Make sure that the names of the keys belonging to each other are identical on al x - + bredd Rotate log files - + Rotera loggfiler MB - + MB Limit log file size @@ -1916,11 +1936,11 @@ Make sure that the names of the keys belonging to each other are identical on al Log to standard error output - + Logga till standardfelutmatning Write to logging system of operating system - + Skriv till operativsystemets loggningssystem Clear all log files @@ -1928,47 +1948,47 @@ Make sure that the names of the keys belonging to each other are identical on al Authentication is set up properly on this computer. - + Autentiseringen är korrekt inställd på den här datorn. Authentication keys are not set up properly on this computer. - + Autentiseringsnycklarna är inte konfigurerade korrekt på denna dator. %1 service - + %1 tjänst The %1 service needs to be stopped temporarily in order to remove the log files. Continue? - + %1 service måste stoppas tillfälligt för att ta bort loggfilerna. Fortsätter du? Log files cleared - + Loggfiler rensade All log files were cleared successfully. - + Alla loggfiler rensades framgångsrikt. Error - + Fel Could not remove all log files. - + Det gick inte att ta bort alla loggfiler. Authentication test - + Autentiseringstest User groups - + Användargrupper Include user groups from domain - + Inkludera användargrupper från domänen Missing user groups backend @@ -1976,6 +1996,18 @@ Make sure that the names of the keys belonging to each other are identical on al No user groups plugin was found. Please check your installation! + Inget plugin för användargrupper hittades. Vänligen kontrollera din installation! + + + Color scheme: + + + + Light + + + + Dark @@ -1983,28 +2015,28 @@ Make sure that the names of the keys belonging to each other are identical on al HeadlessVncServer Headless VNC server - + Huvudlös VNC-server LdapBrowseDialog Browse LDAP - + Bläddra i LDAP LdapClient LDAP error description: %1 - + Beskrivning av LDAP-fel: %1 LdapConfigurationPage Basic settings - + Standardinställningar General @@ -2012,370 +2044,377 @@ Make sure that the names of the keys belonging to each other are identical on al Anonymous bind - + Anonym bindning Use bind credentials - + Använd inloggningsuppgifter för bindning Query timeout - + Tidsgräns för förfrågningar Bind DN - + Binda DN ms - + ms LDAP server and port - + LDAP-server och port Bind password - + Bind lösenord Connection security - + Anslutningssäkerhet TLS certificate verification - + Verifiering av TLS-certifikat Encryption protocol - + Krypteringsprotokoll System defaults - + Systemets standardinställningar Never (insecure!) - + Aldrig (osäker!) Custom CA certificate file - + Anpassad CA-certifikatfil None - + Ingen TLS - + TLS SSL - + SSL Base DN - + Bas DN Discover base DN by naming context - + Upptäck bas-DN genom att namnge sammanhang e.g. namingContexts or defaultNamingContext - + t.ex. namingContexts eller defaultNamingContext Fixed base DN - + Fast bas DN e.g. dc=example,dc=org - + t.ex. dc=exempel,dc=org Environment settings - + Miljöinställningar Object trees - + Objektträd (only if different from group tree) - + (endast om det skiljer sig från gruppträdet) Computer tree - + Dator träd Perform recursive search operations in object trees - + Utföra rekursiva sökoperationer i objektträd User tree - + Användarträd e.g. OU=Computers - + t.ex. OU=Datorer Group tree - + Gruppträd Computer group tree - + Dator grupp träd e.g. OU=Users - + t.ex. OU=Användare e.g. OU=Groups - + t.ex. OU=Grupper Object attributes - + Objektets attribut e.g. name or description - + t.ex. namn eller beskrivning Hostnames stored as fully qualified domain names (FQDN, e.g. myhost.example.org) - + Värdnamn lagrade som fullständigt kvalificerade domännamn (FQDN, t.ex. myhost.example.org) e.g. room or computerLab - + t.ex. rum eller datorLab User login name attribute - + Attribut för användarens inloggningsnamn Computer location attribute - + Attribut för datorplats e.g. member or memberUid - + t.ex. medlem eller memberUid Group member attribute - + Attribut för gruppmedlem e.g. hwAddress - + t.ex. hwAddress Computer MAC address attribute - + MAC-adressattribut för dator e.g. dNSHostName - + t.ex. dNSHostName e.g. uid or sAMAccountName - + t.ex. uid eller sAMAccountName Computer display name attribute - + Attribut för datorns visningsnamn Computer hostname attribute - + Attribut för datorns värdnamn Location name attribute - + Attribut för platsnamn e.g. cn or displayName - + t.ex. cn eller displayName Advanced settings - + Avancerade inställningar Optional object filters - + Valfria objektfilter Filter for computer groups - + Filter för datorgrupper e.g. (objectClass=computer) - + t.ex. (objektKlass=dator) e.g. (objectClass=group) - + t.ex. (objektKlass=grupp) e.g. (objectClass=person) - + t.ex. (objektKlass=person) Filter for users - + Filter för användare Filter for computers - + Filter för datorer Filter for user groups - + Filter för användargrupper e.g. (objectClass=room) or (objectClass=computerLab) - + t.ex. (objektKlass=rum) eller (objektKlass=datalabb) Filter for computer containers - + Filter för datorbehållare e.g. (objectClass=container) or (objectClass=organizationalUnit) - + t.ex. (objectClass=container) eller (objectClass=organizationalUnit) Query options - + Alternativ för frågor Query nested user groups (supported by AD only) - + Fråga efter nästlade användargrupper (stöds endast av AD) Group member identification - + Identifiering av gruppmedlem Distinguished name (Samba/AD) - + Särskiljande namn (Samba/AD) Configured attribute for user login name or computer hostname (OpenLDAP) - + Konfigurerat attribut för användarens inloggningsnamn eller datorns värdnamn (OpenLDAP) Computer locations identification - + Identifiering av datorplatser Identify computer locations (e.g. rooms) via: - + Identifiera datorplatser (t.ex. rum) via: Computer groups - + Datorgrupper Computer containers or OUs - + Datorbehållare eller OU:er Location attribute in computer objects - + Platsattribut i datorobjekt Integration tests - + Integrationstest List all groups of a user - + Lista alla grupper för en användare List all groups of a computer - + Lista alla grupper i en dator Get computer object by IP address - + Hämta datorobjekt via IP-adress List all entries of a location - + Lista alla poster för en plats List all locations - + Lista alla platser Browse - + Bläddra Test - Test + Testa LDAP base DN test failed - + Test av LDAP-bas-DN misslyckades Could not query the configured base DN. Please check the base DN parameter. %1 - + Det gick inte att fråga efter det konfigurerade bas-DN:et. Kontrollera parametern för bas-DN. + +%1 LDAP base DN test successful - + Test av LDAP-bas-DN framgångsrikt The LDAP base DN has been queried successfully. The following entries were found: %1 - + LDAP-bas-DN:n har sökts framgångsrikt. Följande poster hittades: + +%1 LDAP naming context test failed - + Test av LDAP-namngivningskontext misslyckades Could not query the base DN via naming contexts. Please check the naming context attribute parameter. %1 - + Det gick inte att fråga efter bas-DN via namngivningskontexter. Kontrollera parametern för attribut för namngivningskontext. + +%1 LDAP naming context test successful - + Test av LDAP-namngivningskontext framgångsrikt The LDAP naming context has been queried successfully. The following base DN was found: %1 - + LDAP-namngivningskontexten har sökts framgångsrikt. Följande bas-DN hittades: +%1 user tree - + användarträd group tree - + gruppträd computer tree - + datorträd computer group tree - + datorgrupp träd Enter username @@ -2383,381 +2422,393 @@ Make sure that the names of the keys belonging to each other are identical on al Please enter a user login name (wildcards allowed) which to query: - + Ange ett användarinloggningsnamn (jokertecken tillåtna) som du vill fråga: user objects - + användarobjekt Enter group name - + Ange gruppnamn Please enter a group name whose members to query: - + Ange ett gruppnamn vars medlemmar du vill fråga: group members - + gruppmedlemmar Group not found - + Gruppen hittades inte Could not find a group with the name "%1". Please check the group name or the group tree parameter. - + Det gick inte att hitta en grupp med namnet "%1". Kontrollera gruppnamnet eller parametern för gruppträdet. Enter computer display name - + Ange datorns visningsnamn Please enter a computer display name to query: - + Ange en dators visningsnamn för att ställa en fråga: computer objects - + datorobjekt Enter computer name - + Ange datorns namn Please enter a computer hostname to query: - + Ange en dators värdnamn för att ställa en fråga: Invalid hostname - + Ogiltigt värdnamn You configured computer hostnames to be stored as fully qualified domain names (FQDN) but entered a hostname without domain. - + Du konfigurerade datorns värdnamn så att de lagras som fullständigt kvalificerade domännamn (FQDN) men angav ett värdnamn utan domän. You configured computer hostnames to be stored as simple hostnames without a domain name but entered a hostname with a domain name part. - + Du konfigurerade datorns värdnamn så att de lagras som enkla värdnamn utan domännamn, men angav ett värdnamn med en domännamnsdel. Enter computer DN - + Gå in i datorn DN Please enter the DN of a computer whose MAC address to query: - + Ange DN för en dator vars MAC-adress du vill fråga efter: computer MAC addresses - + mAC-adresser till datorer Enter computer location name - + Ange datorns platsnamn Please enter the name of a computer location (wildcards allowed): - + Ange namnet på en datorplats (jokertecken tillåtna): computer locations - + datorplatser Enter location name - + Ange platsens namn users - + användare user groups - + användargrupper computers - + datorer computer groups - + datorgrupper computer containers - + datorbehållare Please enter a user login name whose group memberships to query: - + Ange ett inloggningsnamn för den användare vars gruppmedlemskap ska efterfrågas: groups of user - + grupper av användare User not found - + Användare kunde inte hittas Could not find a user with the name "%1". Please check the username or the user tree parameter. - + Det gick inte att hitta en användare med namnet "%1". Kontrollera användarnamnet eller parametern för användarträdet. Enter hostname - + Ange värdnamn Please enter a computer hostname whose group memberships to query: - + Ange ett värdnamn på en dator vars gruppmedlemskap ska frågas: groups of computer - + grupper av datorer Computer not found - + Datorn hittades inte Could not find a computer with the hostname "%1". Please check the hostname or the computer tree parameter. - + Det gick inte att hitta en dator med värdnamnet "%1". Kontrollera värdnamnet eller parametern för datorträdet. Enter computer IP address - + Ange datorns IP-adress Please enter a computer IP address which to resolve to an computer object: - + Ange en IP-adress för en dator som ska lösas upp till ett datorobjekt: Hostname lookup failed - + Sökningen efter värdnamn misslyckades Could not lookup hostname for IP address %1. Please check your DNS server settings. - + Det gick inte att söka efter värdnamn för IP-adressen %1. Kontrollera inställningarna för din DNS-server. Please enter the name of a location whose entries to query: - + Ange namnet på en plats vars poster du vill söka efter: location entries - + platsangivelser Certificate files (*.pem) - + Certifikatfiler (*.pem) LDAP connection failed - + LDAP-anslutningen misslyckades Could not connect to the LDAP server. Please check the server parameters. %1 - + Det gick inte att ansluta till LDAP-servern. Kontrollera serverns parametrar. + +%1 LDAP bind failed - + LDAP-bindning misslyckades Could not bind to the LDAP server. Please check the server parameters and bind credentials. %1 - + Det gick inte att binda till LDAP-servern. Kontrollera serverparametrarna och bindningsuppgifterna. + +%1 LDAP bind successful - + LDAP bindning framgångsrik Successfully connected to the LDAP server and performed an LDAP bind. The basic LDAP settings are configured correctly. - + Anslöt till LDAP-servern och utförde en LDAP-bindning. De grundläggande LDAP-inställningarna är korrekt konfigurerade. LDAP %1 test failed - + LDAP %1-testet misslyckades Could not query any entries in configured %1. Please check the parameter "%2". %3 - + Det gick inte att fråga efter några poster i konfigurerad %1. Vänligen kontrollera parametern "%2". + +%3 LDAP %1 test successful - + LDAP %1-test framgångsrikt The %1 has been queried successfully and %2 entries were found. - + %1 har sökts framgångsrikt och %2 entries hittades. LDAP test failed - + LDAP-testet misslyckades Could not query any %1. Please check the parameter(s) %2 and enter the name of an existing object. %3 - + Kunde inte fråga någon %1. Kontrollera parametern/parametrarna %2 och ange namnet på ett befintligt objekt. + +%3 and - + och LDAP test successful - + LDAP-test framgångsrikt %1 %2 have been queried successfully: %3 - + %1 %2 har sökts framgångsrikt: + +%3 LDAP filter test failed - + Test av LDAP-filter misslyckades Could not query any %1 using the configured filter. Please check the LDAP filter for %1. %2 - + Kunde inte fråga någon %1 using det konfigurerade filtret. Kontrollera LDAP-filtret för %1. + +%2 LDAP filter test successful - + Test av LDAP-filter framgångsrikt %1 %2 have been queried successfully using the configured filter. - + %1 %2 har sökts framgångsrikt med hjälp av det konfigurerade filtret. LdapPlugin Auto-configure the base DN via naming context - + Automatisk konfiguration av bas-DN via namngivningskontext Query objects from LDAP directory - + Fråga efter objekt från LDAP-katalog Show help about command - + Visa hjälp om kommandot Please specify a valid LDAP url following the schema "ldap[s]://[user[:password]@]hostname[:port]" - + Ange en giltig LDAP-url enligt schemat "ldap[s]://[user[:password]@]hostname[:port]" No naming context attribute name given - falling back to configured value. - + Inget namn på attribut i namngivningskontext anges - faller tillbaka till konfigurerat värde. Could not query base DN. Please check your LDAP configuration. - + Kunde inte fråga bas DN. Kontrollera din LDAP-konfiguration. Configuring %1 as base DN and disabling naming context queries. - + Konfigurera %1 som bas-DN och inaktivera frågor om namngivningskontext. Basic LDAP/AD support for Veyon - + Grundläggande LDAP/AD-stöd för Veyon Commands for configuring and testing LDAP/AD integration - + Kommandon för att konfigurera och testa LDAP/AD-integration %1 (load computers and locations from LDAP/AD) - + %1 (ladda datorer och platser från LDAP/AD) %1 (load users and groups from LDAP/AD) - + %1 (ladda användare och grupper från LDAP/AD) LinuxPlatformConfigurationPage Linux - + Linux User authentication - + Autentisering av användare Custom PAM service for user authentication - + Anpassad PAM-tjänst för autentisering av användare User sessions - + Användarsessioner Minimum session lifetime before server start - + Minsta sessionslivslängd före serverstart User login - + Användarinloggning Login key sequence - + Tangentsekvens för inloggning LinuxPlatformPlugin Plugin implementing abstract functions for the Linux platform - + Plugin som implementerar abstrakta funktioner för Linux-plattformen LocationDialog Select location - + Välj plats enter search filter... - + ange sökfilter ... MainToolBar Configuration - + Konfiguration Disable tooltips - + Inaktivera verktygstips Show icons only - + Visa endast ikoner MainWindow Veyon Configurator - + Veyon konfigurator General @@ -2765,15 +2816,15 @@ Make sure that the names of the keys belonging to each other are identical on al Service - + Tjänst Master - + Säkerhetsansvarig Access control - + Åtkomstkontroll &File @@ -2785,7 +2836,7 @@ Make sure that the names of the keys belonging to each other are identical on al &View - + &Visa &Quit @@ -2797,7 +2848,7 @@ Make sure that the names of the keys belonging to each other are identical on al &Save settings to file - + &Spara inställningar till fil Save settings to file @@ -2825,15 +2876,15 @@ Make sure that the names of the keys belonging to each other are identical on al Reset configuration - + Återställ konfiguration &Standard - + Skärm %1$u Standard (%2$u:%3$u) &Advanced - + Avancerat MainWindow @@ -2841,11 +2892,11 @@ Make sure that the names of the keys belonging to each other are identical on al Adjust size of computer icons automatically - + Justera storleken på datorikoner automatiskt Auto - + Auto About @@ -2853,35 +2904,35 @@ Make sure that the names of the keys belonging to each other are identical on al Search users and computers - + Sök användare och datorer Align computers to grid - + Rikta in datorerna i rutnätet Only show powered on computers - + Visa endast datorer som är påslagna Locations && computers - + Platser & & datorer Screenshots - + Skärmbilder Slideshow - + Bildspel Spotlight - + Strålkastare Only show computers with logged on users - + Visa endast datorer med inloggade användare toolBar @@ -2889,7 +2940,7 @@ Make sure that the names of the keys belonging to each other are identical on al %1 Configurator %2 - + %1 Konfigurator %2 Load settings from file @@ -2897,15 +2948,15 @@ Make sure that the names of the keys belonging to each other are identical on al JSON files (*.json) - + JSON-filer (*.json) Do you really want to reset the local configuration and revert all settings to their defaults? - + Vill du verkligen återställa den lokala konfigurationen och återställa alla inställningar till standardvärdena? %1 Configurator - + %1 Konfigurator Unsaved settings @@ -2917,11 +2968,11 @@ Make sure that the names of the keys belonging to each other are identical on al Insufficient privileges - + Otillräckliga privilegier Could not start with administrative privileges. Please make sure a sudo-like program is installed for your desktop environment! The program will be run with normal user privileges. - + Kunde inte starta med administrativa behörigheter. Se till att ett sudo-liknande program är installerat för din skrivbordsmiljö! Programmet kommer att köras med normala användarrättigheter. Configuration not writable @@ -2929,15 +2980,15 @@ Make sure that the names of the keys belonging to each other are identical on al The local configuration backend reported that the configuration is not writable! Please run the %1 Configurator with higher privileges. - + Den lokala konfigurationsbackend rapporterade att konfigurationen inte är skrivbar! Kör %1 Configurator med högre behörigheter. Authentication impossible - + Autentisering inte möjlig No authentication key files were found or your current ones are outdated. Please create new key files using the %1 Configurator. Alternatively set up logon authentication using the %1 Configurator. Otherwise you won't be able to access computers using %1. - + Inga filer för autentiseringsnycklar hittades eller så är dina nuvarande utdaterade. Skapa nya nyckelfiler med hjälp av %1 Konfigurator. Alternativt konfigurera inloggningsautentisering med %1 Konfigurator. Annars kommer du inte kunna komma åt datorer som använder %1. Access denied @@ -2945,48 +2996,50 @@ Make sure that the names of the keys belonging to each other are identical on al According to the local configuration you're not allowed to access computers in the network. Please log in with a different account or let your system administrator check the local configuration. - + Enligt den lokala konfigurationen har du inte åtkomst till datorer i nätverket. Logga in med ett annat konto eller låt din systemadministratör kontrollera den lokala konfigurationen. Feature active - + Funktion aktiv The feature "%1" is still active. Please stop it before closing %2. - + Funktionen "%1" är fortfarande aktiv. Vänligen stoppa den innan du stänger %2. Use custom computer arrangement. Press and hold to load arrangement from a file or save current arrangement to a file. - + Använd anpassade datorarrangemang. + +Håll nedtryckt för att ladda arrangemanget från en fil eller spara aktuellt arrangemang i en fil. Load computer positions - + Ladda datorpositioner Save computer positions - + Spara datorpositioner MasterConfigurationPage Basic settings - + Standardinställningar Directories - + Kataloger User configuration - + Konfiguration av användare Screenshots - + Skärmbilder User interface @@ -2994,307 +3047,307 @@ Press and hold to load arrangement from a file or save current arrangement to a Text color - + Textfärg ms - + ms Background color - + Bakgrundsfärg Thumbnail spacing - + Avstånd mellan miniatyrbilder px - + bildpunkter Auto - + Auto Computer thumbnail caption - + Bildtext för datorns miniatyrbild Computer and user name - + Dator och användarnamn Only user name - + Endast användarnamn Only computer name - + Endast datorns namn User and computer name - + Användar- och datornamn Thumbnail update interval - + Uppdateringsintervall för miniatyrbilder Sort order - + Sorteringsordning Thumbnail aspect ratio - + Bildförhållande för miniatyrbilder Highest - + Högst High - + Hög Medium - + Medium Low - + Låg Lowest - + Lägsta Image quality in monitoring mode - + Bildkvalitet i övervakningsläge Remote access image quality - + Bildkvalitet för fjärråtkomst Behaviour - + Beteende Program start - + Start av program Perform access control - + Utföra åtkomstkontroll Automatically select current location - + Välj automatiskt aktuell plats Automatically adjust computer icon size - + Justera automatiskt storleken på datorikonen Automatically open computer select panel - + Öppna automatiskt datorns urvalspanel Computer locations - + Datorplatser Show current location only - + Visa endast den aktuella platsen Allow adding hidden locations manually - + Tillåt att lägga till dolda platser manuellt Hide local computer - + Dölj lokal dator Hide local session - + Dölj lokal session Hide empty locations - + Dölj tomma platser Hide computer filter field - + Dölj datorns filterfält Modes and features - + Modi och funktioner Enforce selected mode for client computers - + Tillämpa valt läge för klientdatorer Actions such as rebooting or powering down computers - + Åtgärder som att starta om eller stänga av datorer Show confirmation dialog for potentially unsafe actions - + Visa bekräftelsedialog för potentiellt osäkra åtgärder Feature on computer double click: - + Funktion på datorn dubbelklicka: Open feature windows on the same screen as the main window - + Öppna funktionsfönster på samma skärm som huvudfönstret Features - + Funktioner All features - + Alla funktioner Disabled features - + Funktioner för funktionshindrade <no feature> - + <no feature> Always expand all locations - + Expandera alltid alla platser Configuration templates - + Konfigurationsmallar Advanced - + Avancerat Computer name source - + Datornamn källa Default - + Standard Host address - + Värdadress Session client address - + Sessionens klientadress Session client name - + Sessionens klientnamn Session host name - + Sessionens värdnamn Session metadata - + Metadata för sessionen Full name of user - + Fullständigt namn på användaren User login name - + Användarens inloggningsnamn Computer UID role - + Dator UID roll Session meta data hash - + Hash för sessionens metadata MonitoringMode Monitoring - + Monitorering This mode allows you to monitor all computers at one or more locations. - + I det här läget kan du övervaka alla datorer på en eller flera platser. Query application version of the server - + Fråga efter serverns applikationsversion Query active features - + Fråga efter aktiva funktioner Query properties of remotely available screens - + Fråga efter egenskaper för fjärrtillgängliga skärmar Builtin monitoring mode - + Inbyggt övervakningsläge NetworkObjectTreeModel Locations/Computers - + Platser/Datorer OpenWebsiteDialog Open website - + Öppna webbplats e.g. Veyon - + t.ex. Veyon Remember and add to website menu - + Kom ihåg och lägg till i webbplatsens meny e.g. www.veyon.io - + t.ex. www.veyon.io Please enter the URL of the website to open: - + Ange webbadressen till den webbplats som ska öppnas: Name: - + Namn: PasswordDialog Veyon Logon - + Veyon inloggning Please enter your username and password in order to access computers. - + Ange ditt användarnamn och lösenord för att få tillgång till datorerna. Username @@ -3310,49 +3363,49 @@ Press and hold to load arrangement from a file or save current arrangement to a Logon failed with given username and password. Please try again! - + Inloggning misslyckades med angivet användarnamn och lösenord. Vänligen försök igen! PluginCommands List names of all installed plugins - + Lista namn på alla installerade plugins Show table with details of all installed plugins - + Visa en tabell med information om alla installerade plugins Name - + Namn Description - + Beskrivning Version - + Version UID - + UID Plugin-related CLI operations - + Plugin-relaterade CLI-åtgärder Commands for managing plugins - + Kommandon för hantering av plugins PowerControlFeaturePlugin Power on a computer via Wake-on-LAN (WOL) - + Slå på en dator via Wake-on-LAN (WOL) Power on @@ -3360,7 +3413,7 @@ Press and hold to load arrangement from a file or save current arrangement to a Click this button to power on all computers. This way you do not have to power on each computer by hand. - + Klicka på den här knappen för att slå på alla datorer. På så sätt behöver du inte slå på varje dator för hand. Reboot @@ -3368,7 +3421,7 @@ Press and hold to load arrangement from a file or save current arrangement to a Click this button to reboot all computers. - + Klicka på den här knappen för att starta om alla datorer. Power down @@ -3376,81 +3429,83 @@ Press and hold to load arrangement from a file or save current arrangement to a Click this button to power down all computers. This way you do not have to power down each computer by hand. - + Klicka på den här knappen för att stänga av alla datorer. På så sätt behöver du inte stänga av varje dator för hand. Power down now - + Stäng av strömmen nu Install updates and power down - + Installera uppdateringar och stäng av strömmen Power down after user confirmation - + Avstängning efter användarens bekräftelse Power down after timeout - + Stängs av efter timeout MAC ADDRESS - + MAC-ADRESS This command broadcasts a Wake-on-LAN (WOL) packet to the network in order to power on the computer with the given MAC address. - + Detta kommando sänder ett WOL-paket (Wake-on-LAN) till nätverket för att slå på datorn med den angivna MAC-adressen. Please specify the command to display help for! - + Ange det kommando som du vill visa hjälp för! Confirm reboot - + Bekräfta omstart Do you really want to reboot <b>ALL</b> computers? - + Vill du verkligen starta om <b>ALLA</b> datorer? Do you really want to reboot the selected computers? - + Vill du verkligen starta om de utvalda datorerna? Confirm power down - + Bekräfta avstängning Do you really want to power down <b>ALL</b> computers? - + Vill du verkligen stänga av <b>ALLA</b> datorer? Do you really want to power down the selected computers? - + Vill du verkligen stänga av de utvalda datorerna? Invalid MAC address specified! - + Ogiltig MAC-adress angiven! The computer was remotely requested to power down. Do you want to power down the computer now? - + Datorn fick en fjärrstyrd begäran om avstängning. Vill du stänga av datorn nu? The computer will be powered down in %1 minutes, %2 seconds. Please save your work and close all programs. - + Datorn kommer att stängas av om %1 minuter, %2 second. + +Spara ditt arbete och stäng alla program. Power on/down or reboot a computer - + Slå på/av eller starta om en dator Commands for controlling power status of computers - + Kommandon för att kontrollera datorers strömstatus @@ -3461,26 +3516,26 @@ Please save your work and close all programs. Please specify a timeout for powering down the selected computers: - + Ange en tidsgräns för när de valda datorerna ska stängas av: minutes - + minuter seconds - + sekunder RemoteAccessFeaturePlugin Remote view - + Fjärrvisning Open a remote view for a computer without interaction. - + Öppna en fjärrvy för en dator utan interaktion. Remote control @@ -3488,38 +3543,38 @@ Please save your work and close all programs. Open a remote control window for a computer. - + Öppna ett fjärrkontrollfönster för en dator. Exchange clipboard contents - + Innehåll i Exchange-klippbord Show help about command - + Visa hjälp om kommandot Remote access - + Fjärråtkomst No computer has been selected so you can enter a hostname or IP address of a computer for manual access: - + Ingen dator har valts så du kan ange ett värdnamn eller en IP-adress för en dator för manuell åtkomst: Remote view or control a computer - + Fjärrvisning eller fjärrstyrning av en dator RemoteAccessWidget %1 - %2 Remote Access - + %1 - %2 Fjärråtkomst %1 - %2 - %3 Remote Access - + %1 - %2 - %3 Fjärråtkomst @@ -3534,15 +3589,15 @@ Please save your work and close all programs. Select screen - + Välj skärm Send shortcut - + Genväg för att skicka Screenshot - + Skärmbild Fullscreen @@ -3554,39 +3609,39 @@ Please save your work and close all programs. Exit - + Avsluta Ctrl+Alt+Del - + Ctrl+Alt+Del Ctrl+Esc - + Ctrl+Esc Alt+Tab - + Alt+Tab Alt+F4 - + Alt+F4 Win+Tab - + Win+Tab Win - + Vinst Menu - + Meny Alt+Ctrl+F1 - + Alt+Ctrl+F1 Connected. @@ -3594,42 +3649,42 @@ Please save your work and close all programs. Connecting... - + Ansluter... All screens - + Alla skärmar ScreenLockFeaturePlugin Lock - + Lås Unlock - + Lås upp To reclaim all user's full attention you can lock their computers using this button. In this mode all input devices are locked and the screens are blacked. - + För att återfå alla användares fulla uppmärksamhet kan du låsa deras datorer med den här knappen. I det här läget är alla inmatningsenheter låsta och skärmarna är mörklagda. Lock input devices - + Lås inmatningsenheter Unlock input devices - + Lås upp inmatningsenheter To reclaim all user's full attention you can lock their computers using this button. In this mode all input devices are locked while the desktop is still visible. - + För att återfå alla användares fulla uppmärksamhet kan du låsa deras datorer med den här knappen. I det här läget är alla inmatningsenheter låsta medan skrivbordet fortfarande är synligt. Lock screen and input devices of a computer - + Låsskärm och inmatningsenheter på en dator @@ -3640,45 +3695,45 @@ Please save your work and close all programs. Could not take a screenshot as directory %1 doesn't exist and couldn't be created. - + Det gick inte att ta en skärmdump eftersom katalogen %1 d inte finns och inte kunde skapas. Screenshot - + Skärmbild Could not open screenshot file %1 for writing. - + Det gick inte att öppna skärmdumpfilen %1 f eller skriva. ScreenshotFeaturePlugin Screenshot - + Skärmbild Use this function to take a screenshot of selected computers. - + Använd den här funktionen för att ta en skärmdump av valda datorer. Screenshots taken - + Skärmdumpar tagna Screenshot of %1 computer have been taken successfully. - + Skärmdump av %1 computer har tagits framgångsrikt. Take screenshots of computers and save them locally. - + Ta skärmdumpar av datorer och spara dem lokalt. ScreenshotManagementPanel All screenshots taken by you are listed here. You can take screenshots by clicking the "Screenshot" item in the context menu of a computer. The screenshots can be managed using the buttons below. - + Här listas alla skärmdumpar som du har tagit. Du kan ta skärmdumpar genom att klicka på objektet "Skärmdump" i snabbmenyn på en dator. Skärmdumparna kan hanteras med hjälp av knapparna nedan. User: @@ -3686,7 +3741,7 @@ Please save your work and close all programs. Computer: - + Dator: Date: @@ -3706,10 +3761,41 @@ Please save your work and close all programs. Screenshot - + Skärmbild Do you really want to delete all selected screenshots? + Vill du verkligen ta bort alla valda skärmdumpar? + + + + ServerAccessControlManager + + Requested authentication method not available + Begärd autentiseringsmetod är inte tillgänglig + + + Access allowed by rule "%1" + + + + Access denied by rule "%1" + + + + No rule allowed access + + + + Accessing user not member of an authorized user group + + + + User has denied access + + + + User confirmed access @@ -3721,11 +3807,11 @@ Please save your work and close all programs. Show notification when an unauthorized access is blocked - + Visa meddelande när en obehörig åtkomst blockeras Show notification on remote connection - + Visa meddelande om fjärranslutning Hide tray icon @@ -3753,44 +3839,45 @@ Please save your work and close all programs. Session mode - + Sessionsläge Local session mode (single server instance for primary local session) - + Läge för lokal session (en enda serverinstans för primär lokal session) Enabling this option will make the service launch a server process for every interactive session on a computer. Typically this is required to support terminal servers. - + Om du aktiverar det här alternativet kommer tjänsten att starta en serverprocess för varje interaktiv session på en dator. +Detta krävs vanligtvis för att stödja terminalservrar. Active session mode (single server instance for active local or remote session) - + Aktivt sessionsläge (en enda serverinstans för aktiv lokal session eller fjärrsession) Multi session mode (distinct server instance for each local and remote desktop session) - + Multisessionsläge (separat serverinstans för varje lokal skrivbordssession och fjärrskrivbordssession) Maximum session count - + Maximalt antal sessioner Network port numbers - + Portnummer för nätverk Veyon server - + Veyon server Internal VNC server - + Intern VNC-server Feature manager - + Funktionschef Demo server @@ -3798,7 +3885,7 @@ Typically this is required to support terminal servers. Miscellaneous settings - + Övriga inställningar Enable firewall exception @@ -3806,27 +3893,27 @@ Typically this is required to support terminal servers. Allow connections from localhost only - + Tillåt endast anslutningar från localhost Disable clipboard synchronization - + Inaktivera synkronisering av urklipp VNC server - + VNC-server Plugin: - + Tillägg: Restart %1 Service - + Starta om %1-tjänsten All settings were saved successfully. In order to take effect the %1 service needs to be restarted. Restart it now? - + Alla inställningar sparades framgångsrikt. För att de ska träda i kraft måste %1 service startas om. Starta om den nu? Running @@ -3834,63 +3921,69 @@ Typically this is required to support terminal servers. Session metadata - + Metadata för sessionen Content - + Innehåll None - + Ingen Value of an environment variable - + Värde för en miljövariabel Value of a registry key - + Värde för en registernyckel Environment variable name: - + Namn på miljövariabel: Registry key name: - + Namn på registernyckel: Optionally enter a regular expression with a capture to extract a part of the computer name and use it as the display name for the computer. Example: [^-]*-(PC[0-9]*) - + Ange eventuellt ett reguljärt uttryck med en capture för att extrahera en del av datornamnet och använda det som datorns visningsnamn. + +Exempel: [^-]*-(pc[0-9]*) [^-]*-(PC[0-9]*) Enable if a single Veyon Server instance should be launched for the currently active session, no matter if local or remote. - + Aktivera om en enda Veyon Server-instans ska startas för den aktuella aktiva sessionen, oavsett om den är lokal eller fjärrstyrd. ServiceControl - Starting service %1 + Service control + Servicekontroll + + + Starting %1 - Stopping service %1 + Stopping %1 - Registering service %1 + Restarting %1 - Unregistering service %1 + Registering %1 - Service control + Unregistering %1 @@ -3898,168 +3991,168 @@ Example: [^-]*-(PC[0-9]*) ServiceControlCommands Register Veyon Service - + Registrera Veyon Service Unregister Veyon Service - + Avregistrera Veyon Service Start Veyon Service - + Starta Veyon Service Stop Veyon Service - + Stoppa Veyon Service Restart Veyon Service - + Starta om Veyon Service Query status of Veyon Service - + Förfrågningsstatus för Veyon Service Service is running - + Tjänsten är igång Service is not running - + Tjänsten är inte igång Configure and control Veyon service - + Konfigurera och kontrollera Veyon-tjänster Commands for configuring and controlling Veyon Service - + Kommandon för att konfigurera och styra Veyon Service ShellCommands Run command file - + Kör kommandofilen File "%1" does not exist! - + Filen "%1" finns inte! Interactive shell and script execution for Veyon CLI - + Interaktiv shell- och skriptexekvering för Veyon CLI Commands for shell functionalities - + Kommandon för shell-funktioner SlideshowPanel Previous - + Föregående Start/pause - + Starta/pausa Next - + Nästa Duration: - + Varaktighet: SpotlightPanel Add computers by clicking with the middle mouse button or clicking the first button below. - + Lägg till datorer genom att klicka med mittenmusknappen eller klicka på första knappen nedan. Add selected computers - + Lägg till valda datorer Remove selected computers - + Ta bort valda datorer Update computers in realtime - + Uppdatera datorer i realtid Spotlight - + Strålkastare Please select at least one computer to add. - + Vänligen välj minst en dator att lägga till. Please select at least one computer to remove. - + Välj minst en dator att ta bort. StartAppDialog Start application - + Starta ansökan Name: - + Namn: e.g. "C:\Program Files\VideoLAN\VLC\vlc.exe" - + t.ex. "C:\Program Files\VideoLAN\VLC\vlc.exe" Remember and add to application menu - + Kom ihåg och lägg till i applikationsmenyn e.g. VLC - + t.ex. VLC Please enter the applications to start on the selected computers. You can separate multiple applications by line. - + Ange de program som ska startas på de valda datorerna. Du kan separera flera program med en rad. SystemTrayIcon System tray icon - + Ikon för systemfältet SystemUserGroupsPlugin User groups backend for system user groups - + Användargrupper backend för systemets användargrupper Default (system user groups) - + Standard (systemets användargrupper) TestingCommandLinePlugin Test internal Veyon components and functions - + Testa Veyons interna komponenter och funktioner Commands for testing internal components and functions of Veyon - + Kommandon för att testa interna komponenter och funktioner i Veyon @@ -4070,7 +4163,7 @@ Example: [^-]*-(PC[0-9]*) Use the field below to type your message which will be sent to all selected users. - + Använd fältet nedan för att skriva ditt meddelande som ska skickas till alla valda användare. @@ -4081,26 +4174,26 @@ Example: [^-]*-(PC[0-9]*) Use this function to send a text message to all users e.g. to assign them new tasks. - + Använd den här funktionen för att skicka ett textmeddelande till alla användare, t.ex. för att tilldela dem nya uppgifter. Message from teacher - + Meddelande från lärare Send a message to a user - + Skicka ett meddelande till en användare UltraVncConfigurationWidget Builtin UltraVNC server configuration - + Inbyggd konfiguration av UltraVNC-server Maximum CPU usage - + Maximal CPU-användning Low accuracy (turbo mode) @@ -4108,15 +4201,15 @@ Example: [^-]*-(PC[0-9]*) Poll full screen (leave this enabled per default) - + Poll fullskärm (låt detta vara aktiverat som standard) Enable Desktop Duplication Engine on Windows 8 and newer - + Aktivera Desktop Duplication Engine i Windows 8 och nyare Enable multi monitor support - + Aktivera stöd för flera skärmar Enable capturing of layered (semi-transparent) windows @@ -4127,11 +4220,11 @@ Example: [^-]*-(PC[0-9]*) UserLoginDialog User login - + Användarinloggning Please enter a username and password for automatic login on all computers. - + Ange användarnamn och lösenord för automatisk inloggning på alla datorer. Username @@ -4146,106 +4239,106 @@ Example: [^-]*-(PC[0-9]*) UserSessionControlPlugin Log in - + Logga in Click this button to log in a specific user on all computers. - + Klicka på den här knappen för att logga in en viss användare på alla datorer. Log off - + Logga ut Click this button to log off users from all computers. - + Klicka på den här knappen för att logga ut användare från alla datorer. Confirm user logoff - + Bekräfta utloggning av användare Do you really want to log off <b>ALL</b> users? - + Vill du verkligen logga ut <b>ALLA</b> användare? Do you really want to log off the selected users? - + Vill du verkligen logga ut de utvalda användarna? User session control - + Kontroll av användarsessioner VeyonCore [OK] - + Ok [FAIL] - + [FAIL] Invalid command! - + Ogiltigt kommando! Invalid arguments given - + Ogiltiga argument angivna Not enough arguments given - use "%1 help" for more information - + Inte tillräckligt med argument angivna - använd "%1 help" för mer information Plugin not licensed - + Plugin inte licensierat Unknown result! - + Okänt resultat! Available commands: - + Tillgängliga kommandon: Available modules: - + Tillgängliga moduler: No module specified or module not found - available modules are: - + Ingen modul angiven eller modul hittades inte - tillgängliga moduler är: INFO - + INFO WARNING - + VARNING ERROR - + FEL USAGE - + Användning DESCRIPTION - + BESKRIVNING EXAMPLES - + Exempel Screen %1 - + Skärm %1 @@ -4256,21 +4349,21 @@ Example: [^-]*-(PC[0-9]*) Could not save your personal settings! Please check the user configuration file path using the %1 Configurator. - + Det gick inte att spara dina personliga inställningar! Kontrollera sökvägen till användarkonfigurationsfilen med hjälp av %1 Configurator. VeyonServiceControl Veyon Service - + Veyon Service WebApiConfigurationPage Web API - + Web-API General @@ -4278,51 +4371,51 @@ Example: [^-]*-(PC[0-9]*) Network port - + Nätverksport Enable WebAPI server - + Aktivera WebAPI-server Connection settings - + Anslutningsinställningar Lifetime - + Livstid h - + h s - + s Idle timeout - + Tidsgräns för inaktivitet Authentication timeout - + Timeout för autentisering Maximum number of open connections - + Maximalt antal öppna anslutningar Connection encryption - + Kryptering av anslutning TLS certificate file - + TLS-certifikatfil TLS private key file - + TLS privat nyckelfil ... @@ -4330,44 +4423,44 @@ Example: [^-]*-(PC[0-9]*) Use HTTPS with TLS 1.3 instead of HTTP - + Använd HTTPS med TLS 1.3 i stället för HTTP WebApiPlugin Run WebAPI server - + Kör WebAPI-server Failed to start WebAPI server at port %1 - + Misslyckades med att starta WebAPI-servern på port %1 WebAPI server running at port %1 - + WebAPI-servern körs på port %1 Provide access to a computer via HTTP - + Tillhandahåll åtkomst till en dator via HTTP Commands for running the WebAPI server - + Kommandon för att köra WebAPI-servern WindowsPlatformConfiguration Could not change the setting for SAS generation by software. Sending Ctrl+Alt+Del via remote control will not work! - + Det gick inte att ändra inställningen för SAS-generering med programvaran. Att skicka Ctrl+Alt+Del via fjärrkontroll fungerar inte! WindowsPlatformConfigurationPage Windows - + Fönster General @@ -4375,116 +4468,116 @@ Example: [^-]*-(PC[0-9]*) Enable SAS generation by software (Ctrl+Alt+Del) - + Aktivera SAS-generering med programvara (Ctrl+Alt+Del) User authentication - + Autentisering av användare Use alternative user authentication mechanism - + Använd alternativ mekanism för användarautentisering User login - + Användarinloggning Input start delay - + Fördröjning av start av ingång Simulated key presses interval - + Intervall för simulerade tangenttryckningar Confirm legal notice (message displayed before user logs in) - + Bekräfta juridiskt meddelande (meddelande som visas innan användaren loggar in) Screen lock - + Skärmlås Hide taskbar - + Dölj aktivitetsfältet Hide start menu - + Dölj startmenyn Hide desktop - + Dölj skrivbordet Use input device interception driver - + Använd drivrutin för avlyssning av inmatningsenheter Use custom power scheme with disabled power button - + Använd ett anpassat strömschema med inaktiverad strömknapp WindowsPlatformPlugin Internal display - + Intern display Plugin implementing abstract functions for the Windows platform - + Plugin som implementerar abstrakta funktioner för Windows-plattformen WindowsServiceControl The service "%1" is already installed. - + Tjänsten "%1" är redan installerad. The service "%1" could not be installed (error %2). - + Tjänsten "%1" kunde inte installeras (fel %2). Could not change the failure actions config for service "%1" (error %2). - + Det gick inte att ändra konfigurationen för felåtgärder för tjänsten "%1" (fel %2). The service "%1" has been installed successfully. - + Tjänsten "%1" har installerats framgångsrikt. The service "%1" could not be uninstalled (error %2). - + Tjänsten "%1" kunde inte avinstalleras (fel %2). The service "%1" has been uninstalled successfully. - + Tjänsten "%1" har avinstallerats framgångsrikt. The start type of service "%1" could not be changed (error %2). - + Det gick inte att ändra starttypen för tjänsten "%1" (fel %2). Service "%1" could not be found. - + Tjänsten "%1" kunde inte hittas. X11VncConfigurationWidget Builtin x11vnc server configuration - + Inbyggd konfiguration av x11vnc-server Custom x11vnc parameters: - + Anpassade x11vnc-parametrar: Do not use X Damage extension - + Använd inte X Damage-tillägget \ No newline at end of file diff --git a/translations/veyon_th.ts b/translations/veyon_th.ts index d27237546..97d46b50a 100644 --- a/translations/veyon_th.ts +++ b/translations/veyon_th.ts @@ -131,6 +131,13 @@ If you're interested in translating Veyon into your local or another langua + + AccessControlProvider + + Provider for access control features + + + AccessControlRuleEditDialog @@ -1003,14 +1010,6 @@ Make sure that the names of the keys belonging to each other are identical on al Location: %1 - - Host/IP address: %1 - - - - invalid - - Active features: %1 @@ -1052,7 +1051,23 @@ Make sure that the names of the keys belonging to each other are identical on al ผู้ใช้ที่เข้าสู่ระบบ: %1 - [none] + Hostname: %1 + + + + unknown + ไม่รู้จัก + + + IP address: %1 + + + + Hostname could not be resolved + + + + No features active @@ -1979,6 +1994,18 @@ Make sure that the names of the keys belonging to each other are identical on al No user groups plugin was found. Please check your installation! + + Color scheme: + + + + Light + + + + Dark + + HeadlessVncServer @@ -3715,6 +3742,37 @@ Please save your work and close all programs. + + ServerAccessControlManager + + Requested authentication method not available + + + + Access allowed by rule "%1" + + + + Access denied by rule "%1" + + + + No rule allowed access + + + + Accessing user not member of an authorized user group + + + + User has denied access + + + + User confirmed access + + + ServiceConfigurationPage @@ -3876,24 +3934,28 @@ Example: [^-]*-(PC[0-9]*) ServiceControl - Starting service %1 - กำลังเริ่มเซอร์วิส %1 + Service control + การควบคุมเซอร์วิส + + + Starting %1 + - Stopping service %1 - กำลังหยุดเซอร์วิส %1 + Stopping %1 + - Registering service %1 - กำลังลงทะเบียนเซอร์วิส %1 + Restarting %1 + - Unregistering service %1 - กำลังถอนการลงทะเบียนเซอร์วิส %1 + Registering %1 + - Service control - การควบคุมเซอร์วิส + Unregistering %1 + diff --git a/translations/veyon_tr.ts b/translations/veyon_tr.ts index 9e2d0071c..cac25dfb0 100644 --- a/translations/veyon_tr.ts +++ b/translations/veyon_tr.ts @@ -15,7 +15,7 @@ Website: - Web Sitesi: + İnternet Sitesi: Support Veyon project with a donation @@ -133,6 +133,13 @@ Veyon'u kendi dilinizde veya başka bir dile çevirmek istiyorsanız veya v Bu yapılandırmayla, belirtilen kullanıcının bilgisayarlara erişmesine izin verilmemiştir. + + AccessControlProvider + + Provider for access control features + Erişim denetimi özellikleri sağlayıcısı + + AccessControlRuleEditDialog @@ -245,7 +252,7 @@ Veyon'u kendi dilinizde veya başka bir dile çevirmek istiyorsanız veya v Local computer is already being accessed - + Yerel bilgisayara zaten erişiliyor @@ -411,7 +418,9 @@ Genel anahtar, istemci bilgisayarlarda gelen bağlantı isteğinin kimliğini do Please enter the name of the user group or role for which to import the authentication key. Make sure that the names of the keys belonging to each other are identical on all computers. - + Lütfen kimlik doğrulama anahtarının içe aktarılacağı kullanıcı grubu veya rolünün adını girin. + +Birbirine ait anahtarların isimlerinin tüm bilgisayarlarda aynı olduğundan emin olun. @@ -581,7 +590,7 @@ Make sure that the names of the keys belonging to each other are identical on al Please specify the command to display help for. - + Lütfen yardımın görüntüleneceği komutu belirtin. NAME @@ -629,11 +638,11 @@ Make sure that the names of the keys belonging to each other are identical on al The specified command does not exist or no help is available for it. - + Belirtilen komut mevcut değil veya bu komut için yardım mevcut değil. Please specify the key name (e.g. "teacher/public") as the first argument. - + Lütfen ilk argüman olarak anahtar adını belirtin (örneğin "öğretmen/genel"). TYPE @@ -645,7 +654,7 @@ Make sure that the names of the keys belonging to each other are identical on al Command line support for managing authentication keys - + Kimlik doğrulama anahtarlarını yönetmek için komut satırı desteği Commands for managing authentication keys @@ -774,11 +783,11 @@ Make sure that the names of the keys belonging to each other are identical on al FORMAT-STRING-WITH-PLACEHOLDERS - + BİÇİMLENDİRME-DİZİSİ-YER-TUTUCULARLA REGULAR-EXPRESSION-WITH-PLACEHOLDER - + DÜZENLİ-İFADE-YER-TUTUCULU Imports objects from the specified text file using the given format string or regular expression containing one or multiple placeholders. Valid placeholders are: %1 @@ -862,7 +871,7 @@ Make sure that the names of the keys belonging to each other are identical on al The specified command does not exist or no help is available for it. - + Belirtilen komut mevcut değil veya bu komut için yardım mevcut değil. Invalid type specified. Valid values are "%1" or "%2". @@ -978,7 +987,7 @@ Make sure that the names of the keys belonging to each other are identical on al Location "%1" not found. - + "%1" konumu bulunamadı. @@ -999,27 +1008,19 @@ Make sure that the names of the keys belonging to each other are identical on al ComputerControlListModel Name: %1 - + İsim: %1 Location: %1 Konum: %1 - - Host/IP address: %1 - Ana makine/IP adresi: %1 - - - invalid - - Active features: %1 Etkin özellikler: %1 [no user] - + [kullanıcı yok] Online and connected @@ -1035,7 +1036,7 @@ Make sure that the names of the keys belonging to each other are identical on al Veyon Server unreachable or not running - + Veyon Sunucusuna erişilemiyor veya çalışmıyor Authentication failed or access denied @@ -1054,7 +1055,23 @@ Make sure that the names of the keys belonging to each other are identical on al Oturum açan kullanıcı: %1 - [none] + Hostname: %1 + Ana bilgisayar adı: %1 + + + unknown + bilinmeyen + + + IP address: %1 + IP adresi: %1 + + + Hostname could not be resolved + Ana bilgisayar adı çözülemedi + + + No features active @@ -1101,7 +1118,7 @@ Make sure that the names of the keys belonging to each other are identical on al Logged in since - + beri giriş yapıldı Missing network object directory plugin @@ -1117,11 +1134,11 @@ Make sure that the names of the keys belonging to each other are identical on al %1 days - + %1 gün 1 day - + 1 gün Location detection failed @@ -1136,7 +1153,7 @@ Make sure that the names of the keys belonging to each other are identical on al ComputerSelectPanel Search computers - + Bilgisayarları ara Add location @@ -1308,18 +1325,18 @@ Make sure that the names of the keys belonging to each other are identical on al Bandwidth limit - + Bant genişliği sınırı MB/s - + MB/s DemoFeaturePlugin Demo - + Gösteri Stop demo @@ -1327,11 +1344,11 @@ Make sure that the names of the keys belonging to each other are identical on al Share your screen or allow a user to share his screen with other users. - + Ekranınızı paylaşın veya bir kullanıcının ekranını diğer kullanıcılarla paylaşmasına izin verin. Full screen demo - + Tam ekran demosu Window demo @@ -1339,15 +1356,15 @@ Make sure that the names of the keys belonging to each other are identical on al Share your own screen in fullscreen mode - + Kendi ekranınızı tam ekran modunda paylaşın In this mode your screen is being displayed in full screen mode on all computers while the input devices of the users are locked. - + Bu modda ekranınız tüm bilgisayarlarda tam ekran modunda görüntülenirken kullanıcıların giriş cihazları kilitlidir. Share your own screen in a window - + Kendi ekranınızı bir pencerede paylaşın In this mode your screen being displayed in a window on all computers. The users are able to switch to other windows as needed. @@ -1355,31 +1372,31 @@ Make sure that the names of the keys belonging to each other are identical on al Share selected user's screen in fullscreen mode - + Seçili kullanıcının ekranını tam ekran modunda paylaşın In this mode the screen of the selected user is being displayed in full screen mode on all computers while the input devices of the users are locked. - + Bu modda, seçili kullanıcının ekranı tüm bilgisayarlarda tam ekran modunda görüntülenirken, kullanıcıların giriş cihazları kilitlidir. Share selected user's screen in a window - + Seçili kullanıcının ekranını bir pencerede paylaş In this mode the screen of the selected user being displayed in a window on all computers. The users are able to switch to other windows as needed. - + Bu modda seçili kullanıcının ekranı tüm bilgisayarlarda bir pencerede görüntülenir. Kullanıcılar ihtiyaç duyduklarında diğer pencerelere geçebilirler. Please select a user screen to share. - + Lütfen paylaşmak için bir kullanıcı ekranı seçin. Please select only one user screen to share. - + Lütfen paylaşmak için yalnızca bir kullanıcı ekranı seçin. All screens - + Tüm ekranlar Give a demonstration by screen broadcasting @@ -1413,11 +1430,11 @@ Make sure that the names of the keys belonging to each other are identical on al DesktopServicesConfigurationPage Applications & websites - + Uygulamalar ve internet siteleri Predefined applications - + Önceden tanımlanmış uygulamalar Name @@ -1429,23 +1446,23 @@ Make sure that the names of the keys belonging to each other are identical on al Add new application - + Yeni uygulama ekle Remove selected application - + Seçili uygulamayı kaldır Predefined websites - Önceden tanımlanmış web siteleri + Önceden tanımlanmış İnternet siteleri Add new website - + Yeni internet sitesi ekle Remove selected website - Seçilen web sitesini kaldır + Seçilen internet sitesini kaldır URL @@ -1453,50 +1470,50 @@ Make sure that the names of the keys belonging to each other are identical on al New application - + Yeni uygulama New website - Yeni web sitesi + Yeni internet sitesi DesktopServicesFeaturePlugin Start application - + Uygulamayı başlat Click this button to start an application on all computers. - + Bir uygulamayı tüm bilgisayarlarda başlatmak için bu butona tıklayın. Open website - Web sitesi aç + İnternet sitesi aç Click this button to open a website on all computers. - Tüm bilgisayarlarda bir web sitesi açmak için bu düğmeye tıklayın. + Tüm bilgisayarlarda bir internet sitesi açmak için bu düğmeye tıklayın. Start application "%1" - + "%1" uygulamasını başlat Custom application - + Özel uygulama Open website "%1" - Web sitesini "%1" açın + "%1" internet sitesini aç Custom website - Özel web sitesi + Özel internet sitesi Start apps and open websites in user sessions - + Kullanıcı oturumlarında uygulamaları başlatın ve internet sitelerini açın @@ -1519,7 +1536,7 @@ Make sure that the names of the keys belonging to each other are identical on al Custom website - Özel web sitesi + Özel internet sitesi Open file manager @@ -1535,7 +1552,7 @@ Make sure that the names of the keys belonging to each other are identical on al Custom application - + Özel uygulama Handout @@ -1572,31 +1589,31 @@ Make sure that the names of the keys belonging to each other are identical on al FeatureCommands List names of all available features - + Mevcut tüm özelliklerin adlarını listeleyin Show table with details of all available features - + Tüm mevcut özelliklerin ayrıntılarını içeren tabloyu göster Start a feature on a remote host - + Uzak bir ana bilgisayarda bir özelliği başlatın Stop a feature on a remote host - + Uzak bir ana bilgisayarda bir özelliği durdurun Please specify the command to display help for. - + Lütfen yardımın görüntüleneceği komutu belirtin. Displays a list with the names of all available features. - + Mevcut tüm özelliklerin adlarını içeren bir liste görüntüler. Displays a table with detailed information about all available features. This information include a description, the UID, the name of the plugin providing the respective feature and some other implementation-related details. - + Mevcut tüm özellikler hakkında ayrıntılı bilgi içeren bir tablo görüntüler. Bu bilgiler bir açıklama, UID, ilgili özelliği sağlayan eklentinin adı ve diğer bazı uygulamayla ilgili ayrıntıları içerir. HOST ADDRESS @@ -1604,43 +1621,43 @@ Make sure that the names of the keys belonging to each other are identical on al FEATURE - + ÖZELLİK ARGUMENTS - + ARGÜMANLAR Starts the specified feature on the specified host by connecting to the Veyon Server running remotely. The feature can be specified by name or UID. Use the ``show`` command to see all available features. Depending on the feature, additional arguments (such as the text message to display) encoded as a single JSON string have to be specified. Please refer to the developer documentation for more information - + Belirtilen özelliği belirtilen ana bilgisayarda uzaktan çalışan Veyon Sunucusuna bağlanarak başlatır. Özellik, ad veya UID ile belirtilebilir. Tüm kullanılabilir özellikleri görmek için ``show`` komutunu kullanın. Özelliğe bağlı olarak, tek bir JSON dizesi olarak kodlanmış ek argümanlar (görüntülenecek metin mesajı gibi) belirtilmelidir. Daha fazla bilgi için lütfen geliştirici belgelerine bakın Lock the screen - + Ekranı kilitle Display a text message - + Bir metin mesajı görüntüle Test message - + Test mesajı Start an application - + Bir uygulamayı başlat Stops the specified feature on the specified host by connecting to the Veyon Server running remotely. The feature can be specified by name or UID. Use the ``show`` command to see all available features. - + Uzaktan çalışan Veyon Sunucusuna bağlanarak belirtilen ana bilgisayarda belirtilen özelliği durdurur. Özellik ad veya UID ile belirtilebilir. Kullanılabilir tüm özellikleri görmek için ``show`` komutunu kullanın. Unlock the screen - + Ekranın kilidini aç The specified command does not exist or no help is available for it. - + Belirtilen komut mevcut değil veya bu komut için yardım mevcut değil. Name @@ -1660,7 +1677,7 @@ Make sure that the names of the keys belonging to each other are identical on al Worker - + Çalışan UID @@ -1668,35 +1685,35 @@ Make sure that the names of the keys belonging to each other are identical on al Plugin - + Eklenti Invalid feature name or UID specified - + Geçersiz özellik adı veya UID belirtildi Error parsing the JSON-encoded arguments: %1 - + JSON kodlu argümanları ayrıştırırken hata oluştu: %1 Failed to initialize credentials - + Kimlik bilgileri başlatılamadı Could not establish a connection to host %1 - + %1 ana makinesine bağlantı kurulamadı Failed to send feature control message to host %1 - + Özellik kontrol mesajı %1 ana bilgisayarına gönderilemedi Feature-related CLI operations - + Özellik ile ilgili CLI işlemleri Commands for controlling features - + Özellikleri kontrol etmek için komutlar @@ -1711,11 +1728,11 @@ Make sure that the names of the keys belonging to each other are identical on al Destination directory - + Hedef dizin Default source directory - + Varsayılan kaynak dizini Options @@ -1723,11 +1740,11 @@ Make sure that the names of the keys belonging to each other are identical on al Remember last source directory - + Son kaynak dizinini hatırla Create destination directory if it does not exist - + Hedef dizin yoksa oluşturun @@ -1823,11 +1840,11 @@ Make sure that the names of the keys belonging to each other are identical on al Style: - + Stil: Native - + Yerel Authentication @@ -1935,7 +1952,7 @@ Make sure that the names of the keys belonging to each other are identical on al Authentication keys are not set up properly on this computer. - + Bu bilgisayarda kimlik doğrulama anahtarları düzgün şekilde ayarlanmamış. %1 service @@ -1971,7 +1988,7 @@ Make sure that the names of the keys belonging to each other are identical on al Include user groups from domain - + Etki alanından kullanıcı gruplarını dahil et Missing user groups backend @@ -1979,6 +1996,18 @@ Make sure that the names of the keys belonging to each other are identical on al No user groups plugin was found. Please check your installation! + Hiçbir kullanıcı grubu eklentisi bulunamadı. Lütfen kurulumunuzu kontrol edin! + + + Color scheme: + + + + Light + + + + Dark @@ -1986,7 +2015,7 @@ Make sure that the names of the keys belonging to each other are identical on al HeadlessVncServer Headless VNC server - + Başlıksız VNC sunucusu @@ -2023,7 +2052,7 @@ Make sure that the names of the keys belonging to each other are identical on al Query timeout - + Sorgu zaman aşımı Bind DN @@ -2151,7 +2180,7 @@ Make sure that the names of the keys belonging to each other are identical on al Hostnames stored as fully qualified domain names (FQDN, e.g. myhost.example.org) - + Tam nitelikli alan adları (FQDN, örn. myhost.example.org) olarak depolanan ana bilgisayar adları e.g. room or computerLab @@ -2203,7 +2232,7 @@ Make sure that the names of the keys belonging to each other are identical on al e.g. cn or displayName - + ör. cn veya displayName Advanced settings @@ -2243,7 +2272,7 @@ Make sure that the names of the keys belonging to each other are identical on al e.g. (objectClass=room) or (objectClass=computerLab) - + e.g. (objectClass=room) VEYA (objectClass=computerLab) Filter for computer containers @@ -2251,15 +2280,15 @@ Make sure that the names of the keys belonging to each other are identical on al e.g. (objectClass=container) or (objectClass=organizationalUnit) - + ör. (objectClass=container) veya (objectClass=organizationalUnit) Query options - + Sorgu seçenekleri Query nested user groups (supported by AD only) - + İç içe geçmiş kullanıcı gruplarını sorgula (yalnızca AD tarafından desteklenir) Group member identification @@ -2271,7 +2300,7 @@ Make sure that the names of the keys belonging to each other are identical on al Configured attribute for user login name or computer hostname (OpenLDAP) - + Kullanıcı oturum açma adı veya bilgisayar ana bilgisayar adı için yapılandırılmış öznitelik (OpenLDAP) Computer locations identification @@ -2287,11 +2316,11 @@ Make sure that the names of the keys belonging to each other are identical on al Computer containers or OUs - + Bilgisayar konteynerleri veya OU'lar Location attribute in computer objects - + Bilgisayar nesnelerindeki konum niteliği Integration tests @@ -2345,7 +2374,9 @@ Make sure that the names of the keys belonging to each other are identical on al The LDAP base DN has been queried successfully. The following entries were found: %1 - + LDAP temel DN'si başarıyla sorgulandı. Aşağıdaki girdiler bulundu:: + +%1 LDAP naming context test failed @@ -2355,7 +2386,9 @@ Make sure that the names of the keys belonging to each other are identical on al Could not query the base DN via naming contexts. Please check the naming context attribute parameter. %1 - + Adlandırma bağlamları aracılığıyla temel DN sorgulanamadı. Lütfen adlandırma bağlamı öznitelik parametresini kontrol edin. + +%1 LDAP naming context test successful @@ -2433,7 +2466,7 @@ Make sure that the names of the keys belonging to each other are identical on al Please enter a computer hostname to query: - + Lütfen sorgulanacak bir bilgisayar adı girin: Invalid hostname @@ -2441,11 +2474,11 @@ Make sure that the names of the keys belonging to each other are identical on al You configured computer hostnames to be stored as fully qualified domain names (FQDN) but entered a hostname without domain. - + Bilgisayar ana bilgisayar adlarını tam nitelikli etki alanı adları (FQDN) olarak depolanacak şekilde yapılandırdınız ancak etki alanı olmayan bir ana bilgisayar adı girdiniz. You configured computer hostnames to be stored as simple hostnames without a domain name but entered a hostname with a domain name part. - + Bilgisayar ana bilgisayar adlarını, etki alanı adı olmadan basit ana bilgisayar adları olarak depolanacak şekilde yapılandırdınız ancak etki alanı adı kısmı olan bir ana bilgisayar adı girdiniz. Enter computer DN @@ -2465,7 +2498,7 @@ Make sure that the names of the keys belonging to each other are identical on al Please enter the name of a computer location (wildcards allowed): - + Lütfen bilgisayar konumunun adını girin (joker karakterlere izin verilir): computer locations @@ -2509,7 +2542,7 @@ Make sure that the names of the keys belonging to each other are identical on al Could not find a user with the name "%1". Please check the username or the user tree parameter. - + "%1" adlı bir kullanıcı bulunamadı. Lütfen kullanıcı adını veya kullanıcı ağacı parametresini kontrol edin. Enter hostname @@ -2517,7 +2550,7 @@ Make sure that the names of the keys belonging to each other are identical on al Please enter a computer hostname whose group memberships to query: - + Lütfen sorgulanacak grup üyeliklerinin bulunduğu bilgisayarın adını girin: groups of computer @@ -2529,7 +2562,7 @@ Make sure that the names of the keys belonging to each other are identical on al Could not find a computer with the hostname "%1". Please check the hostname or the computer tree parameter. - + "%1" ana bilgisayar adına sahip bir bilgisayar bulunamadı. Lütfen ana bilgisayar adını veya bilgisayar ağacı parametresini kontrol edin. Enter computer IP address @@ -2545,11 +2578,11 @@ Make sure that the names of the keys belonging to each other are identical on al Could not lookup hostname for IP address %1. Please check your DNS server settings. - + IP adresi %1 için ana bilgisayar adı bulunamadı. Lütfen DNS sunucu ayarlarınızı kontrol edin. Please enter the name of a location whose entries to query: - + Lütfen sorgulanacak girişlerin bulunduğu konumun adını girin: location entries @@ -2599,7 +2632,9 @@ Make sure that the names of the keys belonging to each other are identical on al Could not query any entries in configured %1. Please check the parameter "%2". %3 - + Yapılandırılan %1'deki hiçbir girdi sorgulanamadı. Lütfen "%2" parametresini kontrol edin. + +%3 LDAP %1 test successful @@ -2617,7 +2652,9 @@ Make sure that the names of the keys belonging to each other are identical on al Could not query any %1. Please check the parameter(s) %2 and enter the name of an existing object. %3 - + %1 sorgulanamadı. Lütfen %2 parametresini kontrol edin ve var olan bir nesnenin adını girin. + +%3 and @@ -2672,23 +2709,23 @@ Make sure that the names of the keys belonging to each other are identical on al Please specify a valid LDAP url following the schema "ldap[s]://[user[:password]@]hostname[:port]" - + Lütfen şemayı takip eden geçerli bir LDAP URL'si belirtin"ldap[s]://[user[:password]@]hostname[:port]" No naming context attribute name given - falling back to configured value. - + Adlandırma bağlamı özniteliği adı verilmedi - yapılandırılmış değere geri dönülüyor. Could not query base DN. Please check your LDAP configuration. - + Temel DN sorgulanamadı. Lütfen LDAP yapılandırmanızı kontrol edin. Configuring %1 as base DN and disabling naming context queries. - + %1'i temel DN olarak yapılandırıyor ve adlandırma bağlamı sorgularını devre dışı bırakıyor. Basic LDAP/AD support for Veyon - + Veyon için temel LDAP/AD desteği Commands for configuring and testing LDAP/AD integration @@ -2696,11 +2733,11 @@ Make sure that the names of the keys belonging to each other are identical on al %1 (load computers and locations from LDAP/AD) - + %1 (LDAP/AD'den bilgisayarlar ve konumlar yükleme) %1 (load users and groups from LDAP/AD) - + %1 (LDAP/AD'den kullanıcıları ve grupları yükleme) @@ -2719,11 +2756,11 @@ Make sure that the names of the keys belonging to each other are identical on al User sessions - + Kullanıcı oturumları Minimum session lifetime before server start - + Sunucu başlamadan önceki minimum oturum ömrü User login @@ -2731,7 +2768,7 @@ Make sure that the names of the keys belonging to each other are identical on al Login key sequence - + Oturum açma anahtarı dizisi @@ -2760,7 +2797,7 @@ Make sure that the names of the keys belonging to each other are identical on al Disable tooltips - + Araç ipuçlarını devre dışı bırak Show icons only @@ -2855,7 +2892,7 @@ Make sure that the names of the keys belonging to each other are identical on al Adjust size of computer icons automatically - + Bilgisayar simgelerinin boyutunu otomatik olarak ayarla Auto @@ -2887,15 +2924,15 @@ Make sure that the names of the keys belonging to each other are identical on al Slideshow - + Slayt gösterisi Spotlight - + Spot ışığı Only show computers with logged on users - + Yalnızca oturum açmış kullanıcıların olduğu bilgisayarları göster toolBar @@ -2973,15 +3010,17 @@ Make sure that the names of the keys belonging to each other are identical on al Use custom computer arrangement. Press and hold to load arrangement from a file or save current arrangement to a file. - + Özel bilgisayar düzenlemesini kullanın. + +Düzenlemeyi bir dosyadan yüklemek veya mevcut düzenlemeyi bir dosyaya kaydetmek için basılı tutun. Load computer positions - + Bilgisayar pozisyonlarını yükle Save computer positions - + Bilgisayar pozisyonlarını kaydet @@ -3020,11 +3059,11 @@ Press and hold to load arrangement from a file or save current arrangement to a Thumbnail spacing - + Küçük resim aralığı px - + px Auto @@ -3060,35 +3099,35 @@ Press and hold to load arrangement from a file or save current arrangement to a Thumbnail aspect ratio - + Küçük resim en boy oranı Highest - + En yüksek High - + Yüksek Medium - + Orta Low - + Düşük Lowest - + En düşük Image quality in monitoring mode - + İzleme modunda görüntü kalitesi Remote access image quality - + Uzaktan erişim görüntü kalitesi Behaviour @@ -3108,7 +3147,7 @@ Press and hold to load arrangement from a file or save current arrangement to a Automatically adjust computer icon size - + Bilgisayar simgesi boyutunu otomatik olarak ayarla Automatically open computer select panel @@ -3132,7 +3171,7 @@ Press and hold to load arrangement from a file or save current arrangement to a Hide local session - + Yerel oturumu gizle Hide empty locations @@ -3164,7 +3203,7 @@ Press and hold to load arrangement from a file or save current arrangement to a Open feature windows on the same screen as the main window - + Özellik pencerelerini ana pencereyle aynı ekranda açın Features @@ -3184,23 +3223,23 @@ Press and hold to load arrangement from a file or save current arrangement to a Always expand all locations - + Her zaman tüm konumları genişlet Configuration templates - + Yapılandırma şablonları Advanced - + Gelişmiş Computer name source - + Bilgisayar adı kaynağı Default - + Varsayılan Host address @@ -3208,35 +3247,35 @@ Press and hold to load arrangement from a file or save current arrangement to a Session client address - + Oturum istemci adresi Session client name - + Oturum istemci adı Session host name - + Oturum ana bilgisayar adı Session metadata - + Oturum meta verileri Full name of user - + Kullanıcının tam adı User login name - + Kullanıcı oturum açma adı Computer UID role - + Bilgisayar UID rolü Session meta data hash - + Oturum meta verileri karma değeri @@ -3251,15 +3290,15 @@ Press and hold to load arrangement from a file or save current arrangement to a Query application version of the server - + Sunucunun uygulama sürümünü sorgula Query active features - + Etkin özellikleri sorgula Query properties of remotely available screens - + Uzaktan erişilebilen ekranların sorgu özellikleri Builtin monitoring mode @@ -3277,7 +3316,7 @@ Press and hold to load arrangement from a file or save current arrangement to a OpenWebsiteDialog Open website - Web sitesi aç + İnternet sitesi aç e.g. Veyon @@ -3285,7 +3324,7 @@ Press and hold to load arrangement from a file or save current arrangement to a Remember and add to website menu - Unutmayın ve web sitesi menüsüne ekleyin + Hatırla ve internet sitesi menüsüne ekle e.g. www.veyon.io @@ -3293,7 +3332,7 @@ Press and hold to load arrangement from a file or save current arrangement to a Please enter the URL of the website to open: - Lütfen açılacak web sitesinin URL'sini girin: + Lütfen açılacak internet sitesinin URL'sini girin: Name: @@ -3426,7 +3465,7 @@ Press and hold to load arrangement from a file or save current arrangement to a Do you really want to reboot <b>ALL</b> computers? - + Gerçekten <b>TÜM</b> bilgisayarları yeniden başlatmak istiyor musunuz? Do you really want to reboot the selected computers? @@ -3438,11 +3477,11 @@ Press and hold to load arrangement from a file or save current arrangement to a Do you really want to power down <b>ALL</b> computers? - + Gerçekten <b>TÜM</b> bilgisayarları kapatmak istiyor musunuz? Do you really want to power down the selected computers? - + Seçili bilgisayarların gerçekten kapanmasını istiyor musunuz? Invalid MAC address specified! @@ -3508,7 +3547,7 @@ Lütfen çalışmalarınızı kaydedip tüm açık pencereleri kapatın. Exchange clipboard contents - + Panodaki içerikleri değiştir Show help about command @@ -3520,7 +3559,7 @@ Lütfen çalışmalarınızı kaydedip tüm açık pencereleri kapatın. No computer has been selected so you can enter a hostname or IP address of a computer for manual access: - + Hiçbir bilgisayar seçilmediğinden manuel erişim için bir bilgisayarın ana bilgisayar adını veya IP adresini girebilirsiniz: Remote view or control a computer @@ -3535,7 +3574,7 @@ Lütfen çalışmalarınızı kaydedip tüm açık pencereleri kapatın. %1 - %2 - %3 Remote Access - + %1 - %2 - %3 Uzaktan Erişim @@ -3550,7 +3589,7 @@ Lütfen çalışmalarınızı kaydedip tüm açık pencereleri kapatın. Select screen - + Ekran seç Send shortcut @@ -3610,11 +3649,11 @@ Lütfen çalışmalarınızı kaydedip tüm açık pencereleri kapatın. Connecting... - + Bağlanıyor... All screens - + Tüm ekranlar @@ -3633,15 +3672,15 @@ Lütfen çalışmalarınızı kaydedip tüm açık pencereleri kapatın. Lock input devices - + Giriş aygıtlarını kilitle Unlock input devices - + Giriş aygıtlarının kilidini aç To reclaim all user's full attention you can lock their computers using this button. In this mode all input devices are locked while the desktop is still visible. - + Tüm kullanıcıların tüm dikkatini geri kazanmak için bu düğmeyi kullanarak bilgisayarlarını kilitleyebilirsiniz. Bu modda masaüstü hala görünürken tüm giriş aygıtları kilitlenir. Lock screen and input devices of a computer @@ -3726,8 +3765,39 @@ Lütfen çalışmalarınızı kaydedip tüm açık pencereleri kapatın. Do you really want to delete all selected screenshots? + Seçili tüm ekran görüntülerini gerçekten silmek istiyor musunuz? + + + + ServerAccessControlManager + + Requested authentication method not available + İstenen kimlik doğrulama yöntemi mevcut değil + + + Access allowed by rule "%1" + "%1" kuralı tarafından erişime izin verildi + + + Access denied by rule "%1" + Erişim "%1" kuralı tarafından engellendi + + + No rule allowed access + Hiçbir kurala erişime izin verilmiyor + + + Accessing user not member of an authorized user group + Yetkili bir kullanıcı grubunun üyesi olmayan kullanıcıya erişim + + + User has denied access + + User confirmed access + Kullanıcı erişimi onayladı + ServiceConfigurationPage @@ -3769,11 +3839,11 @@ Lütfen çalışmalarınızı kaydedip tüm açık pencereleri kapatın. Session mode - + Oturum modu Local session mode (single server instance for primary local session) - + Yerel oturum modu (birincil yerel oturum için tek sunucu örneği) Enabling this option will make the service launch a server process for every interactive session on a computer. @@ -3783,31 +3853,31 @@ Bu genellikle terminal sunucularını desteklemek için gereklidir. Active session mode (single server instance for active local or remote session) - + Etkin oturum modu (etkin yerel veya uzak oturum için tek sunucu örneği) Multi session mode (distinct server instance for each local and remote desktop session) - + Çoklu oturum modu (her yerel ve uzak masaüstü oturumu için ayrı sunucu örneği) Maximum session count - + Maksimum oturum sayısı Network port numbers - + Ağ bağlantı noktası numaraları Veyon server - + Veyon sunucusu Internal VNC server - + Dahili VNC sunucusu Feature manager - + Özellik yöneticisi Demo server @@ -3815,7 +3885,7 @@ Bu genellikle terminal sunucularını desteklemek için gereklidir. Miscellaneous settings - + Çeşitli ayarlar Enable firewall exception @@ -3827,7 +3897,7 @@ Bu genellikle terminal sunucularını desteklemek için gereklidir. Disable clipboard synchronization - + Pano senkronizasyonunu devre dışı bırak VNC server @@ -3851,11 +3921,11 @@ Bu genellikle terminal sunucularını desteklemek için gereklidir. Session metadata - + Oturum meta verileri Content - + İçerik None @@ -3863,52 +3933,58 @@ Bu genellikle terminal sunucularını desteklemek için gereklidir. Value of an environment variable - + Bir ortam değişkeninin değeri Value of a registry key - + Bir kayıt defteri anahtarının değeri Environment variable name: - + Ortam değişkeni adı: Registry key name: - + Kayıt anahtarı adı: Optionally enter a regular expression with a capture to extract a part of the computer name and use it as the display name for the computer. Example: [^-]*-(PC[0-9]*) - + İsteğe bağlı olarak, bilgisayar adının bir kısmını çıkarmak ve bunu bilgisayar için görüntü adı olarak kullanmak üzere bir yakalama içeren düzenli bir ifade girin. + +Örnek: [^-]*-(PC[0-9]*) Enable if a single Veyon Server instance should be launched for the currently active session, no matter if local or remote. - + Yerel veya uzak olması fark etmeksizin, geçerli etkin oturum için tek bir Veyon Sunucu örneğinin başlatılması gerekiyorsa etkinleştirin. ServiceControl - Starting service %1 - Hizmet başlatılıyor %1 + Service control + Hizmet kontrolü - Stopping service %1 - Hizmet durduruluyor %1 + Starting %1 + - Registering service %1 - Hizmet kaydediliyor %1 + Stopping %1 + - Unregistering service %1 - Hizmet kaydedilimiyor %1 + Restarting %1 + - Service control - Hizmet kontrolü + Registering %1 + + + + Unregistering %1 + @@ -3966,7 +4042,7 @@ Example: [^-]*-(PC[0-9]*) Interactive shell and script execution for Veyon CLI - + Veyon CLI için etkileşimli kabuk ve betik yürütme Commands for shell functionalities @@ -3977,57 +4053,57 @@ Example: [^-]*-(PC[0-9]*) SlideshowPanel Previous - + Önceki Start/pause - + Başlat/duraklat Next - + Sonraki Duration: - + Süre: SpotlightPanel Add computers by clicking with the middle mouse button or clicking the first button below. - + Orta fare tuşuna tıklayarak veya alttaki ilk butona tıklayarak bilgisayarları ekleyin. Add selected computers - + Seçili bilgisayarları ekle Remove selected computers - + Seçili bilgisayarları kaldır Update computers in realtime - + Bilgisayarları gerçek zamanlı olarak güncelle Spotlight - + Spot ışığı Please select at least one computer to add. - + Lütfen eklemek için en az bir bilgisayar seçin. Please select at least one computer to remove. - + Lütfen kaldırmak için en az bir bilgisayar seçin. StartAppDialog Start application - + Uygulamayı başlat Name: @@ -4039,7 +4115,7 @@ Example: [^-]*-(PC[0-9]*) Remember and add to application menu - + Hatırla ve uygulama menüsüne ekle e.g. VLC @@ -4047,7 +4123,7 @@ Example: [^-]*-(PC[0-9]*) Please enter the applications to start on the selected computers. You can separate multiple applications by line. - + Lütfen seçili bilgisayarlarda başlatılacak uygulamaları girin. Birden fazla uygulamayı satırla ayırabilirsiniz. @@ -4117,7 +4193,7 @@ Example: [^-]*-(PC[0-9]*) Maximum CPU usage - + Maksimum işlemci kullanımı Low accuracy (turbo mode) @@ -4183,7 +4259,7 @@ Example: [^-]*-(PC[0-9]*) Do you really want to log off <b>ALL</b> users? - + Gerçekten <b>TÜM</b> kullanıcıların oturumunu kapatmak istiyor musunuz? Do you really want to log off the selected users? @@ -4262,7 +4338,7 @@ Example: [^-]*-(PC[0-9]*) Screen %1 - + Ekran %1 @@ -4287,7 +4363,7 @@ Example: [^-]*-(PC[0-9]*) WebApiConfigurationPage Web API - + Ağ API General @@ -4295,23 +4371,23 @@ Example: [^-]*-(PC[0-9]*) Network port - + Ağ bağlantı noktası Enable WebAPI server - + WebAPI sunucusunu etkinleştir Connection settings - + Bağlantı ayarları Lifetime - + Ömür boyu h - + s s @@ -4319,27 +4395,27 @@ Example: [^-]*-(PC[0-9]*) Idle timeout - + Boşta kalma zaman aşımı Authentication timeout - + Kimlik doğrulama zaman aşımı Maximum number of open connections - + Maksimum açık bağlantı sayısı Connection encryption - + Bağlantı şifrelemesi TLS certificate file - + TLS sertifika dosyası TLS private key file - + TLS özel anahtar dosyası ... @@ -4347,30 +4423,30 @@ Example: [^-]*-(PC[0-9]*) Use HTTPS with TLS 1.3 instead of HTTP - + HTTP yerine TLS 1.3 ile HTTPS kullanın WebApiPlugin Run WebAPI server - + WebAPI sunucusunu çalıştır Failed to start WebAPI server at port %1 - + %1 bağlantı noktasında WebAPI sunucusu başlatılamadı WebAPI server running at port %1 - + WebAPI sunucusu %1 bağlantı noktasında çalışıyor Provide access to a computer via HTTP - + HTTP aracılığıyla bir bilgisayara erişim sağlayın Commands for running the WebAPI server - + WebAPI sunucusunu çalıştırma komutları @@ -4440,14 +4516,14 @@ Example: [^-]*-(PC[0-9]*) Use custom power scheme with disabled power button - + Güç düğmesi devre dışıyken özel güç şemasını kullan WindowsPlatformPlugin Internal display - + Dahili ekran Plugin implementing abstract functions for the Windows platform @@ -4462,11 +4538,11 @@ Example: [^-]*-(PC[0-9]*) The service "%1" could not be installed (error %2). - + "%1" hizmeti yüklenemedi (hata %2). Could not change the failure actions config for service "%1" (error %2). - + "%1" hizmeti için hata eylemleri yapılandırması değiştirilemedi (hata %2). The service "%1" has been installed successfully. @@ -4474,7 +4550,7 @@ Example: [^-]*-(PC[0-9]*) The service "%1" could not be uninstalled (error %2). - + "%1" hizmeti kaldırılamadı (hata %2). The service "%1" has been uninstalled successfully. @@ -4482,7 +4558,7 @@ Example: [^-]*-(PC[0-9]*) The start type of service "%1" could not be changed (error %2). - + "%1" hizmetinin başlangıç ​​türü değiştirilemedi (hata %2). Service "%1" could not be found. diff --git a/translations/veyon_uk.ts b/translations/veyon_uk.ts index 5e7bcba40..d905cd8eb 100644 --- a/translations/veyon_uk.ts +++ b/translations/veyon_uk.ts @@ -133,6 +133,13 @@ If you're interested in translating Veyon into your local or another langua Вказаному користувачеві заборонено доступ до комп’ютерів з цими налаштуваннями. + + AccessControlProvider + + Provider for access control features + Надавач можливостей керування доступом + + AccessControlRuleEditDialog @@ -1004,14 +1011,6 @@ Make sure that the names of the keys belonging to each other are identical on al Location: %1 Місце: %1 - - Host/IP address: %1 - Вузол/IP-адреса: %1 - - - invalid - некоректний - Active features: %1 Задіяні можливості: %1 @@ -1053,8 +1052,24 @@ Make sure that the names of the keys belonging to each other are identical on al Користувач у системі: %1 - [none] - [немає] + Hostname: %1 + Назва вузла: %1 + + + unknown + невідомий + + + IP address: %1 + IP-адреса: %1 + + + Hostname could not be resolved + Не вдалося визначити адресу за назвою вузла + + + No features active + Немає активних можливостей @@ -1980,6 +1995,18 @@ Make sure that the names of the keys belonging to each other are identical on al No user groups plugin was found. Please check your installation! Не знайдено додатка груп користувачів. Будь ласка, перевірте, чи належним чином встановлено програму! + + Color scheme: + Схема кольорів: + + + Light + Світла + + + Dark + Темна + HeadlessVncServer @@ -3740,6 +3767,37 @@ Please save your work and close all programs. Справді хочете вилучити усі позначені знімки вікон? + + ServerAccessControlManager + + Requested authentication method not available + Запитаний спосіб розпізнавання недоступний + + + Access allowed by rule "%1" + Доступ дозволено за правилом «%1» + + + Access denied by rule "%1" + Доступ заборонено за правилом «%1» + + + No rule allowed access + Жодне правило не надає доступу + + + Accessing user not member of an authorized user group + Доступ для користувача, який не є учасником уповноваженої групи користувачів + + + User has denied access + Доступ користувачеві заборонено + + + User confirmed access + Доступ підтверджено користувачем + + ServiceConfigurationPage @@ -3904,24 +3962,28 @@ Example: [^-]*-(PC[0-9]*) ServiceControl - Starting service %1 - Запускаємо службу %1 + Service control + Керування службами - Stopping service %1 - Зупиняємо службу %1 + Starting %1 + Запускаємо %1 - Registering service %1 - Реєструємо службу %1 + Stopping %1 + Зупиняємо %1 - Unregistering service %1 - Скасовуємо реєстрацію служби %1 + Restarting %1 + Перезапускаємо %1 - Service control - Керування службами + Registering %1 + Реєструємо %1 + + + Unregistering %1 + Скасовуємо реєстрацію %1 diff --git a/translations/veyon_vi.ts b/translations/veyon_vi.ts index 744fd0a87..0a3b27747 100644 --- a/translations/veyon_vi.ts +++ b/translations/veyon_vi.ts @@ -133,6 +133,13 @@ Nếu bạn quan tâm đến việc dịch Veyon thành ngôn ngữ bản địa Người dùng đã chỉ định không được phép truy cập máy tính với cấu hình này. + + AccessControlProvider + + Provider for access control features + + + AccessControlRuleEditDialog @@ -1005,14 +1012,6 @@ Make sure that the names of the keys belonging to each other are identical on al Location: %1 - - Host/IP address: %1 - - - - invalid - - Active features: %1 @@ -1054,7 +1053,23 @@ Make sure that the names of the keys belonging to each other are identical on al - [none] + Hostname: %1 + + + + unknown + + + + IP address: %1 + + + + Hostname could not be resolved + + + + No features active @@ -1981,6 +1996,18 @@ Make sure that the names of the keys belonging to each other are identical on al No user groups plugin was found. Please check your installation! + + Color scheme: + + + + Light + + + + Dark + + HeadlessVncServer @@ -3716,6 +3743,37 @@ Please save your work and close all programs. + + ServerAccessControlManager + + Requested authentication method not available + + + + Access allowed by rule "%1" + + + + Access denied by rule "%1" + + + + No rule allowed access + + + + Accessing user not member of an authorized user group + + + + User has denied access + + + + User confirmed access + + + ServiceConfigurationPage @@ -3877,23 +3935,27 @@ Example: [^-]*-(PC[0-9]*) ServiceControl - Starting service %1 + Service control - Stopping service %1 + Starting %1 - Registering service %1 + Stopping %1 - Unregistering service %1 + Restarting %1 - Service control + Registering %1 + + + + Unregistering %1 diff --git a/translations/veyon_zh_CN.ts b/translations/veyon_zh_CN.ts index 639f64250..92808fe56 100644 --- a/translations/veyon_zh_CN.ts +++ b/translations/veyon_zh_CN.ts @@ -133,6 +133,13 @@ If you're interested in translating Veyon into your local or another langua 指定的用户不允许使用此配置访问计算机。 + + AccessControlProvider + + Provider for access control features + + + AccessControlRuleEditDialog @@ -1006,14 +1013,6 @@ Make sure that the names of the keys belonging to each other are identical on al Location: %1 地点:%1 - - Host/IP address: %1 - 主机/IP 地址: %1 - - - invalid - 无效 - Active features: %1 激活的功能: %1 @@ -1055,8 +1054,24 @@ Make sure that the names of the keys belonging to each other are identical on al 登录用户: %1 - [none] - [无] + Hostname: %1 + + + + unknown + 未知 + + + IP address: %1 + + + + Hostname could not be resolved + + + + No features active + @@ -1982,6 +1997,18 @@ Make sure that the names of the keys belonging to each other are identical on al No user groups plugin was found. Please check your installation! + + Color scheme: + + + + Light + + + + Dark + + HeadlessVncServer @@ -3738,6 +3765,37 @@ Please save your work and close all programs. 您确定要删除所有选中的屏幕截图吗? + + ServerAccessControlManager + + Requested authentication method not available + + + + Access allowed by rule "%1" + + + + Access denied by rule "%1" + + + + No rule allowed access + + + + Accessing user not member of an authorized user group + + + + User has denied access + + + + User confirmed access + + + ServiceConfigurationPage @@ -3900,24 +3958,28 @@ Example: [^-]*-(PC[0-9]*) ServiceControl - Starting service %1 - 启动服务 %1 + Service control + 服务控制 + + + Starting %1 + - Stopping service %1 - 停止服务 %1 + Stopping %1 + - Registering service %1 - 注册服务 %1 + Restarting %1 + - Unregistering service %1 - 反注册服务 %1 + Registering %1 + - Service control - 服务控制 + Unregistering %1 + diff --git a/translations/veyon_zh_TW.ts b/translations/veyon_zh_TW.ts index 8627e9161..398e42dbb 100644 --- a/translations/veyon_zh_TW.ts +++ b/translations/veyon_zh_TW.ts @@ -133,6 +133,13 @@ If you're interested in translating Veyon into your local or another langua 不允許指定的使用者以這個組態存取電腦。 + + AccessControlProvider + + Provider for access control features + + + AccessControlRuleEditDialog @@ -1007,14 +1014,6 @@ Make sure that the names of the keys belonging to each other are identical on al Location: %1 位置: %1 - - Host/IP address: %1 - 主機/IP 位址: %1 - - - invalid - 無效 - Active features: %1 可用功能: %1 @@ -1056,8 +1055,24 @@ Make sure that the names of the keys belonging to each other are identical on al 登入的使用者: %1 - [none] - [無] + Hostname: %1 + + + + unknown + 未知 + + + IP address: %1 + + + + Hostname could not be resolved + + + + No features active + @@ -1983,6 +1998,18 @@ Make sure that the names of the keys belonging to each other are identical on al No user groups plugin was found. Please check your installation! 找不到使用者群組外掛程式。 請檢查您的安裝! + + Color scheme: + + + + Light + + + + Dark + + HeadlessVncServer @@ -3739,6 +3766,37 @@ Please save your work and close all programs. 您真的要刪除所有的螢幕快照嗎? + + ServerAccessControlManager + + Requested authentication method not available + + + + Access allowed by rule "%1" + + + + Access denied by rule "%1" + + + + No rule allowed access + + + + Accessing user not member of an authorized user group + + + + User has denied access + + + + User confirmed access + + + ServiceConfigurationPage @@ -3903,24 +3961,28 @@ Example: [^-]*-(PC[0-9]*) ServiceControl - Starting service %1 - 正在啟動服務 %1 + Service control + 服務控制 + + + Starting %1 + - Stopping service %1 - 正在停止服務 %1 + Stopping %1 + - Registering service %1 - 註冊服務 %1 + Restarting %1 + - Unregistering service %1 - 取消註冊服務 %1 + Registering %1 + - Service control - 服務控制 + Unregistering %1 + diff --git a/worker/src/FeatureWorkerManagerConnection.cpp b/worker/src/FeatureWorkerManagerConnection.cpp index 7b6a3b93b..26cfa404c 100644 --- a/worker/src/FeatureWorkerManagerConnection.cpp +++ b/worker/src/FeatureWorkerManagerConnection.cpp @@ -62,7 +62,7 @@ bool FeatureWorkerManagerConnection::sendMessage( const FeatureMessage& message { vDebug() << message; - return message.send( &m_socket ); + return message.sendPlain(&m_socket); } @@ -86,7 +86,7 @@ void FeatureWorkerManagerConnection::sendInitMessage() m_connectTimer.stop(); - FeatureMessage( m_featureUid, FeatureMessage::InitCommand ).send( &m_socket ); + FeatureMessage(m_featureUid, FeatureMessage::InitCommand).sendPlain(&m_socket); }