279 lines
10 KiB
C++
279 lines
10 KiB
C++
#include "./trayicon.h"
|
|
#include "./traywidget.h"
|
|
|
|
#include "../../widgets/misc/errorviewdialog.h"
|
|
#include "../../widgets/misc/statusinfo.h"
|
|
#include "../../widgets/misc/textviewdialog.h"
|
|
#include "../../widgets/settings/settings.h"
|
|
|
|
#include "../../model/syncthingicons.h"
|
|
|
|
#include "../../connector/syncthingconnection.h"
|
|
#ifdef LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD
|
|
#include "../../connector/syncthingservice.h"
|
|
#endif
|
|
#include "../../connector/utils.h"
|
|
|
|
#include <qtutilities/misc/dialogutils.h>
|
|
|
|
#include <QCoreApplication>
|
|
#include <QPainter>
|
|
#include <QPixmap>
|
|
#include <QStringBuilder>
|
|
#ifdef LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD
|
|
#include <QNetworkReply>
|
|
#endif
|
|
|
|
using namespace std;
|
|
using namespace Dialogs;
|
|
using namespace Data;
|
|
#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS
|
|
using namespace MiscUtils;
|
|
#endif
|
|
|
|
namespace QtGui {
|
|
|
|
/*!
|
|
* \brief Instantiates a new tray icon.
|
|
*/
|
|
TrayIcon::TrayIcon(const QString &connectionConfig, QObject *parent)
|
|
: QSystemTrayIcon(parent)
|
|
, m_trayMenu(connectionConfig, this)
|
|
#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS
|
|
, m_dbusNotificationsEnabled(Settings::values().dbusNotifications)
|
|
#endif
|
|
, m_notifyOnSyncthingErrors(Settings::values().notifyOn.syncthingErrors)
|
|
, m_messageClickedAction(TrayIconMessageClickedAction::None)
|
|
{
|
|
// get widget, connection and notifier
|
|
const auto &widget(m_trayMenu.widget());
|
|
const auto &connection(widget.connection());
|
|
const auto ¬ifier(widget.notifier());
|
|
|
|
// set context menu
|
|
connect(m_contextMenu.addAction(QIcon::fromTheme(QStringLiteral("internet-web-browser"),
|
|
QIcon(QStringLiteral(":/icons/hicolor/scalable/apps/internet-web-browser.svg"))),
|
|
tr("Web UI")),
|
|
&QAction::triggered, &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, &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, &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, &widget, &TrayWidget::showLog);
|
|
m_errorsAction = m_contextMenu.addAction(
|
|
QIcon::fromTheme(QStringLiteral("emblem-error"), QIcon(QStringLiteral(":/icons/hicolor/scalable/emblems/8/emblem-error.svg"))),
|
|
tr("Show internal errors"));
|
|
m_errorsAction->setVisible(false);
|
|
connect(m_errorsAction, &QAction::triggered, this, &TrayIcon::showInternalErrorsDialog);
|
|
m_contextMenu.addMenu(m_trayMenu.widget().connectionsMenu());
|
|
connect(m_contextMenu.addAction(
|
|
QIcon::fromTheme(QStringLiteral("help-about"), QIcon(QStringLiteral(":/icons/hicolor/scalable/apps/help-about.svg"))), tr("About")),
|
|
&QAction::triggered, &widget, &TrayWidget::showAboutDialog);
|
|
m_contextMenu.addSeparator();
|
|
connect(m_contextMenu.addAction(
|
|
QIcon::fromTheme(QStringLiteral("window-close"), QIcon(QStringLiteral(":/icons/hicolor/scalable/actions/window-close.svg"))),
|
|
tr("Close")),
|
|
&QAction::triggered, this, &TrayIcon::deleteLater);
|
|
setContextMenu(&m_contextMenu);
|
|
|
|
// connect signals and slots
|
|
connect(this, &TrayIcon::activated, this, &TrayIcon::handleActivated);
|
|
connect(this, &TrayIcon::messageClicked, this, &TrayIcon::handleMessageClicked);
|
|
connect(&connection, &SyncthingConnection::error, this, &TrayIcon::showInternalError);
|
|
connect(&connection, &SyncthingConnection::newNotification, this, &TrayIcon::showSyncthingNotification);
|
|
connect(¬ifier, &SyncthingNotifier::disconnected, this, &TrayIcon::showDisconnected);
|
|
connect(¬ifier, &SyncthingNotifier::syncComplete, this, &TrayIcon::showSyncComplete);
|
|
connect(¬ifier, &SyncthingNotifier::newDevice, this, &TrayIcon::showNewDev);
|
|
connect(¬ifier, &SyncthingNotifier::newDir, this, &TrayIcon::showNewDir);
|
|
connect(&connection, &SyncthingConnection::statusChanged, this, &TrayIcon::updateStatusIconAndText);
|
|
connect(&connection, &SyncthingConnection::newDevices, this, &TrayIcon::updateStatusIconAndText);
|
|
connect(&connection, &SyncthingConnection::devStatusChanged, this, &TrayIcon::updateStatusIconAndText);
|
|
#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS
|
|
connect(&m_dbusNotifier, &DBusStatusNotifier::connectRequested, &connection,
|
|
static_cast<void (SyncthingConnection::*)(void)>(&SyncthingConnection::connect));
|
|
connect(&m_dbusNotifier, &DBusStatusNotifier::dismissNotificationsRequested, &widget, &TrayWidget::dismissNotifications);
|
|
connect(&m_dbusNotifier, &DBusStatusNotifier::showNotificationsRequested, &widget, &TrayWidget::showNotifications);
|
|
connect(&m_dbusNotifier, &DBusStatusNotifier::errorDetailsRequested, this, &TrayIcon::showInternalErrorsDialog);
|
|
connect(&m_dbusNotifier, &DBusStatusNotifier::webUiRequested, &widget, &TrayWidget::showWebUi);
|
|
connect(¬ifier, &SyncthingNotifier::connected, &m_dbusNotifier, &DBusStatusNotifier::hideDisconnect);
|
|
#endif
|
|
}
|
|
|
|
/*!
|
|
* \brief Moves the specified \a point in the specified \a rect.
|
|
*/
|
|
void moveInside(QPoint &point, const QRect &rect)
|
|
{
|
|
if (point.y() < rect.top()) {
|
|
point.setY(rect.top());
|
|
} else if (point.y() > rect.bottom()) {
|
|
point.setY(rect.bottom());
|
|
}
|
|
if (point.x() < rect.left()) {
|
|
point.setX(rect.left());
|
|
} else if (point.x() > rect.right()) {
|
|
point.setX(rect.right());
|
|
}
|
|
}
|
|
|
|
void TrayIcon::handleActivated(QSystemTrayIcon::ActivationReason reason)
|
|
{
|
|
switch (reason) {
|
|
case QSystemTrayIcon::Context:
|
|
// can't catch that event on Plasma 5 anyways
|
|
break;
|
|
case QSystemTrayIcon::MiddleClick:
|
|
m_trayMenu.widget().showWebUi();
|
|
break;
|
|
case QSystemTrayIcon::Trigger: {
|
|
m_trayMenu.showAtCursor();
|
|
break;
|
|
}
|
|
default:;
|
|
}
|
|
}
|
|
|
|
void TrayIcon::handleMessageClicked()
|
|
{
|
|
switch (m_messageClickedAction) {
|
|
case TrayIconMessageClickedAction::None:
|
|
return;
|
|
case TrayIconMessageClickedAction::DismissNotification:
|
|
m_trayMenu.widget().dismissNotifications();
|
|
break;
|
|
case TrayIconMessageClickedAction::ShowInternalErrors:
|
|
showInternalErrorsDialog();
|
|
break;
|
|
case TrayIconMessageClickedAction::ShowWebUi:
|
|
m_trayMenu.widget().showWebUi();
|
|
break;
|
|
}
|
|
}
|
|
|
|
void TrayIcon::showDisconnected()
|
|
{
|
|
#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS
|
|
if (m_dbusNotificationsEnabled) {
|
|
m_dbusNotifier.showDisconnect();
|
|
} else
|
|
#endif
|
|
{
|
|
m_messageClickedAction = TrayIconMessageClickedAction::None;
|
|
showMessage(QCoreApplication::applicationName(), tr("Disconnected from Syncthing"), QSystemTrayIcon::Warning);
|
|
}
|
|
}
|
|
|
|
void TrayIcon::showSyncComplete(const QString &message)
|
|
{
|
|
#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS
|
|
if (m_dbusNotificationsEnabled) {
|
|
m_dbusNotifier.showSyncComplete(message);
|
|
} else
|
|
#endif
|
|
{
|
|
m_messageClickedAction = TrayIconMessageClickedAction::None;
|
|
showMessage(QCoreApplication::applicationName(), message, QSystemTrayIcon::Information);
|
|
}
|
|
}
|
|
|
|
void TrayIcon::handleErrorsCleared()
|
|
{
|
|
m_errorsAction->setVisible(false);
|
|
}
|
|
|
|
void TrayIcon::showInternalError(
|
|
const QString &errorMsg, SyncthingErrorCategory category, int networkError, const QNetworkRequest &request, const QByteArray &response)
|
|
{
|
|
if (!InternalError::isRelevant(m_trayMenu.widget().connection(), category, networkError)) {
|
|
return;
|
|
}
|
|
InternalError error(errorMsg, request.url(), response);
|
|
#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS
|
|
if (m_dbusNotificationsEnabled) {
|
|
m_dbusNotifier.showInternalError(error);
|
|
} else
|
|
#endif
|
|
{
|
|
m_messageClickedAction = TrayIconMessageClickedAction::ShowInternalErrors;
|
|
showMessage(tr("Error"), errorMsg, QSystemTrayIcon::Critical);
|
|
}
|
|
ErrorViewDialog::addError(move(error));
|
|
m_errorsAction->setVisible(true);
|
|
}
|
|
|
|
void TrayIcon::showSyncthingNotification(ChronoUtilities::DateTime when, const QString &message)
|
|
{
|
|
if (m_notifyOnSyncthingErrors) {
|
|
#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS
|
|
if (m_dbusNotificationsEnabled) {
|
|
m_dbusNotifier.showSyncthingNotification(when, message);
|
|
} else
|
|
#else
|
|
Q_UNUSED(when)
|
|
#endif
|
|
{
|
|
m_messageClickedAction = TrayIconMessageClickedAction::DismissNotification;
|
|
showMessage(tr("Syncthing notification - click to dismiss"), message, QSystemTrayIcon::Warning);
|
|
}
|
|
}
|
|
updateStatusIconAndText();
|
|
}
|
|
|
|
void TrayIcon::updateStatusIconAndText()
|
|
{
|
|
const StatusInfo statusInfo(trayMenu().widget().connection());
|
|
if (statusInfo.additionalStatusText().isEmpty()) {
|
|
setToolTip(statusInfo.statusText());
|
|
} else {
|
|
setToolTip(statusInfo.statusText() % QChar('\n') % statusInfo.additionalStatusText());
|
|
}
|
|
setIcon(statusInfo.statusIcon());
|
|
}
|
|
|
|
void TrayIcon::showNewDev(const QString &devId, const QString &message)
|
|
{
|
|
#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS
|
|
if (m_dbusNotificationsEnabled) {
|
|
m_dbusNotifier.showNewDev(devId, message);
|
|
} else
|
|
#else
|
|
Q_UNUSED(devId)
|
|
#endif
|
|
{
|
|
m_messageClickedAction = TrayIconMessageClickedAction::ShowWebUi;
|
|
showMessage(tr("Syncthing device wants to connect - click for web UI"), message, QSystemTrayIcon::Information);
|
|
}
|
|
}
|
|
|
|
void TrayIcon::showNewDir(const QString &devId, const QString &dirId, const QString &message)
|
|
{
|
|
#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS
|
|
if (m_dbusNotificationsEnabled) {
|
|
m_dbusNotifier.showNewDir(devId, dirId, message);
|
|
} else
|
|
#else
|
|
Q_UNUSED(devId)
|
|
Q_UNUSED(dirId)
|
|
#endif
|
|
{
|
|
m_messageClickedAction = TrayIconMessageClickedAction::ShowWebUi;
|
|
showMessage(tr("New Syncthing directory - click for web UI"), message, QSystemTrayIcon::Information);
|
|
}
|
|
}
|
|
|
|
void TrayIcon::showInternalErrorsDialog()
|
|
{
|
|
auto *const errorViewDlg = ErrorViewDialog::instance();
|
|
connect(errorViewDlg, &ErrorViewDialog::errorsCleared, this, &TrayIcon::handleErrorsCleared);
|
|
centerWidget(errorViewDlg);
|
|
errorViewDlg->show();
|
|
}
|
|
} // namespace QtGui
|