So far the backend libraries' include paths were relative within this repository. This means the header files could not be used at their installed location. This change replaces them with "<>" includes to fix that problem and adds a new include directory so building everything at once still works. With this change it should be easier to actually split some parts into another repository if this one would become too big.
304 lines
12 KiB
C++
304 lines
12 KiB
C++
#include "./trayicon.h"
|
|
#include "./traywidget.h"
|
|
|
|
#include <syncthingwidgets/misc/internalerrorsdialog.h>
|
|
#include <syncthingwidgets/misc/statusinfo.h>
|
|
#include <syncthingwidgets/misc/textviewdialog.h>
|
|
#include <syncthingwidgets/settings/settings.h>
|
|
|
|
#include <syncthingmodel/syncthingicons.h>
|
|
|
|
#include <syncthingconnector/syncthingconnection.h>
|
|
#ifdef LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD
|
|
#include <syncthingconnector/syncthingservice.h>
|
|
#endif
|
|
#include <syncthingconnector/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 QtUtilities;
|
|
using namespace Data;
|
|
|
|
namespace QtGui {
|
|
|
|
/*!
|
|
* \brief Instantiates a new tray icon.
|
|
*/
|
|
TrayIcon::TrayIcon(const QString &connectionConfig, QObject *parent)
|
|
: QSystemTrayIcon(parent)
|
|
, m_trayMenu(new TrayMenu(this, &m_parentWidget))
|
|
#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(trayMenu().widget());
|
|
const auto &connection(widget.connection());
|
|
const auto ¬ifier(widget.notifier());
|
|
|
|
// set context menu
|
|
#ifndef SYNCTHINGTRAY_UNIFY_TRAY_MENUS
|
|
connect(m_contextMenu.addAction(QIcon(QStringLiteral(":/icons/hicolor/scalable/status/syncthing-default.svg")), tr("Open Syncthing")),
|
|
&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(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);
|
|
#endif
|
|
|
|
// 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::syncthingProcessError, this, &TrayIcon::showLauncherError);
|
|
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);
|
|
connect(&IconManager::instance(), &IconManager::statusIconsChanged, 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
|
|
|
|
// apply settings, this also establishes the connection to Syncthing (according to settings)
|
|
// note: It is important to apply settings only after all Signals & Slots have been connected (e.g. to handle SyncthingConnection::error()).
|
|
// note: This weirdly calls updateStatusIconAndText(). So there is not need to call it again within this constructor.
|
|
trayMenu().widget().applySettings(connectionConfig);
|
|
}
|
|
|
|
/*!
|
|
* \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:
|
|
trayMenu().widget().showWebUi();
|
|
break;
|
|
case QSystemTrayIcon::Trigger: {
|
|
trayMenu().showUsingPositioningSettings();
|
|
break;
|
|
}
|
|
default:;
|
|
}
|
|
}
|
|
|
|
void TrayIcon::handleMessageClicked()
|
|
{
|
|
switch (m_messageClickedAction) {
|
|
case TrayIconMessageClickedAction::None:
|
|
return;
|
|
case TrayIconMessageClickedAction::DismissNotification:
|
|
trayMenu().widget().dismissNotifications();
|
|
break;
|
|
case TrayIconMessageClickedAction::ShowInternalErrors:
|
|
showInternalErrorsDialog();
|
|
break;
|
|
case TrayIconMessageClickedAction::ShowWebUi:
|
|
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()
|
|
{
|
|
#ifndef SYNCTHINGTRAY_UNIFY_TRAY_MENUS
|
|
m_errorsAction->setVisible(false);
|
|
#endif
|
|
}
|
|
|
|
void TrayIcon::showInternalError(
|
|
const QString &errorMessage, SyncthingErrorCategory category, int networkError, const QNetworkRequest &request, const QByteArray &response)
|
|
{
|
|
if (!InternalError::isRelevant(trayMenu().widget().connection(), category, networkError)) {
|
|
return;
|
|
}
|
|
InternalError error(errorMessage, 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"), errorMessage, QSystemTrayIcon::Critical);
|
|
}
|
|
InternalErrorsDialog::addError(move(error));
|
|
#ifdef SYNCTHINGTRAY_UNIFY_TRAY_MENUS
|
|
trayMenu().widget().showInternalErrorsButton();
|
|
#else
|
|
m_errorsAction->setVisible(true);
|
|
#endif
|
|
}
|
|
|
|
void TrayIcon::showLauncherError(const QString &errorMessage, const QString &additionalInfo)
|
|
{
|
|
#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS
|
|
if (m_dbusNotificationsEnabled) {
|
|
m_dbusNotifier.showLauncherError(errorMessage, additionalInfo);
|
|
} else
|
|
#endif
|
|
{
|
|
m_messageClickedAction = TrayIconMessageClickedAction::None;
|
|
showMessage(tr("Launcher error"), QStringList({ errorMessage, additionalInfo }).join(QChar('\n')), QSystemTrayIcon::Critical);
|
|
}
|
|
}
|
|
|
|
void TrayIcon::showSyncthingNotification(CppUtilities::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()
|
|
{
|
|
auto &trayWidget = trayMenu().widget();
|
|
const auto statusInfo = StatusInfo(trayMenu().widget().connection(),
|
|
TrayWidget::instances().size() > 1 && trayWidget.selectedConnection() ? trayWidget.selectedConnection()->label : QString());
|
|
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 = InternalErrorsDialog::instance();
|
|
connect(errorViewDlg, &InternalErrorsDialog::errorsCleared, this, &TrayIcon::handleErrorsCleared);
|
|
centerWidget(errorViewDlg);
|
|
errorViewDlg->show();
|
|
}
|
|
} // namespace QtGui
|