Implement autostart and launcher

This commit is contained in:
Martchus 2016-09-03 19:39:43 +02:00
parent 2360b2a482
commit cb251fd123
28 changed files with 1429 additions and 296 deletions

5
.gitignore vendored
View File

@ -42,3 +42,8 @@ Makefile*
# tests
testfiles/output.*
# experimental
plasmoid/
scripts/

View File

@ -20,6 +20,7 @@ set(HEADER_FILES
data/syncthingdirectorymodel.h
data/syncthingdevicemodel.h
data/syncthingconfig.h
data/syncthingprocess.h
data/utils.h
)
set(SRC_FILES
@ -27,6 +28,7 @@ set(SRC_FILES
data/syncthingdirectorymodel.cpp
data/syncthingdevicemodel.cpp
data/syncthingconfig.cpp
data/syncthingprocess.cpp
data/utils.cpp
)
@ -65,6 +67,7 @@ set(WIDGETS_UI_FILES
gui/notificationsoptionpage.ui
gui/appearanceoptionpage.ui
gui/autostartoptionpage.ui
gui/launcheroptionpage.ui
gui/webviewoptionpage.ui
)

View File

@ -3,7 +3,10 @@
Qt 5-based tray application for [Syncthing](https://github.com/syncthing/syncthing)
* Designed to work under any desktop environment with tray icon support
* Tested under Plasma 5 and Openbox/qt5ct/Tint2
* Tested under
* Plasma 5
* Openbox/qt5ct/Tint2
* Cinnamon
* Could be shown as regular window if no tray icon support is available
* Doesn't require desktop environment specific libraries
* Provides quick access to most frequently used features but does not intend to replace the official web UI
@ -11,18 +14,21 @@ Qt 5-based tray application for [Syncthing](https://github.com/syncthing/syncthi
* Check current traffic statistics
* Display further details about direcoties and devices, like last file, last
scan, ...
* Trigger re-scan of a specific directory
* Trigger re-scan of a specific directory or all directories at once
* Open a directory with the default file browser
* Pause/resume devices
* Pause/resume a specific device or all devices at once
* Shows Syncthing notifications
* Does *not* allow configuring Syncthing itself (currently I do not intend to add this feature as it could cause more harm than good when not implemented correctly)
* Can read the Syncthing configuration file for quick setup when just connecting to local instance
* Provides an option to conveniently add the tray to the applications launched when the desktop environment starts
* Can launch Syncthing when started and display stdout/stderr (useful under Windows)
* 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)
* Still under development; the following features are planned
* Connect to multiple instances of Syncthing at a time
* Add option to conveniently add the tray to the applications launched when the desktop environment starts
* Add option to launch Syncthing when the tray is started and log stdout/stderr (would make sense for me under Windows, otherwise starting Syncthing via systemd is more preferable of course)
* Show currently processed items
* Show recently processed items
## Screenshots
### Under Openbox/Tint2

View File

@ -1,6 +1,7 @@
#include "./settings.h"
#include "../gui/trayicon.h"
#include "../gui/traywidget.h"
#include "../data/syncthingprocess.h"
#include "resources/config.h"
@ -21,6 +22,7 @@
using namespace std;
using namespace ApplicationUtilities;
using namespace QtGui;
using namespace Data;
int main(int argc, char *argv[])
{
@ -46,12 +48,18 @@ int main(int argc, char *argv[])
QtUtilitiesResources::init();
int res;
if(windowedArg.isPresent()) {
if(Settings::launchSynchting()) {
syncthingProcess().startSyncthing();
}
TrayWidget trayWidget;
trayWidget.show();
res = application.exec();
} else {
#ifndef QT_NO_SYSTEMTRAYICON
if(QSystemTrayIcon::isSystemTrayAvailable()) {
if(Settings::launchSynchting()) {
syncthingProcess().startSyncthing();
}
application.setQuitOnLastWindowClosed(false);
TrayIcon trayIcon;
trayIcon.show();

View File

@ -6,6 +6,7 @@
#include <QByteArray>
#include <QApplication>
#include <QSettings>
#include <QFrame>
using namespace Media;
@ -77,6 +78,11 @@ QSize &trayMenuSize()
static QSize v(350, 300);
return v;
}
int &frameStyle()
{
static int v = QFrame::StyledPanel | QFrame::Sunken;
return v;
}
// autostart/launcher
bool &launchSynchting()
@ -84,7 +90,16 @@ bool &launchSynchting()
static bool v = false;
return v;
}
QString &syncthingCommand()
QString &syncthingPath()
{
#ifdef PLATFORM_WINDOWS
static QString v(QStringLiteral("syncthing.exe"));
#else
static QString v(QStringLiteral("syncthing"));
#endif
return v;
}
QString &syncthingArgs()
{
static QString v;
return v;
@ -138,8 +153,13 @@ void restore()
showSyncthingNotifications() = settings.value(QStringLiteral("showSyncthingNotifications"), true).toBool();
showTraffic() = settings.value(QStringLiteral("showTraffic"), true).toBool();
trayMenuSize() = settings.value(QStringLiteral("trayMenuSize"), trayMenuSize()).toSize();
frameStyle() = settings.value(QStringLiteral("frameStyle"), frameStyle()).toInt();
settings.endGroup();
settings.beginGroup(QStringLiteral("startup"));
launchSynchting() = settings.value(QStringLiteral("launchSynchting"), false).toBool();
syncthingCommand() = settings.value(QStringLiteral("syncthingCommand"), QStringLiteral("syncthing")).toString();
syncthingPath() = settings.value(QStringLiteral("syncthingPath"), syncthingPath()).toString();
syncthingArgs() = settings.value(QStringLiteral("syncthingArgs"), syncthingArgs()).toString();
settings.endGroup();
#if defined(SYNCTHINGTRAY_USE_WEBENGINE) || defined(SYNCTHINGTRAY_USE_WEBKIT)
@ -170,8 +190,13 @@ void save()
settings.setValue(QStringLiteral("showSyncthingNotifications"), showSyncthingNotifications());
settings.setValue(QStringLiteral("showTraffic"), showTraffic());
settings.setValue(QStringLiteral("trayMenuSize"), trayMenuSize());
settings.setValue(QStringLiteral("frameStyle"), frameStyle());
settings.endGroup();
settings.beginGroup(QStringLiteral("startup"));
settings.setValue(QStringLiteral("launchSynchting"), launchSynchting());
settings.setValue(QStringLiteral("syncthingCommand"), syncthingCommand());
settings.setValue(QStringLiteral("syncthingPath"), syncthingPath());
settings.setValue(QStringLiteral("syncthingArgs"), syncthingArgs());
settings.endGroup();
#if defined(SYNCTHINGTRAY_USE_WEBENGINE) || defined(SYNCTHINGTRAY_USE_WEBKIT)

View File

@ -38,10 +38,12 @@ bool &showSyncthingNotifications();
// apprearance
bool &showTraffic();
QSize &trayMenuSize();
int &frameStyle();
// autostart/launcher
bool &launchSynchting();
QString &syncthingCommand();
QString &syncthingPath();
QString &syncthingArgs();
// web view
#if defined(SYNCTHINGTRAY_USE_WEBENGINE) || defined(SYNCTHINGTRAY_USE_WEBKIT)

View File

@ -37,8 +37,13 @@ QNetworkAccessManager &networkAccessManager()
* \brief Assigns the status from the specified status string.
* \returns Returns whether the status has actually changed.
*/
bool SyncthingDir::assignStatus(const QString &statusStr)
bool SyncthingDir::assignStatus(const QString &statusStr, DateTime time)
{
if(lastStatusUpdate > time) {
return false;
} else {
lastStatusUpdate = time;
}
DirStatus newStatus;
if(statusStr == QLatin1String("idle")) {
progressPercentage = 0;
@ -71,6 +76,27 @@ bool SyncthingDir::assignStatus(const QString &statusStr)
return false;
}
bool SyncthingDir::assignStatus(DirStatus newStatus, DateTime time)
{
if(lastStatusUpdate > time) {
return false;
} else {
lastStatusUpdate = time;
}
if(newStatus != status) {
switch(status) {
case DirStatus::Scanning:
lastScanTime = DateTime::now();
break;
default:
;
}
status = newStatus;
return true;
}
return false;
}
/*!
* \class SyncthingConnection
* \brief The SyncthingConnection class allows Qt applications to access Syncthing.
@ -119,7 +145,7 @@ QString SyncthingConnection::statusText() const
switch(m_status) {
case SyncthingStatus::Disconnected:
return tr("disconnected");
case SyncthingStatus::Default:
case SyncthingStatus::Idle:
return tr("connected");
case SyncthingStatus::NotificationsAvailable:
return tr("connected, notifications available");
@ -215,6 +241,11 @@ void SyncthingConnection::rescanAllDirs()
}
}
void SyncthingConnection::restart()
{
QObject::connect(postData(QStringLiteral("system/restart"), QUrlQuery()), &QNetworkReply::finished, this, &SyncthingConnection::readRestart);
}
void SyncthingConnection::notificationsRead()
{
m_unreadNotifications = false;
@ -379,12 +410,12 @@ void SyncthingConnection::requestEvents()
*
* The specified \a callback is called on success; otherwise error() is emitted.
*/
void SyncthingConnection::requestQrCode(const QString &text, std::function<void(const QPixmap &)> callback)
QMetaObject::Connection SyncthingConnection::requestQrCode(const QString &text, std::function<void(const QPixmap &)> callback)
{
QUrlQuery query;
query.addQueryItem(QStringLiteral("text"), text);
QNetworkReply *reply = requestData(QStringLiteral("/qr/"), query, false);
QObject::connect(reply, &QNetworkReply::finished, [this, reply, callback] {
return QObject::connect(reply, &QNetworkReply::finished, [this, reply, callback] {
reply->deleteLater();
QPixmap pixmap;
switch(reply->error()) {
@ -403,10 +434,10 @@ void SyncthingConnection::requestQrCode(const QString &text, std::function<void(
*
* The specified \a callback is called on success; otherwise error() is emitted.
*/
void SyncthingConnection::requestLog(std::function<void (const std::vector<SyncthingLogEntry> &)> callback)
QMetaObject::Connection SyncthingConnection::requestLog(std::function<void (const std::vector<SyncthingLogEntry> &)> callback)
{
QNetworkReply *reply = requestData(QStringLiteral("system/log"), QUrlQuery());
QObject::connect(reply, &QNetworkReply::finished, [this, reply, callback] {
return QObject::connect(reply, &QNetworkReply::finished, [this, reply, callback] {
reply->deleteLater();
switch(reply->error()) {
case QNetworkReply::NoError: {
@ -812,11 +843,11 @@ void SyncthingConnection::readEvents()
if(eventType == QLatin1String("Starting")) {
readStartingEvent(eventData);
} else if(eventType == QLatin1String("StateChanged")) {
readStatusChangedEvent(eventData);
readStatusChangedEvent(eventTime, eventData);
} else if(eventType == QLatin1String("DownloadProgress")) {
readDownloadProgressEvent(eventData);
} else if(eventType.startsWith(QLatin1String("Folder"))) {
readDirEvent(eventType, eventData);
readDirEvent(eventTime, eventType, eventData);
} else if(eventType.startsWith(QLatin1String("Device"))) {
readDeviceEvent(eventTime, eventType, eventData);
} else if(eventType == QLatin1String("ItemStarted")) {
@ -856,7 +887,7 @@ void SyncthingConnection::readEvents()
if(m_keepPolling) {
requestEvents();
// TODO: need to change the status somewhere else
setStatus(SyncthingStatus::Default);
setStatus(SyncthingStatus::Idle);
} else {
setStatus(SyncthingStatus::Disconnected);
}
@ -880,14 +911,14 @@ void SyncthingConnection::readStartingEvent(const QJsonObject &eventData)
/*!
* \brief Reads results of requestEvents().
*/
void SyncthingConnection::readStatusChangedEvent(const QJsonObject &eventData)
void SyncthingConnection::readStatusChangedEvent(DateTime eventTime, const QJsonObject &eventData)
{
const QString dir(eventData.value(QStringLiteral("folder")).toString());
if(!dir.isEmpty()) {
// dir status changed
int index;
if(SyncthingDir *dirInfo = findDirInfo(dir, index)) {
if(dirInfo->assignStatus(eventData.value(QStringLiteral("to")).toString())) {
if(dirInfo->assignStatus(eventData.value(QStringLiteral("to")).toString(), eventTime)) {
emit dirStatusChanged(*dirInfo, index);
}
}
@ -906,7 +937,7 @@ void SyncthingConnection::readDownloadProgressEvent(const QJsonObject &eventData
/*!
* \brief Reads results of requestEvents().
*/
void SyncthingConnection::readDirEvent(const QString &eventType, const QJsonObject &eventData)
void SyncthingConnection::readDirEvent(DateTime eventTime, const QString &eventType, const QJsonObject &eventData)
{
const QString dir(eventData.value(QStringLiteral("folder")).toString());
if(!dir.isEmpty()) {
@ -920,7 +951,7 @@ void SyncthingConnection::readDirEvent(const QString &eventType, const QJsonObje
const QJsonObject error(errorVal.toObject());
if(!error.isEmpty()) {
dirInfo->errors.emplace_back(error.value(QStringLiteral("error")).toString(), error.value(QStringLiteral("path")).toString());
dirInfo->status = DirStatus::OutOfSync;
dirInfo->assignStatus(DirStatus::OutOfSync, eventTime);
emit newNotification(dirInfo->errors.back().message);
}
}
@ -958,7 +989,8 @@ void SyncthingConnection::readDirEvent(const QString &eventType, const QJsonObje
if(current > 0 && total > 0) {
dirInfo->progressPercentage = current * 100 / total;
dirInfo->progressRate = rate;
dirInfo->status = DirStatus::Scanning; // ensure state is scanning
dirInfo->assignStatus(DirStatus::Scanning, eventTime); // ensure state is scanning
emit dirStatusChanged(*dirInfo, index);
}
}
}
@ -1040,7 +1072,7 @@ void SyncthingConnection::readItemFinished(DateTime eventTime, const QJsonObject
}
emit dirStatusChanged(*dirInfo, index);
}
} else {
} else if(dirInfo->status == DirStatus::OutOfSync) { // FIXME: find better way to check whether the event is still relevant
dirInfo->errors.emplace_back(error, item);
emit newNotification(error);
}
@ -1078,6 +1110,21 @@ void SyncthingConnection::readPauseResume()
}
}
/*!
* \brief Reads results of restart().
*/
void SyncthingConnection::readRestart()
{
auto *reply = static_cast<QNetworkReply *>(sender());
reply->deleteLater();
switch(reply->error()) {
case QNetworkReply::NoError:
break;
default:
emit error(tr("Unable to request restart: ") + reply->errorString());
}
}
/*!
* \brief Sets the connection status. Ensures statusChanged() is emitted.
* \param status Specifies the status; should be either SyncthingStatus::Disconnected or SyncthingStatus::Default. There is no use
@ -1092,16 +1139,20 @@ void SyncthingConnection::setStatus(SyncthingStatus status)
if(m_unreadNotifications) {
status = SyncthingStatus::NotificationsAvailable;
} else {
// check whether at least one directory is synchronizing
// check whether at least one directory is scanning or synchronizing
bool scanning = false;
bool synchronizing = false;
for(const SyncthingDir &dir : m_dirs) {
for(const SyncthingDir &dir : m_dirs)
if(dir.status == DirStatus::Synchronizing) {
synchronizing = true;
break;
}
} else if(dir.status == DirStatus::Scanning) {
scanning = true;
}
if(synchronizing) {
status = SyncthingStatus::Synchronizing;
} else if(scanning) {
status = SyncthingStatus::Scanning;
} else {
// check whether at least one device is paused
bool paused = false;
@ -1114,7 +1165,7 @@ void SyncthingConnection::setStatus(SyncthingStatus status)
if(paused) {
status = SyncthingStatus::Paused;
} else {
status = SyncthingStatus::Default;
status = SyncthingStatus::Idle;
}
}
}

View File

@ -24,7 +24,8 @@ QNetworkAccessManager &networkAccessManager();
enum class SyncthingStatus
{
Disconnected,
Default,
Idle,
Scanning,
NotificationsAvailable,
Paused,
Synchronizing
@ -62,6 +63,7 @@ struct SyncthingDir
int rescanInterval = 0;
int minDiskFreePercentage = 0;
DirStatus status = DirStatus::Idle;
ChronoUtilities::DateTime lastStatusUpdate;
int progressPercentage = 0;
int progressRate = 0;
std::vector<DirErrors> errors;
@ -73,7 +75,8 @@ struct SyncthingDir
QString lastFileName;
bool lastFileDeleted = false;
bool assignStatus(const QString &statusStr);
bool assignStatus(const QString &statusStr, ChronoUtilities::DateTime time);
bool assignStatus(DirStatus newStatus, ChronoUtilities::DateTime time);
};
enum class DevStatus
@ -146,8 +149,8 @@ public:
double totalOutgoingRate() const;
const std::vector<SyncthingDir> &dirInfo() const;
const std::vector<SyncthingDev> &devInfo() const;
void requestQrCode(const QString &text, std::function<void (const QPixmap &)> callback);
void requestLog(std::function<void (const std::vector<SyncthingLogEntry> &)> callback);
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();
public Q_SLOTS:
@ -161,6 +164,7 @@ public Q_SLOTS:
void resumeAllDevs();
void rescan(const QString &dir);
void rescanAllDirs();
void restart();
void notificationsRead();
Q_SIGNALS:
@ -249,14 +253,15 @@ private Q_SLOTS:
void readDeviceStatistics();
void readEvents();
void readStartingEvent(const QJsonObject &eventData);
void readStatusChangedEvent(const QJsonObject &eventData);
void readStatusChangedEvent(ChronoUtilities::DateTime eventTime, const QJsonObject &eventData);
void readDownloadProgressEvent(const QJsonObject &eventData);
void readDirEvent(const QString &eventType, const QJsonObject &eventData);
void readDirEvent(ChronoUtilities::DateTime eventTime, const QString &eventType, const QJsonObject &eventData);
void readDeviceEvent(ChronoUtilities::DateTime eventTime, const QString &eventType, const QJsonObject &eventData);
void readItemStarted(ChronoUtilities::DateTime eventTime, const QJsonObject &eventData);
void readItemFinished(ChronoUtilities::DateTime eventTime, const QJsonObject &eventData);
void readRescan();
void readPauseResume();
void readRestart();
void setStatus(SyncthingStatus status);

View File

@ -100,7 +100,7 @@ QVariant SyncthingDirectoryModel::data(const QModelIndex &index, int role) const
case 1: return dir.path;
case 2: return dir.devices.join(QStringLiteral(", "));
case 3: return dir.readOnly ? tr("yes") : tr("no");
case 4: return QStringLiteral("%1 s").arg(dir.rescanInterval);
case 4: return QString::fromLatin1(TimeSpan::fromSeconds(dir.rescanInterval).toString(TimeSpanOutputFormat::WithMeasures, true).data());
case 5: return dir.lastScanTime.isNull() ? tr("unknown") : QString::fromLatin1(dir.lastScanTime.toString(DateTimeOutputFormat::DateAndTime, true).data());
case 6: return dir.lastFileName.isEmpty() ? tr("unknown") : dir.lastFileName;
}

58
data/syncthingprocess.cpp Normal file
View File

@ -0,0 +1,58 @@
#include "./syncthingprocess.h"
#include "../application/settings.h"
#include <QTimer>
#include <QStringBuilder>
namespace Data {
SyncthingProcess::SyncthingProcess(QObject *parent) :
QProcess(parent),
m_restarting(false)
{
setProcessChannelMode(QProcess::MergedChannels);
connect(this, static_cast<void(SyncthingProcess::*)(int exitCode, QProcess::ExitStatus exitStatus)>(&SyncthingProcess::finished), this, &SyncthingProcess::handleFinished);
}
void SyncthingProcess::restartSyncthing()
{
if(state() == QProcess::Running) {
m_restarting = true;
// give Syncthing 5 seconds to terminate, otherwise kill it
QTimer::singleShot(5000, this, SLOT(killToRestart()));
terminate();
} else {
startSyncthing();
}
}
void SyncthingProcess::startSyncthing()
{
start(Settings::syncthingPath() % QChar(' ') % Settings::syncthingArgs(), QProcess::ReadOnly);
}
void SyncthingProcess::handleFinished(int exitCode, QProcess::ExitStatus exitStatus)
{
Q_UNUSED(exitCode)
Q_UNUSED(exitStatus)
if(m_restarting) {
m_restarting = false;
startSyncthing();
}
}
void SyncthingProcess::killToRestart()
{
if(m_restarting) {
kill();
}
}
SyncthingProcess &syncthingProcess()
{
static SyncthingProcess process;
return process;
}
} // namespace Data

30
data/syncthingprocess.h Normal file
View File

@ -0,0 +1,30 @@
#ifndef DATA_SYNCTHINGPROCESS_H
#define DATA_SYNCTHINGPROCESS_H
#include <QProcess>
namespace Data {
class SyncthingProcess : public QProcess
{
Q_OBJECT
public:
SyncthingProcess(QObject *parent = nullptr);
public Q_SLOTS:
void restartSyncthing();
void startSyncthing();
private Q_SLOTS:
void handleFinished(int exitCode, QProcess::ExitStatus exitStatus);
void killToRestart();
private:
bool m_restarting;
};
SyncthingProcess &syncthingProcess();
} // namespace Data
#endif // DATA_SYNCTHINGPROCESS_H

View File

@ -6,17 +6,21 @@
<rect>
<x>0</x>
<y>0</y>
<width>283</width>
<height>74</height>
<width>422</width>
<height>149</height>
</rect>
</property>
<property name="windowTitle">
<string>Appearance</string>
</property>
<property name="windowIcon">
<iconset theme="preferences-desktop"/>
<iconset theme="preferences-desktop">
<normaloff>.</normaloff>.</iconset>
</property>
<layout class="QFormLayout" name="formLayout">
<property name="verticalSpacing">
<number>4</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="sizeLabel">
<property name="text">
@ -48,12 +52,21 @@
<property name="maximum">
<number>1000</number>
</property>
<property name="singleStep">
<number>10</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="sizeTimesLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>x</string>
<string> x </string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
@ -68,12 +81,15 @@
<property name="maximum">
<number>1000</number>
</property>
<property name="singleStep">
<number>10</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="sizePxLabel">
<property name="text">
<string>px</string>
<string> px</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
@ -82,6 +98,63 @@
</item>
</layout>
</item>
<item row="3" column="0">
<widget class="QLabel" name="frameShapeLabel">
<property name="text">
<string>Frame shape</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="frameShadowLabel">
<property name="text">
<string>Frame shadow</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="frameShapeComboBox">
<item>
<property name="text">
<string>No frame</string>
</property>
</item>
<item>
<property name="text">
<string>Box</string>
</property>
</item>
<item>
<property name="text">
<string>Panel</string>
</property>
</item>
<item>
<property name="text">
<string>Styled panel</string>
</property>
</item>
</widget>
</item>
<item row="4" column="1">
<widget class="QComboBox" name="frameShadowComboBox">
<item>
<property name="text">
<string>Plain</string>
</property>
</item>
<item>
<property name="text">
<string>Raised</string>
</property>
</item>
<item>
<property name="text">
<string>Sunken</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
<resources/>

View File

@ -6,24 +6,54 @@
<rect>
<x>0</x>
<y>0</y>
<width>575</width>
<height>52</height>
<width>376</width>
<height>80</height>
</rect>
</property>
<property name="windowTitle">
<string>Autostart</string>
</property>
<property name="windowIcon">
<iconset theme="system-run"/>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<widget class="QCheckBox" name="autostartCheckBox">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Not implemented yet&lt;/span&gt;&lt;/p&gt;&lt;p&gt;This will allow launching the tray when the desktop environment starts and to launch Syncthing when the tray is started.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>Start the tray icon when the desktop environment launches</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="infoIconLabel">
<property name="minimumSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="platformNoteLabel">
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>

View File

@ -6,9 +6,13 @@
<string>Connection</string>
</property>
<property name="windowIcon">
<iconset theme="network-connect"/>
<iconset theme="network-connect">
<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="urlLabel">
<property name="text">

207
gui/launcheroptionpage.ui Normal file
View File

@ -0,0 +1,207 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>QtGui::LauncherOptionPage</class>
<widget class="QWidget" name="QtGui::LauncherOptionPage">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>457</width>
<height>345</height>
</rect>
</property>
<property name="windowTitle">
<string>Syncthing launcher</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QCheckBox" name="enabledCheckBox">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Launch Syncthing when starting the tray icon</string>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="launcherFormWidget" native="true">
<property name="enabled">
<bool>false</bool>
</property>
<layout class="QFormLayout" name="formLayout">
<property name="leftMargin">
<number>30</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="syncthingPathLabel">
<property name="text">
<string>Syncthing executable</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="Widgets::PathSelection" name="syncthingPathSelection" native="true"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="argumentsLabel">
<property name="text">
<string>Arguments</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="Widgets::ClearLineEdit" name="argumentsLineEdit"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="Line" name="line">
<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>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="logLabel">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Syncthing log (interleaved stdout/stderr)</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="launchNowPushButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Apply and launch now</string>
</property>
<property name="icon">
<iconset theme="view-refresh">
<normaloff>.</normaloff>.</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="stopPushButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Stop launched instance</string>
</property>
<property name="icon">
<iconset theme="process-stop">
<normaloff>.</normaloff>.</iconset>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="Widgets::ClearPlainTextEdit" name="logTextEdit">
<property name="undoRedoEnabled">
<bool>false</bool>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
<property name="placeholderText">
<string>No log messages available yet</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="ensureCursorVisibleCheckBox">
<property name="text">
<string>Ensure latest log is visible</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>Widgets::ClearLineEdit</class>
<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>
<customwidget>
<class>Widgets::ClearPlainTextEdit</class>
<extends>QPlainTextEdit</extends>
<header location="global">qtutilities/widgets/clearplaintextedit.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>enabledCheckBox</sender>
<signal>toggled(bool)</signal>
<receiver>launcherFormWidget</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>142</x>
<y>17</y>
</hint>
<hint type="destinationlabel">
<x>142</x>
<y>65</y>
</hint>
</hints>
</connection>
<connection>
<sender>enabledCheckBox</sender>
<signal>toggled(bool)</signal>
<receiver>launchNowPushButton</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>259</x>
<y>19</y>
</hint>
<hint type="destinationlabel">
<x>257</x>
<y>130</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -2,6 +2,14 @@
<ui version="4.0">
<class>QtGui::NotificationsOptionPage</class>
<widget class="QWidget" name="QtGui::NotificationsOptionPage">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>240</width>
<height>193</height>
</rect>
</property>
<property name="windowTitle">
<string>Notifications</string>
</property>
@ -12,6 +20,12 @@
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="notifyOnLabel">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Notify on</string>
</property>

View File

@ -3,11 +3,13 @@
#include "../application/settings.h"
#include "../data/syncthingconnection.h"
#include "../data/syncthingconfig.h"
#include "../data/syncthingprocess.h"
#include "ui_connectionoptionpage.h"
#include "ui_notificationsoptionpage.h"
#include "ui_appearanceoptionpage.h"
#include "ui_autostartoptionpage.h"
#include "ui_launcheroptionpage.h"
#include "ui_webviewoptionpage.h"
#include "resources/config.h"
@ -22,10 +24,18 @@
#include <QFileDialog>
#include <QMessageBox>
#include <QHostAddress>
#if defined(PLATFORM_LINUX) && !defined(Q_OS_ANDROID)
# include <QStandardPaths>
#elif defined(PLATFORM_WINDOWS)
# include <QSettings>
#endif
#include <QFontDatabase>
#include <QTextCursor>
#include <functional>
using namespace std;
using namespace std::placeholders;
using namespace Settings;
using namespace Dialogs;
using namespace Data;
@ -172,6 +182,19 @@ bool AppearanceOptionPage::apply()
trayMenuSize().setWidth(ui()->widthSpinBox->value());
trayMenuSize().setHeight(ui()->heightSpinBox->value());
showTraffic() = ui()->showTrafficCheckBox->isChecked();
int style;
switch(ui()->frameShapeComboBox->currentIndex()) {
case 0: style = QFrame::NoFrame; break;
case 1: style = QFrame::Box; break;
case 2: style = QFrame::Panel; break;
default: style = QFrame::StyledPanel;
}
switch(ui()->frameShadowComboBox->currentIndex()) {
case 0: style |= QFrame::Plain; break;
case 1: style |= QFrame::Raised; break;
default: style |= QFrame::Sunken;
}
frameStyle() = style;
}
return true;
}
@ -182,10 +205,24 @@ void AppearanceOptionPage::reset()
ui()->widthSpinBox->setValue(trayMenuSize().width());
ui()->heightSpinBox->setValue(trayMenuSize().height());
ui()->showTrafficCheckBox->setChecked(showTraffic());
int index;
switch(frameStyle() & QFrame::Shape_Mask) {
case QFrame::NoFrame: index = 0; break;
case QFrame::Box: index = 1; break;
case QFrame::Panel: index = 2; break;
default: index = 3;
}
ui()->frameShapeComboBox->setCurrentIndex(index);
switch(frameStyle() & QFrame::Shadow_Mask) {
case QFrame::Plain: index = 0; break;
case QFrame::Raised: index = 1; break;
default: index = 2;
}
ui()->frameShadowComboBox->setCurrentIndex(index);
}
}
// LauncherOptionPage
// AutostartOptionPage
AutostartOptionPage::AutostartOptionPage(QWidget *parentWidget) :
AutostartOptionPageBase(parentWidget)
{}
@ -193,16 +230,217 @@ AutostartOptionPage::AutostartOptionPage(QWidget *parentWidget) :
AutostartOptionPage::~AutostartOptionPage()
{}
QWidget *AutostartOptionPage::setupWidget()
{
auto *widget = AutostartOptionPageBase::setupWidget();
ui()->infoIconLabel->setPixmap(QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation, nullptr, ui()->infoIconLabel).pixmap(ui()->infoIconLabel->size()));
#if defined(PLATFORM_LINUX) && !defined(Q_OS_ANDROID)
ui()->platformNoteLabel->setText(QCoreApplication::translate("QtGui::AutostartOptionPage", "This is achieved by adding a *.desktop file under <i>~/.config/autostart</i> so the setting only affects the current user."));
#elif defined(PLATFORM_WINDOWS)
ui()->platformNoteLabel->setText(QCoreApplication::translate("QtGui::AutostartOptionPage", "This is achieved by adding a registry key under <i>HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run</i> so the setting only affects the current user. Note that the startup entry is invalidated when moving <i>syncthingtray.exe</i>."));
#else
ui()->platformNoteLabel->setText(QCoreApplication::translate("QtGui::AutostartOptionPage", "This feature has not been implemented for your platform (yet)."));
ui()->autostartCheckBox->setEnabled(false);
#endif
return widget;
}
/*!
* \brief Returns whether the application is launched on startup.
* \remarks
* - Only implemented under Linux/Windows. Always returns false on other platforms.
* - Does not check whether the startup entry is functional (eg. the specified path is still valid).
* -
*/
bool isAutostartEnabled()
{
#if defined(PLATFORM_LINUX) && !defined(Q_OS_ANDROID)
QFile desktopFile(QStandardPaths::locate(QStandardPaths::ConfigLocation, QStringLiteral("autostart/" PROJECT_NAME ".desktop")));
// check whether the file can be opeed and whether it is enabled but prevent reading large files
if(desktopFile.open(QFile::ReadOnly) && (desktopFile.size() > (5 * 1024) || !desktopFile.readAll().contains("Hidden=true"))) {
return true;
}
return false;
#elif defined(PLATFORM_WINDOWS)
QSettings settings(QStringLiteral("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"), QSettings::NativeFormat);
return settings.contains(QStringLiteral(PROJECT_NAME));
#else
return false;
#endif
}
/*!
* \brief Sets whether the application is launchedc on startup.
* \remarks
* - Only implemented under Linux/Windows. Does nothing on other platforms.
* - If a startup entry already exists and \a enabled is true, this function will ensure the path of the existing entry is valid.
* - If no startup entry could be detected via isAutostartEnabled() and \a enabled is false this function doesn't touch anything.
*/
bool setAutostartEnabled(bool enabled)
{
if(!isAutostartEnabled() && !enabled) {
return true;
}
#if defined(PLATFORM_LINUX) && !defined(Q_OS_ANDROID)
const QString configPath(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation));
if(configPath.isEmpty()) {
return !enabled;
}
if(enabled && !QDir().mkpath(configPath + QStringLiteral("/autostart"))) {
return false;
}
QFile desktopFile(configPath + QStringLiteral("/autostart/" PROJECT_NAME ".desktop"));
if(enabled) {
if(desktopFile.open(QFile::WriteOnly | QFile::Truncate)) {
desktopFile.write("[Desktop Entry]\n");
desktopFile.write("Name=" APP_NAME "\n");
desktopFile.write("Exec=");
desktopFile.write(QCoreApplication::applicationFilePath().toLocal8Bit().data());
desktopFile.write("\nComment=" APP_DESCRIPTION "\n");
desktopFile.write("Icon=" PROJECT_NAME "\n");
desktopFile.write("Type=Application\n");
desktopFile.write("Terminal=false\n");
desktopFile.write("X-GNOME-Autostart-Delay=0\n");
desktopFile.write("X-GNOME-Autostart-enabled=true");
return desktopFile.error() == QFile::NoError && desktopFile.flush();
}
return false;
} else {
return !desktopFile.exists() || desktopFile.remove();
}
#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("\\")));
} else {
settings.remove(QStringLiteral(PROJECT_NAME));
}
settings.sync();
return true;
#endif
}
bool AutostartOptionPage::apply()
{
bool ok = true;
if(hasBeenShown()) {
if(!setAutostartEnabled(ui()->autostartCheckBox->isChecked())) {
errors() << QCoreApplication::translate("QtGui::AutostartOptionPage", "unable to modify startup entry");
ok = false;
}
}
return true;
return ok;
}
void AutostartOptionPage::reset()
{
if(hasBeenShown()) {
ui()->autostartCheckBox->setChecked(isAutostartEnabled());
}
}
// LauncherOptionPage
LauncherOptionPage::LauncherOptionPage(QWidget *parentWidget) :
LauncherOptionPageBase(parentWidget),
m_kill(false)
{}
LauncherOptionPage::~LauncherOptionPage()
{
for(const QMetaObject::Connection &connection : m_connections) {
QObject::disconnect(connection);
}
}
QWidget *LauncherOptionPage::setupWidget()
{
auto *widget = LauncherOptionPageBase::setupWidget();
ui()->syncthingPathSelection->provideCustomFileMode(QFileDialog::ExistingFile);
ui()->logTextEdit->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
m_connections << QObject::connect(&syncthingProcess(), &SyncthingProcess::readyRead, bind(&LauncherOptionPage::handleSyncthingReadyRead, this));
m_connections << QObject::connect(&syncthingProcess(), static_cast<void(SyncthingProcess::*)(int exitCode, QProcess::ExitStatus exitStatus)>(&SyncthingProcess::finished), bind(&LauncherOptionPage::handleSyncthingExited, this, _1, _2));
QObject::connect(ui()->launchNowPushButton, &QPushButton::clicked, bind(&LauncherOptionPage::launch, this));
QObject::connect(ui()->stopPushButton, &QPushButton::clicked, bind(&LauncherOptionPage::stop, this));
const bool running = syncthingProcess().state() != QProcess::NotRunning;
ui()->launchNowPushButton->setHidden(running);
ui()->stopPushButton->setHidden(!running);
return widget;
}
bool LauncherOptionPage::apply()
{
if(hasBeenShown()) {
Settings::launchSynchting() = ui()->enabledCheckBox->isChecked(),
Settings::syncthingPath() = ui()->syncthingPathSelection->lineEdit()->text(),
Settings::syncthingArgs() = ui()->argumentsLineEdit->text();
}
return true;
}
void LauncherOptionPage::reset()
{
if(hasBeenShown()) {
ui()->enabledCheckBox->setChecked(Settings::launchSynchting());
ui()->syncthingPathSelection->lineEdit()->setText(Settings::syncthingPath());
ui()->argumentsLineEdit->setText(Settings::syncthingArgs());
}
}
void LauncherOptionPage::handleSyncthingReadyRead()
{
if(hasBeenShown()) {
QTextCursor cursor = ui()->logTextEdit->textCursor();
cursor.movePosition(QTextCursor::End);
cursor.insertText(QString::fromLocal8Bit(syncthingProcess().readAll()));
if(ui()->ensureCursorVisibleCheckBox->isChecked()) {
ui()->logTextEdit->ensureCursorVisible();
}
}
}
void LauncherOptionPage::handleSyncthingExited(int exitCode, QProcess::ExitStatus exitStatus)
{
if(hasBeenShown()) {
QTextCursor cursor = ui()->logTextEdit->textCursor();
cursor.movePosition(QTextCursor::End);
switch(exitStatus) {
case QProcess::NormalExit:
cursor.insertText(QCoreApplication::translate("QtGui::LauncherOptionPage", "Syncthing existed with exit code %1\n").arg(exitCode));
break;
case QProcess::CrashExit:
cursor.insertText(QCoreApplication::translate("QtGui::LauncherOptionPage", "Syncthing crashed with exit code %1\n").arg(exitCode));
break;
}
ui()->stopPushButton->hide();
ui()->launchNowPushButton->show();
}
}
void LauncherOptionPage::launch()
{
if(hasBeenShown()) {
apply();
if(syncthingProcess().state() == QProcess::NotRunning) {
ui()->launchNowPushButton->hide();
ui()->stopPushButton->show();
m_kill = false;
syncthingProcess().startSyncthing();
}
}
}
void LauncherOptionPage::stop()
{
if(hasBeenShown()) {
if(syncthingProcess().state() != QProcess::NotRunning) {
if(m_kill) {
syncthingProcess().kill();
} else {
m_kill = true;
syncthingProcess().terminate();
}
}
}
}
@ -214,7 +452,7 @@ WebViewOptionPage::WebViewOptionPage(QWidget *parentWidget) :
WebViewOptionPage::~WebViewOptionPage()
{}
#if !defined(SYNCTHINGTRAY_USE_WEBENGINE) && !defined(SYNCTHINGTRAY_USE_WEBKIT)
#ifdef SYNCTHINGTRAY_NO_WEBVIEW
QWidget *WebViewOptionPage::setupWidget()
{
auto *label = new QLabel;
@ -227,7 +465,7 @@ QWidget *WebViewOptionPage::setupWidget()
bool WebViewOptionPage::apply()
{
#if defined(SYNCTHINGTRAY_USE_WEBENGINE) || defined(SYNCTHINGTRAY_USE_WEBKIT)
#ifndef SYNCTHINGTRAY_NO_WEBVIEW
if(hasBeenShown()) {
webViewDisabled() = ui()->disableCheckBox->isChecked();
webViewZoomFactor() = ui()->zoomDoubleSpinBox->value();
@ -239,7 +477,7 @@ bool WebViewOptionPage::apply()
void WebViewOptionPage::reset()
{
#if defined(SYNCTHINGTRAY_USE_WEBENGINE) || defined(SYNCTHINGTRAY_USE_WEBKIT)
#ifndef SYNCTHINGTRAY_NO_WEBVIEW
if(hasBeenShown()) {
ui()->disableCheckBox->setChecked(webViewDisabled());
ui()->zoomDoubleSpinBox->setValue(webViewZoomFactor());
@ -257,9 +495,7 @@ SettingsDialog::SettingsDialog(Data::SyncthingConnection *connection, QWidget *p
category = new OptionCategory(this);
category->setDisplayName(tr("Tray"));
category->assignPages(QList<Dialogs::OptionPage *>()
<< new ConnectionOptionPage(connection) << new NotificationsOptionPage
<< new AppearanceOptionPage << new AutostartOptionPage);
category->assignPages(QList<Dialogs::OptionPage *>() << new ConnectionOptionPage(connection) << new NotificationsOptionPage << new AppearanceOptionPage);
category->setIcon(QIcon(QStringLiteral(":/icons/hicolor/scalable/app/syncthingtray.svg")));
categories << category;
@ -269,6 +505,12 @@ SettingsDialog::SettingsDialog(Data::SyncthingConnection *connection, QWidget *p
category->setIcon(QIcon::fromTheme(QStringLiteral("internet-web-browser"), QIcon(QStringLiteral(":/icons/hicolor/scalable/apps/internet-web-browser.svg"))));
categories << category;
category = new OptionCategory(this);
category->setDisplayName(tr("Startup"));
category->assignPages(QList<Dialogs::OptionPage *>() << new AutostartOptionPage << new LauncherOptionPage);
category->setIcon(QIcon::fromTheme(QStringLiteral("system-run"), QIcon(QStringLiteral(":/icons/hicolor/scalable/apps/system-run.svg"))));
categories << category;
categories << Settings::qtSettings().category();
categoryModel()->setCategories(categories);

View File

@ -6,6 +6,7 @@
#include <qtutilities/settingsdialog/qtsettings.h>
#include <QWidget>
#include <QProcess>
namespace Settings {
class KnownFieldModel;
@ -33,9 +34,20 @@ DECLARE_UI_FILE_BASED_OPTION_PAGE(NotificationsOptionPage)
DECLARE_UI_FILE_BASED_OPTION_PAGE(AppearanceOptionPage)
DECLARE_UI_FILE_BASED_OPTION_PAGE(AutostartOptionPage)
DECLARE_UI_FILE_BASED_OPTION_PAGE_CUSTOM_SETUP(AutostartOptionPage)
#if defined(SYNCTHINGTRAY_USE_WEBENGINE) || defined(SYNCTHINGTRAY_USE_WEBKIT)
BEGIN_DECLARE_UI_FILE_BASED_OPTION_PAGE(LauncherOptionPage)
private:
DECLARE_SETUP_WIDGETS
void handleSyncthingReadyRead();
void handleSyncthingExited(int exitCode, QProcess::ExitStatus exitStatus);
void launch();
void stop();
QList<QMetaObject::Connection> m_connections;
bool m_kill;
END_DECLARE_OPTION_PAGE
#ifndef SYNCTHINGTRAY_NO_WEBVIEW
DECLARE_UI_FILE_BASED_OPTION_PAGE(WebViewOptionPage)
#else
DECLARE_OPTION_PAGE(WebViewOptionPage)

View File

@ -23,7 +23,8 @@ TrayIcon::TrayIcon(QObject *parent) :
QSystemTrayIcon(parent),
m_size(QSize(128, 128)),
m_statusIconDisconnected(QIcon(renderSvgImage(QStringLiteral(":/icons/hicolor/scalable/status/syncthing-disconnected.svg")))),
m_statusIconDefault(QIcon(renderSvgImage(QStringLiteral(":/icons/hicolor/scalable/status/syncthing-default.svg")))),
m_statusIconIdling(QIcon(renderSvgImage(QStringLiteral(":/icons/hicolor/scalable/status/syncthing-ok.svg")))),
m_statusIconScanning(QIcon(renderSvgImage(QStringLiteral(":/icons/hicolor/scalable/status/syncthing-default.svg")))),
m_statusIconNotify(QIcon(renderSvgImage(QStringLiteral(":/icons/hicolor/scalable/status/syncthing-notify.svg")))),
m_statusIconPause(QIcon(renderSvgImage(QStringLiteral(":/icons/hicolor/scalable/status/syncthing-pause.svg")))),
m_statusIconSync(QIcon(renderSvgImage(QStringLiteral(":/icons/hicolor/scalable/status/syncthing-sync.svg")))),
@ -54,18 +55,16 @@ void TrayIcon::handleActivated(QSystemTrayIcon::ActivationReason reason)
case QSystemTrayIcon::Context:
// can't catch that event on Plasma 5 anyways
break;
case QSystemTrayIcon::MiddleClick:
m_trayMenu.widget()->showWebUi();
break;
case QSystemTrayIcon::Trigger:
// either show web UI or context menu
if(false) {
m_trayMenu.widget()->showWebUi();
} else {
m_trayMenu.resize(m_trayMenu.sizeHint());
// when showing the menu manually
// move the menu to the closest of the currently available screen
// this implies that the tray icon is located near the edge of the screen; otherwise this behavior makes no sense
cornerWidget(&m_trayMenu);
m_trayMenu.show();
}
m_trayMenu.resize(m_trayMenu.sizeHint());
// when showing the menu manually
// move the menu to the closest of the currently available screen
// this implies that the tray icon is located near the edge of the screen; otherwise this behavior makes no sense
cornerWidget(&m_trayMenu);
m_trayMenu.show();
break;
default:
;
@ -96,9 +95,13 @@ void TrayIcon::updateStatusIconAndText(SyncthingStatus status)
showMessage(QCoreApplication::applicationName(), tr("Disconnected from Syncthing"), QSystemTrayIcon::Warning);
}
break;
case SyncthingStatus::Default:
setIcon(m_statusIconDefault);
setToolTip(tr("Syncthing is running"));
case SyncthingStatus::Idle:
setIcon(m_statusIconIdling);
setToolTip(tr("Syncthing is idling"));
break;
case SyncthingStatus::Scanning:
setIcon(m_statusIconScanning);
setToolTip(tr("Syncthing is scanning"));
break;
case SyncthingStatus::NotificationsAvailable:
setIcon(m_statusIconNotify);

View File

@ -35,7 +35,8 @@ private:
const QSize m_size;
const QIcon m_statusIconDisconnected;
const QIcon m_statusIconDefault;
const QIcon m_statusIconIdling;
const QIcon m_statusIconScanning;
const QIcon m_statusIconNotify;
const QIcon m_statusIconPause;
const QIcon m_statusIconSync;

View File

@ -24,6 +24,7 @@
#include <QDir>
#include <QTextBrowser>
#include <QStringBuilder>
#include <QFontDatabase>
#include <functional>
@ -56,34 +57,38 @@ TrayWidget::TrayWidget(TrayMenu *parent) :
m_ui->dirsTreeView->setModel(&m_dirModel);
m_ui->devsTreeView->setModel(&m_devModel);
// apply settings, this also establishes the connection to Syncthing
applySettings();
// setup sync-all button
auto *cornerFrame = new QFrame(this);
cornerFrame->setFrameStyle(QFrame::StyledPanel), cornerFrame->setFrameShadow(QFrame::Sunken);
auto *cornerFrameLayout = new QHBoxLayout(cornerFrame);
m_cornerFrame = new QFrame(this);
auto *cornerFrameLayout = new QHBoxLayout(m_cornerFrame);
cornerFrameLayout->setSpacing(0), cornerFrameLayout->setMargin(0);
cornerFrameLayout->addStretch();
cornerFrame->setLayout(cornerFrameLayout);
auto *viewIdButton = new QPushButton(cornerFrame);
//cornerFrameLayout->addStretch();
m_cornerFrame->setLayout(cornerFrameLayout);
auto *viewIdButton = new QPushButton(m_cornerFrame);
viewIdButton->setToolTip(tr("View own device ID"));
viewIdButton->setIcon(QIcon::fromTheme(QStringLiteral("view-barcode"), QIcon(QStringLiteral(":/icons/hicolor/scalable/actions/view-barcode.svg"))));
viewIdButton->setFlat(true);
cornerFrameLayout->addWidget(viewIdButton);
auto *showLogButton = new QPushButton(cornerFrame);
auto *restartButton = new QPushButton(m_cornerFrame);
restartButton->setToolTip(tr("Restart Syncthing"));
restartButton->setIcon(QIcon::fromTheme(QStringLiteral("system-reboot"), QIcon(QStringLiteral(":/icons/hicolor/scalable/actions/view-refresh.svg"))));
restartButton->setFlat(true);
connect(restartButton, &QPushButton::clicked, &m_connection, &SyncthingConnection::restart);
cornerFrameLayout->addWidget(restartButton);
auto *showLogButton = new QPushButton(m_cornerFrame);
showLogButton->setToolTip(tr("Show Syncthing log"));
showLogButton->setIcon(QIcon::fromTheme(QStringLiteral("text-x-generic"), QIcon(QStringLiteral(":/icons/hicolor/scalable/actions/text-x-generic.svg"))));
showLogButton->setIcon(QIcon::fromTheme(QStringLiteral("text-x-generic"), QIcon(QStringLiteral(":/icons/hicolor/scalable/mimetypes/text-x-generic.svg"))));
showLogButton->setFlat(true);
connect(showLogButton, &QPushButton::clicked, this, &TrayWidget::showLog);
cornerFrameLayout->addWidget(showLogButton);
auto *scanAllButton = new QPushButton(cornerFrame);
auto *scanAllButton = new QPushButton(m_cornerFrame);
scanAllButton->setToolTip(tr("Rescan all directories"));
scanAllButton->setIcon(QIcon::fromTheme(QStringLiteral("folder-sync"), QIcon(QStringLiteral(":/icons/hicolor/scalable/actions/folder-sync.svg"))));
scanAllButton->setFlat(true);
cornerFrameLayout->addWidget(scanAllButton);
m_ui->tabWidget->setCornerWidget(cornerFrame, Qt::BottomRightCorner);
m_ui->tabWidget->setCornerWidget(m_cornerFrame, Qt::BottomRightCorner);
// apply settings, this also establishes the connection to Syncthing
applySettings();
m_ui->trafficIconLabel->setPixmap(QIcon::fromTheme(QStringLiteral("network-card"), QIcon(QStringLiteral(":/icons/hicolor/scalable/devices/network-card.svg"))).pixmap(32));
@ -167,7 +172,7 @@ void TrayWidget::showWebUi()
void TrayWidget::showOwnDeviceId()
{
auto *dlg = new QDialog(this);
auto *dlg = new QWidget(this, Qt::Window);
dlg->setWindowTitle(tr("Own device ID") + QStringLiteral(" - " APP_NAME));
dlg->setWindowIcon(QIcon(QStringLiteral(":/icons/hicolor/scalable/app/syncthingtray.svg")));
dlg->setAttribute(Qt::WA_DeleteOnClose);
@ -189,7 +194,10 @@ void TrayWidget::showOwnDeviceId()
copyPushButton->setText(tr("Copy to clipboard"));
connect(copyPushButton, &QPushButton::clicked, bind(&QClipboard::setText, QGuiApplication::clipboard(), m_connection.myId(), QClipboard::Clipboard));
layout->addWidget(copyPushButton);
m_connection.requestQrCode(m_connection.myId(), bind(&QLabel::setPixmap, pixmapLabel, placeholders::_1));
connect(dlg, &QWidget::destroyed,
bind(static_cast<bool(*)(const QMetaObject::Connection &)>(&QObject::disconnect),
m_connection.requestQrCode(m_connection.myId(), bind(&QLabel::setPixmap, pixmapLabel, placeholders::_1))
));
dlg->setLayout(layout);
dlg->show();
centerWidget(dlg);
@ -201,18 +209,23 @@ void TrayWidget::showOwnDeviceId()
void TrayWidget::showLog()
{
auto *dlg = new QDialog(this);
auto *dlg = new QWidget(this, Qt::Window);
dlg->setWindowTitle(tr("Log") + QStringLiteral(" - " APP_NAME));
dlg->setWindowIcon(QIcon(QStringLiteral(":/icons/hicolor/scalable/app/syncthingtray.svg")));
dlg->setAttribute(Qt::WA_DeleteOnClose);
auto *layout = new QVBoxLayout(dlg);
layout->setAlignment(Qt::AlignCenter);
auto *browser = new QTextBrowser(dlg);
m_connection.requestLog([browser] (const std::vector<SyncthingLogEntry> &entries) {
for(const SyncthingLogEntry &entry : entries) {
browser->append(entry.when % QChar(':') % QChar(' ') % QChar('\n') % entry.message % QChar('\n'));
}
});
connect(dlg, &QWidget::destroyed,
bind(static_cast<bool(*)(const QMetaObject::Connection &)>(&QObject::disconnect),
m_connection.requestLog([browser] (const std::vector<SyncthingLogEntry> &entries) {
for(const SyncthingLogEntry &entry : entries) {
browser->append(entry.when % QChar(':') % QChar(' ') % QChar('\n') % entry.message % QChar('\n'));
}
})
));
browser->setReadOnly(true);
browser->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
layout->addWidget(browser);
dlg->setLayout(layout);
dlg->show();
@ -232,7 +245,8 @@ void TrayWidget::updateStatusButton(SyncthingStatus status)
m_ui->statusPushButton->setToolTip(tr("Not connected to Syncthing, click to connect"));
m_ui->statusPushButton->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh"), QIcon(QStringLiteral(":/icons/hicolor/scalable/actions/view-refresh.svg"))));
break;
case SyncthingStatus::Default:
case SyncthingStatus::Idle:
case SyncthingStatus::Scanning:
case SyncthingStatus::NotificationsAvailable:
case SyncthingStatus::Synchronizing:
m_ui->statusPushButton->setText(tr("Pause"));
@ -262,6 +276,13 @@ void TrayWidget::applySettings()
if(Settings::showTraffic()) {
updateTraffic();
}
m_ui->trafficFrame->setFrameStyle(Settings::frameStyle());
m_ui->buttonsFrame->setFrameStyle(Settings::frameStyle());
if(QApplication::style() && !QApplication::style()->objectName().compare(QLatin1String("adwaita"), Qt::CaseInsensitive)) {
m_cornerFrame->setFrameStyle(QFrame::NoFrame);
} else {
m_cornerFrame->setFrameStyle(Settings::frameStyle());
}
}
void TrayWidget::openDir(const QModelIndex &dirIndex)
@ -299,7 +320,8 @@ void TrayWidget::changeStatus()
case SyncthingStatus::Disconnected:
m_connection.connect();
break;
case SyncthingStatus::Default:
case SyncthingStatus::Idle:
case SyncthingStatus::Scanning:
case SyncthingStatus::NotificationsAvailable:
case SyncthingStatus::Synchronizing:
m_connection.pauseAllDevs();

View File

@ -6,11 +6,14 @@
#include "../data/syncthingconnection.h"
#include "../data/syncthingdirectorymodel.h"
#include "../data/syncthingdevicemodel.h"
#include "../data/syncthingprocess.h"
#include <QWidget>
#include <memory>
QT_FORWARD_DECLARE_CLASS(QFrame)
namespace ApplicationUtilities {
class QtConfigArguments;
}
@ -65,6 +68,7 @@ private:
#ifndef SYNCTHINGTRAY_NO_WEBVIEW
WebViewDialog *m_webViewDlg;
#endif
QFrame *m_cornerFrame;
Data::SyncthingConnection m_connection;
Data::SyncthingDirectoryModel m_dirModel;
Data::SyncthingDeviceModel m_devModel;

View File

@ -1,4 +1,4 @@
#if defined(SYNCTHINGTRAY_USE_WEBENGINE) || defined(SYNCTHINGTRAY_USE_WEBKIT)
#ifndef SYNCTHINGTRAY_NO_WEBVIEW
#include "./webpage.h"
#include "../application/settings.h"
@ -29,7 +29,7 @@ WebPage::WebPage(WEB_VIEW_PROVIDER *view) :
WEB_PAGE_PROVIDER(view),
m_view(view)
{
#if defined(SYNCTHINGTRAY_USE_WEBENGINE)
#ifdef SYNCTHINGTRAY_USE_WEBENGINE
settings()->setAttribute(QWebEngineSettings::JavascriptCanOpenWindows, true);
connect(this, &WebPage::authenticationRequired, this, static_cast<void(WebPage::*)(const QUrl &, QAuthenticator *)>(&WebPage::supplyCredentials));
#else
@ -40,7 +40,7 @@ WebPage::WebPage(WEB_VIEW_PROVIDER *view) :
#endif
if(!m_view) {
// delegate to external browser if no view is assigned
#if defined(SYNCTHINGTRAY_USE_WEBENGINE)
#ifdef SYNCTHINGTRAY_USE_WEBENGINE
connect(this, &WebPage::urlChanged, this, &WebPage::delegateToExternalBrowser);
#else
connect(this->mainFrame(), &QWebFrame::urlChanged, this, &WebPage::delegateToExternalBrowser);
@ -109,4 +109,4 @@ void WebPage::handleSslErrors(QNetworkReply *reply, const QList<QSslError> &erro
}
#endif // defined(SYNCTHINGTRAY_USE_WEBENGINE) || defined(SYNCTHINGTRAY_USE_WEBKIT)
#endif // SYNCTHINGTRAY_NO_WEBVIEW

View File

@ -1,6 +1,6 @@
#ifndef WEBPAGE_H
#define WEBPAGE_H
#if defined(SYNCTHINGTRAY_USE_WEBENGINE) || defined(SYNCTHINGTRAY_USE_WEBKIT)
#ifndef SYNCTHINGTRAY_NO_WEBVIEW
#include "./webviewprovider.h"
@ -44,5 +44,5 @@ private:
}
#endif // defined(SYNCTHINGTRAY_USE_WEBENGINE) || defined(SYNCTHINGTRAY_USE_WEBKIT)
#endif // SYNCTHINGTRAY_NO_WEBVIEW
#endif // WEBPAGE_H

View File

@ -25,5 +25,6 @@
<file>icons/hicolor/scalable/places/folder-open.svg</file>
<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>
</qresource>
</RCC>

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg width="32" version="1.1" xmlns="http://www.w3.org/2000/svg" height="32" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape">
<defs id="defs5455">
<linearGradient inkscape:collect="always" id="linearGradient4293">
<stop id="stop4295"/>
<stop offset="1" style="stop-opacity:0" id="stop4297"/>
</linearGradient>
<linearGradient inkscape:collect="always" id="linearGradient4303-6">
<stop style="stop-color:#c6cdd1" id="stop4305-7"/>
<stop offset="1" style="stop-color:#e0e5e7" id="stop4307-0"/>
</linearGradient>
<linearGradient inkscape:collect="always" id="linearGradient4298">
<stop style="stop-color:#42a603" id="stop4300"/>
<stop offset="1" style="stop-color:#78da06" id="stop4302"/>
</linearGradient>
<linearGradient inkscape:collect="always" xlink:href="#linearGradient4298" id="linearGradient4308" y1="539.79797" y2="527.79797" x2="0" gradientUnits="userSpaceOnUse"/>
<linearGradient inkscape:collect="always" id="linearGradient4643-8" xlink:href="#linearGradient4303-6" y1="543.79797" y2="502.65509" x2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.66666726 0 0 0.63518419 141.19014 191.51873)"/>
<linearGradient inkscape:collect="always" id="linearGradient4183" xlink:href="#linearGradient4293" y1="525.79797" y2="540.79797" x1="391.57144" gradientUnits="userSpaceOnUse" x2="406.57147" gradientTransform="matrix(1 0 0 1 12.999989 -6.99997)"/>
<linearGradient inkscape:collect="always" xlink:href="#linearGradient4293" id="linearGradient4256" y1="11" x1="5" y2="27" x2="21" gradientUnits="userSpaceOnUse"/>
</defs>
<metadata id="metadata5458"/>
<g inkscape:label="Capa 1" inkscape:groupmode="layer" id="layer1" transform="matrix(1 0 0 1 -384.57143 -515.798)">
<g id="g4244" transform="matrix(1 0 0 1 -12.999996 6.999998)">
<rect width="32" x="397.57144" y="510.79797" rx="0" height="28" style="fill:url(#linearGradient4643-8)" id="rect4641-5"/>
<path inkscape:connector-curvature="0" style="fill:url(#linearGradient4183);opacity:0.2;fill-rule:evenodd" id="path4167" d="m 398.57142,536.79803 30,-20 1.00001,1 -1e-5,20.99997 -29,3e-5 z"/>
<rect width="31.999983" x="397.57141" y="537.79797" height="1" style="fill:#99a1a7" id="rect4645-7-7"/>
<rect width="32.00001" x="397.57141" y="510.79797" height="4" style="fill:#566069" id="rect4647-8"/>
<rect width="31.999968" x="397.57141" y="514.79797" height="1" style="fill:#3daee9" id="rect4649-8"/>
<rect width="30" x="398.57141" y="516.79797" height="20.00003" style="fill:#ffffff" id="rect4653-5"/>
<rect width="2" x="426.57141" y="511.79797" rx="1" height="2" style="fill:#eff0f1" id="rect4661-1"/>
</g>
<path style="fill:url(#linearGradient4256);opacity:0.2;fill-rule:evenodd" id="path4242" d="M 21 18 L 12 24 L 18 30 L 25 30 L 32 30 L 21 18 z " transform="matrix(1 0 0 1 384.57143 515.798)"/>
<path inkscape:connector-curvature="0" style="fill:url(#linearGradient4308);fill-rule:evenodd" id="path4237-9" d="m 396.57141,527.79796 0,12 9,-6 z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -4,119 +4,124 @@
<context>
<name>Data::SyncthingConnection</name>
<message>
<location filename="../data/syncthingconnection.cpp" line="120"/>
<location filename="../data/syncthingconnection.cpp" line="147"/>
<source>disconnected</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="122"/>
<location filename="../data/syncthingconnection.cpp" line="149"/>
<source>connected</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="124"/>
<location filename="../data/syncthingconnection.cpp" line="151"/>
<source>connected, notifications available</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="126"/>
<location filename="../data/syncthingconnection.cpp" line="153"/>
<source>connected, paused</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="128"/>
<location filename="../data/syncthingconnection.cpp" line="155"/>
<source>connected, synchronizing</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="130"/>
<location filename="../data/syncthingconnection.cpp" line="157"/>
<source>unknown</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="427"/>
<location filename="../data/syncthingconnection.cpp" line="459"/>
<source>Unable to parse Syncthing log: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="431"/>
<location filename="../data/syncthingconnection.cpp" line="463"/>
<source>Unable to request system log: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="452"/>
<location filename="../data/syncthingconnection.cpp" line="484"/>
<source>Unable to locate certificate used by Syncthing GUI.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="458"/>
<location filename="../data/syncthingconnection.cpp" line="490"/>
<source>Unable to load 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="590"/>
<location filename="../data/syncthingconnection.cpp" line="522"/>
<location filename="../data/syncthingconnection.cpp" line="622"/>
<source>Unable to parse Syncthing config: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="495"/>
<location filename="../data/syncthingconnection.cpp" line="595"/>
<location filename="../data/syncthingconnection.cpp" line="527"/>
<location filename="../data/syncthingconnection.cpp" line="627"/>
<source>Unable to request Syncthing config: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="670"/>
<location filename="../data/syncthingconnection.cpp" line="702"/>
<source>Unable to parse connections: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="675"/>
<location filename="../data/syncthingconnection.cpp" line="707"/>
<source>Unable to request connections: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="725"/>
<location filename="../data/syncthingconnection.cpp" line="762"/>
<source>Unable to parse directory statistics: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="730"/>
<location filename="../data/syncthingconnection.cpp" line="767"/>
<source>Unable to request directory statistics: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="767"/>
<location filename="../data/syncthingconnection.cpp" line="804"/>
<source>Unable to parse device statistics: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="772"/>
<location filename="../data/syncthingconnection.cpp" line="809"/>
<source>Unable to request device statistics: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="823"/>
<location filename="../data/syncthingconnection.cpp" line="860"/>
<source>Unable to parse Syncthing events: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="845"/>
<location filename="../data/syncthingconnection.cpp" line="882"/>
<source>Unable to request Syncthing events: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="1051"/>
<location filename="../data/syncthingconnection.cpp" line="1094"/>
<source>Unable to request rescan: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="1066"/>
<location filename="../data/syncthingconnection.cpp" line="1109"/>
<source>Unable to request pause/resume: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="395"/>
<location filename="../data/syncthingconnection.cpp" line="1124"/>
<source>Unable to request restart: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="427"/>
<source>Unable to request QR-Code: </source>
<translation type="unfinished"></translation>
</message>
@ -356,28 +361,73 @@
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/appearanceoptionpage.ui" line="23"/>
<location filename="../gui/appearanceoptionpage.ui" line="27"/>
<source>Menu size</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/appearanceoptionpage.ui" line="30"/>
<location filename="../gui/appearanceoptionpage.ui" line="34"/>
<source>Optional GUI elements</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/appearanceoptionpage.ui" line="37"/>
<location filename="../gui/appearanceoptionpage.ui" line="41"/>
<source>Traffic statistics</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/appearanceoptionpage.ui" line="56"/>
<source>x</source>
<location filename="../gui/appearanceoptionpage.ui" line="69"/>
<source> x </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/appearanceoptionpage.ui" line="76"/>
<source>px</source>
<location filename="../gui/appearanceoptionpage.ui" line="92"/>
<source> px</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/appearanceoptionpage.ui" line="104"/>
<source>Frame shape</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/appearanceoptionpage.ui" line="111"/>
<source>Frame shadow</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/appearanceoptionpage.ui" line="119"/>
<source>No frame</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/appearanceoptionpage.ui" line="124"/>
<source>Box</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/appearanceoptionpage.ui" line="129"/>
<source>Panel</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/appearanceoptionpage.ui" line="134"/>
<source>Styled panel</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/appearanceoptionpage.ui" line="143"/>
<source>Plain</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/appearanceoptionpage.ui" line="148"/>
<source>Raised</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/appearanceoptionpage.ui" line="153"/>
<source>Sunken</source>
<translation type="unfinished"></translation>
</message>
</context>
@ -389,8 +439,28 @@
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/autostartoptionpage.ui" line="23"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Not implemented yet&lt;/span&gt;&lt;/p&gt;&lt;p&gt;This will allow launching the tray when the desktop environment starts and to launch Syncthing when the tray is started.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<location filename="../gui/autostartoptionpage.ui" line="26"/>
<source>Start the tray icon when the desktop environment launches</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="238"/>
<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"/>
<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"/>
<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"/>
<source>unable to modify startup entry</source>
<translation type="unfinished"></translation>
</message>
</context>
@ -402,57 +472,57 @@
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/connectionoptionpage.ui" line="15"/>
<location filename="../gui/connectionoptionpage.ui" line="19"/>
<source>Syncthing URL</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/connectionoptionpage.ui" line="25"/>
<location filename="../gui/connectionoptionpage.ui" line="29"/>
<source>Authentication</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/connectionoptionpage.ui" line="38"/>
<location filename="../gui/connectionoptionpage.ui" line="42"/>
<source>User</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/connectionoptionpage.ui" line="72"/>
<location filename="../gui/connectionoptionpage.ui" line="76"/>
<source>disconnected</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/connectionoptionpage.ui" line="79"/>
<location filename="../gui/connectionoptionpage.ui" line="83"/>
<source>Status</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/connectionoptionpage.ui" line="86"/>
<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="100"/>
<location filename="../gui/connectionoptionpage.ui" line="104"/>
<source>API key</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/connectionoptionpage.ui" line="110"/>
<location filename="../gui/connectionoptionpage.ui" line="114"/>
<source>Insert values from local Syncthing configuration</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/connectionoptionpage.ui" line="48"/>
<location filename="../gui/connectionoptionpage.ui" line="52"/>
<source>Password</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="60"/>
<location filename="../gui/settingsdialog.cpp" line="70"/>
<source>Select Syncthing config file</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="67"/>
<location filename="../gui/settingsdialog.cpp" line="77"/>
<source>Unable to parse the Syncthing config file.</source>
<translation type="unfinished"></translation>
</message>
@ -493,6 +563,66 @@
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QtGui::LauncherOptionPage</name>
<message>
<location filename="../gui/launcheroptionpage.ui" line="14"/>
<source>Syncthing launcher</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/launcheroptionpage.ui" line="26"/>
<source>Launch Syncthing when starting the tray icon</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/launcheroptionpage.ui" line="42"/>
<source>Syncthing executable</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/launcheroptionpage.ui" line="52"/>
<source>Arguments</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/launcheroptionpage.ui" line="86"/>
<source>Syncthing log (stdout/stderr)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/launcheroptionpage.ui" line="102"/>
<source>Apply and launch now</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/launcheroptionpage.ui" line="119"/>
<source>Stop launched instance</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/launcheroptionpage.ui" line="138"/>
<source>No log messages available yet</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/launcheroptionpage.ui" line="145"/>
<source>Ensure latest log is visible</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="409"/>
<source>Syncthing existed with exit code %1
</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="412"/>
<source>Syncthing crashed with exit code %1
</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QtGui::NotificationsOptionPage</name>
<message>
@ -501,27 +631,27 @@
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/notificationsoptionpage.ui" line="23"/>
<location filename="../gui/notificationsoptionpage.ui" line="30"/>
<source>Notify on</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/notificationsoptionpage.ui" line="30"/>
<location filename="../gui/notificationsoptionpage.ui" line="37"/>
<source>disconnect</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/notificationsoptionpage.ui" line="37"/>
<location filename="../gui/notificationsoptionpage.ui" line="44"/>
<source>internal errors</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/notificationsoptionpage.ui" line="44"/>
<source>Syncthing errors</source>
<location filename="../gui/notificationsoptionpage.ui" line="51"/>
<source>errors/notifications from Syncthing</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/notificationsoptionpage.ui" line="51"/>
<location filename="../gui/notificationsoptionpage.ui" line="58"/>
<source>sync complete</source>
<translation type="unfinished"></translation>
</message>
@ -529,12 +659,17 @@
<context>
<name>QtGui::SettingsDialog</name>
<message>
<location filename="../gui/settingsdialog.cpp" line="259"/>
<location filename="../gui/settingsdialog.cpp" line="497"/>
<source>Tray</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="267"/>
<location filename="../gui/settingsdialog.cpp" line="509"/>
<source>Startup</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="503"/>
<source>Web view</source>
<translation type="unfinished"></translation>
</message>
@ -542,67 +677,72 @@
<context>
<name>QtGui::TrayIcon</name>
<message>
<location filename="../gui/trayicon.cpp" line="33"/>
<location filename="../gui/trayicon.cpp" line="34"/>
<source>Web UI</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="34"/>
<location filename="../gui/trayicon.cpp" line="35"/>
<source>Settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="35"/>
<location filename="../gui/trayicon.cpp" line="36"/>
<source>About</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="37"/>
<location filename="../gui/trayicon.cpp" line="38"/>
<source>Close</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="78"/>
<source>Syncthing error</source>
<location filename="../gui/trayicon.cpp" line="77"/>
<source>Error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="85"/>
<location filename="../gui/trayicon.cpp" line="84"/>
<source>Syncthing notification</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="94"/>
<location filename="../gui/trayicon.cpp" line="93"/>
<source>Not connected to Syncthing</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="96"/>
<location filename="../gui/trayicon.cpp" line="95"/>
<source>Disconnected from Syncthing</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="101"/>
<source>Syncthing is running</source>
<location filename="../gui/trayicon.cpp" line="100"/>
<source>Syncthing is idling</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="105"/>
<location filename="../gui/trayicon.cpp" line="104"/>
<source>Syncthing is scanning</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="108"/>
<source>Notifications available</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="109"/>
<location filename="../gui/trayicon.cpp" line="112"/>
<source>At least one device is paused</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="113"/>
<location filename="../gui/trayicon.cpp" line="116"/>
<source>Synchronization is ongoing</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="122"/>
<location filename="../gui/trayicon.cpp" line="125"/>
<source>Synchronization complete</source>
<translation type="unfinished"></translation>
</message>
@ -616,7 +756,7 @@
</message>
<message>
<location filename="../gui/traywidget.ui" line="107"/>
<location filename="../gui/traywidget.cpp" line="230"/>
<location filename="../gui/traywidget.cpp" line="244"/>
<source>Connect</source>
<translation type="unfinished"></translation>
</message>
@ -643,8 +783,8 @@
<message>
<location filename="../gui/traywidget.ui" line="230"/>
<location filename="../gui/traywidget.ui" line="250"/>
<location filename="../gui/traywidget.cpp" line="322"/>
<location filename="../gui/traywidget.cpp" line="329"/>
<location filename="../gui/traywidget.cpp" line="345"/>
<location filename="../gui/traywidget.cpp" line="352"/>
<source>unknown</source>
<translation type="unfinished"></translation>
</message>
@ -670,13 +810,13 @@
</message>
<message>
<location filename="../gui/traywidget.ui" line="80"/>
<location filename="../gui/traywidget.cpp" line="132"/>
<location filename="../gui/traywidget.cpp" line="138"/>
<source>About</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.ui" line="134"/>
<location filename="../gui/traywidget.cpp" line="112"/>
<location filename="../gui/traywidget.cpp" line="118"/>
<source>Settings</source>
<translation type="unfinished"></translation>
</message>
@ -686,70 +826,75 @@
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="70"/>
<location filename="../gui/traywidget.cpp" line="67"/>
<source>View own device ID</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="81"/>
<location filename="../gui/traywidget.cpp" line="84"/>
<source>Rescan all directories</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="75"/>
<location filename="../gui/traywidget.cpp" line="78"/>
<source>Show Syncthing log</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="180"/>
<location filename="../gui/traywidget.cpp" line="72"/>
<source>Restart Syncthing</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="186"/>
<source>device ID is unknown</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="188"/>
<location filename="../gui/traywidget.cpp" line="194"/>
<source>Copy to clipboard</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="231"/>
<location filename="../gui/traywidget.cpp" line="245"/>
<source>Not connected to Syncthing, click to connect</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="237"/>
<location filename="../gui/traywidget.cpp" line="252"/>
<source>Pause</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="238"/>
<location filename="../gui/traywidget.cpp" line="253"/>
<source>Syncthing is running, click to pause all devices</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="243"/>
<location filename="../gui/traywidget.cpp" line="258"/>
<source>At least one device is paused, click to resume</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="242"/>
<location filename="../gui/traywidget.cpp" line="294"/>
<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"/>
<source>Continue</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="170"/>
<location filename="../gui/traywidget.cpp" line="176"/>
<source>Own device ID</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="204"/>
<location filename="../gui/traywidget.cpp" line="213"/>
<source>Log</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="272"/>
<source>The directly &lt;i&gt;%1&lt;/i&gt; does not exist on the local machine.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QtGui::WebViewDialog</name>
@ -763,7 +908,7 @@
<name>QtGui::WebViewOptionPage</name>
<message>
<location filename="../gui/webviewoptionpage.ui" line="14"/>
<location filename="../gui/settingsdialog.cpp" line="221"/>
<location filename="../gui/settingsdialog.cpp" line="459"/>
<source>General</source>
<translation type="unfinished"></translation>
</message>
@ -793,7 +938,7 @@
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="223"/>
<location filename="../gui/settingsdialog.cpp" line="461"/>
<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>
@ -802,22 +947,22 @@ The Web UI will be opened in the default web browser instead.</source>
<context>
<name>main</name>
<message>
<location filename="../application/main.cpp" line="62"/>
<location filename="../application/main.cpp" line="70"/>
<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="63"/>
<location filename="../application/main.cpp" line="71"/>
<source>Note that the settings dialog allows importing URL, credentials and API-key from the local Syncthing configuration.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../application/main.cpp" line="68"/>
<location filename="../application/main.cpp" line="76"/>
<source>The system tray is (currently) not available. You could open the tray menu as a regular window using the -w flag, though.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../application/main.cpp" line="72"/>
<location filename="../application/main.cpp" line="80"/>
<source>The Qt libraries have not been built with tray icon support. You could open the tray menu as a regular window using the -w flag, though.</source>
<translation type="unfinished"></translation>
</message>

View File

@ -4,119 +4,124 @@
<context>
<name>Data::SyncthingConnection</name>
<message>
<location filename="../data/syncthingconnection.cpp" line="120"/>
<location filename="../data/syncthingconnection.cpp" line="147"/>
<source>disconnected</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="122"/>
<location filename="../data/syncthingconnection.cpp" line="149"/>
<source>connected</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="124"/>
<location filename="../data/syncthingconnection.cpp" line="151"/>
<source>connected, notifications available</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="126"/>
<location filename="../data/syncthingconnection.cpp" line="153"/>
<source>connected, paused</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="128"/>
<location filename="../data/syncthingconnection.cpp" line="155"/>
<source>connected, synchronizing</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="130"/>
<location filename="../data/syncthingconnection.cpp" line="157"/>
<source>unknown</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="427"/>
<location filename="../data/syncthingconnection.cpp" line="459"/>
<source>Unable to parse Syncthing log: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="431"/>
<location filename="../data/syncthingconnection.cpp" line="463"/>
<source>Unable to request system log: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="452"/>
<location filename="../data/syncthingconnection.cpp" line="484"/>
<source>Unable to locate certificate used by Syncthing GUI.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="458"/>
<location filename="../data/syncthingconnection.cpp" line="490"/>
<source>Unable to load 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="590"/>
<location filename="../data/syncthingconnection.cpp" line="522"/>
<location filename="../data/syncthingconnection.cpp" line="622"/>
<source>Unable to parse Syncthing config: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="495"/>
<location filename="../data/syncthingconnection.cpp" line="595"/>
<location filename="../data/syncthingconnection.cpp" line="527"/>
<location filename="../data/syncthingconnection.cpp" line="627"/>
<source>Unable to request Syncthing config: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="670"/>
<location filename="../data/syncthingconnection.cpp" line="702"/>
<source>Unable to parse connections: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="675"/>
<location filename="../data/syncthingconnection.cpp" line="707"/>
<source>Unable to request connections: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="725"/>
<location filename="../data/syncthingconnection.cpp" line="762"/>
<source>Unable to parse directory statistics: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="730"/>
<location filename="../data/syncthingconnection.cpp" line="767"/>
<source>Unable to request directory statistics: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="767"/>
<location filename="../data/syncthingconnection.cpp" line="804"/>
<source>Unable to parse device statistics: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="772"/>
<location filename="../data/syncthingconnection.cpp" line="809"/>
<source>Unable to request device statistics: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="823"/>
<location filename="../data/syncthingconnection.cpp" line="860"/>
<source>Unable to parse Syncthing events: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="845"/>
<location filename="../data/syncthingconnection.cpp" line="882"/>
<source>Unable to request Syncthing events: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="1051"/>
<location filename="../data/syncthingconnection.cpp" line="1094"/>
<source>Unable to request rescan: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="1066"/>
<location filename="../data/syncthingconnection.cpp" line="1109"/>
<source>Unable to request pause/resume: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="395"/>
<location filename="../data/syncthingconnection.cpp" line="1124"/>
<source>Unable to request restart: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="427"/>
<source>Unable to request QR-Code: </source>
<translation type="unfinished"></translation>
</message>
@ -356,28 +361,73 @@
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/appearanceoptionpage.ui" line="23"/>
<location filename="../gui/appearanceoptionpage.ui" line="27"/>
<source>Menu size</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/appearanceoptionpage.ui" line="30"/>
<location filename="../gui/appearanceoptionpage.ui" line="34"/>
<source>Optional GUI elements</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/appearanceoptionpage.ui" line="37"/>
<location filename="../gui/appearanceoptionpage.ui" line="41"/>
<source>Traffic statistics</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/appearanceoptionpage.ui" line="56"/>
<source>x</source>
<location filename="../gui/appearanceoptionpage.ui" line="69"/>
<source> x </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/appearanceoptionpage.ui" line="76"/>
<source>px</source>
<location filename="../gui/appearanceoptionpage.ui" line="92"/>
<source> px</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/appearanceoptionpage.ui" line="104"/>
<source>Frame shape</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/appearanceoptionpage.ui" line="111"/>
<source>Frame shadow</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/appearanceoptionpage.ui" line="119"/>
<source>No frame</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/appearanceoptionpage.ui" line="124"/>
<source>Box</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/appearanceoptionpage.ui" line="129"/>
<source>Panel</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/appearanceoptionpage.ui" line="134"/>
<source>Styled panel</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/appearanceoptionpage.ui" line="143"/>
<source>Plain</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/appearanceoptionpage.ui" line="148"/>
<source>Raised</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/appearanceoptionpage.ui" line="153"/>
<source>Sunken</source>
<translation type="unfinished"></translation>
</message>
</context>
@ -389,8 +439,28 @@
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/autostartoptionpage.ui" line="23"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Not implemented yet&lt;/span&gt;&lt;/p&gt;&lt;p&gt;This will allow launching the tray when the desktop environment starts and to launch Syncthing when the tray is started.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<location filename="../gui/autostartoptionpage.ui" line="26"/>
<source>Start the tray icon when the desktop environment launches</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="238"/>
<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"/>
<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"/>
<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"/>
<source>unable to modify startup entry</source>
<translation type="unfinished"></translation>
</message>
</context>
@ -402,57 +472,57 @@
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/connectionoptionpage.ui" line="15"/>
<location filename="../gui/connectionoptionpage.ui" line="19"/>
<source>Syncthing URL</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/connectionoptionpage.ui" line="25"/>
<location filename="../gui/connectionoptionpage.ui" line="29"/>
<source>Authentication</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/connectionoptionpage.ui" line="38"/>
<location filename="../gui/connectionoptionpage.ui" line="42"/>
<source>User</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/connectionoptionpage.ui" line="72"/>
<location filename="../gui/connectionoptionpage.ui" line="76"/>
<source>disconnected</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/connectionoptionpage.ui" line="79"/>
<location filename="../gui/connectionoptionpage.ui" line="83"/>
<source>Status</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/connectionoptionpage.ui" line="86"/>
<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="100"/>
<location filename="../gui/connectionoptionpage.ui" line="104"/>
<source>API key</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/connectionoptionpage.ui" line="110"/>
<location filename="../gui/connectionoptionpage.ui" line="114"/>
<source>Insert values from local Syncthing configuration</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/connectionoptionpage.ui" line="48"/>
<location filename="../gui/connectionoptionpage.ui" line="52"/>
<source>Password</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="60"/>
<location filename="../gui/settingsdialog.cpp" line="70"/>
<source>Select Syncthing config file</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="67"/>
<location filename="../gui/settingsdialog.cpp" line="77"/>
<source>Unable to parse the Syncthing config file.</source>
<translation type="unfinished"></translation>
</message>
@ -493,6 +563,66 @@
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QtGui::LauncherOptionPage</name>
<message>
<location filename="../gui/launcheroptionpage.ui" line="14"/>
<source>Syncthing launcher</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/launcheroptionpage.ui" line="26"/>
<source>Launch Syncthing when starting the tray icon</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/launcheroptionpage.ui" line="42"/>
<source>Syncthing executable</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/launcheroptionpage.ui" line="52"/>
<source>Arguments</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/launcheroptionpage.ui" line="86"/>
<source>Syncthing log (stdout/stderr)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/launcheroptionpage.ui" line="102"/>
<source>Apply and launch now</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/launcheroptionpage.ui" line="119"/>
<source>Stop launched instance</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/launcheroptionpage.ui" line="138"/>
<source>No log messages available yet</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/launcheroptionpage.ui" line="145"/>
<source>Ensure latest log is visible</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="409"/>
<source>Syncthing existed with exit code %1
</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="412"/>
<source>Syncthing crashed with exit code %1
</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QtGui::NotificationsOptionPage</name>
<message>
@ -501,27 +631,27 @@
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/notificationsoptionpage.ui" line="23"/>
<location filename="../gui/notificationsoptionpage.ui" line="30"/>
<source>Notify on</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/notificationsoptionpage.ui" line="30"/>
<location filename="../gui/notificationsoptionpage.ui" line="37"/>
<source>disconnect</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/notificationsoptionpage.ui" line="37"/>
<location filename="../gui/notificationsoptionpage.ui" line="44"/>
<source>internal errors</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/notificationsoptionpage.ui" line="44"/>
<source>Syncthing errors</source>
<location filename="../gui/notificationsoptionpage.ui" line="51"/>
<source>errors/notifications from Syncthing</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/notificationsoptionpage.ui" line="51"/>
<location filename="../gui/notificationsoptionpage.ui" line="58"/>
<source>sync complete</source>
<translation type="unfinished"></translation>
</message>
@ -529,12 +659,17 @@
<context>
<name>QtGui::SettingsDialog</name>
<message>
<location filename="../gui/settingsdialog.cpp" line="259"/>
<location filename="../gui/settingsdialog.cpp" line="497"/>
<source>Tray</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="267"/>
<location filename="../gui/settingsdialog.cpp" line="509"/>
<source>Startup</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="503"/>
<source>Web view</source>
<translation type="unfinished"></translation>
</message>
@ -542,67 +677,72 @@
<context>
<name>QtGui::TrayIcon</name>
<message>
<location filename="../gui/trayicon.cpp" line="33"/>
<location filename="../gui/trayicon.cpp" line="34"/>
<source>Web UI</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="34"/>
<location filename="../gui/trayicon.cpp" line="35"/>
<source>Settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="35"/>
<location filename="../gui/trayicon.cpp" line="36"/>
<source>About</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="37"/>
<location filename="../gui/trayicon.cpp" line="38"/>
<source>Close</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="78"/>
<source>Syncthing error</source>
<location filename="../gui/trayicon.cpp" line="77"/>
<source>Error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="85"/>
<location filename="../gui/trayicon.cpp" line="84"/>
<source>Syncthing notification</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="94"/>
<location filename="../gui/trayicon.cpp" line="93"/>
<source>Not connected to Syncthing</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="96"/>
<location filename="../gui/trayicon.cpp" line="95"/>
<source>Disconnected from Syncthing</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="101"/>
<source>Syncthing is running</source>
<location filename="../gui/trayicon.cpp" line="100"/>
<source>Syncthing is idling</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="105"/>
<location filename="../gui/trayicon.cpp" line="104"/>
<source>Syncthing is scanning</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="108"/>
<source>Notifications available</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="109"/>
<location filename="../gui/trayicon.cpp" line="112"/>
<source>At least one device is paused</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="113"/>
<location filename="../gui/trayicon.cpp" line="116"/>
<source>Synchronization is ongoing</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/trayicon.cpp" line="122"/>
<location filename="../gui/trayicon.cpp" line="125"/>
<source>Synchronization complete</source>
<translation type="unfinished"></translation>
</message>
@ -616,7 +756,7 @@
</message>
<message>
<location filename="../gui/traywidget.ui" line="107"/>
<location filename="../gui/traywidget.cpp" line="230"/>
<location filename="../gui/traywidget.cpp" line="244"/>
<source>Connect</source>
<translation type="unfinished"></translation>
</message>
@ -643,8 +783,8 @@
<message>
<location filename="../gui/traywidget.ui" line="230"/>
<location filename="../gui/traywidget.ui" line="250"/>
<location filename="../gui/traywidget.cpp" line="322"/>
<location filename="../gui/traywidget.cpp" line="329"/>
<location filename="../gui/traywidget.cpp" line="345"/>
<location filename="../gui/traywidget.cpp" line="352"/>
<source>unknown</source>
<translation type="unfinished"></translation>
</message>
@ -670,13 +810,13 @@
</message>
<message>
<location filename="../gui/traywidget.ui" line="80"/>
<location filename="../gui/traywidget.cpp" line="132"/>
<location filename="../gui/traywidget.cpp" line="138"/>
<source>About</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.ui" line="134"/>
<location filename="../gui/traywidget.cpp" line="112"/>
<location filename="../gui/traywidget.cpp" line="118"/>
<source>Settings</source>
<translation type="unfinished"></translation>
</message>
@ -686,70 +826,75 @@
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="70"/>
<location filename="../gui/traywidget.cpp" line="67"/>
<source>View own device ID</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="81"/>
<location filename="../gui/traywidget.cpp" line="84"/>
<source>Rescan all directories</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="75"/>
<location filename="../gui/traywidget.cpp" line="78"/>
<source>Show Syncthing log</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="180"/>
<location filename="../gui/traywidget.cpp" line="72"/>
<source>Restart Syncthing</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="186"/>
<source>device ID is unknown</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="188"/>
<location filename="../gui/traywidget.cpp" line="194"/>
<source>Copy to clipboard</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="231"/>
<location filename="../gui/traywidget.cpp" line="245"/>
<source>Not connected to Syncthing, click to connect</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="237"/>
<location filename="../gui/traywidget.cpp" line="252"/>
<source>Pause</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="238"/>
<location filename="../gui/traywidget.cpp" line="253"/>
<source>Syncthing is running, click to pause all devices</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="243"/>
<location filename="../gui/traywidget.cpp" line="258"/>
<source>At least one device is paused, click to resume</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="242"/>
<location filename="../gui/traywidget.cpp" line="294"/>
<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"/>
<source>Continue</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="170"/>
<location filename="../gui/traywidget.cpp" line="176"/>
<source>Own device ID</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="204"/>
<location filename="../gui/traywidget.cpp" line="213"/>
<source>Log</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/traywidget.cpp" line="272"/>
<source>The directly &lt;i&gt;%1&lt;/i&gt; does not exist on the local machine.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QtGui::WebViewDialog</name>
@ -763,7 +908,7 @@
<name>QtGui::WebViewOptionPage</name>
<message>
<location filename="../gui/webviewoptionpage.ui" line="14"/>
<location filename="../gui/settingsdialog.cpp" line="221"/>
<location filename="../gui/settingsdialog.cpp" line="459"/>
<source>General</source>
<translation type="unfinished"></translation>
</message>
@ -793,7 +938,7 @@
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="223"/>
<location filename="../gui/settingsdialog.cpp" line="461"/>
<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>
@ -802,22 +947,22 @@ The Web UI will be opened in the default web browser instead.</source>
<context>
<name>main</name>
<message>
<location filename="../application/main.cpp" line="62"/>
<location filename="../application/main.cpp" line="70"/>
<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="63"/>
<location filename="../application/main.cpp" line="71"/>
<source>Note that the settings dialog allows importing URL, credentials and API-key from the local Syncthing configuration.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../application/main.cpp" line="68"/>
<location filename="../application/main.cpp" line="76"/>
<source>The system tray is (currently) not available. You could open the tray menu as a regular window using the -w flag, though.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../application/main.cpp" line="72"/>
<location filename="../application/main.cpp" line="80"/>
<source>The Qt libraries have not been built with tray icon support. You could open the tray menu as a regular window using the -w flag, though.</source>
<translation type="unfinished"></translation>
</message>