Implement multiple connection configs

This commit is contained in:
Martchus 2016-09-03 20:14:52 +02:00
parent cb251fd123
commit 1b51a582cb
25 changed files with 994 additions and 378 deletions

View File

@ -90,29 +90,36 @@ set(DOC_FILES
)
set(REQUIRED_ICONS
network-card
window-close
dialog-cancel
dialog-ok
dialog-ok-apply
edit-copy
edit-paste
preferences-other
view-barcode
folder-open
media-playback-start
text-plain
help-about
media-playback-pause
view-refresh
folder
network-server
folder-open
folder-sync
help-about
internet-web-browser
list-add
list-remove
media-playback-pause
media-playback-start
network-card
network-connect
system-run
system-search
network-server
preferences-desktop
preferences-desktop-notification
preferences-desktop-icons
preferences-desktop-locale
preferences-desktop-notification
preferences-other
qtcreator
system-run
system-search
system-file-manager
text-plain
view-barcode
view-refresh
window-close
)
# find c++utilities

View File

@ -25,10 +25,11 @@ Qt 5-based tray application for [Syncthing](https://github.com/syncthing/syncthi
* Provides quick access to the official web UI
* Utilizes either Qt WebKit or Qt WebEngine
* Can be built without web view support as well (then the web UI is opened in the regular browser)
* Allows quickly switching between multiple Syncthing instances
* Still under development; the following features are planned
* Connect to multiple instances of Syncthing at a time
* Show currently processed items
* Show recently processed items
* Improve notification handling
## Screenshots
### Under Openbox/Tint2

View File

@ -64,12 +64,12 @@ int main(int argc, char *argv[])
TrayIcon trayIcon;
trayIcon.show();
if(Settings::firstLaunch()) {
trayIcon.trayMenu().widget()->showSettingsDialog();
QMessageBox msgBox;
msgBox.setIcon(QMessageBox::Information);
msgBox.setText(QCoreApplication::translate("main", "You must configure how to connect to Syncthing when using Syncthing Tray the first time."));
msgBox.setInformativeText(QCoreApplication::translate("main", "Note that the settings dialog allows importing URL, credentials and API-key from the local Syncthing configuration."));
msgBox.exec();
trayIcon.trayMenu().widget()->showSettingsDialog();
}
res = application.exec();
} else {

View File

@ -7,7 +7,11 @@
#include <QApplication>
#include <QSettings>
#include <QFrame>
#include <QSslCertificate>
#include <QSslError>
#include <QMessageBox>
using namespace std;
using namespace Media;
namespace Settings {
@ -19,29 +23,15 @@ bool &firstLaunch()
}
// connection
QString &syncthingUrl()
ConnectionSettings &primaryConnectionSettings()
{
static QString v;
static ConnectionSettings v;
return v;
}
bool &authEnabled()
std::vector<ConnectionSettings> &secondaryConnectionSettings()
{
static bool v = false;
return v;
}
QString &userName()
{
static QString v;
return v;
}
QString &password()
{
static QString v;
return v;
}
QByteArray &apiKey()
{
static QByteArray v;
static vector<ConnectionSettings> v;
return v;
}
@ -141,17 +131,45 @@ void restore()
QSettings settings(QSettings::IniFormat, QSettings::UserScope, QApplication::organizationName(), QApplication::applicationName());
settings.beginGroup(QStringLiteral("tray"));
firstLaunch() = !settings.contains(QStringLiteral("syncthingUrl"));
syncthingUrl() = settings.value(QStringLiteral("syncthingUrl"), QStringLiteral("http://localhost:8080/")).toString();
authEnabled() = settings.value(QStringLiteral("authEnabled"), false).toBool();
userName() = settings.value(QStringLiteral("userName")).toString();
password() = settings.value(QStringLiteral("password")).toString();
apiKey() = settings.value(QStringLiteral("apiKey")).toByteArray();
notifyOnDisconnect() = settings.value(QStringLiteral("notifyOnDisconnect"), true).toBool();
notifyOnInternalErrors() = settings.value(QStringLiteral("notifyOnErrors"), true).toBool();
notifyOnSyncComplete() = settings.value(QStringLiteral("notifyOnSyncComplete"), true).toBool();
showSyncthingNotifications() = settings.value(QStringLiteral("showSyncthingNotifications"), true).toBool();
showTraffic() = settings.value(QStringLiteral("showTraffic"), true).toBool();
const int connectionCount = settings.beginReadArray(QStringLiteral("connections"));
if(connectionCount > 0) {
secondaryConnectionSettings().clear();
secondaryConnectionSettings().reserve(static_cast<size_t>(connectionCount));
for(int i = 0; i < connectionCount; ++i) {
ConnectionSettings *connectionSettings;
if(i == 0) {
connectionSettings = &primaryConnectionSettings();
} else {
secondaryConnectionSettings().emplace_back();
connectionSettings = &secondaryConnectionSettings().back();
}
settings.setArrayIndex(i);
connectionSettings->label = settings.value(QStringLiteral("label")).toString();
if(connectionSettings->label.isEmpty()) {
connectionSettings->label = (i == 0 ? QStringLiteral("Primary instance") : QStringLiteral("Secondary instance %1").arg(i));
}
connectionSettings->syncthingUrl = settings.value(QStringLiteral("syncthingUrl"), connectionSettings->syncthingUrl).toString();
connectionSettings->authEnabled = settings.value(QStringLiteral("authEnabled"), connectionSettings->authEnabled).toBool();
connectionSettings->userName = settings.value(QStringLiteral("userName")).toString();
connectionSettings->password = settings.value(QStringLiteral("password")).toString();
connectionSettings->apiKey = settings.value(QStringLiteral("apiKey")).toByteArray();
connectionSettings->httpsCertPath = settings.value(QStringLiteral("httpsCertPath")).toString();
if(!connectionSettings->loadHttpsCert()) {
QMessageBox::critical(nullptr, QCoreApplication::applicationName(), QCoreApplication::translate("Settings::restore", "Unable to load certificate \"%1\" when restoring settings.").arg(connectionSettings->httpsCertPath));
}
}
} else {
firstLaunch() = true;
primaryConnectionSettings().label = QStringLiteral("Primary instance");
}
settings.endArray();
notifyOnDisconnect() = settings.value(QStringLiteral("notifyOnDisconnect"), notifyOnDisconnect()).toBool();
notifyOnInternalErrors() = settings.value(QStringLiteral("notifyOnErrors"), notifyOnInternalErrors()).toBool();
notifyOnSyncComplete() = settings.value(QStringLiteral("notifyOnSyncComplete"), notifyOnSyncComplete()).toBool();
showSyncthingNotifications() = settings.value(QStringLiteral("showSyncthingNotifications"), showSyncthingNotifications()).toBool();
showTraffic() = settings.value(QStringLiteral("showTraffic"), showTraffic()).toBool();
trayMenuSize() = settings.value(QStringLiteral("trayMenuSize"), trayMenuSize()).toSize();
frameStyle() = settings.value(QStringLiteral("frameStyle"), frameStyle()).toInt();
settings.endGroup();
@ -179,11 +197,21 @@ void save()
QSettings settings(QSettings::IniFormat, QSettings::UserScope, QApplication::organizationName(), QApplication::applicationName());
settings.beginGroup(QStringLiteral("tray"));
settings.setValue(QStringLiteral("syncthingUrl"), syncthingUrl());
settings.setValue(QStringLiteral("authEnabled"), authEnabled());
settings.setValue(QStringLiteral("userName"), userName());
settings.setValue(QStringLiteral("password"), password());
settings.setValue(QStringLiteral("apiKey"), apiKey());
const int connectionCount = static_cast<int>(1 + secondaryConnectionSettings().size());
settings.beginWriteArray(QStringLiteral("connections"), connectionCount);
for(int i = 0; i < connectionCount; ++i) {
const ConnectionSettings *connectionSettings = (i == 0 ? &primaryConnectionSettings() : &secondaryConnectionSettings()[static_cast<size_t>(i - 1)]);
settings.setArrayIndex(i);
settings.setValue(QStringLiteral("label"), connectionSettings->label);
settings.setValue(QStringLiteral("syncthingUrl"), connectionSettings->syncthingUrl);
settings.setValue(QStringLiteral("authEnabled"), connectionSettings->authEnabled);
settings.setValue(QStringLiteral("userName"), connectionSettings->userName);
settings.setValue(QStringLiteral("password"), connectionSettings->password);
settings.setValue(QStringLiteral("apiKey"), connectionSettings->apiKey);
settings.setValue(QStringLiteral("httpsCertPath"), connectionSettings->httpsCertPath);
}
settings.endArray();
settings.setValue(QStringLiteral("notifyOnDisconnect"), notifyOnDisconnect());
settings.setValue(QStringLiteral("notifyOnErrors"), notifyOnInternalErrors());
settings.setValue(QStringLiteral("notifyOnSyncComplete"), notifyOnSyncComplete());
@ -211,4 +239,21 @@ void save()
qtSettings().save(settings);
}
bool ConnectionSettings::loadHttpsCert()
{
if(!httpsCertPath.isEmpty()) {
const QList<QSslCertificate> cert = QSslCertificate::fromPath(httpsCertPath);
if(cert.isEmpty()) {
return false;
}
expectedSslErrors.clear();
expectedSslErrors.reserve(4);
expectedSslErrors << QSslError(QSslError::UnableToGetLocalIssuerCertificate, cert.at(0));
expectedSslErrors << QSslError(QSslError::UnableToVerifyFirstCertificate, cert.at(0));
expectedSslErrors << QSslError(QSslError::SelfSignedCertificate, cert.at(0));
expectedSslErrors << QSslError(QSslError::HostNameMismatch, cert.at(0));
}
return true;
}
}

View File

