syncthingtray/tray/gui/traywidget.cpp

655 lines
27 KiB
C++
Raw Normal View History

2016-08-30 20:01:07 +02:00
#include "./traywidget.h"
#include "./trayicon.h"
2017-05-01 03:34:43 +02:00
#include "./traymenu.h"
2016-08-25 00:45:32 +02:00
2017-05-01 03:34:43 +02:00
#include "../../widgets/misc/textviewdialog.h"
#include "../../widgets/settings/settingsdialog.h"
#include "../../widgets/webview/webviewdialog.h"
2016-08-25 00:45:32 +02:00
#ifdef LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD
2017-05-01 03:34:43 +02:00
#include "../../connector/syncthingservice.h"
#include "../../connector/utils.h"
#endif
2017-07-08 01:31:41 +02:00
// use meta-data of syncthingtray application here
#include "resources/../../tray/resources/config.h"
2016-08-25 00:45:32 +02:00
#include "ui_traywidget.h"
2017-05-01 03:34:43 +02:00
#include <qtutilities/aboutdialog/aboutdialog.h>
#include <qtutilities/misc/desktoputils.h>
#include <qtutilities/misc/dialogutils.h>
2016-08-25 00:45:32 +02:00
#include <qtutilities/resources/qtconfigarguments.h>
#include <qtutilities/resources/resources.h>
#include <qtutilities/settingsdialog/qtsettings.h>
2016-08-29 20:51:30 +02:00
#include <c++utilities/conversion/stringconversion.h>
2017-05-01 03:34:43 +02:00
#include <QClipboard>
2016-08-30 20:01:07 +02:00
#include <QCoreApplication>
2017-05-01 03:34:43 +02:00
#include <QCursor>
2016-08-25 00:45:32 +02:00
#include <QDesktopServices>
#include <QDir>
2016-09-03 19:39:43 +02:00
#include <QFontDatabase>
2017-05-01 03:34:43 +02:00
#include <QMessageBox>
#include <QStringBuilder>
#include <QTextBrowser>
2016-08-25 00:45:32 +02:00
#include <algorithm>
2017-05-01 03:34:43 +02:00
#include <functional>
2016-08-25 00:45:32 +02:00
using namespace ApplicationUtilities;
2016-08-29 20:51:30 +02:00
using namespace ConversionUtilities;
using namespace ChronoUtilities;
2016-08-25 00:45:32 +02:00
using namespace Dialogs;
using namespace Data;
using namespace std;
namespace QtGui {
2016-09-25 20:54:09 +02:00
SettingsDialog *TrayWidget::m_settingsDlg = nullptr;
Dialogs::AboutDialog *TrayWidget::m_aboutDlg = nullptr;
vector<TrayWidget *> TrayWidget::m_instances;
2016-08-25 00:45:32 +02:00
/*!
* \brief Instantiates a new tray widget.
*/
TrayWidget::TrayWidget(const QString &connectionConfig, TrayMenu *parent)
2017-05-01 03:34:43 +02:00
: QWidget(parent)
, m_menu(parent)
, m_ui(new Ui::TrayWidget)
,
#ifndef SYNCTHINGWIDGETS_NO_WEBVIEW
2017-05-01 03:34:43 +02:00
m_webViewDlg(nullptr)
,
2016-08-25 00:45:32 +02:00
#endif
2017-05-01 03:34:43 +02:00
m_dirModel(m_connection)
, m_devModel(m_connection)
, m_dlModel(m_connection)
, m_selectedConnection(nullptr)
2016-08-25 00:45:32 +02:00
{
m_instances.push_back(this);
2016-08-25 00:45:32 +02:00
m_ui->setupUi(this);
// setup model and view
m_ui->dirsTreeView->setModel(&m_dirModel);
m_ui->devsTreeView->setModel(&m_devModel);
2016-09-21 21:09:12 +02:00
m_ui->downloadsTreeView->setModel(&m_dlModel);
2016-08-25 00:45:32 +02:00
// setup sync-all button
2016-09-03 19:39:43 +02:00
m_cornerFrame = new QFrame(this);
auto *cornerFrameLayout = new QHBoxLayout(m_cornerFrame);
2016-08-25 00:45:32 +02:00
cornerFrameLayout->setSpacing(0), cornerFrameLayout->setMargin(0);
2016-09-03 19:39:43 +02:00
//cornerFrameLayout->addStretch();
m_cornerFrame->setLayout(cornerFrameLayout);
auto *viewIdButton = new QPushButton(m_cornerFrame);
2016-08-25 00:45:32 +02:00
viewIdButton->setToolTip(tr("View own device ID"));
2017-05-01 03:34:43 +02:00
viewIdButton->setIcon(
QIcon::fromTheme(QStringLiteral("view-barcode"), QIcon(QStringLiteral(":/icons/hicolor/scalable/actions/view-barcode.svg"))));
2016-08-25 00:45:32 +02:00
viewIdButton->setFlat(true);
cornerFrameLayout->addWidget(viewIdButton);
2016-09-03 19:39:43 +02:00
auto *restartButton = new QPushButton(m_cornerFrame);
restartButton->setToolTip(tr("Restart Syncthing"));
2017-05-01 03:34:43 +02:00
restartButton->setIcon(
QIcon::fromTheme(QStringLiteral("system-reboot"), QIcon(QStringLiteral(":/icons/hicolor/scalable/actions/view-refresh.svg"))));
2016-09-03 19:39:43 +02:00
restartButton->setFlat(true);
cornerFrameLayout->addWidget(restartButton);
auto *showLogButton = new QPushButton(m_cornerFrame);
2016-08-25 00:45:32 +02:00
showLogButton->setToolTip(tr("Show Syncthing log"));
2017-05-01 03:34:43 +02:00
showLogButton->setIcon(
QIcon::fromTheme(QStringLiteral("text-x-generic"), QIcon(QStringLiteral(":/icons/hicolor/scalable/mimetypes/text-x-generic.svg"))));
2016-08-25 00:45:32 +02:00
showLogButton->setFlat(true);
cornerFrameLayout->addWidget(showLogButton);
2016-09-03 19:39:43 +02:00
auto *scanAllButton = new QPushButton(m_cornerFrame);
2016-08-25 00:45:32 +02:00
scanAllButton->setToolTip(tr("Rescan all directories"));
2017-05-01 03:34:43 +02:00
scanAllButton->setIcon(
QIcon::fromTheme(QStringLiteral("folder-sync"), QIcon(QStringLiteral(":/icons/hicolor/scalable/actions/folder-sync.svg"))));
2016-08-25 00:45:32 +02:00
scanAllButton->setFlat(true);
cornerFrameLayout->addWidget(scanAllButton);
2016-09-03 19:39:43 +02:00
m_ui->tabWidget->setCornerWidget(m_cornerFrame, Qt::BottomRightCorner);
2016-09-03 20:14:52 +02:00
// setup connection menu
m_connectionsActionGroup = new QActionGroup(m_connectionsMenu = new QMenu(tr("Connection"), this));
2017-05-01 03:34:43 +02:00
m_connectionsMenu->setIcon(
QIcon::fromTheme(QStringLiteral("network-connect"), QIcon(QStringLiteral(":/icons/hicolor/scalable/actions/network-connect.svg"))));
2016-09-17 19:13:49 +02:00
m_ui->connectionsPushButton->setMenu(m_connectionsMenu);
2016-09-03 20:14:52 +02:00
2016-12-26 19:19:10 +01:00
// setup notifications menu
m_notificationsMenu = new QMenu(tr("New notifications"), this);
m_notificationsMenu->addAction(m_ui->actionShowNotifications);
m_notificationsMenu->addAction(m_ui->actionDismissNotifications);
m_ui->notificationsPushButton->setMenu(m_notificationsMenu);
2016-12-10 11:55:08 +01:00
// apply settings, this also establishes the connection to Syncthing (according to settings)
applySettings(connectionConfig);
2016-08-25 00:45:32 +02:00
// setup other widgets
m_ui->notificationsPushButton->setHidden(true);
2017-05-01 03:34:43 +02:00
m_ui->trafficIconLabel->setPixmap(
QIcon::fromTheme(QStringLiteral("network-card"), QIcon(QStringLiteral(":/icons/hicolor/scalable/devices/network-card.svg"))).pixmap(32));
#ifndef LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD
delete m_ui->startStopPushButton;
#endif
2016-08-29 20:51:30 +02:00
2016-08-25 00:45:32 +02:00
// connect signals and slots
2016-08-29 20:51:30 +02:00
connect(m_ui->statusPushButton, &QPushButton::clicked, this, &TrayWidget::changeStatus);
connect(m_ui->closePushButton, &QPushButton::clicked, this, &TrayWidget::quitTray);
2016-08-25 00:45:32 +02:00
connect(m_ui->aboutPushButton, &QPushButton::clicked, this, &TrayWidget::showAboutDialog);
connect(m_ui->webUiPushButton, &QPushButton::clicked, this, &TrayWidget::showWebUi);
connect(m_ui->settingsPushButton, &QPushButton::clicked, this, &TrayWidget::showSettingsDialog);
connect(&m_connection, &SyncthingConnection::statusChanged, this, &TrayWidget::handleStatusChanged);
2016-08-29 20:51:30 +02:00
connect(&m_connection, &SyncthingConnection::trafficChanged, this, &TrayWidget::updateTraffic);
2016-09-01 16:34:30 +02:00
connect(&m_connection, &SyncthingConnection::newNotification, this, &TrayWidget::handleNewNotification);
2016-08-25 00:45:32 +02:00
connect(m_ui->dirsTreeView, &DirView::openDir, this, &TrayWidget::openDir);
connect(m_ui->dirsTreeView, &DirView::scanDir, this, &TrayWidget::scanDir);
2017-02-23 15:49:58 +01:00
connect(m_ui->dirsTreeView, &DirView::pauseResumeDir, this, &TrayWidget::pauseResumeDir);
2016-08-26 16:43:53 +02:00
connect(m_ui->devsTreeView, &DevView::pauseResumeDev, this, &TrayWidget::pauseResumeDev);
2016-09-21 21:09:12 +02:00
connect(m_ui->downloadsTreeView, &DownloadView::openDir, this, &TrayWidget::openDir);
connect(m_ui->downloadsTreeView, &DownloadView::openItemDir, this, &TrayWidget::openItemDir);
2016-08-26 16:43:53 +02:00
connect(scanAllButton, &QPushButton::clicked, &m_connection, &SyncthingConnection::rescanAllDirs);
connect(viewIdButton, &QPushButton::clicked, this, &TrayWidget::showOwnDeviceId);
connect(showLogButton, &QPushButton::clicked, this, &TrayWidget::showLog);
connect(m_ui->notificationsPushButton, &QPushButton::clicked, this, &TrayWidget::showNotifications);
2016-10-05 00:01:55 +02:00
connect(restartButton, &QPushButton::clicked, this, &TrayWidget::restartSyncthing);
2016-09-03 20:14:52 +02:00
connect(m_connectionsActionGroup, &QActionGroup::triggered, this, &TrayWidget::handleConnectionSelected);
2016-12-26 19:19:10 +01:00
connect(m_ui->actionShowNotifications, &QAction::triggered, this, &TrayWidget::showNotifications);
connect(m_ui->actionDismissNotifications, &QAction::triggered, this, &TrayWidget::dismissNotifications);
#ifdef LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD
const SyncthingService &service = syncthingService();
connect(m_ui->startStopPushButton, &QPushButton::clicked, &service, &SyncthingService::toggleRunning);
connect(&service, &SyncthingService::systemdAvailableChanged, this, &TrayWidget::handleSystemdStatusChanged);
connect(&service, &SyncthingService::stateChanged, this, &TrayWidget::handleSystemdStatusChanged);
#endif
2016-08-25 00:45:32 +02:00
}
TrayWidget::~TrayWidget()
{
auto i = std::find(m_instances.begin(), m_instances.end(), this);
2017-05-01 03:34:43 +02:00
if (i != m_instances.end()) {
m_instances.erase(i);
}
2017-05-01 03:34:43 +02:00
if (m_instances.empty()) {
QCoreApplication::quit();
}
}
2016-08-25 00:45:32 +02:00
void TrayWidget::showSettingsDialog()
{
2017-05-01 03:34:43 +02:00
if (!m_settingsDlg) {
2016-08-25 00:45:32 +02:00
m_settingsDlg = new SettingsDialog(&m_connection, this);
connect(m_settingsDlg, &SettingsDialog::applied, &TrayWidget::applySettingsOnAllInstances);
2016-08-25 00:45:32 +02:00
}
centerWidget(m_settingsDlg);
showDialog(m_settingsDlg);
2016-08-25 00:45:32 +02:00
}
void TrayWidget::showAboutDialog()
{
2017-05-01 03:34:43 +02:00
if (!m_aboutDlg) {
m_aboutDlg = new AboutDialog(this, QString(),
QStringLiteral(APP_AUTHOR "\nfallback icons from KDE/Breeze project\nSyncthing icons from Syncthing project"), QString(), QString(),
QStringLiteral(APP_DESCRIPTION), QImage(QStringLiteral(":/icons/hicolor/scalable/app/syncthingtray.svg")));
2016-09-01 16:34:30 +02:00
m_aboutDlg->setWindowTitle(tr("About") + QStringLiteral(" - " APP_NAME));
2016-08-25 00:45:32 +02:00
m_aboutDlg->setWindowIcon(QIcon(QStringLiteral(":/icons/hicolor/scalable/app/syncthingtray.svg")));
}
centerWidget(m_aboutDlg);
showDialog(m_aboutDlg);
2016-08-25 00:45:32 +02:00
}
void TrayWidget::showWebUi()
{
#ifndef SYNCTHINGWIDGETS_NO_WEBVIEW
2017-05-01 03:34:43 +02:00
if (Settings::values().webView.disabled) {
2016-08-25 00:45:32 +02:00
#endif
2016-09-03 20:14:52 +02:00
QDesktopServices::openUrl(m_connection.syncthingUrl());
#ifndef SYNCTHINGWIDGETS_NO_WEBVIEW
2016-08-25 00:45:32 +02:00
} else {
2017-05-01 03:34:43 +02:00
if (!m_webViewDlg) {
2016-08-25 00:45:32 +02:00
m_webViewDlg = new WebViewDialog(this);
2017-05-01 03:34:43 +02:00
if (m_selectedConnection) {
2016-09-03 20:14:52 +02:00
m_webViewDlg->applySettings(*m_selectedConnection);
2016-08-25 00:45:32 +02:00
}
2016-09-03 20:14:52 +02:00
connect(m_webViewDlg, &WebViewDialog::destroyed, this, &TrayWidget::handleWebViewDeleted);
2016-08-25 00:45:32 +02:00
}
showDialog(m_webViewDlg);
2016-08-25 00:45:32 +02:00
}
#endif
}
void TrayWidget::showOwnDeviceId()
{
2016-09-03 19:39:43 +02:00
auto *dlg = new QWidget(this, Qt::Window);
2016-09-01 16:34:30 +02:00
dlg->setWindowTitle(tr("Own device ID") + QStringLiteral(" - " APP_NAME));
2016-08-25 00:45:32 +02:00
dlg->setWindowIcon(QIcon(QStringLiteral(":/icons/hicolor/scalable/app/syncthingtray.svg")));
dlg->setAttribute(Qt::WA_DeleteOnClose);
dlg->setBackgroundRole(QPalette::Background);
auto *layout = new QVBoxLayout(dlg);
layout->setAlignment(Qt::AlignCenter);
auto *pixmapLabel = new QLabel(dlg);
pixmapLabel->setAlignment(Qt::AlignCenter);
layout->addWidget(pixmapLabel);
auto *textLabel = new QLabel(dlg);
textLabel->setText(m_connection.myId().isEmpty() ? tr("device ID is unknown") : m_connection.myId());
QFont defaultFont = textLabel->font();
defaultFont.setBold(true);
defaultFont.setPointSize(defaultFont.pointSize() + 2);
textLabel->setFont(defaultFont);
textLabel->setAlignment(Qt::AlignCenter);
layout->addWidget(textLabel);
auto *copyPushButton = new QPushButton(dlg);
copyPushButton->setText(tr("Copy to clipboard"));
2017-05-01 03:34:43 +02:00
connect(
copyPushButton, &QPushButton::clicked, bind(&QClipboard::setText, QGuiApplication::clipboard(), m_connection.myId(), QClipboard::Clipboard));
2016-08-25 00:45:32 +02:00
layout->addWidget(copyPushButton);
2017-05-01 03:34:43 +02:00
connect(dlg, &QWidget::destroyed, bind(static_cast<bool (*)(const QMetaObject::Connection &)>(&QObject::disconnect),
m_connection.requestQrCode(m_connection.myId(), [pixmapLabel](const QByteArray &data) {
QPixmap pixmap;
pixmap.loadFromData(data);
pixmapLabel->setPixmap(pixmap);
})));
2016-08-25 00:45:32 +02:00
dlg->setLayout(layout);
centerWidget(dlg);
showDialog(dlg);
2016-08-25 00:45:32 +02:00
}
void TrayWidget::showLog()
{
auto *dlg = new TextViewDialog(tr("Log"), this);
2016-12-11 20:52:46 +01:00
auto loadLog = [dlg, this] {
2017-05-01 03:34:43 +02:00
connect(dlg, &QWidget::destroyed, bind(static_cast<bool (*)(const QMetaObject::Connection &)>(&QObject::disconnect),
m_connection.requestLog([dlg, this](const std::vector<SyncthingLogEntry> &entries) {
dlg->browser()->clear();
for (const SyncthingLogEntry &entry : entries) {
dlg->browser()->append(
entry.when % QChar(':') % QChar(' ') % QChar('\n') % entry.message % QChar('\n'));
}
})));
2016-12-11 20:52:46 +01:00
};
connect(dlg, &TextViewDialog::reload, loadLog);
loadLog();
showDialog(dlg);
}
void TrayWidget::showNotifications()
{
auto *dlg = new TextViewDialog(tr("New notifications"), this);
2017-05-01 03:34:43 +02:00
for (const SyncthingLogEntry &entry : m_notifications) {
dlg->browser()->append(entry.when % QChar(':') % QChar(' ') % QChar('\n') % entry.message % QChar('\n'));
2016-08-25 00:45:32 +02:00
}
m_notifications.clear();
showDialog(dlg);
2016-12-10 12:03:08 +01:00
dismissNotifications();
}
2016-12-26 19:50:10 +01:00
void TrayWidget::showAtCursor()
{
2017-05-01 03:34:43 +02:00
if (m_menu) {
2016-12-26 19:50:10 +01:00
m_menu->showAtCursor();
} else {
move(QCursor::pos());
show();
}
}
2016-12-10 12:03:08 +01:00
void TrayWidget::dismissNotifications()
{
2016-09-27 21:20:17 +02:00
m_connection.considerAllNotificationsRead();
m_ui->notificationsPushButton->setHidden(true);
2017-05-01 03:34:43 +02:00
if (m_menu && m_menu->icon()) {
m_menu->icon()->updateStatusIconAndText();
}
2016-08-25 00:45:32 +02:00
}
2016-10-05 00:01:55 +02:00
void TrayWidget::restartSyncthing()
{
2017-05-01 03:34:43 +02:00
if (QMessageBox::warning(
this, QCoreApplication::applicationName(), tr("Do you really want to restart Syncthing?"), QMessageBox::Yes, QMessageBox::No)
== QMessageBox::Yes) {
2016-10-05 00:01:55 +02:00
m_connection.restart();
}
}
void TrayWidget::quitTray()
{
QObject *parent;
2017-05-01 03:34:43 +02:00
if (m_menu) {
if (m_menu->icon()) {
parent = m_menu->icon();
} else {
parent = m_menu;
}
} else {
parent = this;
}
parent->deleteLater();
}
void TrayWidget::handleStatusChanged(SyncthingStatus status)
2016-08-25 00:45:32 +02:00
{
2017-05-01 03:34:43 +02:00
switch (status) {
2016-08-25 00:45:32 +02:00
case SyncthingStatus::Disconnected:
m_ui->statusPushButton->setText(tr("Connect"));
m_ui->statusPushButton->setToolTip(tr("Not connected to Syncthing, click to connect"));
2017-05-01 03:34:43 +02:00
m_ui->statusPushButton->setIcon(
QIcon::fromTheme(QStringLiteral("view-refresh"), QIcon(QStringLiteral(":/icons/hicolor/scalable/actions/view-refresh.svg"))));
m_ui->statusPushButton->setHidden(false);
updateTraffic(); // ensure previous traffic statistics are no longer shown
break;
case SyncthingStatus::Reconnecting:
m_ui->statusPushButton->setHidden(true);
2016-08-25 00:45:32 +02:00
break;
2016-09-03 19:39:43 +02:00
case SyncthingStatus::Idle:
case SyncthingStatus::Scanning:
2016-08-25 00:45:32 +02:00
case SyncthingStatus::Synchronizing:
m_ui->statusPushButton->setText(tr("Pause"));
2016-08-26 16:43:53 +02:00
m_ui->statusPushButton->setToolTip(tr("Syncthing is running, click to pause all devices"));
2017-05-01 03:34:43 +02:00
m_ui->statusPushButton->setIcon(QIcon::fromTheme(
QStringLiteral("media-playback-pause"), QIcon(QStringLiteral(":/icons/hicolor/scalable/actions/media-playback-pause.svg"))));
m_ui->statusPushButton->setHidden(false);
2016-08-25 00:45:32 +02:00
break;
case SyncthingStatus::Paused:
m_ui->statusPushButton->setText(tr("Continue"));
2016-08-26 16:43:53 +02:00
m_ui->statusPushButton->setToolTip(tr("At least one device is paused, click to resume"));
2017-05-01 03:34:43 +02:00
m_ui->statusPushButton->setIcon(QIcon::fromTheme(
2017-07-02 21:55:41 +02:00
QStringLiteral("media-playback-start"), QIcon(QStringLiteral(":/icons/hicolor/scalable/actions/media-playback-start.svg"))));
m_ui->statusPushButton->setHidden(false);
2016-08-25 00:45:32 +02:00
break;
2017-05-01 03:34:43 +02:00
default:;
2016-08-25 00:45:32 +02:00
}
}
void TrayWidget::applySettings(const QString &connectionConfig)
2016-08-25 00:45:32 +02:00
{
// update connections menu
int connectionIndex = 0;
auto &settings = Settings::values();
auto &primaryConnectionSettings = settings.connection.primary;
auto &secondaryConnectionSettings = settings.connection.secondary;
const int connectionCount = static_cast<int>(1 + secondaryConnectionSettings.size());
const QList<QAction *> connectionActions = m_connectionsActionGroup->actions();
m_selectedConnection = nullptr;
bool specifiedConnectionConfigFound = false;
for (; connectionIndex < connectionCount; ++connectionIndex) {
SyncthingConnectionSettings &connectionSettings
= (connectionIndex == 0 ? primaryConnectionSettings : secondaryConnectionSettings[static_cast<size_t>(connectionIndex - 1)]);
QAction *action;
if (connectionIndex < connectionActions.size()) {
action = connectionActions.at(connectionIndex);
action->setText(connectionSettings.label);
if (action->isChecked() && !m_selectedConnection) {
m_selectedConnection = &connectionSettings;
2016-09-03 20:14:52 +02:00
}
} else {
action = m_connectionsMenu->addAction(connectionSettings.label);
action->setCheckable(true);
m_connectionsActionGroup->addAction(action);
2016-09-03 20:14:52 +02:00
}
if (!connectionConfig.isEmpty() && !connectionSettings.label.compare(connectionConfig, Qt::CaseInsensitive)) {
m_selectedConnection = &connectionSettings;
specifiedConnectionConfigFound = true;
action->setChecked(true);
2016-09-25 20:54:09 +02:00
}
}
for (; connectionIndex < connectionActions.size(); ++connectionIndex) {
delete connectionActions.at(connectionIndex);
}
if (!m_selectedConnection) {
m_selectedConnection = &primaryConnectionSettings;
m_connectionsMenu->actions().at(0)->setChecked(true);
}
m_ui->connectionsPushButton->setText(m_selectedConnection->label);
const bool reconnectRequired = m_connection.applySettings(*m_selectedConnection);
#ifdef LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD
// reconnect to apply settings considering systemd
const bool couldReconnect = handleSystemdStatusChanged();
if (reconnectRequired && couldReconnect) {
m_connection.reconnect();
}
#else
m_connection.reconnect();
#endif
2016-09-03 20:14:52 +02:00
#ifndef SYNCTHINGWIDGETS_NO_WEBVIEW
// web view
if (m_webViewDlg) {
m_webViewDlg->applySettings(*m_selectedConnection);
}
2016-09-03 20:14:52 +02:00
#endif
// update visual appearance
m_ui->trafficFormWidget->setVisible(settings.appearance.showTraffic);
m_ui->trafficIconLabel->setVisible(settings.appearance.showTraffic);
m_ui->trafficHorizontalSpacer->changeSize(
0, 20, settings.appearance.showTraffic ? QSizePolicy::Expanding : QSizePolicy::Ignored, QSizePolicy::Minimum);
if (settings.appearance.showTraffic) {
updateTraffic();
}
m_ui->infoFrame->setFrameStyle(settings.appearance.frameStyle);
m_ui->buttonsFrame->setFrameStyle(settings.appearance.frameStyle);
if (QApplication::style() && !QApplication::style()->objectName().compare(QLatin1String("adwaita"), Qt::CaseInsensitive)) {
m_cornerFrame->setFrameStyle(QFrame::NoFrame);
} else {
m_cornerFrame->setFrameStyle(settings.appearance.frameStyle);
}
if (settings.appearance.tabPosition >= QTabWidget::North && settings.appearance.tabPosition <= QTabWidget::East) {
m_ui->tabWidget->setTabPosition(static_cast<QTabWidget::TabPosition>(settings.appearance.tabPosition));
}
m_dirModel.setBrightColors(settings.appearance.brightTextColors);
m_devModel.setBrightColors(settings.appearance.brightTextColors);
m_dlModel.setBrightColors(settings.appearance.brightTextColors);
// show warning when explicitely specified connection configuration was not found
if (!specifiedConnectionConfigFound && !connectionConfig.isEmpty()) {
auto *const msgBox = new QMessageBox(QMessageBox::Warning, QCoreApplication::applicationName(),
tr("The specified connection configuration <em>%1</em> is not defined and hence ignored.").arg(connectionConfig));
msgBox->setAttribute(Qt::WA_DeleteOnClose);
msgBox->show();
}
}
void TrayWidget::applySettingsOnAllInstances()
{
for (TrayWidget *instance : m_instances) {
instance->applySettings();
2016-09-03 19:39:43 +02:00
}
2016-08-25 00:45:32 +02:00
}
2016-09-21 21:09:12 +02:00
void TrayWidget::openDir(const SyncthingDir &dir)
2016-08-25 00:45:32 +02:00
{
2017-05-01 03:34:43 +02:00
if (QDir(dir.path).exists()) {
2016-09-21 21:09:12 +02:00
DesktopUtils::openLocalFileOrDir(dir.path);
} else {
2017-05-01 03:34:43 +02:00
QMessageBox::warning(
this, QCoreApplication::applicationName(), tr("The directory <i>%1</i> does not exist on the local machine.").arg(dir.path));
2016-08-25 00:45:32 +02:00
}
}
2016-09-21 21:09:12 +02:00
void TrayWidget::openItemDir(const SyncthingItemDownloadProgress &item)
2016-08-25 00:45:32 +02:00
{
const QDir containingDir(item.fileInfo.absoluteDir());
2017-05-01 03:34:43 +02:00
if (containingDir.exists()) {
DesktopUtils::openLocalFileOrDir(containingDir.path());
2016-09-21 21:09:12 +02:00
} else {
2017-05-01 03:34:43 +02:00
QMessageBox::warning(this, QCoreApplication::applicationName(),
tr("The containing directory <i>%1</i> does not exist on the local machine.").arg(item.fileInfo.filePath()));
2016-08-25 00:45:32 +02:00
}
}
2016-09-21 21:09:12 +02:00
void TrayWidget::scanDir(const SyncthingDir &dir)
2016-08-26 16:43:53 +02:00
{
2016-09-21 21:09:12 +02:00
m_connection.rescan(dir.id);
}
void TrayWidget::pauseResumeDev(const SyncthingDev &dev)
{
2017-05-01 03:34:43 +02:00
if (dev.paused) {
m_connection.resumeDevice(QStringList(dev.id));
2016-09-21 21:09:12 +02:00
} else {
m_connection.pauseDevice(QStringList(dev.id));
2016-08-26 16:43:53 +02:00
}
}
2017-02-23 15:49:58 +01:00
void TrayWidget::pauseResumeDir(const SyncthingDir &dir)
{
2017-05-01 03:34:43 +02:00
if (dir.paused) {
2017-02-23 15:49:58 +01:00
m_connection.resumeDirectories(QStringList(dir.id));
} else {
m_connection.pauseDirectories(QStringList(dir.id));
}
}
2016-08-29 20:51:30 +02:00
void TrayWidget::changeStatus()
2016-08-25 00:45:32 +02:00
{
2017-05-01 03:34:43 +02:00
switch (m_connection.status()) {
2016-08-25 00:45:32 +02:00
case SyncthingStatus::Disconnected:
m_connection.connect();
break;
case SyncthingStatus::Reconnecting:
break;
2016-09-03 19:39:43 +02:00
case SyncthingStatus::Idle:
case SyncthingStatus::Scanning:
2016-08-25 00:45:32 +02:00
case SyncthingStatus::Synchronizing:
m_connection.pauseAllDevs();
break;
case SyncthingStatus::Paused:
m_connection.resumeAllDevs();
break;
2017-05-01 03:34:43 +02:00
default:;
2016-08-25 00:45:32 +02:00
}
}
2016-08-30 20:01:07 +02:00
void TrayWidget::updateTraffic()
2016-08-25 00:45:32 +02:00
{
2017-05-01 03:34:43 +02:00
if (m_ui->trafficFormWidget->isHidden()) {
2016-08-30 20:01:07 +02:00
return;
2016-08-25 00:45:32 +02:00
}
static const QString unknownStr(tr("unknown"));
2017-05-01 03:34:43 +02:00
if (m_connection.isConnected()) {
if (m_connection.totalIncomingRate() != 0.0) {
m_ui->inTrafficLabel->setText(m_connection.totalIncomingTraffic() != SyncthingConnection::unknownTraffic
2017-05-01 03:34:43 +02:00
? QStringLiteral("%1 (%2)").arg(QString::fromUtf8(bitrateToString(m_connection.totalIncomingRate(), true).data()),
QString::fromUtf8(dataSizeToString(m_connection.totalIncomingTraffic()).data()))
: QString::fromUtf8(bitrateToString(m_connection.totalIncomingRate(), true).data()));
} else {
m_ui->inTrafficLabel->setText(m_connection.totalIncomingTraffic() != SyncthingConnection::unknownTraffic
2017-05-01 03:34:43 +02:00
? QString::fromUtf8(dataSizeToString(m_connection.totalIncomingTraffic()).data())
: unknownStr);
}
2017-05-01 03:34:43 +02:00
if (m_connection.totalOutgoingRate() != 0.0) {
m_ui->outTrafficLabel->setText(m_connection.totalIncomingTraffic() != SyncthingConnection::unknownTraffic
2017-05-01 03:34:43 +02:00
? QStringLiteral("%1 (%2)").arg(QString::fromUtf8(bitrateToString(m_connection.totalOutgoingRate(), true).data()),
QString::fromUtf8(dataSizeToString(m_connection.totalOutgoingTraffic()).data()))
: QString::fromUtf8(bitrateToString(m_connection.totalOutgoingRate(), true).data()));
} else {
m_ui->outTrafficLabel->setText(m_connection.totalOutgoingTraffic() != SyncthingConnection::unknownTraffic
2017-05-01 03:34:43 +02:00
? QString::fromUtf8(dataSizeToString(m_connection.totalOutgoingTraffic()).data())
: unknownStr);
}
2016-08-30 20:01:07 +02:00
} else {
m_ui->inTrafficLabel->setText(unknownStr);
m_ui->outTrafficLabel->setText(unknownStr);
2016-08-25 00:45:32 +02:00
}
}
#ifdef LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD
bool TrayWidget::handleSystemdStatusChanged()
{
const SyncthingService &service = syncthingService();
const Settings::Systemd &settings = Settings::values().systemd;
const bool serviceRelevant = service.isSystemdAvailable() && isLocal(QUrl(m_connection.syncthingUrl()));
bool couldConnectNow = true;
2017-05-01 03:34:43 +02:00
if (serviceRelevant) {
const bool isRunning = service.isRunning();
2017-05-01 03:34:43 +02:00
if (settings.showButton) {
m_ui->startStopPushButton->setVisible(true);
2017-05-01 03:34:43 +02:00
if (isRunning) {
m_ui->startStopPushButton->setText(tr("Stop"));
m_ui->startStopPushButton->setToolTip(QStringLiteral("systemctl --user stop ") + service.unitName());
2017-05-01 03:34:43 +02:00
m_ui->startStopPushButton->setIcon(
QIcon::fromTheme(QStringLiteral("process-stop"), QIcon(QStringLiteral(":/icons/hicolor/scalable/actions/process-stop.svg"))));
} else {
m_ui->startStopPushButton->setText(tr("Start"));
m_ui->startStopPushButton->setToolTip(QStringLiteral("systemctl --user start ") + service.unitName());
2017-05-01 03:34:43 +02:00
m_ui->startStopPushButton->setIcon(
QIcon::fromTheme(QStringLiteral("system-run"), QIcon(QStringLiteral(":/icons/hicolor/scalable/apps/system-run.svg"))));
}
}
2017-05-01 03:34:43 +02:00
if (settings.considerForReconnect) {
if (isRunning && m_selectedConnection) {
// auto-reconnect might have been disabled when unit was inactive before, so re-enable it according current connection settings
m_connection.setAutoReconnectInterval(m_selectedConnection->reconnectInterval);
2017-05-01 03:34:43 +02:00
if (!m_connection.isConnected()) {
// FIXME: This will fail if Syncthing has just been started and isn't ready yet
m_connection.connect();
}
} else {
// disable auto-reconnect if unit isn't running
m_connection.setAutoReconnectInterval(0);
couldConnectNow = false;
}
}
}
2017-05-01 03:34:43 +02:00
if (!settings.showButton || !serviceRelevant) {
m_ui->startStopPushButton->setVisible(false);
}
2017-05-01 03:34:43 +02:00
if ((!settings.considerForReconnect || !serviceRelevant) && m_selectedConnection) {
m_connection.setAutoReconnectInterval(m_selectedConnection->reconnectInterval);
}
return couldConnectNow;
}
void TrayWidget::connectIfServiceRunning()
{
2017-05-01 03:34:43 +02:00
if (Settings::values().systemd.considerForReconnect && isLocal(QUrl(m_connection.syncthingUrl())) && syncthingService().isRunning()) {
m_connection.connect();
}
}
#endif
#ifndef SYNCTHINGWIDGETS_NO_WEBVIEW
2016-08-30 20:01:07 +02:00
void TrayWidget::handleWebViewDeleted()
2016-08-25 00:45:32 +02:00
{
2016-08-30 20:01:07 +02:00
m_webViewDlg = nullptr;
2016-08-25 00:45:32 +02:00
}
2016-09-03 20:14:52 +02:00
#endif
2016-08-25 00:45:32 +02:00
void TrayWidget::handleNewNotification(DateTime when, const QString &msg)
2016-09-01 16:34:30 +02:00
{
m_notifications.emplace_back(QString::fromLocal8Bit(when.toString(DateTimeOutputFormat::DateAndTime, true).data()), msg);
m_ui->notificationsPushButton->setHidden(false);
2016-09-01 16:34:30 +02:00
}
2016-09-03 20:14:52 +02:00
void TrayWidget::handleConnectionSelected(QAction *connectionAction)
{
int index = m_connectionsMenu->actions().indexOf(connectionAction);
2017-05-01 03:34:43 +02:00
if (index >= 0) {
m_selectedConnection
= (index == 0) ? &Settings::values().connection.primary : &Settings::values().connection.secondary[static_cast<size_t>(index - 1)];
2016-09-17 19:13:49 +02:00
m_ui->connectionsPushButton->setText(m_selectedConnection->label);
2016-09-03 20:14:52 +02:00
m_connection.reconnect(*m_selectedConnection);
#ifdef LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD
handleSystemdStatusChanged();
#endif
#ifndef SYNCTHINGWIDGETS_NO_WEBVIEW
2017-05-01 03:34:43 +02:00
if (m_webViewDlg) {
2016-09-03 20:14:52 +02:00
m_webViewDlg->applySettings(*m_selectedConnection);
}
#endif
}
}
void TrayWidget::showDialog(QWidget *dlg)
{
2017-05-01 03:34:43 +02:00
if (m_menu) {
m_menu->close();
}
dlg->show();
dlg->activateWindow();
}
2016-08-25 00:45:32 +02:00
}