From 841b250680192fd359b3242e099c518fcc6ff766 Mon Sep 17 00:00:00 2001 From: Martchus Date: Sun, 26 Nov 2017 03:17:30 +0100 Subject: [PATCH] Add SyncthingNotifier class First step of refactoring compution of high-level notifications to prevent code duplication for compution of "disconnected" and "sync complete" events. --- connector/CMakeLists.txt | 2 + connector/syncthingnotifier.cpp | 109 ++++++++++++++++++++++++++++++++ connector/syncthingnotifier.h | 93 +++++++++++++++++++++++++++ 3 files changed, 204 insertions(+) create mode 100644 connector/syncthingnotifier.cpp create mode 100644 connector/syncthingnotifier.h diff --git a/connector/CMakeLists.txt b/connector/CMakeLists.txt index df1fefb..ef7a6fb 100644 --- a/connector/CMakeLists.txt +++ b/connector/CMakeLists.txt @@ -14,6 +14,7 @@ set(HEADER_FILES syncthingdev.h syncthingconnection.h syncthingconnectionsettings.h + syncthingnotifier.h syncthingconfig.h syncthingprocess.h syncthingservice.h @@ -24,6 +25,7 @@ set(SRC_FILES syncthingdev.cpp syncthingconnection.cpp syncthingconnectionsettings.cpp + syncthingnotifier.cpp syncthingconfig.cpp syncthingprocess.cpp syncthingservice.cpp diff --git a/connector/syncthingnotifier.cpp b/connector/syncthingnotifier.cpp new file mode 100644 index 0000000..59679eb --- /dev/null +++ b/connector/syncthingnotifier.cpp @@ -0,0 +1,109 @@ +#include "./syncthingnotifier.h" +#include "./syncthingconnection.h" + +#ifdef LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD +#include "./syncthingservice.h" +#endif + +namespace Data { + +/*! + * \class SyncthingNotifier + * \brief The SyncthingNotifier class emits high-level notification for a given SyncthingConnection. + * + * In contrast to the signals provided by the SyncthingConnection class, these signals take further apply + * further logic and take additional information into account (previous status, service status if known, ...). + * + * \remarks Not tested yet. Supposed to simplify + * - SyncthingApplet::handleConnectionStatusChanged(SyncthingStatus status) + * - and TrayIcon::showStatusNotification(SyncthingStatus status). + */ + +/*! + * \brief Constructs a new SyncthingNotifier instance for the specified \a connection. + * \remarks Use setEnabledNotifications() to enable notifications (only statusChanged() is always emitted). + */ +SyncthingNotifier::SyncthingNotifier(const SyncthingConnection &connection, QObject *parent) + : QObject(parent) + , m_connection(connection) +#ifdef LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD + , m_service(syncthingService()) +#endif + , m_enabledNotifications(SyncthingHighLevelNotification::None) + , m_previousStatus(SyncthingStatus::Disconnected) + , m_initialized(false) +{ +} + +void SyncthingNotifier::handleStatusChangedEvent(SyncthingStatus newStatus) +{ + // skip redundant status updates + if (m_initialized && m_previousStatus == newStatus) { + return; + } + + // emit signals + emit statusChanged(m_previousStatus, newStatus); + emitConnectedAndDisconnected(newStatus); + emitSyncComplete(newStatus); + + // update status variables + m_initialized = true; + m_previousStatus = newStatus; +} + +/*! + * \brief Emits the connected() or disconnected() signal. + */ +void SyncthingNotifier::emitConnectedAndDisconnected(SyncthingStatus newStatus) +{ + if (!(m_enabledNotifications & SyncthingHighLevelNotification::ConnectedDisconnected)) { + return; + } + + switch (newStatus) { + case SyncthingStatus::Disconnected: + if (m_initialized +#ifdef LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD + && m_service.isManuallyStopped() +#endif + ) { + emit disconnected(); + } + break; + default: + switch (m_previousStatus) { + case SyncthingStatus::Disconnected: + case SyncthingStatus::Reconnecting: + emit connected(); + break; + default:; + } + } +} + +/*! + * \brief Emits the syncComplete() signal. + */ +void SyncthingNotifier::emitSyncComplete(SyncthingStatus newStatus) +{ + if (!(m_enabledNotifications & SyncthingHighLevelNotification::SyncComplete)) { + return; + } + + switch (newStatus) { + case SyncthingStatus::Disconnected: + case SyncthingStatus::Reconnecting: + case SyncthingStatus::Synchronizing: + break; + default: + if (m_previousStatus == SyncthingStatus::Synchronizing) { + const auto &completedDirs = m_connection.completedDirs(); + if (!completedDirs.empty()) { + emit syncComplete(completedDirs); + } + } + } +} + +} // namespace Data diff --git a/connector/syncthingnotifier.h b/connector/syncthingnotifier.h new file mode 100644 index 0000000..3468339 --- /dev/null +++ b/connector/syncthingnotifier.h @@ -0,0 +1,93 @@ +#ifndef DATA_SYNCTHINGNOTIFIER_H +#define DATA_SYNCTHINGNOTIFIER_H + +#include "./global.h" + +#include + +namespace Data { + +enum class SyncthingStatus; +class SyncthingConnection; +class SyncthingService; +struct SyncthingDir; + +/*! + * \brief The SyncthingHighLevelNotification enum specifies the high-level notifications provided by the SyncthingNotifier class. + * \remarks The enum is supposed to be used as flag-enum. + */ +enum class SyncthingHighLevelNotification { + None = 0x0, + ConnectedDisconnected = 0x1, + SyncComplete = 0x2, +}; + +/// \cond +constexpr SyncthingHighLevelNotification operator|(SyncthingHighLevelNotification lhs, SyncthingHighLevelNotification rhs) +{ + return static_cast(static_cast(lhs) | static_cast(rhs)); +} + +constexpr bool operator&(SyncthingHighLevelNotification lhs, SyncthingHighLevelNotification rhs) +{ + return static_cast(static_cast(lhs) & static_cast(rhs)); +} +/// \endcond + +class LIB_SYNCTHING_CONNECTOR_EXPORT SyncthingNotifier : public QObject { + Q_OBJECT + Q_PROPERTY(SyncthingHighLevelNotification enabledNotifications READ enabledNotifications WRITE setEnabledNotifications) + +public: + SyncthingNotifier(const SyncthingConnection &connection, QObject *parent = nullptr); + + SyncthingHighLevelNotification enabledNotifications() const; + +public Q_SLOTS: + void setEnabledNotifications(SyncthingHighLevelNotification enabledNotifications); + +Q_SIGNALS: + ///! \brief Emitted when the connection status changes. Also provided the previous status. + void statusChanged(SyncthingStatus previousStatus, SyncthingStatus newStatus); + ///! \brief Emitted when the connection to Syncthing has been established. + void connected(); + ///! \brief Emitted when the connection to Syncthing has been interrupted. + void disconnected(); + ///! \brief Emitted when the specified \a dirs have been completed synchronization. + void syncComplete(const std::vector &dirs); + +private Q_SLOTS: + void handleStatusChangedEvent(SyncthingStatus newStatus); + +private: + void emitConnectedAndDisconnected(SyncthingStatus newStatus); + void emitSyncComplete(SyncthingStatus newStatus); + + const SyncthingConnection &m_connection; +#ifdef LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD + const SyncthingService &m_service; +#endif + SyncthingHighLevelNotification m_enabledNotifications; + SyncthingStatus m_previousStatus; + bool m_initialized; +}; + +/*! + * \brief Returns which notifications are enabled (by default none). + */ +inline SyncthingHighLevelNotification SyncthingNotifier::enabledNotifications() const +{ + return m_enabledNotifications; +} + +/*! + * \brief Sets which notifications are enabled. + */ +inline void SyncthingNotifier::setEnabledNotifications(SyncthingHighLevelNotification enabledNotifications) +{ + m_enabledNotifications = enabledNotifications; +} + +} // namespace Data + +#endif // DATA_SYNCTHINGNOTIFIER_H