@ -3,10 +3,12 @@
#include <c++utilities/conversion/types.h>
#include <QtGlobal>
#include <QString>
#include <QByteArray>
#include <QSslError>
#include <vector>
QT_FORWARD_DECLARE_CLASS(QByteArray)
QT_FORWARD_DECLARE_CLASS(QString)
QT_FORWARD_DECLARE_CLASS(QSize)
namespace Media {
@ -23,11 +25,19 @@ namespace Settings {
bool &firstLaunch();
// connection
QString &syncthingUrl();
bool &authEnabled();
QString &userName();
QString &password();
QByteArray &apiKey();
struct ConnectionSettings {
QString label;
QString syncthingUrl;
bool authEnabled = false;
QString userName;
QString password;
QByteArray apiKey;
QString httpsCertPath;
QList<QSslError> expectedSslErrors;
bool loadHttpsCert();
};
ConnectionSettings &primaryConnectionSettings();
std::vector<ConnectionSettings> &secondaryConnectionSettings();
// notifications
bool &notifyOnDisconnect();

View File

@ -8,7 +8,7 @@ namespace Data {
/*!
* \struct SyncthingConfig
* \brief The SyncthingConfig struct holds the configuration of Syncthing itself read from config.xml in the Syncthing home directory.
* \brief The SyncthingConfig struct holds the configuration of the local Syncthing instance read from config.xml in the Syncthing home directory.
* \remarks Only a few fields are required since most of the Syncthing config can be accessed via SyncthingConnection class.
*/

View File

@ -1,6 +1,8 @@
#include "./syncthingconnection.h"
#include "./syncthingconfig.h"
#include "../application/settings.h"
#include <c++utilities/conversion/conversionexception.h>
#include <QNetworkAccessManager>
@ -102,8 +104,6 @@ bool SyncthingDir::assignStatus(DirStatus newStatus, DateTime time)
* \brief The SyncthingConnection class allows Qt applications to access Syncthing.
*/
QList<QSslError> SyncthingConnection::m_expectedCertificateErrors;
/*!
* \brief Constructs a new instance ready to connect. To establish the connection, call connect().
*/
@ -165,6 +165,10 @@ void SyncthingConnection::connect()
{
if(!isConnected()) {
m_reconnecting = m_hasConfig = m_hasStatus = false;
if(m_apiKey.isEmpty() || m_syncthingUrl.isEmpty()) {
emit error(tr("Connection configuration is insufficient."));
return;
}
requestConfig();
requestStatus();
m_keepPolling = true;
@ -182,6 +186,7 @@ void SyncthingConnection::disconnect()
/*!
* \brief Disconnects if connected, then (re-)connects asynchronously.
* \remarks Clears the currently cached configuration.
*/
void SyncthingConnection::reconnect()
{
@ -190,10 +195,63 @@ void SyncthingConnection::reconnect()
m_hasConfig = m_hasStatus = false;
abortAllRequests();
} else {
connect();
continueReconnect();
}
}
/*!
* \brief Applies the specifies configuration and tries to reconnect via reconnect().
* \remarks The expected SSL errors of the specified configuration are updated accordingly.
*/
void SyncthingConnection::reconnect(Settings::ConnectionSettings &connectionSettings)
{
setSyncthingUrl(connectionSettings.syncthingUrl);
setApiKey(connectionSettings.apiKey);
if(connectionSettings.authEnabled) {
setCredentials(connectionSettings.userName, connectionSettings.password);
} else {
setCredentials(QString(), QString());
}
loadSelfSignedCertificate();
if(connectionSettings.expectedSslErrors.isEmpty()) {
connectionSettings.expectedSslErrors = expectedSslErrors();
}
reconnect();
}
/*!
* \brief Internally called to reconnect; ensures currently cached config is cleared.
*/
void SyncthingConnection::continueReconnect()
{
emit newConfig(QJsonObject()); // configuration will be invalidated
m_status = SyncthingStatus::Disconnected;
m_keepPolling = true;
m_reconnecting = false;
m_lastEventId = 0;
m_configDir.clear();
m_myId.clear();
m_totalIncomingTraffic = 0;
m_totalOutgoingTraffic = 0;
m_totalIncomingRate = 0.0;
m_totalOutgoingRate = 0.0;
m_unreadNotifications = false;
m_hasConfig = false;
m_hasStatus = false;
m_dirs.clear();
m_devs.clear();
m_lastConnectionsUpdate = DateTime();
m_lastFileTime = DateTime();
m_lastFileName.clear();
m_lastFileDeleted = false;
if(m_apiKey.isEmpty() || m_syncthingUrl.isEmpty()) {
emit error(tr("Connection configuration is insufficient."));
return;
}
requestConfig();
requestStatus();
}
void SyncthingConnection::pause(const QString &dev)
{
QUrlQuery query;
@ -273,7 +331,7 @@ QNetworkRequest SyncthingConnection::prepareRequest(const QString &path, const Q
QNetworkReply *SyncthingConnection::requestData(const QString &path, const QUrlQuery &query, bool rest)
{
auto *reply = networkAccessManager().get(prepareRequest(path, query, rest));
reply->ignoreSslErrors(m_expectedCertificateErrors);
reply->ignoreSslErrors(m_expectedSslErrors);
return reply;
}
@ -283,7 +341,7 @@ QNetworkReply *SyncthingConnection::requestData(const QString &path, const QUrlQ
QNetworkReply *SyncthingConnection::postData(const QString &path, const QUrlQuery &query, const QByteArray &data)
{
auto *reply = networkAccessManager().post(prepareRequest(path, query), data);
reply->ignoreSslErrors(m_expectedCertificateErrors);
reply->ignoreSslErrors(m_expectedSslErrors);
return reply;
}
@ -470,14 +528,15 @@ QMetaObject::Connection SyncthingConnection::requestLog(std::function<void (cons
*/
void SyncthingConnection::loadSelfSignedCertificate()
{
// ensure current exceptions for self-signed certificates are cleared
m_expectedSslErrors.clear();
// only possible if the Syncthing instance is running on the local machine
const QString host(QUrl(syncthingUrl()).host());
if(host.compare(QLatin1String("localhost"), Qt::CaseInsensitive) != 0 && !QHostAddress().isLoopback()) {
if(host.compare(QLatin1String("localhost"), Qt::CaseInsensitive) != 0 && !QHostAddress(host).isLoopback()) {
return;
}
// ensure current exceptions for self-signed certificates are cleared
m_expectedCertificateErrors.clear();
// find cert
const QString certPath = !m_configDir.isEmpty() ? (m_configDir + QStringLiteral("/https-cert.pem")) : SyncthingConfig::locateHttpsCertificate();
if(certPath.isEmpty()) {
@ -490,10 +549,11 @@ void SyncthingConnection::loadSelfSignedCertificate()
emit error(tr("Unable to load certificate used by Syncthing GUI."));
return;
}
m_expectedCertificateErrors << QSslError(QSslError::UnableToGetLocalIssuerCertificate, cert.at(0));
m_expectedCertificateErrors << QSslError(QSslError::UnableToVerifyFirstCertificate, cert.at(0));
m_expectedCertificateErrors << QSslError(QSslError::SelfSignedCertificate, cert.at(0));
m_expectedCertificateErrors << QSslError(QSslError::HostNameMismatch, cert.at(0));
m_expectedSslErrors.reserve(4);
m_expectedSslErrors << QSslError(QSslError::UnableToGetLocalIssuerCertificate, cert.at(0));
m_expectedSslErrors << QSslError(QSslError::UnableToVerifyFirstCertificate, cert.at(0));
m_expectedSslErrors << QSslError(QSslError::SelfSignedCertificate, cert.at(0));
m_expectedSslErrors << QSslError(QSslError::HostNameMismatch, cert.at(0));
}
/*!
@ -868,11 +928,7 @@ void SyncthingConnection::readEvents()
// intended disconnect, not an error
if(m_reconnecting) {
// if reconnection flag is set, instantly etstablish a new connection ...
m_reconnecting = false;
requestConfig();
requestStatus();
m_lastEventId = 0;
m_keepPolling = true;
continueReconnect();
} else {
// ... otherwise keep disconnected
setStatus(SyncthingStatus::Disconnected);

View File

@ -17,6 +17,10 @@ QT_FORWARD_DECLARE_CLASS(QUrlQuery)
QT_FORWARD_DECLARE_CLASS(QJsonObject)
QT_FORWARD_DECLARE_CLASS(QJsonArray)
namespace Settings {
struct ConnectionSettings;
}
namespace Data {
QNetworkAccessManager &networkAccessManager();
@ -151,13 +155,14 @@ public:
const std::vector<SyncthingDev> &devInfo() const;
QMetaObject::Connection requestQrCode(const QString &text, std::function<void (const QPixmap &)> callback);
QMetaObject::Connection requestLog(std::function<void (const std::vector<SyncthingLogEntry> &)> callback);
static const QList<QSslError> &expectedCertificateErrors();
const QList<QSslError> &expectedSslErrors();
public Q_SLOTS:
void loadSelfSignedCertificate();
void connect();
void disconnect();
void reconnect();
void reconnect(Settings::ConnectionSettings &connectionSettings);
void pause(const QString &dev);
void pauseAllDevs();
void resume(const QString &dev);
@ -263,6 +268,7 @@ private Q_SLOTS:
void readPauseResume();
void readRestart();
void continueReconnect();
void setStatus(SyncthingStatus status);
private:
@ -300,7 +306,7 @@ private:
ChronoUtilities::DateTime m_lastFileTime;
QString m_lastFileName;
bool m_lastFileDeleted;
static QList<QSslError> m_expectedCertificateErrors;
QList<QSslError> m_expectedSslErrors;
};
/*!
@ -447,9 +453,9 @@ inline const std::vector<SyncthingDev> &SyncthingConnection::devInfo() const
* \brief Returns a list of all expected certificate errors.
* \remarks This list is shared by all instances and updated via loadSelfSignedCertificate().
*/
inline const QList<QSslError> &SyncthingConnection::expectedCertificateErrors()
inline const QList<QSslError> &SyncthingConnection::expectedSslErrors()
{
return m_expectedCertificateErrors;
return m_expectedSslErrors;
}
}

View File

@ -47,6 +47,12 @@
</item>
<item>
<widget class="QLabel" name="platformNoteLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>

View File

@ -2,6 +2,14 @@
<ui version="4.0">
<class>QtGui::ConnectionOptionPage</class>
<widget class="QWidget" name="QtGui::ConnectionOptionPage">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>502</width>
<height>368</height>
</rect>
</property>
<property name="windowTitle">
<string>Connection</string>
</property>
@ -10,30 +18,114 @@
<normaloff>.</normaloff>.</iconset>
</property>
<layout class="QFormLayout" name="formLayout">
<property name="horizontalSpacing">
<number>6</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="instanceLabel">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Config label</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QFrame" name="selectionFrame">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>4</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QComboBox" name="selectionComboBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="addPushButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Add secondary instance</string>
</property>
<property name="icon">
<iconset theme="list-add">
<normaloff>.</normaloff>.</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="removePushButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Remove currently selected secondary instance</string>
</property>
<property name="icon">
<iconset theme="list-remove">
<normaloff>.</normaloff>.</iconset>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="urlLabel">
<property name="text">
<string>Syncthing URL</string>
</property>
</widget>
</item>
<item row="0" column="1">
<item row="3" column="1">
<widget class="Widgets::ClearLineEdit" name="urlLineEdit"/>
</item>
<item row="1" column="0">
<item row="4" column="0">
<widget class="QLabel" name="authLabel">
<property name="text">
<string>Authentication</string>
</property>
</widget>
</item>
<item row="1" column="1">
<item row="4" column="1">
<widget class="QCheckBox" name="authCheckBox"/>
</item>
<item row="2" column="0">
<item row="5" column="0">
<widget class="QLabel" name="userNameLabel">
<property name="enabled">
<bool>false</bool>
@ -43,7 +135,14 @@
</property>
</widget>
</item>
<item row="3" column="0">
<item row="5" column="1">
<widget class="Widgets::ClearLineEdit" name="userNameLineEdit">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="passwordLabel">
<property name="enabled">
<bool>false</bool>
@ -53,14 +152,7 @@
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="Widgets::ClearLineEdit" name="userNameLineEdit">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
<item row="3" column="1">
<item row="6" column="1">
<widget class="QLineEdit" name="passwordLineEdit">
<property name="enabled">
<bool>false</bool>
@ -70,42 +162,17 @@
</property>
</widget>
</item>
<item row="11" column="1">
<widget class="QLabel" name="statusLabel">
<property name="text">
<string>disconnected</string>
</property>
</widget>
</item>
<item row="11" column="0">
<widget class="QLabel" name="statusTextLabel">
<property name="text">
<string>Status</string>
</property>
</widget>
</item>
<item row="12" column="1">
<widget class="QPushButton" name="connectPushButton">
<property name="text">
<string>Apply connection settings and try to reconnect</string>
</property>
<property name="icon">
<iconset theme="view-refresh">
<normaloff>.</normaloff>.</iconset>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="Widgets::ClearLineEdit" name="apiKeyLineEdit"/>
</item>
<item row="5" column="0">
<item row="8" column="0">
<widget class="QLabel" name="apiKeyLabel">
<property name="text">
<string>API key</string>
</property>
</widget>
</item>
<item row="7" column="1">
<item row="8" column="1">
<widget class="Widgets::ClearLineEdit" name="apiKeyLineEdit"/>
</item>
<item row="11" column="1">
<widget class="QPushButton" name="insertFromConfigFilePushButton">
<property name="styleSheet">
<string notr="true">font-weight: bold;</string>
@ -119,8 +186,8 @@
</property>
</widget>
</item>
<item row="10" column="1">
<widget class="Line" name="line">
<item row="12" column="1">
<widget class="Line" name="line2">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
@ -132,6 +199,83 @@
</property>
</widget>
</item>
<item row="13" column="0">
<widget class="QLabel" name="statusTextLabel">
<property name="text">
<string>Status</string>
</property>
</widget>
</item>
<item row="13" column="1">
<widget class="QLabel" name="statusLabel">
<property name="text">
<string>disconnected</string>
</property>
</widget>
</item>
<item row="14" column="1">
<widget class="QPushButton" name="connectPushButton">
<property name="text">
<string>Apply connection settings and try to reconnect with the currently selected config</string>
</property>
<property name="icon">
<iconset theme="view-refresh">
<normaloff>.</normaloff>.</iconset>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="Line" name="line1">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="instanceNoteLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>42</height>
</size>
</property>
<property name="text">
<string>It is possible to save multiple configurations. This allows switching quickly between multiple Syncthing instances using the arrow in the right corner of the tray menu. The config label is an arbitrary name to identify a configuration and must not match the name of the corresponding Syncthing device.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QLabel" name="certificateLabel">
<property name="text">
<string>HTTPS certificate</string>
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="Widgets::PathSelection" name="certPathSelection" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
@ -140,6 +284,12 @@
<extends>QLineEdit</extends>
<header location="global">qtutilities/widgets/clearlineedit.h</header>
</customwidget>
<customwidget>
<class>Widgets::PathSelection</class>
<extends>QWidget</extends>
<header location="global">qtutilities/widgets/pathselection.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections>

View File

@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>457</width>
<width>517</width>
<height>345</height>
</rect>
</property>
@ -36,6 +36,15 @@
<property name="leftMargin">
<number>30</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="syncthingPathLabel">
<property name="text">

View File

@ -1,6 +1,5 @@
#include "./settingsdialog.h"
#include "../application/settings.h"
#include "../data/syncthingconnection.h"
#include "../data/syncthingconfig.h"
#include "../data/syncthingprocess.h"
@ -14,9 +13,6 @@
#include "resources/config.h"
#include <tagparser/mediafileinfo.h>
#include <tagparser/backuphelper.h>
#include <qtutilities/settingsdialog/optioncategory.h>
#include <qtutilities/settingsdialog/optioncategorymodel.h>
#include <qtutilities/settingsdialog/qtsettings.h>
@ -45,7 +41,8 @@ namespace QtGui {
// ConnectionOptionPage
ConnectionOptionPage::ConnectionOptionPage(Data::SyncthingConnection *connection, QWidget *parentWidget) :
ConnectionOptionPageBase(parentWidget),
m_connection(connection)
m_connection(connection),
m_currentIndex(0)
{}
ConnectionOptionPage::~ConnectionOptionPage()
@ -55,9 +52,15 @@ QWidget *ConnectionOptionPage::setupWidget()
{
auto *w = ConnectionOptionPageBase::setupWidget();
updateConnectionStatus();
ui()->certPathSelection->provideCustomFileMode(QFileDialog::ExistingFile);
ui()->certPathSelection->lineEdit()->setPlaceholderText(QCoreApplication::translate("QtGui::ConnectionOptionPage", "Auto-detected for local instance"));
QObject::connect(m_connection, &SyncthingConnection::statusChanged, bind(&ConnectionOptionPage::updateConnectionStatus, this));
QObject::connect(ui()->connectPushButton, &QPushButton::clicked, bind(&ConnectionOptionPage::applyAndReconnect, this));
QObject::connect(ui()->insertFromConfigFilePushButton, &QPushButton::clicked, bind(&ConnectionOptionPage::insertFromConfigFile, this));
QObject::connect(ui()->selectionComboBox, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged), bind(&ConnectionOptionPage::showConnectionSettings, this, _1));
QObject::connect(ui()->selectionComboBox, static_cast<void(QComboBox::*)(const QString &)>(&QComboBox::editTextChanged), bind(&ConnectionOptionPage::saveCurrentConnectionName, this, _1));
QObject::connect(ui()->addPushButton, &QPushButton::clicked, bind(&ConnectionOptionPage::addConnectionSettings, this));
QObject::connect(ui()->removePushButton, &QPushButton::clicked, bind(&ConnectionOptionPage::removeConnectionSettings, this));
return w;
}
@ -102,41 +105,114 @@ void ConnectionOptionPage::updateConnectionStatus()
}
}
bool ConnectionOptionPage::apply()
bool ConnectionOptionPage::showConnectionSettings(int index)
{
if(hasBeenShown()) {
syncthingUrl() = ui()->urlLineEdit->text();
authEnabled() = ui()->authCheckBox->isChecked();
userName() = ui()->userNameLineEdit->text();
password() = ui()->passwordLineEdit->text();
apiKey() = ui()->apiKeyLineEdit->text().toUtf8();
bool ok = true;
if(index != m_currentIndex) {
if((ok = cacheCurrentSettings(false))) {
const ConnectionSettings &connectionSettings = (index == 0 ? m_primarySettings : m_secondarySettings[static_cast<size_t>(index - 1)]);
ui()->urlLineEdit->setText(connectionSettings.syncthingUrl);
ui()->authCheckBox->setChecked(connectionSettings.authEnabled);
ui()->userNameLineEdit->setText(connectionSettings.userName);
ui()->passwordLineEdit->setText(connectionSettings.password);
ui()->apiKeyLineEdit->setText(connectionSettings.apiKey);
ui()->certPathSelection->lineEdit()->setText(connectionSettings.httpsCertPath);
m_currentIndex = index;
} else {
ui()->selectionComboBox->setCurrentIndex(m_currentIndex);
}
}
return true;
ui()->removePushButton->setEnabled(index);
return ok;
}
bool ConnectionOptionPage::cacheCurrentSettings(bool applying)
{
bool ok = true;
if(m_currentIndex >= 0) {
ConnectionSettings &connectionSettings = (m_currentIndex == 0 ? m_primarySettings : m_secondarySettings[static_cast<size_t>(m_currentIndex - 1)]);
connectionSettings.syncthingUrl = ui()->urlLineEdit->text();
connectionSettings.authEnabled = ui()->authCheckBox->isChecked();
connectionSettings.userName = ui()->userNameLineEdit->text();
connectionSettings.password = ui()->passwordLineEdit->text();
connectionSettings.apiKey = ui()->apiKeyLineEdit->text().toUtf8();
connectionSettings.expectedSslErrors.clear();
connectionSettings.httpsCertPath = ui()->certPathSelection->lineEdit()->text();
if(!connectionSettings.loadHttpsCert()) {
const QString errorMessage = QCoreApplication::translate("QtGui::ConnectionOptionPage", "Unable to load specified certificate \"%1\".").arg(connectionSettings.httpsCertPath);
if(!applying) {
QMessageBox::critical(widget(), QCoreApplication::applicationName(), errorMessage);
} else {
errors() << errorMessage;
}
ok = false;
}
}
return ok;
}
void ConnectionOptionPage::saveCurrentConnectionName(const QString &name)
{
const int index = ui()->selectionComboBox->currentIndex();
if(index == m_currentIndex && index >= 0) {
(index == 0 ? m_primarySettings : m_secondarySettings[static_cast<size_t>(index - 1)]).label = name;
ui()->selectionComboBox->setItemText(index, name);
}
}
void ConnectionOptionPage::addConnectionSettings()
{
m_secondarySettings.emplace_back();
m_secondarySettings.back().label = QCoreApplication::translate("QtGui::ConnectionOptionPage", "Instance %1").arg(ui()->selectionComboBox->count() + 1);
ui()->selectionComboBox->addItem(m_secondarySettings.back().label);
ui()->selectionComboBox->setCurrentIndex(ui()->selectionComboBox->count() - 1);
}
void ConnectionOptionPage::removeConnectionSettings()
{
int index = ui()->selectionComboBox->currentIndex();
if(index > 0) {
m_secondarySettings.erase(m_secondarySettings.begin() + (index - 1));
m_currentIndex = -1;
ui()->selectionComboBox->removeItem(index);
}
}
bool ConnectionOptionPage::apply()
{
bool ok = true;
if(hasBeenShown()) {
ok = cacheCurrentSettings(true);
Settings::primaryConnectionSettings() = m_primarySettings;
Settings::secondaryConnectionSettings() = m_secondarySettings;
}
return ok;
}
void ConnectionOptionPage::reset()
{
if(hasBeenShown()) {
ui()->urlLineEdit->setText(syncthingUrl());
ui()->authCheckBox->setChecked(authEnabled());
ui()->userNameLineEdit->setText(userName());
ui()->passwordLineEdit->setText(password());
ui()->apiKeyLineEdit->setText(apiKey());
m_primarySettings = primaryConnectionSettings();
m_secondarySettings = secondaryConnectionSettings();
m_currentIndex = -1;
QStringList itemTexts;
itemTexts.reserve(1 + static_cast<int>(m_secondarySettings.size()));
itemTexts << m_primarySettings.label;
for(const ConnectionSettings &settings : m_secondarySettings) {
itemTexts << settings.label;
}
ui()->selectionComboBox->clear();
ui()->selectionComboBox->addItems(itemTexts);
ui()->selectionComboBox->setCurrentIndex(0);
}
}
void ConnectionOptionPage::applyAndReconnect()
{
apply();
m_connection->setSyncthingUrl(Settings::syncthingUrl());
m_connection->setApiKey(Settings::apiKey());
if(Settings::authEnabled()) {
m_connection->setCredentials(Settings::userName(), Settings::password());
} else {
m_connection->setCredentials(QString(), QString());
}
m_connection->reconnect();
m_connection->reconnect(primaryConnectionSettings());
}
// NotificationsOptionPage
@ -312,7 +388,7 @@ bool setAutostartEnabled(bool enabled)
#elif defined(PLATFORM_WINDOWS)
QSettings settings(QStringLiteral("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"), QSettings::NativeFormat);
if(enabled) {
settings.setValue(QStringLiteral(PROJECT_NAME), QCoreApplication::applicationFilePath().replace(QChar('/'), QChar("\\")));
settings.setValue(QStringLiteral(PROJECT_NAME), QCoreApplication::applicationFilePath().replace(QChar('/'), QChar('\\')));
} else {
settings.remove(QStringLiteral(PROJECT_NAME));
}
@ -515,7 +591,8 @@ SettingsDialog::SettingsDialog(Data::SyncthingConnection *connection, QWidget *p
categoryModel()->setCategories(categories);
setMinimumSize(800, 450);
setMinimumSize(800, 550);
setWindowTitle(tr("Settings") + QStringLiteral(" - " APP_NAME));
setWindowIcon(QIcon::fromTheme(QStringLiteral("preferences-other"), QIcon(QStringLiteral(":/icons/hicolor/scalable/apps/preferences-other.svg"))));
// some settings could be applied without restarting the application, good idea?

View File

@ -1,6 +1,8 @@
#ifndef SETTINGS_DIALOG_H
#define SETTINGS_DIALOG_H
#include "../application/settings.h"
#include <qtutilities/settingsdialog/settingsdialog.h>
#include <qtutilities/settingsdialog/optionpage.h>
#include <qtutilities/settingsdialog/qtsettings.h>
@ -8,11 +10,6 @@
#include <QWidget>
#include <QProcess>
namespace Settings {
class KnownFieldModel;
class TargetLevelModel;
}
namespace Data {
class SyncthingConnection;
}
@ -27,7 +24,15 @@ private:
void insertFromConfigFile();
void updateConnectionStatus();
void applyAndReconnect();
bool showConnectionSettings(int index);
bool cacheCurrentSettings(bool applying);
void saveCurrentConnectionName(const QString &name);
void addConnectionSettings();
void removeConnectionSettings();
Data::SyncthingConnection *m_connection;
Settings::ConnectionSettings m_primarySettings;
std::vector<Settings::ConnectionSettings> m_secondarySettings;
int m_currentIndex;
END_DECLARE_OPTION_PAGE
DECLARE_UI_FILE_BASED_OPTION_PAGE(NotificationsOptionPage)

View File

@ -33,6 +33,7 @@ TrayIcon::TrayIcon(QObject *parent) :
// set context menu
connect(m_contextMenu.addAction(QIcon::fromTheme(QStringLiteral("internet-web-browser"), QIcon(QStringLiteral(":/icons/hicolor/scalable/apps/internet-web-browser.svg"))), tr("Web UI")), &QAction::triggered, m_trayMenu.widget(), &TrayWidget::showWebUi);
connect(m_contextMenu.addAction(QIcon::fromTheme(QStringLiteral("preferences-other"), QIcon(QStringLiteral(":/icons/hicolor/scalable/apps/preferences-other.svg"))), tr("Settings")), &QAction::triggered, m_trayMenu.widget(), &TrayWidget::showSettingsDialog);
m_contextMenu.addMenu(m_trayMenu.widget()->connectionsMenu());
connect(m_contextMenu.addAction(QIcon::fromTheme(QStringLiteral("help-about"), QIcon(QStringLiteral(":/icons/hicolor/scalable/apps/help-about.svg"))), tr("About")), &QAction::triggered, m_trayMenu.widget(), &TrayWidget::showAboutDialog);
m_contextMenu.addSeparator();
connect(m_contextMenu.addAction(QIcon::fromTheme(QStringLiteral("window-close"), QIcon(QStringLiteral(":/icons/hicolor/scalable/actions/window-close.svg"))), tr("Close")), &QAction::triggered, &QCoreApplication::quit);

View File

@ -49,7 +49,8 @@ TrayWidget::TrayWidget(TrayMenu *parent) :
m_webViewDlg(nullptr),
#endif
m_dirModel(m_connection),
m_devModel(m_connection)
m_devModel(m_connection),
m_selectedConnection(nullptr)
{
m_ui->setupUi(this);
@ -87,6 +88,11 @@ TrayWidget::TrayWidget(TrayMenu *parent) :
cornerFrameLayout->addWidget(scanAllButton);
m_ui->tabWidget->setCornerWidget(m_cornerFrame, Qt::BottomRightCorner);
// setup connection menu
m_connectionsActionGroup = new QActionGroup(m_connectionsMenu = new QMenu(tr("Connection"), this));
m_connectionsMenu->setIcon(QIcon::fromTheme(QStringLiteral("network-connect"), QIcon(QStringLiteral(":/icons/hicolor/scalable/actions/network-connect.svg"))));
connect(m_ui->connectionsPushButton, &QPushButton::clicked, this, &TrayWidget::showConnectionsMenu);
// apply settings, this also establishes the connection to Syncthing
applySettings();
@ -106,6 +112,7 @@ TrayWidget::TrayWidget(TrayMenu *parent) :
connect(m_ui->devsTreeView, &DevView::pauseResumeDev, this, &TrayWidget::pauseResumeDev);
connect(scanAllButton, &QPushButton::clicked, &m_connection, &SyncthingConnection::rescanAllDirs);
connect(viewIdButton, &QPushButton::clicked, this, &TrayWidget::showOwnDeviceId);
connect(m_connectionsActionGroup, &QActionGroup::triggered, this, &TrayWidget::handleConnectionSelected);
}
TrayWidget::~TrayWidget()
@ -115,13 +122,7 @@ void TrayWidget::showSettingsDialog()
{
if(!m_settingsDlg) {
m_settingsDlg = new SettingsDialog(&m_connection, this);
m_settingsDlg->setWindowTitle(tr("Settings") + QStringLiteral(" - " APP_NAME));
connect(m_settingsDlg, &SettingsDialog::applied, this, &TrayWidget::applySettings);
#ifndef SYNCTHINGTRAY_NO_WEBVIEW
if(m_webViewDlg) {
connect(m_settingsDlg, &SettingsDialog::applied, m_webViewDlg, &WebViewDialog::applySettings);
}
#endif
}
m_settingsDlg->show();
centerWidget(m_settingsDlg);
@ -151,15 +152,15 @@ void TrayWidget::showWebUi()
#ifndef SYNCTHINGTRAY_NO_WEBVIEW
if(Settings::webViewDisabled()) {
#endif
QDesktopServices::openUrl(Settings::syncthingUrl());
QDesktopServices::openUrl(m_connection.syncthingUrl());
#ifndef SYNCTHINGTRAY_NO_WEBVIEW
} else {
if(!m_webViewDlg) {
m_webViewDlg = new WebViewDialog(this);
connect(m_webViewDlg, &WebViewDialog::destroyed, this, &TrayWidget::handleWebViewDeleted);
if(m_settingsDlg) {
connect(m_settingsDlg, &SettingsDialog::applied, m_webViewDlg, &WebViewDialog::applySettings);
if(m_selectedConnection) {
m_webViewDlg->applySettings(*m_selectedConnection);
}
connect(m_webViewDlg, &WebViewDialog::destroyed, this, &TrayWidget::handleWebViewDeleted);
}
m_webViewDlg->show();
if(m_menu) {
@ -263,16 +264,44 @@ void TrayWidget::updateStatusButton(SyncthingStatus status)
void TrayWidget::applySettings()
{
m_connection.setSyncthingUrl(Settings::syncthingUrl());
m_connection.setApiKey(Settings::apiKey());
if(Settings::authEnabled()) {
m_connection.setCredentials(Settings::userName(), Settings::password());
} else {
m_connection.setCredentials(QString(), QString());
// update connections menu
int connectionIndex = 0;
const int connectionCount = static_cast<int>(1 + Settings::secondaryConnectionSettings().size());
const QList<QAction *> connectionActions = m_connectionsActionGroup->actions();
m_selectedConnection = nullptr;
for(; connectionIndex < connectionCount; ++connectionIndex) {
Settings::ConnectionSettings &connectionSettings = (connectionIndex == 0 ? Settings::primaryConnectionSettings() : Settings::secondaryConnectionSettings()[static_cast<size_t>(connectionIndex - 1)]);
if(connectionIndex < connectionActions.size()) {
QAction *action = connectionActions.at(connectionIndex);
action->setText(connectionSettings.label);
if(action->isChecked()) {
m_selectedConnection = &connectionSettings;
}
} else {
QAction *action = m_connectionsMenu->addAction(connectionSettings.label);
action->setCheckable(true);
m_connectionsActionGroup->addAction(action);
}
}
m_connection.loadSelfSignedCertificate();
m_connection.reconnect();
m_ui->trafficFrame->setVisible(Settings::showTraffic());
for(; connectionIndex < connectionActions.size(); ++connectionIndex) {
m_connectionsActionGroup->removeAction(connectionActions.at(connectionIndex));
}
if(!m_selectedConnection) {
m_selectedConnection = &Settings::primaryConnectionSettings();
m_connectionsMenu->actions().at(0)->setChecked(true);
}
m_connection.reconnect(*m_selectedConnection);
// web view
#ifndef SYNCTHINGTRAY_NO_WEBVIEW
if(m_webViewDlg) {
m_webViewDlg->applySettings(*m_selectedConnection);
}
#endif
// update visual appearance
m_ui->trafficFormWidget->setVisible(Settings::showTraffic());
if(Settings::showTraffic()) {
updateTraffic();
}
@ -354,14 +383,37 @@ void TrayWidget::updateTraffic()
}
#ifndef SYNCTHINGTRAY_NO_WEBVIEW
void TrayWidget::handleWebViewDeleted()
{
m_webViewDlg = nullptr;
}
#endif
void TrayWidget::handleNewNotification(const QString &msg)
{
// FIXME
}
void TrayWidget::handleConnectionSelected(QAction *connectionAction)
{
int index = m_connectionsMenu->actions().indexOf(connectionAction);
if(index >= 0) {
m_selectedConnection = (index == 0)
? &Settings::primaryConnectionSettings()
: &Settings::secondaryConnectionSettings()[static_cast<size_t>(index - 1)];
m_connection.reconnect(*m_selectedConnection);
#ifndef SYNCTHINGTRAY_NO_WEBVIEW
if(m_webViewDlg) {
m_webViewDlg->applySettings(*m_selectedConnection);
}
#endif
}
}
void TrayWidget::showConnectionsMenu()
{
m_connectionsMenu->exec(QCursor::pos());
}
}

View File

@ -7,12 +7,15 @@
#include "../data/syncthingdirectorymodel.h"
#include "../data/syncthingdevicemodel.h"
#include "../data/syncthingprocess.h"
#include "../application/settings.h"
#include <QWidget>
#include <memory>
QT_FORWARD_DECLARE_CLASS(QFrame)
QT_FORWARD_DECLARE_CLASS(QMenu)
QT_FORWARD_DECLARE_CLASS(QActionGroup)
namespace ApplicationUtilities {
class QtConfigArguments;
@ -41,6 +44,7 @@ public:
~TrayWidget();
Data::SyncthingConnection &connection();
QMenu *connectionsMenu();
public slots:
void showSettingsDialog();
@ -57,8 +61,12 @@ private slots:
void pauseResumeDev(const QModelIndex &devIndex);
void changeStatus();
void updateTraffic();
#ifndef SYNCTHINGTRAY_NO_WEBVIEW
void handleWebViewDeleted();
#endif
void handleNewNotification(const QString &msg);
void handleConnectionSelected(QAction *connectionAction);
void showConnectionsMenu();
private:
TrayMenu *m_menu;
@ -72,6 +80,9 @@ private:
Data::SyncthingConnection m_connection;
Data::SyncthingDirectoryModel m_dirModel;
Data::SyncthingDeviceModel m_devModel;
QMenu *m_connectionsMenu;
QActionGroup *m_connectionsActionGroup;
Settings::ConnectionSettings *m_selectedConnection;
};
inline Data::SyncthingConnection &TrayWidget::connection()
@ -79,6 +90,11 @@ inline Data::SyncthingConnection &TrayWidget::connection()
return m_connection;
}
inline QMenu *TrayWidget::connectionsMenu()
{
return m_connectionsMenu;
}
}
#endif // TRAY_WIDGET_H

View File

@ -178,7 +178,7 @@
<number>0</number>
</property>
<property name="rightMargin">
<number>3</number>
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
@ -254,6 +254,22 @@
</layout>
</widget>
</item>
<item>
<widget class="QPushButton" name="connectionsPushButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="icon">
<iconset theme="network-connect"/>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>

View File

@ -1,5 +1,6 @@
#ifndef SYNCTHINGTRAY_NO_WEBVIEW
#include "./webpage.h"
#include "./webviewdialog.h"
#include "../application/settings.h"
#include "../data/syncthingconnection.h"
@ -25,8 +26,9 @@ using namespace Data;
namespace QtGui {
WebPage::WebPage(WEB_VIEW_PROVIDER *view) :
WebPage::WebPage(WebViewDialog *dlg, WEB_VIEW_PROVIDER *view) :
WEB_PAGE_PROVIDER(view),
m_dlg(dlg),
m_view(view)
{
#ifdef SYNCTHINGTRAY_USE_WEBENGINE
@ -52,6 +54,7 @@ WebPage::WebPage(WEB_VIEW_PROVIDER *view) :
WEB_PAGE_PROVIDER *WebPage::createWindow(WEB_PAGE_PROVIDER::WebWindowType type)
{
Q_UNUSED(type)
return new WebPage;
}
@ -92,17 +95,18 @@ void WebPage::supplyCredentials(QNetworkReply *reply, QAuthenticator *authentica
void WebPage::supplyCredentials(QAuthenticator *authenticator)
{
if(Settings::authEnabled()) {
authenticator->setUser(Settings::userName());
authenticator->setPassword(Settings::password());
if(m_dlg && m_dlg->settings().authEnabled) {
authenticator->setUser(m_dlg->settings().userName);
authenticator->setPassword(m_dlg->settings().password);
}
}
#ifdef SYNCTHINGTRAY_USE_WEBKIT
void WebPage::handleSslErrors(QNetworkReply *reply, const QList<QSslError> &errors)
{
if(reply->request().url().host() == m_view->url().host()) {
reply->ignoreSslErrors(SyncthingConnection::expectedCertificateErrors());
Q_UNUSED(errors)
if(m_dlg && reply->request().url().host() == m_view->url().host()) {
reply->ignoreSslErrors(m_dlg->settings().expectedSslErrors);
}
}
#endif

View File

@ -17,11 +17,13 @@ QT_FORWARD_DECLARE_CLASS(QSslError)
namespace QtGui {
class WebViewDialog;
class WebPage : public WEB_PAGE_PROVIDER
{
Q_OBJECT
public:
WebPage(WEB_VIEW_PROVIDER *view = nullptr);
WebPage(WebViewDialog *dlg = nullptr, WEB_VIEW_PROVIDER *view = nullptr);
protected:
WEB_PAGE_PROVIDER *createWindow(WebWindowType type);
@ -39,6 +41,7 @@ private slots:
#endif
private:
WebViewDialog *m_dlg;
WEB_VIEW_PROVIDER *m_view;
};

View File

@ -26,10 +26,8 @@ WebViewDialog::WebViewDialog(QWidget *parent) :
setWindowIcon(QIcon(QStringLiteral(":/icons/hicolor/scalable/app/syncthingtray.svg")));
setCentralWidget(m_view);
m_view->setPage(new WebPage(m_view));
applySettings();
m_view->setPage(new WebPage(this, m_view));
connect(m_view, &WEB_VIEW_PROVIDER::titleChanged, this, &WebViewDialog::setWindowTitle);
if(Settings::webViewGeometry().isEmpty()) {
resize(1200, 800);
@ -44,9 +42,10 @@ QtGui::WebViewDialog::~WebViewDialog()
Settings::webViewGeometry() = saveGeometry();
}
void QtGui::WebViewDialog::applySettings()
void QtGui::WebViewDialog::applySettings(const Settings::ConnectionSettings &connectionSettings)
{
m_view->setUrl(Settings::syncthingUrl());
m_settings = connectionSettings;
m_view->setUrl(connectionSettings.syncthingUrl);
m_view->setZoomFactor(Settings::webViewZoomFactor());
}

View File

@ -4,10 +4,16 @@
#include "./webviewprovider.h"
#include "../application/settings.h"
#include <QMainWindow>
QT_FORWARD_DECLARE_CLASS(WEB_VIEW_PROVIDER)
namespace Settings {
struct ConnectionSettings;
}
namespace QtGui {
class WebViewDialog : public QMainWindow
@ -18,15 +24,22 @@ public:
~WebViewDialog();
public slots:
void applySettings();
void applySettings(const Settings::ConnectionSettings &connectionSettings);
const Settings::ConnectionSettings &settings() const;
protected:
void closeEvent(QCloseEvent *event);
private:
WEB_VIEW_PROVIDER *m_view;
Settings::ConnectionSettings m_settings;
};
inline const Settings::ConnectionSettings &WebViewDialog::settings() const
{
return m_settings;
}
}
#endif // SYNCTHINGTRAY_NO_WEBVIEW

View File

@ -26,5 +26,6 @@
<file>icons/hicolor/scalable/places/folder.svg</file>
<file>icons/hicolor/scalable/places/network-workgroup.svg</file>
<file>icons/hicolor/scalable/apps/system-run.svg</file>
<file>icons/hicolor/scalable/actions/network-connect.svg</file>
</qresource>
</RCC>

View File

@ -0,0 +1,13 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<defs id="defs3051">
<style type="text/css" id="current-color-scheme">
.ColorScheme-Text {
color:#4d4d4d;
}
</style>
</defs>
<path style="fill:currentColor;fill-opacity:1;stroke:none"
d="M 13.300781 2 L 10.650391 4.6503906 L 9.5859375 3.5859375 L 3.5859375 9.5859375 L 4.6503906 10.650391 L 2 13.300781 L 2.6992188 14 L 5.3496094 11.349609 L 6.4140625 12.414062 L 12.414062 6.4140625 L 11.349609 5.3496094 L 14 2.6992188 L 13.300781 2 z "
class="ColorScheme-Text"
/>
</svg>

After

Width:  |  Height:  |  Size: 586 B

View File

@ -34,94 +34,100 @@
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="459"/>
<location filename="../data/syncthingconnection.cpp" line="169"/>
<location filename="../data/syncthingconnection.cpp" line="248"/>
<source>Connection configuration is insufficient.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="517"/>
<source>Unable to parse Syncthing log: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="463"/>
<location filename="../data/syncthingconnection.cpp" line="521"/>
<source>Unable to request system log: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="484"/>
<location filename="../data/syncthingconnection.cpp" line="543"/>
<source>Unable to locate certificate used by Syncthing GUI.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="490"/>
<location filename="../data/syncthingconnection.cpp" line="549"/>
<source>Unable to load certificate used by Syncthing GUI.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="522"/>
<location filename="../data/syncthingconnection.cpp" line="622"/>
<location filename="../data/syncthingconnection.cpp" line="582"/>
<location filename="../data/syncthingconnection.cpp" line="682"/>
<source>Unable to parse Syncthing config: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="527"/>
<location filename="../data/syncthingconnection.cpp" line="627"/>
<location filename="../data/syncthingconnection.cpp" line="587"/>
<location filename="../data/syncthingconnection.cpp" line="687"/>
<source>Unable to request Syncthing config: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="702"/>
<location filename="../data/syncthingconnection.cpp" line="762"/>
<source>Unable to parse connections: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="707"/>
<location filename="../data/syncthingconnection.cpp" line="767"/>
<source>Unable to request connections: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="762"/>
<location filename="../data/syncthingconnection.cpp" line="822"/>
<source>Unable to parse directory statistics: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="767"/>
<location filename="../data/syncthingconnection.cpp" line="827"/>
<source>Unable to request directory statistics: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="804"/>
<location filename="../data/syncthingconnection.cpp" line="864"/>
<source>Unable to parse device statistics: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="809"/>
<location filename="../data/syncthingconnection.cpp" line="869"/>
<source>Unable to request device statistics: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="860"/>
<location filename="../data/syncthingconnection.cpp" line="920"/>
<source>Unable to parse Syncthing events: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="882"/>
<location filename="../data/syncthingconnection.cpp" line="938"/>
<source>Unable to request Syncthing events: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="1094"/>
<location filename="../data/syncthingconnection.cpp" line="1150"/>
<source>Unable to request rescan: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="1109"/>
<location filename="../data/syncthingconnection.cpp" line="1165"/>
<source>Unable to request pause/resume: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="1124"/>
<location filename="../data/syncthingconnection.cpp" line="1180"/>
<source>Unable to request restart: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="427"/>
<location filename="../data/syncthingconnection.cpp" line="485"/>
<source>Unable to request QR-Code: </source>
<translation type="unfinished"></translation>
</message>
@ -444,22 +450,22 @@
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="238"/>
<location filename="../gui/settingsdialog.cpp" line="314"/>
<source>This is achieved by adding a *.desktop file under &lt;i&gt;~/.config/autostart&lt;/i&gt; so the setting only affects the current user.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="240"/>
<location filename="../gui/settingsdialog.cpp" line="316"/>
<source>This is achieved by adding a registry key under &lt;i&gt;HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Run&lt;/i&gt; so the setting only affects the current user. Note that the startup entry is invalidated when moving &lt;i&gt;syncthingtray.exe&lt;/i&gt;.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="242"/>
<location filename="../gui/settingsdialog.cpp" line="318"/>
<source>This feature has not been implemented for your platform (yet).</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="329"/>
<location filename="../gui/settingsdialog.cpp" line="405"/>
<source>unable to modify startup entry</source>
<translation type="unfinished"></translation>
</message>
@ -467,65 +473,105 @@
<context>
<name>QtGui::ConnectionOptionPage</name>
<message>
<location filename="../gui/connectionoptionpage.ui" line="6"/>
<location filename="../gui/connectionoptionpage.ui" line="14"/>
<source>Connection</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/connectionoptionpage.ui" line="19"/>
<location filename="../gui/connectionoptionpage.ui" line="30"/>
<source>Config label</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/connectionoptionpage.ui" line="80"/>
<source>Add secondary instance</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/connectionoptionpage.ui" line="97"/>
<source>Remove currently selected secondary instance</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/connectionoptionpage.ui" line="111"/>
<source>Syncthing URL</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/connectionoptionpage.ui" line="29"/>
<location filename="../gui/connectionoptionpage.ui" line="121"/>
<source>Authentication</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/connectionoptionpage.ui" line="42"/>
<location filename="../gui/connectionoptionpage.ui" line="134"/>
<source>User</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/connectionoptionpage.ui" line="76"/>
<location filename="../gui/connectionoptionpage.ui" line="212"/>
<source>disconnected</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/connectionoptionpage.ui" line="83"/>
<location filename="../gui/connectionoptionpage.ui" line="219"/>
<source>Apply connection settings and try to reconnect with the currently selected config</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/connectionoptionpage.ui" line="255"/>
<source>It is possible to save multiple configurations. This allows switching quickly between multiple Syncthing instances using the arrow in the right corner of the tray menu. The config label is an arbitrary name to identify a configuration and must not match the name of the corresponding Syncthing device.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/connectionoptionpage.ui" line="265"/>
<source>HTTPS certificate</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/connectionoptionpage.ui" line="205"/>
<source>Status</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/connectionoptionpage.ui" line="90"/>
<source>Apply connection settings and try to reconnect</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/connectionoptionpage.ui" line="104"/>
<location filename="../gui/connectionoptionpage.ui" line="168"/>
<source>API key</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/connectionoptionpage.ui" line="114"/>
<location filename="../gui/connectionoptionpage.ui" line="181"/>
<source>Insert values from local Syncthing configuration</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/connectionoptionpage.ui" line="52"/>
<location filename="../gui/connectionoptionpage.ui" line="151"/>
<source>Password</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="70"/>
<location filename="../gui/settingsdialog.cpp" line="56"/>
<source>Auto-detected for local instance</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="73"/>
<source>Select Syncthing config file</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="77"/>
<location filename="../gui/settingsdialog.cpp" line="80"/>
<source>Unable to parse the Syncthing config file.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="143"/>
<source>Unable to load specified certificate &quot;%1&quot;.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="167"/>
<source>Instance %1</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QtGui::DevView</name>
@ -576,48 +622,48 @@
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/launcheroptionpage.ui" line="42"/>
<location filename="../gui/launcheroptionpage.ui" line="51"/>
<source>Syncthing executable</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/launcheroptionpage.ui" line="52"/>
<location filename="../gui/launcheroptionpage.ui" line="61"/>
<source>Arguments</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/launcheroptionpage.ui" line="86"/>
<source>Syncthing log (stdout/stderr)</source>
<location filename="../gui/launcheroptionpage.ui" line="95"/>
<source>Syncthing log (interleaved stdout/stderr)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/launcheroptionpage.ui" line="102"/>
<location filename="../gui/launcheroptionpage.ui" line="111"/>
<source>Apply and launch now</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/launcheroptionpage.ui" line="119"/>
<location filename="../gui/launcheroptionpage.ui" line="128"/>
<source>Stop launched instance</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/launcheroptionpage.ui" line="138"/>
<location filename="../gui/launcheroptionpage.ui" line="147"/>
<source>No log messages available yet</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/launcheroptionpage.ui" line="145"/>
<location filename="../gui/launcheroptionpage.ui" line="154"/>
<source>Ensure latest log is visible</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="409"/>
<location filename="../gui/settingsdialog.cpp" line="485"/>
<source>Syncthing existed with exit code %1
</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="412"/>
<location filename="../gui/settingsdialog.cpp" line="488"/>
<source>Syncthing crashed with exit code %1
</source>
<translation type="unfinished"></translation>
@ -659,17 +705,22 @@
<context>
<name>QtGui::SettingsDialog</name>
<message>
<location filename="../gui/settingsdialog.cpp" line="497"/>
<location filename="../gui/settingsdialog.cpp" line="573"/>
<source>Tray</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="509"/>
<location filename="../gui/settingsdialog.cpp" line="585"/>
<source>Startup</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="503"/>
<location filename="../gui/settingsdialog.cpp" line="595"/>
<source>Settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="579"/>
<source>Web view</source>
<translation type="unfinished"></translation>
</message>
@ -687,62 +738,62 @@
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="36"/>
<location filename="../gui/trayicon.cpp" line="37"/>
<source>About</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="38"/>
<location filename="../gui/trayicon.cpp" line="39"/>
<source>Close</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="77"/>
<location filename="../gui/trayicon.cpp" line="78"/>
<source>Error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="84"/>
<location filename="../gui/trayicon.cpp" line="85"/>
<source>Syncthing notification</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="93"/>
<location filename="../gui/trayicon.cpp" line="94"/>
<source>Not connected to Syncthing</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="95"/>
<location filename="../gui/trayicon.cpp" line="96"/>
<source>Disconnected from Syncthing</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="100"/>
<location filename="../gui/trayicon.cpp" line="101"/>
<source>Syncthing is idling</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="104"/>
<location filename="../gui/trayicon.cpp" line="105"/>
<source>Syncthing is scanning</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="108"/>
<location filename="../gui/trayicon.cpp" line="109"/>
<source>Notifications available</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="112"/>
<location filename="../gui/trayicon.cpp" line="113"/>
<source>At least one device is paused</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="116"/>
<location filename="../gui/trayicon.cpp" line="117"/>
<source>Synchronization is ongoing</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="125"/>
<location filename="../gui/trayicon.cpp" line="126"/>
<source>Synchronization complete</source>
<translation type="unfinished"></translation>
</message>
@ -756,7 +807,7 @@
</message>
<message>
<location filename="../gui/traywidget.ui" line="107"/>
<location filename="../gui/traywidget.cpp" line="244"/>
<location filename="../gui/traywidget.cpp" line="245"/>
<source>Connect</source>
<translation type="unfinished"></translation>
</message>
@ -783,8 +834,8 @@
<message>
<location filename="../gui/traywidget.ui" line="230"/>
<location filename="../gui/traywidget.ui" line="250"/>
<location filename="../gui/traywidget.cpp" line="345"/>
<location filename="../gui/traywidget.cpp" line="352"/>
<location filename="../gui/traywidget.cpp" line="374"/>
<location filename="../gui/traywidget.cpp" line="381"/>
<source>unknown</source>
<translation type="unfinished"></translation>
</message>
@ -799,24 +850,23 @@
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.ui" line="280"/>
<location filename="../gui/traywidget.ui" line="296"/>
<source>Directories</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.ui" line="309"/>
<location filename="../gui/traywidget.ui" line="325"/>
<source>Devices</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.ui" line="80"/>
<location filename="../gui/traywidget.cpp" line="138"/>
<location filename="../gui/traywidget.cpp" line="139"/>
<source>About</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.ui" line="134"/>
<location filename="../gui/traywidget.cpp" line="118"/>
<source>Settings</source>
<translation type="unfinished"></translation>
</message>
@ -826,72 +876,77 @@
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="67"/>
<location filename="../gui/traywidget.cpp" line="68"/>
<source>View own device ID</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="84"/>
<location filename="../gui/traywidget.cpp" line="85"/>
<source>Rescan all directories</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="78"/>
<location filename="../gui/traywidget.cpp" line="79"/>
<source>Show Syncthing log</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="72"/>
<location filename="../gui/traywidget.cpp" line="73"/>
<source>Restart Syncthing</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="186"/>
<location filename="../gui/traywidget.cpp" line="92"/>
<source>Connection</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="187"/>
<source>device ID is unknown</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="194"/>
<location filename="../gui/traywidget.cpp" line="195"/>
<source>Copy to clipboard</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="245"/>
<location filename="../gui/traywidget.cpp" line="246"/>
<source>Not connected to Syncthing, click to connect</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="252"/>
<location filename="../gui/traywidget.cpp" line="253"/>
<source>Pause</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="253"/>
<location filename="../gui/traywidget.cpp" line="254"/>
<source>Syncthing is running, click to pause all devices</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="258"/>
<location filename="../gui/traywidget.cpp" line="259"/>
<source>At least one device is paused, click to resume</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="294"/>
<location filename="../gui/traywidget.cpp" line="323"/>
<source>The directory &lt;i&gt;%1&lt;/i&gt; does not exist on the local machine.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="257"/>
<location filename="../gui/traywidget.cpp" line="258"/>
<source>Continue</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="176"/>
<location filename="../gui/traywidget.cpp" line="177"/>
<source>Own device ID</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="213"/>
<location filename="../gui/traywidget.cpp" line="214"/>
<source>Log</source>
<translation type="unfinished"></translation>
</message>
@ -908,7 +963,7 @@
<name>QtGui::WebViewOptionPage</name>
<message>
<location filename="../gui/webviewoptionpage.ui" line="14"/>
<location filename="../gui/settingsdialog.cpp" line="459"/>
<location filename="../gui/settingsdialog.cpp" line="535"/>
<source>General</source>
<translation type="unfinished"></translation>
</message>
@ -938,21 +993,29 @@
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="461"/>
<location filename="../gui/settingsdialog.cpp" line="537"/>
<source>Syncthing Tray has not been built with vieb view support utilizing either Qt WebKit or Qt WebEngine.
The Web UI will be opened in the default web browser instead.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Settings::restore</name>
<message>
<location filename="../application/settings.cpp" line="159"/>
<source>Unable to load certificate &quot;%1&quot; when restoring settings.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>main</name>
<message>
<location filename="../application/main.cpp" line="70"/>
<location filename="../application/main.cpp" line="69"/>
<source>You must configure how to connect to Syncthing when using Syncthing Tray the first time.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../application/main.cpp" line="71"/>
<location filename="../application/main.cpp" line="70"/>
<source>Note that the settings dialog allows importing URL, credentials and API-key from the local Syncthing configuration.</source>
<translation type="unfinished"></translation>
</message>

View File

@ -34,94 +34,100 @@
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="459"/>
<location filename="../data/syncthingconnection.cpp" line="169"/>
<location filename="../data/syncthingconnection.cpp" line="248"/>
<source>Connection configuration is insufficient.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="517"/>
<source>Unable to parse Syncthing log: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="463"/>
<location filename="../data/syncthingconnection.cpp" line="521"/>
<source>Unable to request system log: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="484"/>
<location filename="../data/syncthingconnection.cpp" line="543"/>
<source>Unable to locate certificate used by Syncthing GUI.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="490"/>
<location filename="../data/syncthingconnection.cpp" line="549"/>
<source>Unable to load certificate used by Syncthing GUI.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="522"/>
<location filename="../data/syncthingconnection.cpp" line="622"/>
<location filename="../data/syncthingconnection.cpp" line="582"/>
<location filename="../data/syncthingconnection.cpp" line="682"/>
<source>Unable to parse Syncthing config: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="527"/>
<location filename="../data/syncthingconnection.cpp" line="627"/>
<location filename="../data/syncthingconnection.cpp" line="587"/>
<location filename="../data/syncthingconnection.cpp" line="687"/>
<source>Unable to request Syncthing config: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="702"/>
<location filename="../data/syncthingconnection.cpp" line="762"/>
<source>Unable to parse connections: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="707"/>
<location filename="../data/syncthingconnection.cpp" line="767"/>
<source>Unable to request connections: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="762"/>
<location filename="../data/syncthingconnection.cpp" line="822"/>
<source>Unable to parse directory statistics: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="767"/>
<location filename="../data/syncthingconnection.cpp" line="827"/>
<source>Unable to request directory statistics: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="804"/>
<location filename="../data/syncthingconnection.cpp" line="864"/>
<source>Unable to parse device statistics: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="809"/>
<location filename="../data/syncthingconnection.cpp" line="869"/>
<source>Unable to request device statistics: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="860"/>
<location filename="../data/syncthingconnection.cpp" line="920"/>
<source>Unable to parse Syncthing events: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="882"/>
<location filename="../data/syncthingconnection.cpp" line="938"/>
<source>Unable to request Syncthing events: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="1094"/>
<location filename="../data/syncthingconnection.cpp" line="1150"/>
<source>Unable to request rescan: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="1109"/>
<location filename="../data/syncthingconnection.cpp" line="1165"/>
<source>Unable to request pause/resume: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="1124"/>
<location filename="../data/syncthingconnection.cpp" line="1180"/>
<source>Unable to request restart: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="427"/>
<location filename="../data/syncthingconnection.cpp" line="485"/>
<source>Unable to request QR-Code: </source>
<translation type="unfinished"></translation>
</message>
@ -444,22 +450,22 @@
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="238"/>
<location filename="../gui/settingsdialog.cpp" line="314"/>
<source>This is achieved by adding a *.desktop file under &lt;i&gt;~/.config/autostart&lt;/i&gt; so the setting only affects the current user.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="240"/>
<location filename="../gui/settingsdialog.cpp" line="316"/>
<source>This is achieved by adding a registry key under &lt;i&gt;HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Run&lt;/i&gt; so the setting only affects the current user. Note that the startup entry is invalidated when moving &lt;i&gt;syncthingtray.exe&lt;/i&gt;.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="242"/>
<location filename="../gui/settingsdialog.cpp" line="318"/>
<source>This feature has not been implemented for your platform (yet).</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="329"/>
<location filename="../gui/settingsdialog.cpp" line="405"/>
<source>unable to modify startup entry</source>
<translation type="unfinished"></translation>
</message>
@ -467,65 +473,105 @@
<context>
<name>QtGui::ConnectionOptionPage</name>
<message>
<location filename="../gui/connectionoptionpage.ui" line="6"/>
<location filename="../gui/connectionoptionpage.ui" line="14"/>
<source>Connection</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/connectionoptionpage.ui" line="19"/>
<location filename="../gui/connectionoptionpage.ui" line="30"/>
<source>Config label</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/connectionoptionpage.ui" line="80"/>
<source>Add secondary instance</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/connectionoptionpage.ui" line="97"/>
<source>Remove currently selected secondary instance</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/connectionoptionpage.ui" line="111"/>
<source>Syncthing URL</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/connectionoptionpage.ui" line="29"/>
<location filename="../gui/connectionoptionpage.ui" line="121"/>
<source>Authentication</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/connectionoptionpage.ui" line="42"/>
<location filename="../gui/connectionoptionpage.ui" line="134"/>
<source>User</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/connectionoptionpage.ui" line="76"/>
<location filename="../gui/connectionoptionpage.ui" line="212"/>
<source>disconnected</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/connectionoptionpage.ui" line="83"/>
<location filename="../gui/connectionoptionpage.ui" line="219"/>
<source>Apply connection settings and try to reconnect with the currently selected config</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/connectionoptionpage.ui" line="255"/>
<source>It is possible to save multiple configurations. This allows switching quickly between multiple Syncthing instances using the arrow in the right corner of the tray menu. The config label is an arbitrary name to identify a configuration and must not match the name of the corresponding Syncthing device.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/connectionoptionpage.ui" line="265"/>
<source>HTTPS certificate</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/connectionoptionpage.ui" line="205"/>
<source>Status</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/connectionoptionpage.ui" line="90"/>
<source>Apply connection settings and try to reconnect</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/connectionoptionpage.ui" line="104"/>
<location filename="../gui/connectionoptionpage.ui" line="168"/>
<source>API key</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/connectionoptionpage.ui" line="114"/>
<location filename="../gui/connectionoptionpage.ui" line="181"/>
<source>Insert values from local Syncthing configuration</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/connectionoptionpage.ui" line="52"/>
<location filename="../gui/connectionoptionpage.ui" line="151"/>
<source>Password</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="70"/>
<location filename="../gui/settingsdialog.cpp" line="56"/>
<source>Auto-detected for local instance</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="73"/>
<source>Select Syncthing config file</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="77"/>
<location filename="../gui/settingsdialog.cpp" line="80"/>
<source>Unable to parse the Syncthing config file.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="143"/>
<source>Unable to load specified certificate &quot;%1&quot;.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="167"/>
<source>Instance %1</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QtGui::DevView</name>
@ -576,48 +622,48 @@
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/launcheroptionpage.ui" line="42"/>
<location filename="../gui/launcheroptionpage.ui" line="51"/>
<source>Syncthing executable</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/launcheroptionpage.ui" line="52"/>
<location filename="../gui/launcheroptionpage.ui" line="61"/>
<source>Arguments</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/launcheroptionpage.ui" line="86"/>
<source>Syncthing log (stdout/stderr)</source>
<location filename="../gui/launcheroptionpage.ui" line="95"/>
<source>Syncthing log (interleaved stdout/stderr)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/launcheroptionpage.ui" line="102"/>
<location filename="../gui/launcheroptionpage.ui" line="111"/>
<source>Apply and launch now</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/launcheroptionpage.ui" line="119"/>
<location filename="../gui/launcheroptionpage.ui" line="128"/>
<source>Stop launched instance</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/launcheroptionpage.ui" line="138"/>
<location filename="../gui/launcheroptionpage.ui" line="147"/>
<source>No log messages available yet</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/launcheroptionpage.ui" line="145"/>
<location filename="../gui/launcheroptionpage.ui" line="154"/>
<source>Ensure latest log is visible</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="409"/>
<location filename="../gui/settingsdialog.cpp" line="485"/>
<source>Syncthing existed with exit code %1
</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="412"/>
<location filename="../gui/settingsdialog.cpp" line="488"/>
<source>Syncthing crashed with exit code %1
</source>
<translation type="unfinished"></translation>
@ -659,17 +705,22 @@
<context>
<name>QtGui::SettingsDialog</name>
<message>
<location filename="../gui/settingsdialog.cpp" line="497"/>
<location filename="../gui/settingsdialog.cpp" line="573"/>
<source>Tray</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="509"/>
<location filename="../gui/settingsdialog.cpp" line="585"/>
<source>Startup</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="503"/>
<location filename="../gui/settingsdialog.cpp" line="595"/>
<source>Settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="579"/>
<source>Web view</source>
<translation type="unfinished"></translation>
</message>
@ -687,62 +738,62 @@
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="36"/>
<location filename="../gui/trayicon.cpp" line="37"/>
<source>About</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="38"/>
<location filename="../gui/trayicon.cpp" line="39"/>
<source>Close</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="77"/>
<location filename="../gui/trayicon.cpp" line="78"/>
<source>Error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="84"/>
<location filename="../gui/trayicon.cpp" line="85"/>
<source>Syncthing notification</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="93"/>
<location filename="../gui/trayicon.cpp" line="94"/>
<source>Not connected to Syncthing</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="95"/>
<location filename="../gui/trayicon.cpp" line="96"/>
<source>Disconnected from Syncthing</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="100"/>
<location filename="../gui/trayicon.cpp" line="101"/>
<source>Syncthing is idling</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="104"/>
<location filename="../gui/trayicon.cpp" line="105"/>
<source>Syncthing is scanning</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="108"/>
<location filename="../gui/trayicon.cpp" line="109"/>
<source>Notifications available</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="112"/>
<location filename="../gui/trayicon.cpp" line="113"/>
<source>At least one device is paused</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="116"/>
<location filename="../gui/trayicon.cpp" line="117"/>
<source>Synchronization is ongoing</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="125"/>
<location filename="../gui/trayicon.cpp" line="126"/>
<source>Synchronization complete</source>
<translation type="unfinished"></translation>
</message>
@ -756,7 +807,7 @@
</message>
<message>
<location filename="../gui/traywidget.ui" line="107"/>
<location filename="../gui/traywidget.cpp" line="244"/>
<location filename="../gui/traywidget.cpp" line="245"/>
<source>Connect</source>
<translation type="unfinished"></translation>
</message>
@ -783,8 +834,8 @@
<message>
<location filename="../gui/traywidget.ui" line="230"/>
<location filename="../gui/traywidget.ui" line="250"/>
<location filename="../gui/traywidget.cpp" line="345"/>
<location filename="../gui/traywidget.cpp" line="352"/>
<location filename="../gui/traywidget.cpp" line="374"/>
<location filename="../gui/traywidget.cpp" line="381"/>
<source>unknown</source>
<translation type="unfinished"></translation>
</message>
@ -799,24 +850,23 @@
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.ui" line="280"/>
<location filename="../gui/traywidget.ui" line="296"/>
<source>Directories</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.ui" line="309"/>
<location filename="../gui/traywidget.ui" line="325"/>
<source>Devices</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.ui" line="80"/>
<location filename="../gui/traywidget.cpp" line="138"/>
<location filename="../gui/traywidget.cpp" line="139"/>
<source>About</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.ui" line="134"/>
<location filename="../gui/traywidget.cpp" line="118"/>
<source>Settings</source>
<translation type="unfinished"></translation>
</message>
@ -826,72 +876,77 @@
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="67"/>
<location filename="../gui/traywidget.cpp" line="68"/>
<source>View own device ID</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="84"/>
<location filename="../gui/traywidget.cpp" line="85"/>
<source>Rescan all directories</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="78"/>
<location filename="../gui/traywidget.cpp" line="79"/>
<source>Show Syncthing log</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="72"/>
<location filename="../gui/traywidget.cpp" line="73"/>
<source>Restart Syncthing</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="186"/>
<location filename="../gui/traywidget.cpp" line="92"/>
<source>Connection</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="187"/>
<source>device ID is unknown</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="194"/>
<location filename="../gui/traywidget.cpp" line="195"/>
<source>Copy to clipboard</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="245"/>
<location filename="../gui/traywidget.cpp" line="246"/>
<source>Not connected to Syncthing, click to connect</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="252"/>
<location filename="../gui/traywidget.cpp" line="253"/>
<source>Pause</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="253"/>
<location filename="../gui/traywidget.cpp" line="254"/>
<source>Syncthing is running, click to pause all devices</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="258"/>
<location filename="../gui/traywidget.cpp" line="259"/>
<source>At least one device is paused, click to resume</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="294"/>
<location filename="../gui/traywidget.cpp" line="323"/>
<source>The directory &lt;i&gt;%1&lt;/i&gt; does not exist on the local machine.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="257"/>
<location filename="../gui/traywidget.cpp" line="258"/>
<source>Continue</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="176"/>
<location filename="../gui/traywidget.cpp" line="177"/>
<source>Own device ID</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="213"/>
<location filename="../gui/traywidget.cpp" line="214"/>
<source>Log</source>
<translation type="unfinished"></translation>
</message>
@ -908,7 +963,7 @@
<name>QtGui::WebViewOptionPage</name>
<message>
<location filename="../gui/webviewoptionpage.ui" line="14"/>
<location filename="../gui/settingsdialog.cpp" line="459"/>
<location filename="../gui/settingsdialog.cpp" line="535"/>
<source>General</source>
<translation type="unfinished"></translation>
</message>
@ -938,21 +993,29 @@
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="461"/>
<location filename="../gui/settingsdialog.cpp" line="537"/>
<source>Syncthing Tray has not been built with vieb view support utilizing either Qt WebKit or Qt WebEngine.
The Web UI will be opened in the default web browser instead.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Settings::restore</name>
<message>
<location filename="../application/settings.cpp" line="159"/>
<source>Unable to load certificate &quot;%1&quot; when restoring settings.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>main</name>
<message>
<location filename="../application/main.cpp" line="70"/>
<location filename="../application/main.cpp" line="69"/>
<source>You must configure how to connect to Syncthing when using Syncthing Tray the first time.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../application/main.cpp" line="71"/>
<location filename="../application/main.cpp" line="70"/>
<source>Note that the settings dialog allows importing URL, credentials and API-key from the local Syncthing configuration.</source>
<translation type="unfinished"></translation>
</message>