From 203370f93308f04362670aaaf72064d3dbaaf205 Mon Sep 17 00:00:00 2001 From: Martchus Date: Sun, 11 Dec 2016 17:58:58 +0100 Subject: [PATCH] Allow notifications via D-Bus --- CMakeLists.txt | 4 +- tray/CMakeLists.txt | 1 + tray/application/settings.cpp | 12 ++++ tray/application/settings.h | 3 + tray/gui/notificationsoptionpage.ui | 91 ++++++++++++++++------------- tray/gui/settingsdialog.cpp | 21 ++++++- tray/gui/trayicon.cpp | 77 ++++++++++++++++++++---- tray/gui/trayicon.h | 12 +++- 8 files changed, 166 insertions(+), 55 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9eb391c..6bd1f3a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,8 +8,8 @@ set(META_APP_URL "https://github.com/${META_APP_AUTHOR}/${META_PROJECT_NAME}") set(META_APP_DESCRIPTION "Tray application for Syncthing") set(META_APP_CATEGORIES "System;Utility;Network;FileTransfer") set(META_VERSION_MAJOR 0) -set(META_VERSION_MINOR 1) -set(META_VERSION_PATCH 1) +set(META_VERSION_MINOR 2) +set(META_VERSION_PATCH 0) set(META_VERSION_EXACT_SONAME ON) project(${META_PROJECT_NAME}) diff --git a/tray/CMakeLists.txt b/tray/CMakeLists.txt index cc6b938..fb85e98 100644 --- a/tray/CMakeLists.txt +++ b/tray/CMakeLists.txt @@ -88,6 +88,7 @@ set(REQUIRED_ICONS media-playback-start network-card network-connect + network-disconnect network-server preferences-desktop preferences-desktop-icons diff --git a/tray/application/settings.cpp b/tray/application/settings.cpp index 42fbc52..a6c2b12 100644 --- a/tray/application/settings.cpp +++ b/tray/application/settings.cpp @@ -1,6 +1,9 @@ #include "./settings.h" #include +#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS +# include +#endif #include #include @@ -11,6 +14,9 @@ using namespace std; using namespace Data; +#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS +using namespace MiscUtils; +#endif namespace Settings { @@ -74,6 +80,9 @@ void restore() notifyOn.internalErrors = settings.value(QStringLiteral("notifyOnErrors"), notifyOn.internalErrors).toBool(); notifyOn.syncComplete = settings.value(QStringLiteral("notifyOnSyncComplete"), notifyOn.syncComplete).toBool(); notifyOn.syncthingErrors = settings.value(QStringLiteral("showSyncthingNotifications"), notifyOn.syncthingErrors).toBool(); +#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS + v.dbusNotifications = settings.value(QStringLiteral("dbusNotifications"), DBusNotification::isAvailable()).toBool(); +#endif auto &appearance = v.appearance; appearance.showTraffic = settings.value(QStringLiteral("showTraffic"), appearance.showTraffic).toBool(); appearance.trayMenuSize = settings.value(QStringLiteral("trayMenuSize"), appearance.trayMenuSize).toSize(); @@ -133,6 +142,9 @@ void save() settings.setValue(QStringLiteral("notifyOnErrors"), notifyOn.internalErrors); settings.setValue(QStringLiteral("notifyOnSyncComplete"), notifyOn.syncComplete); settings.setValue(QStringLiteral("showSyncthingNotifications"), notifyOn.syncthingErrors); +#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS + settings.setValue(QStringLiteral("dbusNotifications"), v.dbusNotifications); +#endif const auto &appearance = v.appearance; settings.setValue(QStringLiteral("showTraffic"), appearance.showTraffic); settings.setValue(QStringLiteral("trayMenuSize"), appearance.trayMenuSize); diff --git a/tray/application/settings.h b/tray/application/settings.h index 56e5230..9ccda72 100644 --- a/tray/application/settings.h +++ b/tray/application/settings.h @@ -77,6 +77,9 @@ struct Settings bool firstLaunch = false; Connection connection; NotifyOn notifyOn; +#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS + bool dbusNotifications = false; +#endif Appearance appearance; Launcher launcher; #if defined(SYNCTHINGTRAY_USE_WEBENGINE) || defined(SYNCTHINGTRAY_USE_WEBKIT) diff --git a/tray/gui/notificationsoptionpage.ui b/tray/gui/notificationsoptionpage.ui index 2f0f2da..eef8c9f 100644 --- a/tray/gui/notificationsoptionpage.ui +++ b/tray/gui/notificationsoptionpage.ui @@ -2,14 +2,6 @@ QtGui::NotificationsOptionPage - - - 0 - 0 - 240 - 193 - - Notifications @@ -19,44 +11,63 @@ - - - - 75 - true - - - + + Notify on + + + + + disconnect + + + + + + + internal errors + + + + + + + errors/notifications from Syncthing + + + + + + + sync complete + + + + - - - disconnect - - - - - - - internal errors - - - - - - - errors/notifications from Syncthing - - - - - - - sync complete + + + Notification API + + + + + D-Bus notifi&cations (org.freedesktop.Notifications) + + + + + + + &Method provided by Qt (might be overridden by QPA plugin) + + + + diff --git a/tray/gui/settingsdialog.cpp b/tray/gui/settingsdialog.cpp index 57df3a2..d82f6d2 100644 --- a/tray/gui/settingsdialog.cpp +++ b/tray/gui/settingsdialog.cpp @@ -16,6 +16,9 @@ #include #include #include +#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS +# include +#endif #include #include @@ -35,6 +38,9 @@ using namespace std::placeholders; using namespace Settings; using namespace Dialogs; using namespace Data; +#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS +using namespace MiscUtils; +#endif namespace QtGui { @@ -232,14 +238,21 @@ NotificationsOptionPage::~NotificationsOptionPage() bool NotificationsOptionPage::apply() { + bool ok = true; if(hasBeenShown()) { auto ¬ifyOn = values().notifyOn; notifyOn.disconnect = ui()->notifyOnDisconnectCheckBox->isChecked(); notifyOn.internalErrors = ui()->notifyOnErrorsCheckBox->isChecked(); notifyOn.syncComplete = ui()->notifyOnSyncCompleteCheckBox->isChecked(); notifyOn.syncthingErrors = ui()->showSyncthingNotificationsCheckBox->isChecked(); +#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS + if((values().dbusNotifications = ui()->dbusRadioButton->isChecked()) && !DBusNotification::isAvailable()) { + errors() << QCoreApplication::translate("QtGui::NotificationsOptionPage", "Configured to use D-Bus notifications but D-Bus notification daemon seems unavailabe."); + ok = false; + } +#endif } - return true; + return ok; } void NotificationsOptionPage::reset() @@ -250,6 +263,12 @@ void NotificationsOptionPage::reset() ui()->notifyOnErrorsCheckBox->setChecked(notifyOn.internalErrors); ui()->notifyOnSyncCompleteCheckBox->setChecked(notifyOn.syncComplete); ui()->showSyncthingNotificationsCheckBox->setChecked(notifyOn.syncthingErrors); +#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS + (values().dbusNotifications ? ui()->dbusRadioButton : ui()->qtRadioButton)->setChecked(true); +#else + ui()->dbusRadioButton->setEnabled(false); + ui()->qtRadioButton->setChecked(true); +#endif } } diff --git a/tray/gui/trayicon.cpp b/tray/gui/trayicon.cpp index da26955..55df247 100644 --- a/tray/gui/trayicon.cpp +++ b/tray/gui/trayicon.cpp @@ -15,6 +15,9 @@ using namespace std; using namespace Dialogs; using namespace Data; +#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS +using namespace MiscUtils; +#endif namespace QtGui { @@ -34,6 +37,13 @@ TrayIcon::TrayIcon(QObject *parent) : m_statusIconErrorSync(QIcon(renderSvgImage(QStringLiteral(":/icons/hicolor/scalable/status/syncthing-error-sync.svg")))), m_trayMenu(this), m_status(SyncthingStatus::Disconnected) +#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS + , + m_disconnectedNotification(QCoreApplication::applicationName(), QStringLiteral("network-disconnect"), 5000), + m_internalErrorNotification(QCoreApplication::applicationName() + tr(" - internal error"), NotificationIcon::Critical, 5000), + m_syncthingNotification(tr("Syncthing notification"), NotificationIcon::Warning, 10000), + m_syncCompleteNotification(QCoreApplication::applicationName(), NotificationIcon::Information, 5000) +#endif { // 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, m_trayMenu.widget(), &TrayWidget::showWebUi); @@ -45,13 +55,22 @@ TrayIcon::TrayIcon(QObject *parent) : 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); +#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS + // setup notifications + m_disconnectedNotification.setMessage(tr("Disconnected from Syncthing")); + m_disconnectedNotification.setActions(QStringList(tr("Try to reconnect"))); + connect(&m_disconnectedNotification, &DBusNotification::actionInvoked, &(m_trayMenu.widget()->connection()), &SyncthingConnection::connect); + m_syncthingNotification.setActions(QStringList({QStringLiteral("show"), tr("Show"), QStringLiteral("dismiss"), tr("Dismiss")})); + connect(&m_syncthingNotification, &DBusNotification::actionInvoked, this, &TrayIcon::handleSyncthingNotificationAction); +#endif + // set initial status updateStatusIconAndText(SyncthingStatus::Disconnected); // connect signals and slots SyncthingConnection *connection = &(m_trayMenu.widget()->connection()); connect(this, &TrayIcon::activated, this, &TrayIcon::handleActivated); - connect(this, &TrayIcon::messageClicked, this, &TrayIcon::handleMessageClicked); + connect(this, &TrayIcon::messageClicked, m_trayMenu.widget(), &TrayWidget::dismissNotifications); connect(connection, &SyncthingConnection::error, this, &TrayIcon::showInternalError); connect(connection, &SyncthingConnection::newNotification, this, &TrayIcon::showSyncthingNotification); connect(connection, &SyncthingConnection::statusChanged, this, &TrayIcon::updateStatusIconAndText); @@ -79,23 +98,44 @@ void TrayIcon::handleActivated(QSystemTrayIcon::ActivationReason reason) } } -void TrayIcon::handleMessageClicked() +void TrayIcon::handleSyncthingNotificationAction(const QString &action) { - m_trayMenu.widget()->dismissNotifications(); + if(action == QLatin1String("dismiss")) { + m_trayMenu.widget()->dismissNotifications(); + + } else if(action == QLatin1String("show")) { + m_trayMenu.widget()->showNotifications(); + } } void TrayIcon::showInternalError(const QString &errorMsg) { - if(Settings::values().notifyOn.internalErrors) { - showMessage(tr("Error"), errorMsg, QSystemTrayIcon::Critical); + const auto &settings = Settings::values(); + if(settings.notifyOn.internalErrors) { +#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS + if(settings.dbusNotifications) { + m_internalErrorNotification.update(errorMsg); + } else +#endif + { + showMessage(tr("Error"), errorMsg, QSystemTrayIcon::Critical); + } } } void TrayIcon::showSyncthingNotification(ChronoUtilities::DateTime when, const QString &message) { Q_UNUSED(when) - if(Settings::values().notifyOn.syncthingErrors) { - showMessage(tr("Syncthing notification - click to dismiss"), message, QSystemTrayIcon::Warning); + const auto &settings = Settings::values(); + if(settings.notifyOn.syncthingErrors) { +#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS + if(settings.dbusNotifications) { + m_syncthingNotification.update(message); + } else +#endif + { + showMessage(tr("Syncthing notification - click to dismiss"), message, QSystemTrayIcon::Warning); + } } updateStatusIconAndText(m_status); } @@ -103,12 +143,20 @@ void TrayIcon::showSyncthingNotification(ChronoUtilities::DateTime when, const Q void TrayIcon::updateStatusIconAndText(SyncthingStatus status) { const SyncthingConnection &connection = trayMenu().widget()->connection(); + const auto &settings = Settings::values(); switch(status) { case SyncthingStatus::Disconnected: setIcon(m_statusIconDisconnected); setToolTip(tr("Not connected to Syncthing")); - if(Settings::values().notifyOn.disconnect) { - showMessage(QCoreApplication::applicationName(), tr("Disconnected from Syncthing"), QSystemTrayIcon::Warning); + if(settings.notifyOn.disconnect) { +#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS + if(settings.dbusNotifications) { + m_disconnectedNotification.show(); + } else +#endif + { + showMessage(QCoreApplication::applicationName(), tr("Disconnected from Syncthing"), QSystemTrayIcon::Warning); + } } break; case SyncthingStatus::Reconnecting: @@ -156,7 +204,7 @@ void TrayIcon::updateStatusIconAndText(SyncthingStatus status) case SyncthingStatus::Synchronizing: break; default: - if(m_status == SyncthingStatus::Synchronizing && Settings::values().notifyOn.syncComplete) { + if(m_status == SyncthingStatus::Synchronizing && settings.notifyOn.syncComplete) { const vector &completedDirs = connection.completedDirs(); if(!completedDirs.empty()) { QString message; @@ -170,7 +218,14 @@ void TrayIcon::updateStatusIconAndText(SyncthingStatus status) } message = tr("Synchronization of the following devices complete:\n") + names.join(QStringLiteral(", ")); } - showMessage(QCoreApplication::applicationName(), message, QSystemTrayIcon::Information); +#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS + if(settings.dbusNotifications) { + m_syncCompleteNotification.update(message); + } else +#endif + { + showMessage(QCoreApplication::applicationName(), message, QSystemTrayIcon::Information); + } } } } diff --git a/tray/gui/trayicon.h b/tray/gui/trayicon.h index a4c9bfb..8de045a 100644 --- a/tray/gui/trayicon.h +++ b/tray/gui/trayicon.h @@ -5,6 +5,10 @@ #include +#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS +# include +#endif + #include #include @@ -31,7 +35,7 @@ public slots: private slots: void handleActivated(QSystemTrayIcon::ActivationReason reason); - void handleMessageClicked(); + void handleSyncthingNotificationAction(const QString &action); private: QPixmap renderSvgImage(const QString &path); @@ -48,6 +52,12 @@ private: TrayMenu m_trayMenu; QMenu m_contextMenu; Data::SyncthingStatus m_status; +#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS + MiscUtils::DBusNotification m_disconnectedNotification; + MiscUtils::DBusNotification m_internalErrorNotification; + MiscUtils::DBusNotification m_syncthingNotification; + MiscUtils::DBusNotification m_syncCompleteNotification; +#endif }; inline TrayMenu &TrayIcon::trayMenu()