Allow notifications via D-Bus

This commit is contained in:
Martchus 2016-12-11 17:58:58 +01:00
parent a163c3f046
commit 203370f933
8 changed files with 166 additions and 55 deletions

View File

@ -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})

View File

@ -88,6 +88,7 @@ set(REQUIRED_ICONS
media-playback-start
network-card
network-connect
network-disconnect
network-server
preferences-desktop
preferences-desktop-icons

View File

@ -1,6 +1,9 @@
#include "./settings.h"
#include <qtutilities/settingsdialog/qtsettings.h>
#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS
# include <qtutilities/misc/dbusnotification.h>
#endif
#include <QStringBuilder>
#include <QApplication>
@ -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);

View File

@ -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)

View File

@ -2,14 +2,6 @@
<ui version="4.0">
<class>QtGui::NotificationsOptionPage</class>
<widget class="QWidget" name="QtGui::NotificationsOptionPage">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>240</width>
<height>193</height>
</rect>
</property>
<property name="windowTitle">
<string>Notifications</string>
</property>
@ -19,44 +11,63 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="notifyOnLabel">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<widget class="QGroupBox" name="notifyOnGroupBox">
<property name="title">
<string>Notify on</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QCheckBox" name="notifyOnDisconnectCheckBox">
<property name="text">
<string>disconnect</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="notifyOnErrorsCheckBox">
<property name="text">
<string>internal errors</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="showSyncthingNotificationsCheckBox">
<property name="text">
<string>errors/notifications from Syncthing</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="notifyOnSyncCompleteCheckBox">
<property name="text">
<string>sync complete</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QCheckBox" name="notifyOnDisconnectCheckBox">
<property name="text">
<string>disconnect</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="notifyOnErrorsCheckBox">
<property name="text">
<string>internal errors</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="showSyncthingNotificationsCheckBox">
<property name="text">
<string>errors/notifications from Syncthing</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="notifyOnSyncCompleteCheckBox">
<property name="text">
<string>sync complete</string>
<widget class="QGroupBox" name="apiGroupBox">
<property name="title">
<string>Notification API</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QRadioButton" name="dbusRadioButton">
<property name="text">
<string>D-Bus notifi&amp;cations (org.freedesktop.Notifications)</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="qtRadioButton">
<property name="text">
<string>&amp;Method provided by Qt (might be overridden by QPA plugin)</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>

View File

@ -16,6 +16,9 @@
#include <qtutilities/settingsdialog/optioncategory.h>
#include <qtutilities/settingsdialog/optioncategorymodel.h>
#include <qtutilities/settingsdialog/qtsettings.h>
#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS
# include <qtutilities/misc/dbusnotification.h>
#endif
#include <QFileDialog>
#include <QMessageBox>
@ -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 &notifyOn = 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
}
}

View File

@ -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<SyncthingDir *> &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);
}
}
}
}

View File

@ -5,6 +5,10 @@
#include <c++utilities/chrono/datetime.h>
#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS
# include <qtutilities/misc/dbusnotification.h>
#endif
#include <QSystemTrayIcon>
#include <QIcon>
@ -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()