File indexing completed on 2023-05-30 09:17:24
0001 /** 0002 * SPDX-FileCopyrightText: 2013 Albert Vaca <albertvaka@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0005 */ 0006 0007 #include "notificationsmodel.h" 0008 0009 #include <QDebug> 0010 #include <QIcon> 0011 0012 #include <dbushelper.h> 0013 0014 // In older Qt released, qAsConst isnt available 0015 #include "core/qtcompat_p.h" 0016 #include "interfaces_debug.h" 0017 0018 NotificationsModel::NotificationsModel(QObject *parent) 0019 : QAbstractListModel(parent) 0020 , m_dbusInterface(nullptr) 0021 { 0022 connect(this, &QAbstractItemModel::rowsInserted, this, &NotificationsModel::rowsChanged); 0023 connect(this, &QAbstractItemModel::rowsRemoved, this, &NotificationsModel::rowsChanged); 0024 0025 connect(this, &QAbstractItemModel::dataChanged, this, &NotificationsModel::anyDismissableChanged); 0026 connect(this, &QAbstractItemModel::rowsInserted, this, &NotificationsModel::anyDismissableChanged); 0027 0028 QDBusServiceWatcher *watcher = 0029 new QDBusServiceWatcher(DaemonDbusInterface::activatedService(), QDBusConnection::sessionBus(), QDBusServiceWatcher::WatchForOwnerChange, this); 0030 connect(watcher, &QDBusServiceWatcher::serviceRegistered, this, &NotificationsModel::refreshNotificationList); 0031 connect(watcher, &QDBusServiceWatcher::serviceUnregistered, this, &NotificationsModel::clearNotifications); 0032 } 0033 0034 QHash<int, QByteArray> NotificationsModel::roleNames() const 0035 { 0036 // Role names for QML 0037 QHash<int, QByteArray> names = QAbstractItemModel::roleNames(); 0038 names.insert(DbusInterfaceRole, "dbusInterface"); 0039 names.insert(AppNameModelRole, "appName"); 0040 names.insert(IdModelRole, "notificationId"); 0041 names.insert(DismissableModelRole, "dismissable"); 0042 names.insert(RepliableModelRole, "repliable"); 0043 names.insert(IconPathModelRole, "appIcon"); 0044 names.insert(TitleModelRole, "title"); 0045 names.insert(TextModelRole, "notitext"); 0046 return names; 0047 } 0048 0049 NotificationsModel::~NotificationsModel() 0050 { 0051 } 0052 0053 QString NotificationsModel::deviceId() const 0054 { 0055 return m_deviceId; 0056 } 0057 0058 void NotificationsModel::setDeviceId(const QString &deviceId) 0059 { 0060 m_deviceId = deviceId; 0061 0062 if (m_dbusInterface) { 0063 delete m_dbusInterface; 0064 } 0065 0066 m_dbusInterface = new DeviceNotificationsDbusInterface(deviceId, this); 0067 0068 connect(m_dbusInterface, &OrgKdeKdeconnectDeviceNotificationsInterface::notificationPosted, this, &NotificationsModel::notificationAdded); 0069 connect(m_dbusInterface, &OrgKdeKdeconnectDeviceNotificationsInterface::notificationRemoved, this, &NotificationsModel::notificationRemoved); 0070 connect(m_dbusInterface, &OrgKdeKdeconnectDeviceNotificationsInterface::allNotificationsRemoved, this, &NotificationsModel::clearNotifications); 0071 0072 refreshNotificationList(); 0073 0074 Q_EMIT deviceIdChanged(deviceId); 0075 } 0076 0077 void NotificationsModel::notificationAdded(const QString &id) 0078 { 0079 beginInsertRows(QModelIndex(), 0, 0); 0080 NotificationDbusInterface *dbusInterface = new NotificationDbusInterface(m_deviceId, id, this); 0081 connect(dbusInterface, &NotificationDbusInterface::ready, this, &NotificationsModel::notificationUpdated); 0082 m_notificationList.prepend(dbusInterface); 0083 endInsertRows(); 0084 } 0085 0086 void NotificationsModel::notificationRemoved(const QString &id) 0087 { 0088 for (int i = 0; i < m_notificationList.size(); ++i) { 0089 if (m_notificationList[i]->notificationId() == id) { 0090 beginRemoveRows(QModelIndex(), i, i); 0091 m_notificationList.removeAt(i); 0092 endRemoveRows(); 0093 return; 0094 } 0095 } 0096 qCWarning(KDECONNECT_INTERFACES) << "Attempted to remove unknown notification: " << id; 0097 } 0098 0099 void NotificationsModel::refreshNotificationList() 0100 { 0101 if (!m_dbusInterface) { 0102 return; 0103 } 0104 0105 clearNotifications(); 0106 0107 if (!m_dbusInterface->isValid()) { 0108 qCWarning(KDECONNECT_INTERFACES) << "dbus interface not valid"; 0109 return; 0110 } 0111 0112 QDBusPendingReply<QStringList> pendingNotificationIds = m_dbusInterface->activeNotifications(); 0113 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingNotificationIds, this); 0114 0115 QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, &NotificationsModel::receivedNotifications); 0116 } 0117 0118 void NotificationsModel::receivedNotifications(QDBusPendingCallWatcher *watcher) 0119 { 0120 watcher->deleteLater(); 0121 clearNotifications(); 0122 QDBusPendingReply<QStringList> pendingNotificationIds = *watcher; 0123 0124 if (pendingNotificationIds.isError()) { 0125 qCWarning(KDECONNECT_INTERFACES) << pendingNotificationIds.error(); 0126 return; 0127 } 0128 0129 const QStringList notificationIds = pendingNotificationIds.value(); 0130 if (notificationIds.isEmpty()) { 0131 return; 0132 } 0133 0134 beginInsertRows(QModelIndex(), 0, notificationIds.size() - 1); 0135 for (const QString ¬ificationId : notificationIds) { 0136 NotificationDbusInterface *dbusInterface = new NotificationDbusInterface(m_deviceId, notificationId, this); 0137 m_notificationList.append(dbusInterface); 0138 } 0139 endInsertRows(); 0140 } 0141 0142 QVariant NotificationsModel::data(const QModelIndex &index, int role) const 0143 { 0144 if (!index.isValid() || index.row() < 0 || index.row() >= m_notificationList.count() || !m_notificationList[index.row()]->isValid()) { 0145 return QVariant(); 0146 } 0147 0148 if (!m_dbusInterface || !m_dbusInterface->isValid()) { 0149 return QVariant(); 0150 } 0151 0152 NotificationDbusInterface *notification = m_notificationList[index.row()]; 0153 0154 // FIXME: This function gets called lots of times, producing lots of dbus calls. Add a cache? 0155 switch (role) { 0156 case IconModelRole: 0157 return QIcon::fromTheme(QStringLiteral("device-notifier")); 0158 case IdModelRole: 0159 return notification->internalId(); 0160 case NameModelRole: 0161 return notification->ticker(); 0162 case ContentModelRole: 0163 return QString(); // To implement in the Android side 0164 case AppNameModelRole: 0165 return notification->appName(); 0166 case DbusInterfaceRole: 0167 return QVariant::fromValue<QObject *>(notification); 0168 case DismissableModelRole: 0169 return notification->dismissable(); 0170 case RepliableModelRole: 0171 return !notification->replyId().isEmpty(); 0172 case IconPathModelRole: 0173 return notification->iconPath(); 0174 case TitleModelRole: 0175 return notification->title(); 0176 case TextModelRole: 0177 return notification->text(); 0178 default: 0179 return QVariant(); 0180 } 0181 } 0182 0183 NotificationDbusInterface *NotificationsModel::getNotification(const QModelIndex &index) const 0184 { 0185 if (!index.isValid()) { 0186 return nullptr; 0187 } 0188 0189 int row = index.row(); 0190 if (row < 0 || row >= m_notificationList.size()) { 0191 return nullptr; 0192 } 0193 0194 return m_notificationList[row]; 0195 } 0196 0197 int NotificationsModel::rowCount(const QModelIndex &parent) const 0198 { 0199 if (parent.isValid()) { 0200 // Return size 0 if we are a child because this is not a tree 0201 return 0; 0202 } 0203 0204 return m_notificationList.count(); 0205 } 0206 0207 bool NotificationsModel::isAnyDimissable() const 0208 { 0209 for (NotificationDbusInterface *notification : qAsConst(m_notificationList)) { 0210 if (notification->dismissable()) { 0211 return true; 0212 } 0213 } 0214 return false; 0215 } 0216 0217 void NotificationsModel::dismissAll() 0218 { 0219 for (NotificationDbusInterface *notification : qAsConst(m_notificationList)) { 0220 if (notification->dismissable()) { 0221 notification->dismiss(); 0222 } 0223 } 0224 } 0225 0226 void NotificationsModel::clearNotifications() 0227 { 0228 if (!m_notificationList.isEmpty()) { 0229 beginRemoveRows(QModelIndex(), 0, m_notificationList.size() - 1); 0230 qDeleteAll(m_notificationList); 0231 m_notificationList.clear(); 0232 endRemoveRows(); 0233 } 0234 } 0235 0236 void NotificationsModel::notificationUpdated() 0237 { 0238 Q_EMIT dataChanged(index(0, 0), index(m_notificationList.size() - 1, 0)); 0239 }