Implement further features

This commit is contained in:
Martchus 2016-08-26 16:43:53 +02:00
parent b7609d7d3e
commit 2630e51887
20 changed files with 686 additions and 254 deletions

View File

@ -34,6 +34,7 @@ set(WIDGETS_HEADER_FILES
gui/webviewdialog.h
gui/webviewprovider.h
gui/dirbuttonsitemdelegate.h
gui/devbuttonsitemdelegate.h
gui/dirview.h
gui/devview.h
)
@ -45,6 +46,7 @@ set(WIDGETS_SRC_FILES
gui/webpage.cpp
gui/webviewdialog.cpp
gui/dirbuttonsitemdelegate.cpp
gui/devbuttonsitemdelegate.cpp
gui/dirview.cpp
gui/devview.cpp
resources/icons.qrc

View File

@ -12,8 +12,17 @@ Qt 5-based tray application for [Syncthing](https://github.com/syncthing/syncthi
* Can be built without web view support as well (then the web UI is opened in the regular browser)
## Screenshots
### Openbox/Tint2
![Openbox/Tint2](/resources/screenshots/1.png?raw=true "Under Openbox with Tint2")
### Under Openbox/Tint2
![Openbox/Tint2](/resources/screenshots/tint2.png?raw=true)
### Under Plasma 5 (dark color theme)
![Plasma 5](/resources/screenshots/plasma.png?raw=true)
### Settings dialog (dark color theme)
![Settings dialog](/resources/screenshots/settings.png?raw=true)
### Web view (dark color theme)
![Web view](/resources/screenshots/webview.png?raw=true)
## Download / binary repository
I will provide packages for Arch Linux and Windows when releasing. For more information checkout my

View File

@ -41,10 +41,15 @@ SyncthingConnection::SyncthingConnection(const QString &syncthingUrl, const QByt
m_status(SyncthingStatus::Disconnected),
m_keepPolling(false),
m_reconnecting(false),
m_lastEventId(0),
m_totalIncomingTraffic(0),
m_totalOutgoingTraffic(0),
m_configReply(nullptr),
m_statusReply(nullptr),
m_eventsReply(nullptr),
m_unreadNotifications(false)
m_unreadNotifications(false),
m_hasConfig(false),
m_hasStatus(false)
{}
/*!
@ -82,11 +87,9 @@ QString SyncthingConnection::statusText() const
void SyncthingConnection::connect()
{
if(!isConnected()) {
m_reconnecting = false;
m_reconnecting = m_hasConfig = m_hasStatus = false;
requestConfig();
requestStatus();
m_lastEventId = 0;
requestEvents();
m_keepPolling = true;
}
}
@ -96,16 +99,8 @@ void SyncthingConnection::connect()
*/
void SyncthingConnection::disconnect()
{
m_reconnecting = false;
if(m_configReply) {
m_configReply->abort();
}
if(m_statusReply) {
m_statusReply->abort();
}
if(m_eventsReply) {
m_eventsReply->abort();
}
m_reconnecting = m_hasConfig = m_hasStatus = false;
abortAllRequests();
}
/*!
@ -115,15 +110,8 @@ void SyncthingConnection::reconnect()
{
if(isConnected()) {
m_reconnecting = true;
if(m_configReply) {
m_configReply->abort();
}
if(m_statusReply) {
m_statusReply->abort();
}
if(m_eventsReply) {
m_eventsReply->abort();
}
m_hasConfig = m_hasStatus = false;
abortAllRequests();
} else {
connect();
}
@ -215,6 +203,7 @@ inline QNetworkReply *SyncthingConnection::postData(const QString &path, const Q
SyncthingDir *SyncthingConnection::findDirInfo(const QString &dir, int &row)
{
row = 0;
for(SyncthingDir &d : m_dirs) {
if(d.id == dir) {
return &d;
@ -224,6 +213,50 @@ SyncthingDir *SyncthingConnection::findDirInfo(const QString &dir, int &row)
return nullptr; // TODO: dir is unknown, trigger refreshing the config
}
SyncthingDev *SyncthingConnection::findDevInfo(const QString &dev, int &row)
{
row = 0;
for(SyncthingDev &d : m_devs) {
if(d.id == dev) {
return &d;
}
++row;
}
return nullptr; // TODO: dev is unknown, trigger refreshing the config
}
/*!
* \brief Continues connecting if both - config and status - have been parsed yet and continuous polling is enabled.
*/
void SyncthingConnection::continueConnecting()
{
if(m_keepPolling && m_hasConfig && m_hasStatus) {
requestConnections();
// since config and status could be read successfully, let's poll for events
m_lastEventId = 0;
requestEvents();
}
}
/*!
* \brief Aborts all pending requests.
*/
void SyncthingConnection::abortAllRequests()
{
if(m_configReply) {
m_configReply->abort();
}
if(m_statusReply) {
m_statusReply->abort();
}
if(m_connectionsReply) {
m_connectionsReply->abort();
}
if(m_eventsReply) {
m_eventsReply->abort();
}
}
/*!
* \brief Requests the Syncthing configuration asynchronously.
*
@ -234,11 +267,26 @@ void SyncthingConnection::requestConfig()
QObject::connect(m_configReply = requestData(QStringLiteral("system/config"), QUrlQuery()), &QNetworkReply::finished, this, &SyncthingConnection::readConfig);
}
/*!
* \brief Requests the Syncthing status asynchronously.
*
* The signal configDirChanged() and myIdChanged() emitted when those values have changed; error() is emitted in the error case.
*/
void SyncthingConnection::requestStatus()
{
QObject::connect(m_statusReply = requestData(QStringLiteral("system/status"), QUrlQuery()), &QNetworkReply::finished, this, &SyncthingConnection::readStatus);
}
/*!
* \brief Requests current connections asynchronously.
*
* The signal devStatusChanged() is emitted for each device where the connection status has changed updated; error() is emitted in the error case.
*/
void SyncthingConnection::requestConnections()
{
QObject::connect(m_connectionsReply = requestData(QStringLiteral("system/connections"), QUrlQuery()), &QNetworkReply::finished, this, &SyncthingConnection::readConnections);
}
/*!
* \brief Requests the Syncthing events (since the last successful call) asynchronously.
*
@ -277,6 +325,11 @@ void SyncthingConnection::requestQrCode(const QString &text, std::function<void(
});
}
/*!
* \brief Requests the Syncthing log.
*
* The specified \a callback is called on success; otherwise error() is emitted.
*/
void SyncthingConnection::requestLog(std::function<void (const std::vector<SyncthingLogEntry> &)> callback)
{
QNetworkReply *reply = requestData(QStringLiteral("system/log"), QUrlQuery());
@ -324,10 +377,12 @@ void SyncthingConnection::readConfig()
QJsonParseError jsonError;
const QJsonDocument replyDoc = QJsonDocument::fromJson(reply->readAll(), &jsonError);
if(jsonError.error == QJsonParseError::NoError) {
const QJsonObject replyObj = replyDoc.object();
const QJsonObject replyObj(replyDoc.object());
emit newConfig(replyObj);
readDirs(replyObj.value(QStringLiteral("folders")).toArray());
readDevs(replyObj.value(QStringLiteral("devices")).toArray());
m_hasConfig = true;
continueConnecting();
} else {
emit error(tr("Unable to parse Syncthing config: ") + jsonError.errorString());
}
@ -338,6 +393,9 @@ void SyncthingConnection::readConfig()
}
}
/*!
* \brief Reads directory results of requestConfig(); called by readConfig().
*/
void SyncthingConnection::readDirs(const QJsonArray &dirs)
{
m_dirs.clear();
@ -368,6 +426,9 @@ void SyncthingConnection::readDirs(const QJsonArray &dirs)
emit newDirs(m_dirs);
}
/*!
* \brief Reads device results of requestConfig(); called by readConfig().
*/
void SyncthingConnection::readDevs(const QJsonArray &devs)
{
m_devs.clear();
@ -384,14 +445,19 @@ void SyncthingConnection::readDevs(const QJsonArray &devs)
devItem.compression = devObj.value(QStringLiteral("compression")).toString();
devItem.certName = devObj.value(QStringLiteral("certName")).toString();
devItem.introducer = devObj.value(QStringLiteral("introducer")).toBool(false);
devItem.status = DevStatus::Unknown;
devItem.status = devItem.id == m_myId ? DevStatus::OwnDevice : DevStatus::Unknown;
devItem.progressPercentage = 0;
devItem.paused = false;
devItem.totalIncomingTraffic = devItem.totalOutgoingTraffic = 0;
m_devs.push_back(move(devItem));
}
}
emit newDevices(m_devs);
}
/*!
* \brief Reads results of requestStatus().
*/
void SyncthingConnection::readStatus()
{
auto *reply = static_cast<QNetworkReply *>(sender());
@ -405,12 +471,23 @@ void SyncthingConnection::readStatus()
QJsonParseError jsonError;
const QJsonDocument replyDoc = QJsonDocument::fromJson(reply->readAll(), &jsonError);
if(jsonError.error == QJsonParseError::NoError) {
const QJsonObject replyObj = replyDoc.object();
const QJsonObject replyObj(replyDoc.object());
const QString myId(replyObj.value(QStringLiteral("myID")).toString());
if(myId != m_myId) {
emit configDirChanged(m_myId = myId);
emit myIdChanged(m_myId = myId);
int index = 0;
for(SyncthingDev &dev : m_devs) {
if(dev.id == m_myId) {
dev.status = DevStatus::OwnDevice;
emit devStatusChanged(dev, index);
break;
}
++index;
}
}
// other values are currently not interesting
m_hasStatus = true;
continueConnecting();
} else {
emit error(tr("Unable to parse Syncthing config: ") + jsonError.errorString());
}
@ -421,6 +498,67 @@ void SyncthingConnection::readStatus()
}
}
/*!
* \brief Reads results of requestConnections().
*/
void SyncthingConnection::readConnections()
{
auto *reply = static_cast<QNetworkReply *>(sender());
reply->deleteLater();
if(reply == m_connectionsReply) {
m_connectionsReply = nullptr;
}
switch(reply->error()) {
case QNetworkReply::NoError: {
QJsonParseError jsonError;
const QJsonDocument replyDoc = QJsonDocument::fromJson(reply->readAll(), &jsonError);
if(jsonError.error == QJsonParseError::NoError) {
const QJsonObject replyObj(replyDoc.object());
const QJsonObject totalObj(replyObj.value(QStringLiteral("total")).toObject());
m_totalIncomingTraffic = totalObj.value(QStringLiteral("inBytesTotal")).toInt(0);
m_totalOutgoingTraffic = totalObj.value(QStringLiteral("outBytesTotal")).toInt(0);
const QJsonObject connectionsObj(replyObj.value(QStringLiteral("connections")).toObject());
int index = 0;
for(SyncthingDev &dev : m_devs) {
const QJsonObject connectionObj(connectionsObj.value(dev.id).toObject());
if(!connectionObj.isEmpty()) {
switch(dev.status) {
case DevStatus::OwnDevice:
break;
case DevStatus::Disconnected:
case DevStatus::Unknown:
if(connectionObj.value(QStringLiteral("connected")).toBool(false)) {
dev.status = DevStatus::Idle;
} else {
dev.status = DevStatus::Disconnected;
}
break;
default:
if(!connectionObj.value(QStringLiteral("connected")).toBool(false)) {
dev.status = DevStatus::Disconnected;
}
}
dev.paused = connectionObj.value(QStringLiteral("paused")).toBool(false);
dev.totalIncomingTraffic = connectionObj.value(QStringLiteral("inBytesTotal")).toInt(0);
dev.totalOutgoingTraffic = connectionObj.value(QStringLiteral("outBytesTotal")).toInt(0);
dev.connectionAddress = connectionObj.value(QStringLiteral("address")).toString();
dev.connectionType = connectionObj.value(QStringLiteral("type")).toString();
dev.clientVersion = connectionObj.value(QStringLiteral("clientVersion")).toString();
emit devStatusChanged(dev, index);
}
++index;
}
} else {
emit error(tr("Unable to parse connections: ") + jsonError.errorString());
}
} case QNetworkReply::OperationCanceledError:
return; // intended, not an error
default:
emit error(tr("Unable to request connections: ") + reply->errorString());
}
}
/*!
* \brief Reads results of requestEvents().
*/
@ -443,12 +581,14 @@ void SyncthingConnection::readEvents()
for(const QJsonValue &eventVal : replyArray) {
const QJsonObject event = eventVal.toObject();
m_lastEventId = event.value(QStringLiteral("id")).toInt(m_lastEventId);
const QString eventType = event.value(QStringLiteral("type")).toString();
const QJsonObject eventData = event.value(QStringLiteral("data")).toObject();
const QString eventType(event.value(QStringLiteral("type")).toString());
const QJsonObject eventData(event.value(QStringLiteral("data")).toObject());
if(eventType == QLatin1String("Starting")) {
readStartingEvent(eventData);
} else if(eventType == QLatin1String("StateChanged")) {
readStatusChangedEvent(eventData);
} else if(eventType.startsWith(QLatin1String("Device"))) {
readDeviceEvent(eventType, eventData);
}
}
} else {
@ -467,7 +607,6 @@ void SyncthingConnection::readEvents()
requestConfig();
requestStatus();
m_lastEventId = 0;
requestEvents();
m_keepPolling = true;
} else {
// ... otherwise keep disconnected
@ -492,13 +631,13 @@ void SyncthingConnection::readEvents()
/*!
* \brief Reads results of requestEvents().
*/
void SyncthingConnection::readStartingEvent(const QJsonObject &event)
void SyncthingConnection::readStartingEvent(const QJsonObject &eventData)
{
QString strValue = event.value(QStringLiteral("home")).toString();
QString strValue = eventData.value(QStringLiteral("home")).toString();
if(strValue != m_configDir) {
emit configDirChanged(m_configDir = strValue);
}
strValue = event.value(QStringLiteral("myID")).toString();
strValue = eventData.value(QStringLiteral("myID")).toString();
if(strValue != m_myId) {
emit configDirChanged(m_myId = strValue);
}
@ -507,14 +646,14 @@ void SyncthingConnection::readStartingEvent(const QJsonObject &event)
/*!
* \brief Reads results of requestEvents().
*/
void SyncthingConnection::readStatusChangedEvent(const QJsonObject &event)
void SyncthingConnection::readStatusChangedEvent(const QJsonObject &eventData)
{
const QString dir(event.value(QStringLiteral("folder")).toString());
const QString dir(eventData.value(QStringLiteral("folder")).toString());
if(!dir.isEmpty()) {
// dir status changed
int row;
if(SyncthingDir *dirInfo = findDirInfo(dir, row)) {
const QString statusStr(event.value(QStringLiteral("to")).toString());
const QString statusStr(eventData.value(QStringLiteral("to")).toString());
DirStatus status;
if(statusStr == QLatin1String("idle")) {
status = DirStatus::Idle;
@ -535,6 +674,45 @@ void SyncthingConnection::readStatusChangedEvent(const QJsonObject &event)
}
}
/*!
* \brief Reads results of requestEvents().
*/
void SyncthingConnection::readDeviceEvent(const QString &eventType, const QJsonObject &eventData)
{
const QString dev(eventData.value(QStringLiteral("device")).toString());
if(!dev.isEmpty()) {
// dev status changed
int row;
if(SyncthingDev *devInfo = findDevInfo(dev, row)) {
DevStatus status = devInfo->status;
bool paused = devInfo->paused;
if(eventType == QLatin1String("DeviceConnected")) {
status = DevStatus::Idle; // TODO: figure out when dev is actually syncing
} else if(eventType == QLatin1String("DeviceDisconnected")) {
status = DevStatus::Disconnected;
} else if(eventType == QLatin1String("DevicePaused")) {
paused = true;
} else if(eventType == QLatin1String("DeviceRejected")) {
status = DevStatus::Rejected;
} else if(eventType == QLatin1String("DeviceResumed")) {
paused = false;
} else if(eventType == QLatin1String("DeviceDiscovered")) {
// we know about this device already, set status anyways because it might still be unknown
status = DevStatus::Disconnected;
} else {
return; // can't handle other event types currently
}
if(devInfo->status != status || devInfo->paused != paused) {
if(devInfo->status != DevStatus::OwnDevice) { // don't mess with the status of the own device
devInfo->status = status;
}
devInfo->paused = paused;
emit devStatusChanged(*devInfo, row);
}
}
}
}
/*!
* \brief Reads results of rescan().
*/
@ -542,7 +720,6 @@ void SyncthingConnection::readRescan()
{
auto *reply = static_cast<QNetworkReply *>(sender());
reply->deleteLater();
switch(reply->error()) {
case QNetworkReply::NoError:
break;
@ -558,7 +735,6 @@ void SyncthingConnection::readPauseResume()
{
auto *reply = static_cast<QNetworkReply *>(sender());
reply->deleteLater();
switch(reply->error()) {
case QNetworkReply::NoError:
break;
@ -569,45 +745,47 @@ void SyncthingConnection::readPauseResume()
/*!
* \brief Sets the connection status. Ensures statusChanged() is emitted.
* \param status Specifies the status; should be either SyncthingStatus::Disconnected or SyncthingStatus::Default.
* \remarks If \a status is not SyncthingStatus::Disconnected the best status for the current connection is determined automatically.
* \param status Specifies the status; should be either SyncthingStatus::Disconnected or SyncthingStatus::Default. There is no use
* in specifying other values such as SyncthingStatus::Synchronizing as these are determined automatically within the method.
*/
void SyncthingConnection::setStatus(SyncthingStatus status)
{
if(m_status != status) {
switch(m_status = status) {
case SyncthingStatus::Disconnected:
break;
default:
if(m_unreadNotifications) {
m_status = SyncthingStatus::NotificationsAvailable;
switch(status) {
case SyncthingStatus::Disconnected:
break;
default:
if(m_unreadNotifications) {
status = SyncthingStatus::NotificationsAvailable;
} else {
// check whether at least one directory is synchronizing
bool synchronizing = false;
for(const SyncthingDir &dir : m_dirs) {
if(dir.status == DirStatus::Synchronizing) {
synchronizing = true;
break;
}
}
if(synchronizing) {
status = SyncthingStatus::Synchronizing;
} else {
// check whether at least one directory is synchronizing
bool synchronizing = false;
for(const SyncthingDir &dir : m_dirs) {
if(dir.status == DirStatus::Synchronizing) {
synchronizing = true;
// check whether at least one device is paused
bool paused = false;
for(const SyncthingDev &dev : m_devs) {
if(dev.paused) {
paused = true;
break;
}
}
if(synchronizing) {
m_status = SyncthingStatus::Synchronizing;
if(paused) {
status = SyncthingStatus::Paused;
} else {
// check whether at least one device is paused
bool paused = false;
for(const SyncthingDev &dev : m_devs) {
if(dev.status == DevStatus::Paused) {
paused = true;
}
}
if(paused) {
m_status = SyncthingStatus::Paused;
} else {
m_status = SyncthingStatus::Default;
}
status = SyncthingStatus::Default;
}
}
}
emit statusChanged(m_status);
}
if(m_status != status) {
emit statusChanged(m_status = status);
}
}

View File

@ -55,10 +55,11 @@ enum class DevStatus
{
Unknown,
Disconnected,
OwnDevice,
Idle,
Synchronizing,
Paused,
OutOfSync
OutOfSync,
Rejected,
};
struct SyncthingDev
@ -71,6 +72,12 @@ struct SyncthingDev
DevStatus status;
int progressPercentage;
bool introducer;
bool paused;
int totalIncomingTraffic;
int totalOutgoingTraffic;
QString connectionAddress;
QString connectionType;
QString clientVersion;
};
struct SyncthingLogEntry
@ -154,6 +161,14 @@ Q_SIGNALS:
*/
void dirStatusChanged(const SyncthingDir &dir, int index);
/*!
* \brief Indicates the status of the specified \a dev changed.
*/
void devStatusChanged(const SyncthingDev &dev, int index);
/*!
* \brief Indicates a new Syncthing notification is available.
*/
void newNotification(const QString &message);
/*!
@ -179,17 +194,19 @@ Q_SIGNALS:
private Q_SLOTS:
void requestConfig();
void requestStatus();
void requestConnections();
void requestEvents();
void abortAllRequests();
void readConfig();
void readDirs(const QJsonArray &dirs);
void readDevs(const QJsonArray &devs);
void readStatus();
void readConnections();
void readEvents();
void readStartingEvent(const QJsonObject &event);
void readStatusChangedEvent(const QJsonObject &event);
void readStartingEvent(const QJsonObject &eventData);
void readStatusChangedEvent(const QJsonObject &eventData);
void readDeviceEvent(const QString &eventType, const QJsonObject &eventData);
void readRescan();
void readPauseResume();
@ -200,6 +217,8 @@ private:
QNetworkReply *requestData(const QString &path, const QUrlQuery &query, bool rest = true);
QNetworkReply *postData(const QString &path, const QUrlQuery &query, const QByteArray &data = QByteArray());
SyncthingDir *findDirInfo(const QString &dir, int &row);
SyncthingDev *findDevInfo(const QString &dev, int &row);
void continueConnecting();
QString m_syncthingUrl;
QByteArray m_apiKey;
@ -211,10 +230,15 @@ private:
int m_lastEventId;
QString m_configDir;
QString m_myId;
int m_totalIncomingTraffic;
int m_totalOutgoingTraffic;
QNetworkReply *m_configReply;
QNetworkReply *m_statusReply;
QNetworkReply *m_connectionsReply;
QNetworkReply *m_eventsReply;
bool m_unreadNotifications;
bool m_hasConfig;
bool m_hasStatus;
std::vector<SyncthingDir> m_dirs;
std::vector<SyncthingDev> m_devs;
};

View File

@ -14,7 +14,9 @@ SyncthingDeviceModel::SyncthingDeviceModel(SyncthingConnection &connection, QObj
m_pausedIcon(QIcon(QStringLiteral(":/icons/hicolor/scalable/status/syncthing-pause.svg"))),
m_otherIcon(QIcon(QStringLiteral(":/icons/hicolor/scalable/status/syncthing-default.svg")))
{
connect(&m_connection, &SyncthingConnection::newConfig, this, &SyncthingDeviceModel::newConfig);
connect(&m_connection, &SyncthingConnection::newDevices, this, &SyncthingDeviceModel::newDevices);
connect(&m_connection, &SyncthingConnection::devStatusChanged, this, &SyncthingDeviceModel::devStatusChanged);
}
/*!
@ -111,13 +113,18 @@ QVariant SyncthingDeviceModel::data(const QModelIndex &index, int role) const
switch(index.column()) {
case 0: return dev.name.isEmpty() ? dev.id : dev.name;
case 1:
switch(dev.status) {
case DevStatus::Unknown: return tr("Unknown status");
case DevStatus::Idle: return tr("Idle");
case DevStatus::Disconnected: return tr("Idle");
case DevStatus::Synchronizing: return dev.progressPercentage > 0 ? tr("Synchronizing (%1 %)").arg(dev.progressPercentage) : tr("Synchronizing");
case DevStatus::Paused: return tr("Paused");
case DevStatus::OutOfSync: return tr("Out of sync");
if(dev.paused) {
return tr("Paused");
} else {
switch(dev.status) {
case DevStatus::Unknown: return tr("Unknown status");
case DevStatus::OwnDevice: return tr("Own device");
case DevStatus::Idle: return tr("Idle");
case DevStatus::Disconnected: return tr("Disconnected");
case DevStatus::Synchronizing: return dev.progressPercentage > 0 ? tr("Synchronizing (%1 %)").arg(dev.progressPercentage) : tr("Synchronizing");
case DevStatus::OutOfSync: return tr("Out of sync");
case DevStatus::Rejected: return tr("Rejected");
}
}
break;
}
@ -125,13 +132,18 @@ QVariant SyncthingDeviceModel::data(const QModelIndex &index, int role) const
case Qt::DecorationRole:
switch(index.column()) {
case 0:
switch(dev.status) {
case DevStatus::Unknown:
case DevStatus::Disconnected: return m_unknownIcon;
case DevStatus::Idle: return m_idleIcon;
case DevStatus::Synchronizing: return m_syncIcon;
case DevStatus::Paused: return m_pausedIcon;
case DevStatus::OutOfSync: return m_errorIcon;
if(dev.paused) {
return m_pausedIcon;
} else {
switch(dev.status) {
case DevStatus::Unknown:
case DevStatus::Disconnected: return m_unknownIcon;
case DevStatus::OwnDevice:
case DevStatus::Idle: return m_idleIcon;
case DevStatus::Synchronizing: return m_syncIcon;
case DevStatus::OutOfSync:
case DevStatus::Rejected: return m_errorIcon;
}
}
break;
}
@ -146,17 +158,26 @@ QVariant SyncthingDeviceModel::data(const QModelIndex &index, int role) const
switch(index.column()) {
case 0: break;
case 1:
switch(dev.status) {
case DevStatus::Unknown: break;
case DevStatus::Disconnected: break;
case DevStatus::Idle: return QColor(Qt::darkGreen);
case DevStatus::Synchronizing: return QColor(Qt::blue);
case DevStatus::Paused: break;
case DevStatus::OutOfSync: return QColor(Qt::red);
if(!dev.paused) {
switch(dev.status) {
case DevStatus::Unknown: break;
case DevStatus::Disconnected: break;
case DevStatus::OwnDevice:
case DevStatus::Idle: return QColor(Qt::darkGreen);
case DevStatus::Synchronizing: return QColor(Qt::darkBlue);
case DevStatus::OutOfSync:
case DevStatus::Rejected: return QColor(Qt::red);
}
}
break;
}
break;
case DeviceStatus:
return static_cast<int>(dev.status);
case DevicePaused:
return dev.paused;
case IsOwnDevice:
return dev.status == DevStatus::OwnDevice;
default:
;
}
@ -192,4 +213,22 @@ int SyncthingDeviceModel::columnCount(const QModelIndex &parent) const
}
}
void SyncthingDeviceModel::newConfig()
{
beginResetModel();
}
void SyncthingDeviceModel::newDevices()
{
endResetModel();
}
void SyncthingDeviceModel::devStatusChanged(const SyncthingDev &, int index)
{
const QModelIndex modelIndex1(this->index(index, 0, QModelIndex()));
emit dataChanged(modelIndex1, modelIndex1, QVector<int>() << Qt::DecorationRole);
const QModelIndex modelIndex2(this->index(index, 1, QModelIndex()));
emit dataChanged(modelIndex2, modelIndex2, QVector<int>() << Qt::DisplayRole << Qt::ForegroundRole << DeviceStatus);
}
} // namespace Data

View File

@ -15,6 +15,13 @@ class SyncthingDeviceModel : public QAbstractItemModel
{
Q_OBJECT
public:
enum SyncthingDevideModelRole
{
DeviceStatus = Qt::UserRole + 1,
DevicePaused,
IsOwnDevice
};
explicit SyncthingDeviceModel(SyncthingConnection &connection, QObject *parent = nullptr);
public Q_SLOTS:
@ -27,6 +34,11 @@ public Q_SLOTS:
int columnCount(const QModelIndex &parent) const;
const SyncthingDev *devInfo(const QModelIndex &index) const;
private slots:
void newConfig();
void newDevices();
void devStatusChanged(const SyncthingDev &, int index);
private:
Data::SyncthingConnection &m_connection;
const std::vector<SyncthingDev> &m_devs;

View File

@ -0,0 +1,63 @@
#include "./devbuttonsitemdelegate.h"
#include "../data/syncthingdevicemodel.h"
#include "../data/syncthingconnection.h"
#include <QPixmap>
#include <QPainter>
#include <QApplication>
#include <QStyle>
#include <QTextOption>
#include <QStyleOptionViewItem>
#include <QBrush>
#include <QPalette>
using namespace Data;
namespace QtGui {
inline int centerObj(int avail, int size)
{
return (avail - size) / 2;
}
DevButtonsItemDelegate::DevButtonsItemDelegate(QObject* parent) :
QStyledItemDelegate(parent),
m_pauseIcon(QIcon::fromTheme(QStringLiteral("media-playback-pause")).pixmap(QSize(16, 16))),
m_resumeIcon(QIcon::fromTheme(QStringLiteral("media-playback-start")).pixmap(QSize(16, 16)))
{}
void DevButtonsItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
// use the customization only on top-level rows
if(index.parent().isValid()) {
QStyledItemDelegate::paint(painter, option, index);
} else {
// init style options to use drawControl(), except for the text
QStyleOptionViewItem opt = option;
initStyleOption(&opt, index);
opt.text.clear();
opt.features = QStyleOptionViewItem::None;
QApplication::style()->drawControl(QStyle::CE_ItemViewItem, &opt, painter);
// draw text
QRectF textRect = option.rect;
//textRect.setWidth(textRect.width() - 38);
textRect.setWidth(textRect.width() - 20);
QTextOption textOption;
textOption.setAlignment(opt.displayAlignment);
painter->setFont(opt.font);
painter->setPen(opt.palette.color(QPalette::Text));
painter->drawText(textRect, displayText(index.data(Qt::DisplayRole), option.locale), textOption);
// draw buttons
const int buttonY = option.rect.y() + centerObj(option.rect.height(), 16);
//painter->drawPixmap(option.rect.right() - 34, buttonY, 16, 16, m_refreshIcon);
//if(!index.data(SyncthingDeviceModel::IsOwnDevice).toBool()) {
painter->drawPixmap(option.rect.right() - 16, buttonY, 16, 16, index.data(SyncthingDeviceModel::DevicePaused).toBool() ? m_resumeIcon : m_pauseIcon);
//}
}
}
}

View File

@ -0,0 +1,24 @@
#ifndef DEVBUTTONSITEMDELEGATE_H
#define DEVBUTTONSITEMDELEGATE_H
#include <QStyledItemDelegate>
#include <QPixmap>
namespace QtGui {
class DevButtonsItemDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
DevButtonsItemDelegate(QObject *parent);
void paint(QPainter *, const QStyleOptionViewItem &, const QModelIndex &) const;
private:
const QPixmap m_pauseIcon;
const QPixmap m_resumeIcon;
};
}
#endif // DEVBUTTONSITEMDELEGATE_H

View File

@ -1,4 +1,5 @@
#include "./devview.h"
#include "./devbuttonsitemdelegate.h"
#include <QHeaderView>
#include <QMouseEvent>
@ -14,10 +15,28 @@ DevView::DevView(QWidget *parent) :
{
header()->setSectionResizeMode(QHeaderView::ResizeToContents);
header()->hide();
setItemDelegateForColumn(1, new DevButtonsItemDelegate(this));
setContextMenuPolicy(Qt::CustomContextMenu);
connect(this, &DevView::customContextMenuRequested, this, &DevView::showContextMenu);
}
void DevView::mouseReleaseEvent(QMouseEvent *event)
{
QTreeView::mouseReleaseEvent(event);
const QPoint pos(event->pos());
const QModelIndex clickedIndex(indexAt(event->pos()));
if(clickedIndex.isValid() && clickedIndex.column() == 1 && !clickedIndex.parent().isValid()) {
const QRect itemRect(visualRect(clickedIndex));
//if(pos.x() > itemRect.right() - 34) {
if(pos.x() > itemRect.right() - 17) {
emit pauseResumeDev(clickedIndex);
// } else {
// emit scanDir(clickedIndex);
// }
}
}
}
void DevView::showContextMenu()
{
if(selectionModel() && selectionModel()->selectedRows(0).size() == 1) {

View File

@ -11,6 +11,12 @@ class DevView : public QTreeView
public:
DevView(QWidget *parent = nullptr);
Q_SIGNALS:
void pauseResumeDev(const QModelIndex &index);
protected:
void mouseReleaseEvent(QMouseEvent *event);
private Q_SLOTS:
void showContextMenu();
void copySelectedItem();

View File

@ -52,9 +52,4 @@ void DirButtonsItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem
}
//QSize DirButtonsItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
//{
// return QSize(16, 16);
//}
}

View File

@ -13,7 +13,6 @@ public:
DirButtonsItemDelegate(QObject *parent);
void paint(QPainter *, const QStyleOptionViewItem &, const QModelIndex &) const;
//QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
private:
const QPixmap m_refreshIcon;

View File

@ -78,7 +78,6 @@ TrayWidget::TrayWidget(TrayMenu *parent) :
viewIdButton->setToolTip(tr("View own device ID"));
viewIdButton->setIcon(QIcon::fromTheme(QStringLiteral("view-barcode")));
viewIdButton->setFlat(true);
connect(viewIdButton, &QPushButton::clicked, this, &TrayWidget::showOwnDeviceId);
cornerFrameLayout->addWidget(viewIdButton);
auto *showLogButton = new QPushButton(cornerFrame);
showLogButton->setToolTip(tr("Show Syncthing log"));
@ -90,7 +89,7 @@ TrayWidget::TrayWidget(TrayMenu *parent) :
scanAllButton->setToolTip(tr("Rescan all directories"));
scanAllButton->setIcon(QIcon::fromTheme(QStringLiteral("folder-sync")));
scanAllButton->setFlat(true);
connect(scanAllButton, &QPushButton::clicked, &m_connection, &SyncthingConnection::rescanAllDirs);
cornerFrameLayout->addWidget(scanAllButton);
m_ui->tabWidget->setCornerWidget(cornerFrame, Qt::BottomRightCorner);
@ -103,6 +102,9 @@ TrayWidget::TrayWidget(TrayMenu *parent) :
connect(&m_connection, &SyncthingConnection::statusChanged, this, &TrayWidget::updateStatusButton);
connect(m_ui->dirsTreeView, &DirView::openDir, this, &TrayWidget::openDir);
connect(m_ui->dirsTreeView, &DirView::scanDir, this, &TrayWidget::scanDir);
connect(m_ui->devsTreeView, &DevView::pauseResumeDev, this, &TrayWidget::pauseResumeDev);
connect(scanAllButton, &QPushButton::clicked, &m_connection, &SyncthingConnection::rescanAllDirs);
connect(viewIdButton, &QPushButton::clicked, this, &TrayWidget::showOwnDeviceId);
}
TrayWidget::~TrayWidget()
@ -238,12 +240,12 @@ void TrayWidget::updateStatusButton(SyncthingStatus status)
case SyncthingStatus::NotificationsAvailable:
case SyncthingStatus::Synchronizing:
m_ui->statusPushButton->setText(tr("Pause"));
m_ui->statusPushButton->setToolTip(tr("Syncthing is doing its job, click to pause"));
m_ui->statusPushButton->setToolTip(tr("Syncthing is running, click to pause all devices"));
m_ui->statusPushButton->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-pause")));
break;
case SyncthingStatus::Paused:
m_ui->statusPushButton->setText(tr("Continue"));
m_ui->statusPushButton->setToolTip(tr("Syncthing is suspended, click to continue"));
m_ui->statusPushButton->setToolTip(tr("At least one device is paused, click to resume"));
m_ui->statusPushButton->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-start")));
break;
}
@ -261,9 +263,9 @@ void TrayWidget::applySettings()
m_connection.reconnect();
}
void TrayWidget::openDir(const QModelIndex &index)
void TrayWidget::openDir(const QModelIndex &dirIndex)
{
if(const SyncthingDir *dir = m_dirModel.dirInfo(index)) {
if(const SyncthingDir *dir = m_dirModel.dirInfo(dirIndex)) {
if(QDir(dir->path).exists()) {
DesktopUtils::openLocalFileOrDir(dir->path);
} else {
@ -272,13 +274,24 @@ void TrayWidget::openDir(const QModelIndex &index)
}
}
void TrayWidget::scanDir(const QModelIndex &index)
void TrayWidget::scanDir(const QModelIndex &dirIndex)
{
if(const SyncthingDir *dir = m_dirModel.dirInfo(index)) {
if(const SyncthingDir *dir = m_dirModel.dirInfo(dirIndex)) {
m_connection.rescan(dir->id);
}
}
void TrayWidget::pauseResumeDev(const QModelIndex &devIndex)
{
if(const SyncthingDev *dev = m_devModel.devInfo(devIndex)) {
if(dev->paused) {
m_connection.resume(dev->id);
} else {
m_connection.pause(dev->id);
}
}
}
void TrayWidget::handleStatusButtonClicked()
{
switch(m_connection.status()) {
@ -417,7 +430,7 @@ void TrayIcon::updateStatusIconAndText(SyncthingStatus status)
break;
case SyncthingStatus::Paused:
setIcon(m_statusIconPause);
setToolTip(tr("Syncthing has been suspended"));
setToolTip(tr("At least one device is paused"));
break;
case SyncthingStatus::Synchronizing:
setIcon(m_statusIconSync);

View File

@ -51,8 +51,9 @@ public slots:
private slots:
void updateStatusButton(Data::SyncthingStatus status);
void applySettings();
void openDir(const QModelIndex &index);
void scanDir(const QModelIndex &index);
void openDir(const QModelIndex &dirIndex);
void scanDir(const QModelIndex &dirIndex);
void pauseResumeDev(const QModelIndex &devIndex);
void handleStatusButtonClicked();
void handleWebViewDeleted();

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

View File

Before

Width:  |  Height:  |  Size: 116 KiB

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

View File

@ -4,79 +4,89 @@
<context>
<name>Data::SyncthingConnection</name>
<message>
<location filename="../data/syncthingconnection.cpp" line="65"/>
<location filename="../data/syncthingconnection.cpp" line="70"/>
<source>disconnected</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="67"/>
<location filename="../data/syncthingconnection.cpp" line="72"/>
<source>connected</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="69"/>
<location filename="../data/syncthingconnection.cpp" line="74"/>
<source>connected, notifications available</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="71"/>
<location filename="../data/syncthingconnection.cpp" line="76"/>
<source>connected, paused</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="73"/>
<location filename="../data/syncthingconnection.cpp" line="78"/>
<source>connected, synchronizing</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="75"/>
<location filename="../data/syncthingconnection.cpp" line="80"/>
<source>unknown</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="302"/>
<location filename="../data/syncthingconnection.cpp" line="355"/>
<source>Unable to parse Syncthing log: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="306"/>
<location filename="../data/syncthingconnection.cpp" line="359"/>
<source>Unable to request system log: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="332"/>
<location filename="../data/syncthingconnection.cpp" line="415"/>
<location filename="../data/syncthingconnection.cpp" line="387"/>
<location filename="../data/syncthingconnection.cpp" line="492"/>
<source>Unable to parse Syncthing config: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="337"/>
<location filename="../data/syncthingconnection.cpp" line="420"/>
<location filename="../data/syncthingconnection.cpp" line="392"/>
<location filename="../data/syncthingconnection.cpp" line="497"/>
<source>Unable to request Syncthing config: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="455"/>
<location filename="../data/syncthingconnection.cpp" line="553"/>
<source>Unable to parse connections: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="558"/>
<source>Unable to request connections: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="595"/>
<source>Unable to parse Syncthing events: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="478"/>
<location filename="../data/syncthingconnection.cpp" line="617"/>
<source>Unable to request Syncthing events: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="550"/>
<location filename="../data/syncthingconnection.cpp" line="727"/>
<source>Unable to request rescan: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="566"/>
<location filename="../data/syncthingconnection.cpp" line="742"/>
<source>Unable to request pause/resume: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="275"/>
<location filename="../data/syncthingconnection.cpp" line="323"/>
<source>Unable to request QR-Code: </source>
<translation type="unfinished"></translation>
</message>
@ -84,82 +94,96 @@
<context>
<name>Data::SyncthingDeviceModel</name>
<message>
<location filename="../data/syncthingdevicemodel.cpp" line="56"/>
<location filename="../data/syncthingdevicemodel.cpp" line="82"/>
<location filename="../data/syncthingdevicemodel.cpp" line="58"/>
<location filename="../data/syncthingdevicemodel.cpp" line="84"/>
<source>ID</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingdevicemodel.cpp" line="57"/>
<location filename="../data/syncthingdevicemodel.cpp" line="59"/>
<source>Status</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingdevicemodel.cpp" line="83"/>
<location filename="../data/syncthingdevicemodel.cpp" line="85"/>
<source>Addresses</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingdevicemodel.cpp" line="84"/>
<location filename="../data/syncthingdevicemodel.cpp" line="86"/>
<source>Compression</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingdevicemodel.cpp" line="85"/>
<location filename="../data/syncthingdevicemodel.cpp" line="87"/>
<source>Certificate</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingdevicemodel.cpp" line="86"/>
<location filename="../data/syncthingdevicemodel.cpp" line="88"/>
<source>Introducer</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingdevicemodel.cpp" line="95"/>
<location filename="../data/syncthingdevicemodel.cpp" line="97"/>
<source>none</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingdevicemodel.cpp" line="96"/>
<location filename="../data/syncthingdevicemodel.cpp" line="98"/>
<source>yes</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingdevicemodel.cpp" line="96"/>
<location filename="../data/syncthingdevicemodel.cpp" line="98"/>
<source>no</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingdevicemodel.cpp" line="115"/>
<location filename="../data/syncthingdevicemodel.cpp" line="120"/>
<source>Unknown status</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingdevicemodel.cpp" line="116"/>
<location filename="../data/syncthingdevicemodel.cpp" line="117"/>
<location filename="../data/syncthingdevicemodel.cpp" line="122"/>
<source>Idle</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingdevicemodel.cpp" line="118"/>
<location filename="../data/syncthingdevicemodel.cpp" line="123"/>
<source>Disconnected</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingdevicemodel.cpp" line="124"/>
<source>Synchronizing (%1 %)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingdevicemodel.cpp" line="118"/>
<location filename="../data/syncthingdevicemodel.cpp" line="124"/>
<source>Synchronizing</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingdevicemodel.cpp" line="119"/>
<location filename="../data/syncthingdevicemodel.cpp" line="121"/>
<source>Own device</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingdevicemodel.cpp" line="117"/>
<source>Paused</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingdevicemodel.cpp" line="120"/>
<location filename="../data/syncthingdevicemodel.cpp" line="125"/>
<source>Out of sync</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingdevicemodel.cpp" line="126"/>
<source>Rejected</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Data::SyncthingDirectoryModel</name>
@ -296,7 +320,7 @@
<context>
<name>QtGui::DevView</name>
<message>
<location filename="../gui/devview.cpp" line="25"/>
<location filename="../gui/devview.cpp" line="44"/>
<source>Copy</source>
<translation type="unfinished"></translation>
</message>
@ -361,67 +385,67 @@
<context>
<name>QtGui::TrayIcon</name>
<message>
<location filename="../gui/tray.cpp" line="333"/>
<location filename="../gui/tray.cpp" line="346"/>
<source>Web UI</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="334"/>
<location filename="../gui/tray.cpp" line="347"/>
<source>Settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="335"/>
<location filename="../gui/tray.cpp" line="348"/>
<source>About</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="337"/>
<location filename="../gui/tray.cpp" line="350"/>
<source>Close</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="389"/>
<location filename="../gui/tray.cpp" line="402"/>
<source>Syncthing error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="396"/>
<location filename="../gui/tray.cpp" line="409"/>
<source>Syncthing notification</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="405"/>
<location filename="../gui/tray.cpp" line="418"/>
<source>Not connected to Syncthing</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="407"/>
<location filename="../gui/tray.cpp" line="420"/>
<source>Disconnected from Syncthing</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="412"/>
<location filename="../gui/tray.cpp" line="425"/>
<source>Syncthing is running</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="416"/>
<location filename="../gui/tray.cpp" line="429"/>
<source>Notifications available</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="420"/>
<source>Syncthing has been suspended</source>
<location filename="../gui/tray.cpp" line="433"/>
<source>At least one device is paused</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="424"/>
<location filename="../gui/tray.cpp" line="437"/>
<source>Synchronization is ongoing</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="433"/>
<location filename="../gui/tray.cpp" line="446"/>
<source>Synchronization complete</source>
<translation type="unfinished"></translation>
</message>
@ -440,7 +464,7 @@
</message>
<message>
<location filename="../gui/traywidget.ui" line="103"/>
<location filename="../gui/tray.cpp" line="233"/>
<location filename="../gui/tray.cpp" line="235"/>
<source>Connect</source>
<translation type="unfinished"></translation>
</message>
@ -475,77 +499,77 @@
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="115"/>
<location filename="../gui/tray.cpp" line="117"/>
<source>Settings - Syncthing tray</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="134"/>
<location filename="../gui/tray.cpp" line="136"/>
<source>Tray application for Syncthing</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="90"/>
<location filename="../gui/tray.cpp" line="89"/>
<source>Rescan all directories</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="84"/>
<location filename="../gui/tray.cpp" line="83"/>
<source>Show Syncthing log</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="135"/>
<location filename="../gui/tray.cpp" line="137"/>
<source>About - Syncthing Tray</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="173"/>
<location filename="../gui/tray.cpp" line="175"/>
<source>Own device ID - Syncthing Tray</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="183"/>
<location filename="../gui/tray.cpp" line="185"/>
<source>device ID is unknown</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="191"/>
<location filename="../gui/tray.cpp" line="193"/>
<source>Copy to clipboard</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="207"/>
<location filename="../gui/tray.cpp" line="209"/>
<source>Log - Syncthing</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="234"/>
<location filename="../gui/tray.cpp" line="236"/>
<source>Not connected to Syncthing, click to connect</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="240"/>
<location filename="../gui/tray.cpp" line="242"/>
<source>Pause</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="241"/>
<source>Syncthing is doing its job, click to pause</source>
<location filename="../gui/tray.cpp" line="243"/>
<source>Syncthing is running, click to pause all devices</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="245"/>
<location filename="../gui/tray.cpp" line="248"/>
<source>At least one device is paused, click to resume</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="247"/>
<source>Continue</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="246"/>
<source>Syncthing is suspended, click to continue</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="270"/>
<location filename="../gui/tray.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>

View File

@ -4,79 +4,89 @@
<context>
<name>Data::SyncthingConnection</name>
<message>
<location filename="../data/syncthingconnection.cpp" line="65"/>
<location filename="../data/syncthingconnection.cpp" line="70"/>
<source>disconnected</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="67"/>
<location filename="../data/syncthingconnection.cpp" line="72"/>
<source>connected</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="69"/>
<location filename="../data/syncthingconnection.cpp" line="74"/>
<source>connected, notifications available</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="71"/>
<location filename="../data/syncthingconnection.cpp" line="76"/>
<source>connected, paused</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="73"/>
<location filename="../data/syncthingconnection.cpp" line="78"/>
<source>connected, synchronizing</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="75"/>
<location filename="../data/syncthingconnection.cpp" line="80"/>
<source>unknown</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="302"/>
<location filename="../data/syncthingconnection.cpp" line="355"/>
<source>Unable to parse Syncthing log: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="306"/>
<location filename="../data/syncthingconnection.cpp" line="359"/>
<source>Unable to request system log: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="332"/>
<location filename="../data/syncthingconnection.cpp" line="415"/>
<location filename="../data/syncthingconnection.cpp" line="387"/>
<location filename="../data/syncthingconnection.cpp" line="492"/>
<source>Unable to parse Syncthing config: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="337"/>
<location filename="../data/syncthingconnection.cpp" line="420"/>
<location filename="../data/syncthingconnection.cpp" line="392"/>
<location filename="../data/syncthingconnection.cpp" line="497"/>
<source>Unable to request Syncthing config: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="455"/>
<location filename="../data/syncthingconnection.cpp" line="553"/>
<source>Unable to parse connections: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="558"/>
<source>Unable to request connections: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="595"/>
<source>Unable to parse Syncthing events: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="478"/>
<location filename="../data/syncthingconnection.cpp" line="617"/>
<source>Unable to request Syncthing events: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="550"/>
<location filename="../data/syncthingconnection.cpp" line="727"/>
<source>Unable to request rescan: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="566"/>
<location filename="../data/syncthingconnection.cpp" line="742"/>
<source>Unable to request pause/resume: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingconnection.cpp" line="275"/>
<location filename="../data/syncthingconnection.cpp" line="323"/>
<source>Unable to request QR-Code: </source>
<translation type="unfinished"></translation>
</message>
@ -84,82 +94,96 @@
<context>
<name>Data::SyncthingDeviceModel</name>
<message>
<location filename="../data/syncthingdevicemodel.cpp" line="56"/>
<location filename="../data/syncthingdevicemodel.cpp" line="82"/>
<location filename="../data/syncthingdevicemodel.cpp" line="58"/>
<location filename="../data/syncthingdevicemodel.cpp" line="84"/>
<source>ID</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingdevicemodel.cpp" line="57"/>
<location filename="../data/syncthingdevicemodel.cpp" line="59"/>
<source>Status</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingdevicemodel.cpp" line="83"/>
<location filename="../data/syncthingdevicemodel.cpp" line="85"/>
<source>Addresses</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingdevicemodel.cpp" line="84"/>
<location filename="../data/syncthingdevicemodel.cpp" line="86"/>
<source>Compression</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingdevicemodel.cpp" line="85"/>
<location filename="../data/syncthingdevicemodel.cpp" line="87"/>
<source>Certificate</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingdevicemodel.cpp" line="86"/>
<location filename="../data/syncthingdevicemodel.cpp" line="88"/>
<source>Introducer</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingdevicemodel.cpp" line="95"/>
<location filename="../data/syncthingdevicemodel.cpp" line="97"/>
<source>none</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingdevicemodel.cpp" line="96"/>
<location filename="../data/syncthingdevicemodel.cpp" line="98"/>
<source>yes</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingdevicemodel.cpp" line="96"/>
<location filename="../data/syncthingdevicemodel.cpp" line="98"/>
<source>no</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingdevicemodel.cpp" line="115"/>
<location filename="../data/syncthingdevicemodel.cpp" line="120"/>
<source>Unknown status</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingdevicemodel.cpp" line="116"/>
<location filename="../data/syncthingdevicemodel.cpp" line="117"/>
<location filename="../data/syncthingdevicemodel.cpp" line="122"/>
<source>Idle</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingdevicemodel.cpp" line="118"/>
<location filename="../data/syncthingdevicemodel.cpp" line="123"/>
<source>Disconnected</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingdevicemodel.cpp" line="124"/>
<source>Synchronizing (%1 %)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingdevicemodel.cpp" line="118"/>
<location filename="../data/syncthingdevicemodel.cpp" line="124"/>
<source>Synchronizing</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingdevicemodel.cpp" line="119"/>
<location filename="../data/syncthingdevicemodel.cpp" line="121"/>
<source>Own device</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingdevicemodel.cpp" line="117"/>
<source>Paused</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingdevicemodel.cpp" line="120"/>
<location filename="../data/syncthingdevicemodel.cpp" line="125"/>
<source>Out of sync</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../data/syncthingdevicemodel.cpp" line="126"/>
<source>Rejected</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Data::SyncthingDirectoryModel</name>
@ -296,7 +320,7 @@
<context>
<name>QtGui::DevView</name>
<message>
<location filename="../gui/devview.cpp" line="25"/>
<location filename="../gui/devview.cpp" line="44"/>
<source>Copy</source>
<translation type="unfinished"></translation>
</message>
@ -361,67 +385,67 @@
<context>
<name>QtGui::TrayIcon</name>
<message>
<location filename="../gui/tray.cpp" line="333"/>
<location filename="../gui/tray.cpp" line="346"/>
<source>Web UI</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="334"/>
<location filename="../gui/tray.cpp" line="347"/>
<source>Settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="335"/>
<location filename="../gui/tray.cpp" line="348"/>
<source>About</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="337"/>
<location filename="../gui/tray.cpp" line="350"/>
<source>Close</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="389"/>
<location filename="../gui/tray.cpp" line="402"/>
<source>Syncthing error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="396"/>
<location filename="../gui/tray.cpp" line="409"/>
<source>Syncthing notification</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="405"/>
<location filename="../gui/tray.cpp" line="418"/>
<source>Not connected to Syncthing</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="407"/>
<location filename="../gui/tray.cpp" line="420"/>
<source>Disconnected from Syncthing</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="412"/>
<location filename="../gui/tray.cpp" line="425"/>
<source>Syncthing is running</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="416"/>
<location filename="../gui/tray.cpp" line="429"/>
<source>Notifications available</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="420"/>
<source>Syncthing has been suspended</source>
<location filename="../gui/tray.cpp" line="433"/>
<source>At least one device is paused</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="424"/>
<location filename="../gui/tray.cpp" line="437"/>
<source>Synchronization is ongoing</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="433"/>
<location filename="../gui/tray.cpp" line="446"/>
<source>Synchronization complete</source>
<translation type="unfinished"></translation>
</message>
@ -440,7 +464,7 @@
</message>
<message>
<location filename="../gui/traywidget.ui" line="103"/>
<location filename="../gui/tray.cpp" line="233"/>
<location filename="../gui/tray.cpp" line="235"/>
<source>Connect</source>
<translation type="unfinished"></translation>
</message>
@ -475,77 +499,77 @@
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="115"/>
<location filename="../gui/tray.cpp" line="117"/>
<source>Settings - Syncthing tray</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="134"/>
<location filename="../gui/tray.cpp" line="136"/>
<source>Tray application for Syncthing</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="90"/>
<location filename="../gui/tray.cpp" line="89"/>
<source>Rescan all directories</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="84"/>
<location filename="../gui/tray.cpp" line="83"/>
<source>Show Syncthing log</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="135"/>
<location filename="../gui/tray.cpp" line="137"/>
<source>About - Syncthing Tray</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="173"/>
<location filename="../gui/tray.cpp" line="175"/>
<source>Own device ID - Syncthing Tray</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="183"/>
<location filename="../gui/tray.cpp" line="185"/>
<source>device ID is unknown</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="191"/>
<location filename="../gui/tray.cpp" line="193"/>
<source>Copy to clipboard</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="207"/>
<location filename="../gui/tray.cpp" line="209"/>
<source>Log - Syncthing</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="234"/>
<location filename="../gui/tray.cpp" line="236"/>
<source>Not connected to Syncthing, click to connect</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="240"/>
<location filename="../gui/tray.cpp" line="242"/>
<source>Pause</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="241"/>
<source>Syncthing is doing its job, click to pause</source>
<location filename="../gui/tray.cpp" line="243"/>
<source>Syncthing is running, click to pause all devices</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="245"/>
<location filename="../gui/tray.cpp" line="248"/>
<source>At least one device is paused, click to resume</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="247"/>
<source>Continue</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="246"/>
<source>Syncthing is suspended, click to continue</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tray.cpp" line="270"/>
<location filename="../gui/tray.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>