2016-12-11 17:31:49 +01:00
|
|
|
#ifndef MISC_UTILS_NOTIFICATION_H
|
|
|
|
#define MISC_UTILS_NOTIFICATION_H
|
|
|
|
|
|
|
|
#include "../global.h"
|
|
|
|
|
|
|
|
#include <QObject>
|
2018-03-31 23:35:39 +02:00
|
|
|
#include <QSet>
|
2016-12-11 17:31:49 +01:00
|
|
|
#include <QVariantMap>
|
|
|
|
|
2018-04-05 12:03:01 +02:00
|
|
|
#include <functional>
|
|
|
|
|
2016-12-11 17:31:49 +01:00
|
|
|
QT_FORWARD_DECLARE_CLASS(QDBusPendingCallWatcher)
|
|
|
|
|
|
|
|
class OrgFreedesktopNotificationsInterface;
|
|
|
|
|
2019-06-10 21:57:46 +02:00
|
|
|
namespace QtUtilities {
|
2016-12-11 17:31:49 +01:00
|
|
|
|
2017-05-01 03:16:25 +02:00
|
|
|
enum class NotificationIcon { NoIcon, Information, Warning, Critical };
|
2016-12-11 17:31:49 +01:00
|
|
|
|
2017-05-01 03:16:25 +02:00
|
|
|
enum class NotificationCloseReason { Undefined, Expired, Dismissed, Manually, ActionInvoked };
|
2016-12-11 17:31:49 +01:00
|
|
|
|
2017-05-01 03:16:25 +02:00
|
|
|
class QT_UTILITIES_EXPORT DBusNotification : public QObject {
|
2016-12-11 17:31:49 +01:00
|
|
|
Q_OBJECT
|
2019-06-16 17:35:31 +02:00
|
|
|
Q_PROPERTY(QString applicationName READ applicationName WRITE setApplicationName)
|
2016-12-11 17:31:49 +01:00
|
|
|
Q_PROPERTY(QString title READ title WRITE setTitle)
|
|
|
|
Q_PROPERTY(QString message READ message WRITE setMessage)
|
|
|
|
Q_PROPERTY(QString icon READ icon WRITE setIcon)
|
|
|
|
Q_PROPERTY(int timeout READ timeout WRITE setTimeout)
|
|
|
|
Q_PROPERTY(QStringList actions READ actions WRITE setActions)
|
|
|
|
Q_PROPERTY(bool visible READ isVisible)
|
|
|
|
|
|
|
|
public:
|
2018-03-31 23:35:39 +02:00
|
|
|
class QT_UTILITIES_EXPORT Capabilities : public QSet<QString> {
|
|
|
|
public:
|
|
|
|
explicit Capabilities();
|
|
|
|
explicit Capabilities(const QStringList &capabilities);
|
|
|
|
bool isValid() const;
|
|
|
|
bool supportsBody() const;
|
|
|
|
bool supportsLinks() const;
|
|
|
|
bool supportsMarkup() const;
|
|
|
|
bool supportsImages() const;
|
|
|
|
bool supportsIcon() const;
|
|
|
|
bool supportsActions() const;
|
|
|
|
bool supportsAnimatedIcon() const;
|
|
|
|
bool supportsActionIcons() const;
|
|
|
|
bool supportsSound() const;
|
|
|
|
bool supportsPercistence() const;
|
|
|
|
|
|
|
|
private:
|
|
|
|
bool m_valid;
|
|
|
|
};
|
|
|
|
|
2017-05-01 03:16:25 +02:00
|
|
|
explicit DBusNotification(
|
|
|
|
const QString &title, NotificationIcon icon = NotificationIcon::Information, int timeout = 10000, QObject *parent = nullptr);
|
2016-12-11 17:31:49 +01:00
|
|
|
explicit DBusNotification(const QString &title, const QString &icon, int timeout = 10000, QObject *parent = nullptr);
|
2019-05-28 21:33:24 +02:00
|
|
|
~DBusNotification() override;
|
2016-12-11 17:31:49 +01:00
|
|
|
|
|
|
|
static bool isAvailable();
|
2019-06-16 17:35:31 +02:00
|
|
|
const QString &applicationName() const;
|
|
|
|
void setApplicationName(const QString &applicationName);
|
2016-12-11 17:31:49 +01:00
|
|
|
const QString &title() const;
|
|
|
|
void setTitle(const QString &title);
|
|
|
|
const QString &message() const;
|
|
|
|
void setMessage(const QString &message);
|
|
|
|
const QString &icon() const;
|
|
|
|
void setIcon(const QString &icon);
|
|
|
|
void setIcon(NotificationIcon icon);
|
2018-03-18 03:07:03 +01:00
|
|
|
const QImage image() const;
|
|
|
|
void setImage(const QImage &image);
|
|
|
|
const QString imagePath() const;
|
|
|
|
void setImagePath(const QString &imagePath);
|
2016-12-11 17:31:49 +01:00
|
|
|
int timeout() const;
|
|
|
|
void setTimeout(int timeout);
|
2019-06-16 17:35:31 +02:00
|
|
|
int urgency() const;
|
|
|
|
void setUrgency(quint8 urgency);
|
|
|
|
bool isResident() const;
|
|
|
|
void setResident(bool resident);
|
|
|
|
QString category() const;
|
|
|
|
void setCategory(const QString &category);
|
2016-12-11 17:31:49 +01:00
|
|
|
const QStringList &actions() const;
|
|
|
|
void setActions(const QStringList &actions);
|
|
|
|
const QVariantMap &hints() const;
|
|
|
|
QVariantMap &hints();
|
2018-03-18 03:07:03 +01:00
|
|
|
QVariant hint(const QString &name) const;
|
|
|
|
QVariant hint(const QString &name, const QString &fallbackNames...) const;
|
2016-12-11 17:31:49 +01:00
|
|
|
bool isVisible() const;
|
|
|
|
void deleteOnCloseOrError();
|
2018-03-31 23:35:39 +02:00
|
|
|
static bool queryCapabilities(const std::function<void(Capabilities &&capabilities)> &callback);
|
2016-12-11 17:31:49 +01:00
|
|
|
|
|
|
|
public Q_SLOTS:
|
|
|
|
bool show();
|
|
|
|
bool show(const QString &message);
|
|
|
|
bool update(const QString &line);
|
2019-06-16 17:35:31 +02:00
|
|
|
bool hide();
|
2016-12-11 17:31:49 +01:00
|
|
|
|
|
|
|
Q_SIGNALS:
|
|
|
|
/// \brief Emitted when the notification could be shown successful.
|
|
|
|
void shown();
|
|
|
|
/// \brief Emitted when the notification couldn't be shown.
|
|
|
|
void error();
|
|
|
|
/// \brief Emitted when the notification has been closed.
|
|
|
|
void closed(NotificationCloseReason reason);
|
|
|
|
/// \brief Emitted when \a action has been invoked.
|
|
|
|
void actionInvoked(const QString &action);
|
|
|
|
|
|
|
|
private Q_SLOTS:
|
|
|
|
void handleNotifyResult(QDBusPendingCallWatcher *);
|
|
|
|
static void handleNotificationClosed(uint id, uint reason);
|
|
|
|
static void handleActionInvoked(uint id, const QString &action);
|
|
|
|
|
|
|
|
private:
|
|
|
|
static void initInterface();
|
|
|
|
|
|
|
|
uint m_id;
|
|
|
|
QDBusPendingCallWatcher *m_watcher;
|
2019-06-16 17:35:31 +02:00
|
|
|
QString m_applicationName;
|
2016-12-11 17:31:49 +01:00
|
|
|
QString m_title;
|
|
|
|
QString m_msg;
|
|
|
|
QString m_icon;
|
|
|
|
int m_timeout;
|
|
|
|
QStringList m_actions;
|
|
|
|
QVariantMap m_hints;
|
2018-03-31 23:35:39 +02:00
|
|
|
static OrgFreedesktopNotificationsInterface *s_dbusInterface;
|
2016-12-11 17:31:49 +01:00
|
|
|
};
|
|
|
|
|
2018-03-31 23:35:39 +02:00
|
|
|
inline DBusNotification::Capabilities::Capabilities()
|
|
|
|
: m_valid(false)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
inline DBusNotification::Capabilities::Capabilities(const QStringList &capabilities)
|
|
|
|
: QSet<QString>(capabilities.toSet())
|
|
|
|
, m_valid(true)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool DBusNotification::Capabilities::isValid() const
|
|
|
|
{
|
|
|
|
return m_valid;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool DBusNotification::Capabilities::supportsBody() const
|
|
|
|
{
|
|
|
|
return contains(QStringLiteral("body"));
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool DBusNotification::Capabilities::supportsLinks() const
|
|
|
|
{
|
|
|
|
return contains(QStringLiteral("body-hyperlinks"));
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool DBusNotification::Capabilities::supportsMarkup() const
|
|
|
|
{
|
|
|
|
return contains(QStringLiteral("body-markup"));
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool DBusNotification::Capabilities::supportsImages() const
|
|
|
|
{
|
|
|
|
return contains(QStringLiteral("body-images"));
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool DBusNotification::Capabilities::supportsIcon() const
|
|
|
|
{
|
|
|
|
return contains(QStringLiteral("icon-static")) || supportsAnimatedIcon();
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool DBusNotification::Capabilities::supportsActions() const
|
|
|
|
{
|
|
|
|
return contains(QStringLiteral("actions"));
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool DBusNotification::Capabilities::supportsAnimatedIcon() const
|
|
|
|
{
|
|
|
|
return contains(QStringLiteral("icon-multi"));
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool DBusNotification::Capabilities::supportsActionIcons() const
|
|
|
|
{
|
|
|
|
return contains(QStringLiteral("action-icons"));
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool DBusNotification::Capabilities::supportsSound() const
|
|
|
|
{
|
|
|
|
return contains(QStringLiteral("sound"));
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool DBusNotification::Capabilities::supportsPercistence() const
|
|
|
|
{
|
|
|
|
return contains(QStringLiteral("persistence"));
|
|
|
|
}
|
|
|
|
|
2019-06-16 17:35:31 +02:00
|
|
|
/*!
|
|
|
|
* \brief Returns the application name to be used.
|
|
|
|
* \remarks If the application name is empty (which is the default), QCoreApplication::applicationName() is used instead.
|
|
|
|
*/
|
|
|
|
inline const QString &DBusNotification::applicationName() const
|
|
|
|
{
|
|
|
|
return m_applicationName;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Sets the application name to be used.
|
|
|
|
* \remarks If the application name is empty (which is the default), QCoreApplication::applicationName() is used instead.
|
|
|
|
*/
|
|
|
|
inline void DBusNotification::setApplicationName(const QString &applicationName)
|
|
|
|
{
|
|
|
|
m_applicationName = applicationName;
|
|
|
|
}
|
|
|
|
|
2016-12-11 17:31:49 +01:00
|
|
|
inline const QString &DBusNotification::title() const
|
|
|
|
{
|
|
|
|
return m_title;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void DBusNotification::setTitle(const QString &title)
|
|
|
|
{
|
|
|
|
m_title = title;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline const QString &DBusNotification::message() const
|
|
|
|
{
|
|
|
|
return m_msg;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void DBusNotification::setMessage(const QString &message)
|
|
|
|
{
|
|
|
|
m_msg = message;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns the icon name.
|
|
|
|
* \sa setIcon() for more details
|
|
|
|
*/
|
|
|
|
inline const QString &DBusNotification::icon() const
|
|
|
|
{
|
|
|
|
return m_icon;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Sets the icon name.
|
|
|
|
* \remarks
|
2017-05-04 22:46:37 +02:00
|
|
|
* The specified \a icon should be either an URI (file:// is the only URI schema
|
2017-08-20 02:03:21 +02:00
|
|
|
* supported right now) or a name in an icon theme.
|
2016-12-11 17:31:49 +01:00
|
|
|
*/
|
|
|
|
inline void DBusNotification::setIcon(const QString &icon)
|
|
|
|
{
|
|
|
|
m_icon = icon;
|
|
|
|
}
|
|
|
|
|
2018-03-18 03:07:03 +01:00
|
|
|
/*!
|
|
|
|
* \brief Returns the hint with the specified \a name.
|
|
|
|
*/
|
|
|
|
inline QVariant DBusNotification::hint(const QString &name) const
|
|
|
|
{
|
|
|
|
return m_hints[name];
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns the hint with the specified \a name. If no hint is present, the \a fallbackNames are tried in the specified order.
|
|
|
|
*/
|
|
|
|
inline QVariant DBusNotification::hint(const QString &name, const QString &fallbackNames...) const
|
|
|
|
{
|
|
|
|
const auto variant(m_hints[name]);
|
|
|
|
return variant.isNull() ? this->hint(fallbackNames) : variant;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns the image path.
|
|
|
|
* \sa setImagePath() for more details
|
|
|
|
*/
|
|
|
|
inline const QString DBusNotification::imagePath() const
|
|
|
|
{
|
|
|
|
return hint(QStringLiteral("image-data"), QStringLiteral("image_path")).toString();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Sets the image path.
|
|
|
|
* \remarks
|
|
|
|
* Alternative way to define the notification image; setImage() precedes.
|
|
|
|
*/
|
|
|
|
inline void DBusNotification::setImagePath(const QString &imagePath)
|
|
|
|
{
|
|
|
|
m_hints[QStringLiteral("image-path")] = imagePath;
|
|
|
|
}
|
|
|
|
|
2016-12-11 17:31:49 +01:00
|
|
|
inline int DBusNotification::timeout() const
|
|
|
|
{
|
|
|
|
return m_timeout;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void DBusNotification::setTimeout(int timeout)
|
|
|
|
{
|
|
|
|
m_timeout = timeout;
|
|
|
|
}
|
|
|
|
|
2019-06-16 17:35:31 +02:00
|
|
|
/*!
|
|
|
|
* \brief Returns the urgency level (0 = low, 1 = normal, 2 = critical).
|
|
|
|
*/
|
|
|
|
inline int DBusNotification::urgency() const
|
|
|
|
{
|
|
|
|
return m_hints[QStringLiteral("urgency")].toInt();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Sets the urgency level (0 = low, 1 = normal, 2 = critical).
|
|
|
|
*/
|
|
|
|
inline void DBusNotification::setUrgency(quint8 urgency)
|
|
|
|
{
|
|
|
|
m_hints[QStringLiteral("urgency")] = urgency;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns whether the notification will remain visible after an action has been clicked.
|
|
|
|
*/
|
|
|
|
inline bool DBusNotification::isResident() const
|
|
|
|
{
|
|
|
|
return m_hints[QStringLiteral("resident")].toBool();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Sets whether the notification will remain visible after an action has been clicked.
|
|
|
|
*/
|
|
|
|
inline void DBusNotification::setResident(bool resident)
|
|
|
|
{
|
|
|
|
m_hints[QStringLiteral("resident")] = resident;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns the category.
|
|
|
|
* \sa https://developer.gnome.org/notification-spec/#categories
|
|
|
|
*/
|
|
|
|
inline QString DBusNotification::category() const
|
|
|
|
{
|
|
|
|
return m_hints[QStringLiteral("category")].toString();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Sets the category.
|
|
|
|
* \sa https://developer.gnome.org/notification-spec/#categories
|
|
|
|
*/
|
|
|
|
inline void DBusNotification::setCategory(const QString &category)
|
|
|
|
{
|
|
|
|
m_hints[QStringLiteral("category")] = category;
|
|
|
|
}
|
|
|
|
|
2017-08-20 02:03:21 +02:00
|
|
|
/*!
|
|
|
|
* \brief Returns the actions for the notification.
|
|
|
|
*
|
|
|
|
* The actions are a list of action IDs and action names. The ID is returned by
|
|
|
|
* the actionInvoked() signal if an action is triggered. The action name is the
|
|
|
|
* user-visible name of the notification.
|
|
|
|
*
|
|
|
|
* Example: { QStringLiteral("dismiss"), tr("Dismiss notification"),
|
|
|
|
* QStringLiteral("details"), tr("Show details") }
|
|
|
|
*/
|
2016-12-11 17:31:49 +01:00
|
|
|
inline const QStringList &DBusNotification::actions() const
|
|
|
|
{
|
|
|
|
return m_actions;
|
|
|
|
}
|
|
|
|
|
2017-08-20 02:03:21 +02:00
|
|
|
/*!
|
|
|
|
* \brief Sets the actions for the notification.
|
|
|
|
* \sa see actions() for details and an example
|
|
|
|
*/
|
2016-12-11 17:31:49 +01:00
|
|
|
inline void DBusNotification::setActions(const QStringList &actions)
|
|
|
|
{
|
|
|
|
m_actions = actions;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline const QVariantMap &DBusNotification::hints() const
|
|
|
|
{
|
|
|
|
return m_hints;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline QVariantMap &DBusNotification::hints()
|
|
|
|
{
|
|
|
|
return m_hints;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool DBusNotification::isVisible() const
|
|
|
|
{
|
|
|
|
return m_id != 0;
|
|
|
|
}
|
2019-06-10 21:57:46 +02:00
|
|
|
} // namespace QtUtilities
|
2016-12-11 17:31:49 +01:00
|
|
|
|
|
|
|
#endif // MISC_UTILS_NOTIFICATION_H
|