mirror of
https://github.com/Qortal/Brooklyn.git
synced 2025-02-14 11:15:54 +00:00
239 lines
8.4 KiB
C++
239 lines
8.4 KiB
C++
/*
|
|
SPDX-FileCopyrightText: 2008 Dmitry Suzdalev <dimsuz@gmail.com>
|
|
|
|
SPDX-License-Identifier: LGPL-2.0-or-later
|
|
*/
|
|
|
|
#include "notificationsengine.h"
|
|
#include "notificationservice.h"
|
|
|
|
#include "notification.h"
|
|
#include "server.h"
|
|
|
|
#include <KConfig>
|
|
#include <KConfigGroup>
|
|
#include <KNotifyConfigWidget>
|
|
#include <KSharedConfig>
|
|
#include <QGuiApplication>
|
|
#include <klocalizedstring.h>
|
|
|
|
#include <Plasma/DataContainer>
|
|
#include <Plasma/Service>
|
|
|
|
#include <QImage>
|
|
|
|
#include "debug.h"
|
|
|
|
using namespace NotificationManager;
|
|
|
|
NotificationsEngine::NotificationsEngine(QObject *parent, const QVariantList &args)
|
|
: Plasma::DataEngine(parent, args)
|
|
{
|
|
init();
|
|
}
|
|
|
|
NotificationsEngine::~NotificationsEngine()
|
|
{
|
|
}
|
|
|
|
void NotificationsEngine::init()
|
|
{
|
|
connect(&Server::self(), &Server::notificationAdded, this, [this](const Notification ¬ification) {
|
|
notificationAdded(notification);
|
|
});
|
|
|
|
connect(&Server::self(), &Server::notificationReplaced, this, [this](uint replacedId, const Notification ¬ification) {
|
|
// Notification will already have the correct identical ID
|
|
Q_UNUSED(replacedId);
|
|
notificationAdded(notification);
|
|
});
|
|
|
|
connect(&Server::self(), &Server::notificationRemoved, this, [this](uint id, Server::CloseReason reason) {
|
|
Q_UNUSED(reason);
|
|
const QString source = QStringLiteral("notification %1").arg(id);
|
|
// if we don't have that notification in our local list,
|
|
// it has already been closed so don't notify a second time
|
|
if (m_activeNotifications.remove(source) > 0) {
|
|
removeSource(source);
|
|
}
|
|
});
|
|
|
|
Server::self().init();
|
|
}
|
|
|
|
void NotificationsEngine::notificationAdded(const Notification ¬ification)
|
|
{
|
|
const QString app_name = notification.applicationName();
|
|
const QString appRealName = notification.notifyRcName();
|
|
const QString eventId = notification.eventId(); // FIXME = hints[QStringLiteral("x-kde-eventId")].toString();
|
|
const QStringList urls = QUrl::toStringList(notification.urls());
|
|
const QString desktopEntry = notification.desktopEntry();
|
|
const QString summary = notification.summary();
|
|
|
|
QString bodyFinal = notification.body(); // is already sanitized by NotificationManager
|
|
QString summaryFinal = notification.summary();
|
|
int timeout = notification.timeout();
|
|
|
|
if (bodyFinal.isEmpty()) {
|
|
// some ridiculous apps will send just a title (#372112), in that case, treat it as though there's only a body
|
|
bodyFinal = summary;
|
|
summaryFinal = app_name;
|
|
}
|
|
|
|
uint id = notification.id(); // replaces_id ? replaces_id : m_nextId++;
|
|
|
|
QString appname_str = app_name;
|
|
if (appname_str.isEmpty()) {
|
|
appname_str = i18n("Unknown Application");
|
|
}
|
|
|
|
bool isPersistent = (timeout == 0);
|
|
|
|
const int AVERAGE_WORD_LENGTH = 6;
|
|
const int WORD_PER_MINUTE = 250;
|
|
int count = notification.summary().length() + notification.body().length() - strlen("<?xml version=\"1.0\"><html></html>");
|
|
|
|
// -1 is "server default", 0 is persistent with "server default" display time,
|
|
// anything more should honor the setting
|
|
if (timeout <= 0) {
|
|
timeout = 60000 * count / AVERAGE_WORD_LENGTH / WORD_PER_MINUTE;
|
|
|
|
// Add two seconds for the user to notice the notification, and ensure
|
|
// it last at least five seconds, otherwise all the user see is a
|
|
// flash
|
|
timeout = 2000 + qMax(timeout, 3000);
|
|
}
|
|
|
|
const QString source = QStringLiteral("notification %1").arg(id);
|
|
|
|
Plasma::DataEngine::Data notificationData;
|
|
notificationData.insert(QStringLiteral("id"), QString::number(id));
|
|
notificationData.insert(QStringLiteral("eventId"), eventId);
|
|
notificationData.insert(QStringLiteral("appName"), notification.applicationName());
|
|
// TODO should be proper passed in icon?
|
|
notificationData.insert(QStringLiteral("appIcon"), notification.applicationIconName());
|
|
notificationData.insert(QStringLiteral("summary"), summaryFinal);
|
|
notificationData.insert(QStringLiteral("body"), bodyFinal);
|
|
|
|
QStringList actions;
|
|
for (int i = 0; i < notification.actionNames().count(); ++i) {
|
|
actions << notification.actionNames().at(i) << notification.actionLabels().at(i);
|
|
}
|
|
// NotificationManager hides the configure and default stuff from us but we need to re-add them
|
|
// to the actions list for compatibility
|
|
if (!notification.configureActionLabel().isEmpty()) {
|
|
actions << QStringLiteral("settings") << notification.configureActionLabel();
|
|
}
|
|
if (notification.hasDefaultAction()) {
|
|
actions << QStringLiteral("default") << QString();
|
|
}
|
|
|
|
notificationData.insert(QStringLiteral("actions"), actions);
|
|
notificationData.insert(QStringLiteral("isPersistent"), isPersistent);
|
|
notificationData.insert(QStringLiteral("expireTimeout"), timeout);
|
|
|
|
notificationData.insert(QStringLiteral("desktopEntry"), desktopEntry);
|
|
|
|
KService::Ptr service = KService::serviceByStorageId(desktopEntry);
|
|
if (service) {
|
|
notificationData.insert(QStringLiteral("appServiceName"), service->name());
|
|
notificationData.insert(QStringLiteral("appServiceIcon"), service->icon());
|
|
}
|
|
|
|
notificationData.insert(QStringLiteral("appRealName"), appRealName);
|
|
// NotificationManager configurable is anything that has a notifyrc or desktop entry
|
|
// but the old stuff assumes only stuff with notifyrc to be configurable
|
|
notificationData.insert(QStringLiteral("configurable"), !notification.notifyRcName().isEmpty());
|
|
|
|
QImage image = notification.image();
|
|
notificationData.insert(QStringLiteral("image"), image.isNull() ? QVariant() : image);
|
|
|
|
int urgency = -1;
|
|
switch (notification.urgency()) {
|
|
case Notifications::LowUrgency:
|
|
urgency = 0;
|
|
break;
|
|
case Notifications::NormalUrgency:
|
|
urgency = 1;
|
|
break;
|
|
case Notifications::CriticalUrgency:
|
|
urgency = 2;
|
|
break;
|
|
}
|
|
|
|
if (urgency > -1) {
|
|
notificationData.insert(QStringLiteral("urgency"), urgency);
|
|
}
|
|
|
|
notificationData.insert(QStringLiteral("urls"), urls);
|
|
|
|
setData(source, notificationData);
|
|
|
|
m_activeNotifications.insert(source, notification.applicationName() + notification.summary());
|
|
}
|
|
|
|
void NotificationsEngine::removeNotification(uint id, uint closeReason)
|
|
{
|
|
const QString source = QStringLiteral("notification %1").arg(id);
|
|
// if we don't have that notification in our local list,
|
|
// it has already been closed so don't notify a second time
|
|
if (m_activeNotifications.remove(source) > 0) {
|
|
removeSource(source);
|
|
Server::self().closeNotification(id, static_cast<Server::CloseReason>(closeReason));
|
|
}
|
|
}
|
|
|
|
Plasma::Service *NotificationsEngine::serviceForSource(const QString &source)
|
|
{
|
|
return new NotificationService(this, source);
|
|
}
|
|
|
|
int NotificationsEngine::createNotification(const QString &appName,
|
|
const QString &appIcon,
|
|
const QString &summary,
|
|
const QString &body,
|
|
int timeout,
|
|
const QStringList &actions,
|
|
const QVariantMap &hints)
|
|
{
|
|
Notification notification;
|
|
notification.setApplicationName(appName);
|
|
notification.setApplicationIconName(appIcon);
|
|
notification.setSummary(summary);
|
|
notification.setBody(body); // sanitizes
|
|
notification.setActions(actions);
|
|
notification.setTimeout(timeout);
|
|
notification.processHints(hints);
|
|
Server::self().add(notification);
|
|
return 0;
|
|
}
|
|
|
|
void NotificationsEngine::configureNotification(const QString &appName, const QString &eventId)
|
|
{
|
|
KNotifyConfigWidget *widget = KNotifyConfigWidget::configure(nullptr, appName);
|
|
if (!eventId.isEmpty()) {
|
|
widget->selectEvent(eventId);
|
|
}
|
|
}
|
|
|
|
QSharedPointer<NotificationInhibiton> NotificationsEngine::createInhibition(const QString &hint, const QString &value)
|
|
{
|
|
auto ni = new NotificationInhibiton;
|
|
ni->hint = hint;
|
|
ni->value = value;
|
|
|
|
QPointer<NotificationsEngine> guard(this);
|
|
QSharedPointer<NotificationInhibiton> rc(ni, [this, guard](NotificationInhibiton *ni) {
|
|
if (guard) {
|
|
m_inhibitions.removeOne(ni);
|
|
}
|
|
delete ni;
|
|
});
|
|
m_inhibitions.append(ni);
|
|
return rc;
|
|
}
|
|
|
|
K_PLUGIN_CLASS_WITH_JSON(NotificationsEngine, "plasma-dataengine-notifications.json")
|
|
|
|
#include "notificationsengine.moc"
|