syncthingtray/tray/gui/trayicon.cpp

245 lines
9.3 KiB
C++
Raw Normal View History

2016-08-30 20:01:07 +02:00
#include "./trayicon.h"
#include "./traywidget.h"
#include "../../widgets/misc/statusinfo.h"
2017-05-01 03:34:43 +02:00
#include "../../widgets/settings/settings.h"
2017-02-20 18:03:20 +01:00
#include "../../model/syncthingicons.h"
#include "../../connector/syncthingconnection.h"
#ifdef LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD
2017-05-01 03:34:43 +02:00
#include "../../connector/syncthingservice.h"
#include "../../connector/utils.h"
#endif
2016-08-30 20:01:07 +02:00
#include <qtutilities/misc/dialogutils.h>
2016-12-26 19:50:10 +01:00
#include <QCoreApplication>
2016-08-30 20:01:07 +02:00
#include <QPainter>
#include <QPixmap>
#ifdef LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD
2017-05-01 03:34:43 +02:00
#include <QNetworkReply>
#endif
2016-08-30 20:01:07 +02:00
2016-11-08 19:44:45 +01:00
using namespace std;
2016-08-30 20:01:07 +02:00
using namespace Dialogs;
using namespace Data;
2016-12-11 17:58:58 +01:00
#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS
using namespace MiscUtils;
#endif
2016-08-30 20:01:07 +02:00
namespace QtGui {
/*!
* \brief Instantiates a new tray icon.
*/
2017-05-01 03:34:43 +02:00
TrayIcon::TrayIcon(QObject *parent)
: QSystemTrayIcon(parent)
, m_initialized(false)
, m_trayMenu(this)
, m_status(SyncthingStatus::Disconnected)
2016-08-30 20:01:07 +02:00
{
// set context menu
2017-05-01 03:34:43 +02:00
connect(m_contextMenu.addAction(QIcon::fromTheme(QStringLiteral("internet-web-browser"),
QIcon(QStringLiteral(":/icons/hicolor/scalable/apps/internet-web-browser.svg"))),
tr("Web UI")),
&QAction::triggered, m_trayMenu.widget(), &TrayWidget::showWebUi);
connect(m_contextMenu.addAction(
QIcon::fromTheme(QStringLiteral("preferences-other"), QIcon(QStringLiteral(":/icons/hicolor/scalable/apps/preferences-other.svg"))),
tr("Settings")),
&QAction::triggered, m_trayMenu.widget(), &TrayWidget::showSettingsDialog);
connect(m_contextMenu.addAction(
QIcon::fromTheme(QStringLiteral("folder-sync"), QIcon(QStringLiteral(":/icons/hicolor/scalable/actions/folder-sync.svg"))),
tr("Rescan all")),
&QAction::triggered, &m_trayMenu.widget()->connection(), &SyncthingConnection::rescanAllDirs);
connect(m_contextMenu.addAction(
QIcon::fromTheme(QStringLiteral("text-x-generic"), QIcon(QStringLiteral(":/icons/hicolor/scalable/mimetypes/text-x-generic.svg"))),
tr("Log")),
&QAction::triggered, m_trayMenu.widget(), &TrayWidget::showLog);
2016-09-03 20:14:52 +02:00
m_contextMenu.addMenu(m_trayMenu.widget()->connectionsMenu());
2017-05-01 03:34:43 +02:00
connect(m_contextMenu.addAction(
QIcon::fromTheme(QStringLiteral("help-about"), QIcon(QStringLiteral(":/icons/hicolor/scalable/apps/help-about.svg"))), tr("About")),
&QAction::triggered, m_trayMenu.widget(), &TrayWidget::showAboutDialog);
2016-08-30 20:01:07 +02:00
m_contextMenu.addSeparator();
2017-05-01 03:34:43 +02:00
connect(m_contextMenu.addAction(
QIcon::fromTheme(QStringLiteral("window-close"), QIcon(QStringLiteral(":/icons/hicolor/scalable/actions/window-close.svg"))),
tr("Close")),
&QAction::triggered, this, &TrayIcon::deleteLater);
2016-08-30 20:01:07 +02:00
setContextMenu(&m_contextMenu);
// set initial status
handleConnectionStatusChanged(SyncthingStatus::Disconnected);
2016-08-30 20:01:07 +02:00
// connect signals and slots
SyncthingConnection *connection = &(m_trayMenu.widget()->connection());
connect(this, &TrayIcon::activated, this, &TrayIcon::handleActivated);
2016-12-11 17:58:58 +01:00
connect(this, &TrayIcon::messageClicked, m_trayMenu.widget(), &TrayWidget::dismissNotifications);
2016-09-01 16:34:30 +02:00
connect(connection, &SyncthingConnection::error, this, &TrayIcon::showInternalError);
2016-08-30 20:01:07 +02:00
connect(connection, &SyncthingConnection::newNotification, this, &TrayIcon::showSyncthingNotification);
connect(connection, &SyncthingConnection::statusChanged, this, &TrayIcon::handleConnectionStatusChanged);
2017-05-01 03:34:43 +02:00
connect(&m_dbusNotifier, &DBusStatusNotifier::connectRequested, connection,
static_cast<void (SyncthingConnection::*)(void)>(&SyncthingConnection::connect));
connect(&m_dbusNotifier, &DBusStatusNotifier::dismissNotificationsRequested, m_trayMenu.widget(), &TrayWidget::dismissNotifications);
connect(&m_dbusNotifier, &DBusStatusNotifier::showNotificationsRequested, m_trayMenu.widget(), &TrayWidget::showNotifications);
m_initialized = true;
2016-08-30 20:01:07 +02:00
}
/*!
* \brief Moves the specified \a point in the specified \a rect.
*/
void moveInside(QPoint &point, const QRect &rect)
{
2017-05-01 03:34:43 +02:00
if (point.y() < rect.top()) {
point.setY(rect.top());
2017-05-01 03:34:43 +02:00
} else if (point.y() > rect.bottom()) {
point.setY(rect.bottom());
}
2017-05-01 03:34:43 +02:00
if (point.x() < rect.left()) {
point.setX(rect.left());
2017-05-01 03:34:43 +02:00
} else if (point.x() > rect.right()) {
point.setX(rect.right());
}
}
2016-08-30 20:01:07 +02:00
void TrayIcon::handleActivated(QSystemTrayIcon::ActivationReason reason)
{
2017-05-01 03:34:43 +02:00
switch (reason) {
2016-08-30 20:01:07 +02:00
case QSystemTrayIcon::Context:
// can't catch that event on Plasma 5 anyways
break;
2016-09-03 19:39:43 +02:00
case QSystemTrayIcon::MiddleClick:
m_trayMenu.widget()->showWebUi();
break;
case QSystemTrayIcon::Trigger: {
2016-12-26 19:50:10 +01:00
m_trayMenu.showAtCursor();
2016-08-30 20:01:07 +02:00
break;
}
2017-05-01 03:34:43 +02:00
default:;
2016-08-30 20:01:07 +02:00
}
}
void TrayIcon::handleConnectionStatusChanged(SyncthingStatus status)
{
2017-05-01 03:34:43 +02:00
if (m_initialized && m_status == status) {
return;
2016-12-11 17:58:58 +01:00
}
updateStatusIconAndText();
showStatusNotification(status);
m_status = status;
}
void TrayIcon::showInternalError(const QString &errorMsg, SyncthingErrorCategory category, int networkError)
2016-08-30 20:01:07 +02:00
{
2016-12-11 17:58:58 +01:00
const auto &settings = Settings::values();
#ifdef LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD
const SyncthingService &service = syncthingService();
const bool serviceRelevant = service.isSystemdAvailable() && isLocal(QUrl(m_trayMenu.widget()->connection().syncthingUrl()));
#endif
2017-05-01 03:34:43 +02:00
if (settings.notifyOn.internalErrors
&& (m_trayMenu.widget()->connection().autoReconnectTries() < 1 || category != SyncthingErrorCategory::OverallConnection)
#ifdef LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD
2017-05-01 03:34:43 +02:00
&& (!settings.systemd.considerForReconnect || !serviceRelevant
|| !(networkError == QNetworkReply::RemoteHostClosedError && service.isManuallyStopped()))
&& (settings.ignoreInavailabilityAfterStart == 0
|| !(networkError == QNetworkReply::ConnectionRefusedError && service.isRunning()
&& !service.isActiveWithoutSleepFor(settings.ignoreInavailabilityAfterStart)))
#endif
) {
2016-12-11 17:58:58 +01:00
#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS
2017-05-01 03:34:43 +02:00
if (settings.dbusNotifications) {
m_dbusNotifier.showInternalError(errorMsg, category, networkError);
2016-12-11 17:58:58 +01:00
} else
#endif
{
showMessage(tr("Error"), errorMsg, QSystemTrayIcon::Critical);
}
2016-08-30 20:01:07 +02:00
}
}
void TrayIcon::showSyncthingNotification(ChronoUtilities::DateTime when, const QString &message)
2016-08-30 20:01:07 +02:00
{
2016-12-11 17:58:58 +01:00
const auto &settings = Settings::values();
2017-05-01 03:34:43 +02:00
if (settings.notifyOn.syncthingErrors) {
2016-12-11 17:58:58 +01:00
#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS
2017-05-01 03:34:43 +02:00
if (settings.dbusNotifications) {
m_dbusNotifier.showSyncthingNotification(when, message);
2016-12-11 17:58:58 +01:00
} else
#else
Q_UNUSED(when)
2016-12-11 17:58:58 +01:00
#endif
{
showMessage(tr("Syncthing notification - click to dismiss"), message, QSystemTrayIcon::Warning);
}
2016-08-30 20:01:07 +02:00
}
updateStatusIconAndText();
2016-08-30 20:01:07 +02:00
}
void TrayIcon::updateStatusIconAndText()
2016-08-30 20:01:07 +02:00
{
const StatusInfo statusInfo(trayMenu().widget()->connection());
setToolTip(statusInfo.statusText());
setIcon(statusInfo.statusIcon());
}
void TrayIcon::showStatusNotification(SyncthingStatus status)
{
2016-10-04 23:42:17 +02:00
const SyncthingConnection &connection = trayMenu().widget()->connection();
2016-12-11 17:58:58 +01:00
const auto &settings = Settings::values();
2017-05-01 03:34:43 +02:00
switch (status) {
2016-08-30 20:01:07 +02:00
case SyncthingStatus::Disconnected:
2017-05-01 03:34:43 +02:00
if (m_initialized && settings.notifyOn.disconnect
#ifdef LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD
2017-05-01 03:34:43 +02:00
&& !syncthingService().isManuallyStopped()
#endif
) {
2016-12-11 17:58:58 +01:00
#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS
2017-05-01 03:34:43 +02:00
if (settings.dbusNotifications) {
m_dbusNotifier.showDisconnect();
2016-12-11 17:58:58 +01:00
} else
#endif
{
showMessage(QCoreApplication::applicationName(), tr("Disconnected from Syncthing"), QSystemTrayIcon::Warning);
}
2016-08-30 20:01:07 +02:00
}
#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS
break;
2016-10-04 23:42:17 +02:00
default:
m_dbusNotifier.hideDisconnect();
#endif
2016-08-30 20:01:07 +02:00
}
2017-05-01 03:34:43 +02:00
switch (status) {
2016-08-30 20:01:07 +02:00
case SyncthingStatus::Disconnected:
case SyncthingStatus::Reconnecting:
2016-08-30 20:01:07 +02:00
case SyncthingStatus::Synchronizing:
break;
default:
2017-05-01 03:34:43 +02:00
if (m_status == SyncthingStatus::Synchronizing && settings.notifyOn.syncComplete) {
2016-11-08 19:44:45 +01:00
const vector<SyncthingDir *> &completedDirs = connection.completedDirs();
2017-05-01 03:34:43 +02:00
if (!completedDirs.empty()) {
2016-11-08 19:44:45 +01:00
QString message;
2017-05-01 03:34:43 +02:00
if (completedDirs.size() == 1) {
2016-11-08 19:44:45 +01:00
message = tr("Synchronization of %1 complete").arg(completedDirs.front()->displayName());
} else {
QStringList names;
names.reserve(static_cast<int>(completedDirs.size()));
2017-05-01 03:34:43 +02:00
for (const SyncthingDir *dir : completedDirs) {
2016-11-08 19:44:45 +01:00
names << dir->displayName();
}
message = tr("Synchronization of the following devices complete:\n") + names.join(QStringLiteral(", "));
}
2016-12-11 17:58:58 +01:00
#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS
2017-05-01 03:34:43 +02:00
if (settings.dbusNotifications) {
m_dbusNotifier.showSyncComplete(message);
2016-12-11 17:58:58 +01:00
} else
#endif
{
showMessage(QCoreApplication::applicationName(), message, QSystemTrayIcon::Information);
}
2016-11-08 19:44:45 +01:00
}
2016-08-30 20:01:07 +02:00
}
}
}
}