File indexing completed on 2024-04-28 16:54:37
0001 /* 0002 SPDX-FileCopyrightText: 2019 Kai Uwe Broulik <kde@privat.broulik.de> 0003 0004 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0005 */ 0006 0007 #pragma once 0008 0009 #include <QQmlParserStatus> 0010 #include <QScopedPointer> 0011 #include <QSortFilterProxyModel> 0012 #include <QWindow> 0013 0014 #include "notificationmanager_export.h" 0015 0016 namespace NotificationManager 0017 { 0018 /** 0019 * @brief A model with notifications and jobs 0020 * 0021 * This model contains application notifications as well as jobs 0022 * and lets you apply fine-grained filter, sorting, and grouping rules. 0023 * 0024 * @author Kai Uwe Broulik <kde@privat.broulik.de> 0025 **/ 0026 class NOTIFICATIONMANAGER_EXPORT Notifications : public QSortFilterProxyModel, public QQmlParserStatus 0027 { 0028 Q_OBJECT 0029 Q_INTERFACES(QQmlParserStatus) 0030 0031 /** 0032 * The number of notifications the model should at most contain. 0033 * 0034 * Default is 0, which is no limit. 0035 */ 0036 Q_PROPERTY(int limit READ limit WRITE setLimit NOTIFY limitChanged) 0037 0038 /** 0039 * Whether to show expired notifications. 0040 * 0041 * Expired notifications are those that timed out, i.e. ones that were not explicitly 0042 * closed or acted upon by the user, nor revoked by the issuing application. 0043 * 0044 * An expired notification has its actions removed. 0045 * 0046 * Default is false. 0047 */ 0048 Q_PROPERTY(bool showExpired READ showExpired WRITE setShowExpired NOTIFY showExpiredChanged) 0049 0050 /** 0051 * Whether to show dismissed notifications. 0052 * 0053 * Dismissed notifications are those that are temporarily hidden by the user. 0054 * This can e.g. be a copy job that has its popup closed but still continues in the background. 0055 * 0056 * Default is false. 0057 */ 0058 Q_PROPERTY(bool showDismissed READ showDismissed WRITE setShowDismissed NOTIFY showDismissedChanged) 0059 0060 /** 0061 * A list of desktop entries for which no notifications should be shown. 0062 * 0063 * If the same desktop entry is present in both blacklist and whitelist, 0064 * the blacklist takes precedence, i.e. the notification is not shown. 0065 */ 0066 Q_PROPERTY(QStringList blacklistedDesktopEntries READ blacklistedDesktopEntries WRITE setBlacklistedDesktopEntries NOTIFY blacklistedDesktopEntriesChanged) 0067 0068 /** 0069 * A list of notifyrc names for which no notifications should be shown. 0070 * 0071 * If the same notifyrc name is present in both blacklist and whitelist, 0072 * the blacklist takes precedence, i.e. the notification is not shown. 0073 */ 0074 Q_PROPERTY(QStringList blacklistedNotifyRcNames READ blacklistedNotifyRcNames WRITE setBlacklistedNotifyRcNames NOTIFY blacklistedNotifyRcNamesChanged) 0075 0076 /** 0077 * A list of desktop entries for which notifications should be shown. 0078 * 0079 * This bypasses any filtering for urgency. 0080 * 0081 * If the same desktop entry is present in both whitelist and blacklist, 0082 * the blacklist takes precedence, i.e. the notification is not shown. 0083 * 0084 * Default is empty list, which means normal filtering is applied. 0085 */ 0086 Q_PROPERTY(QStringList whitelistedDesktopEntries READ whitelistedDesktopEntries WRITE setWhitelistedDesktopEntries NOTIFY whitelistedDesktopEntriesChanged) 0087 0088 /** 0089 * A list of notifyrc names for which notifications should be shown. 0090 * 0091 * This bypasses any filtering for urgency. 0092 * 0093 * If the same notifyrc name is present in both whitelist and blacklist, 0094 * the blacklist takes precedence, i.e. the notification is not shown. 0095 * 0096 * Default is empty list, which means normal filtering is applied. 0097 */ 0098 Q_PROPERTY(QStringList whitelistedNotifyRcNames READ whitelistedNotifyRcNames WRITE setWhitelistedNotifyRcNames NOTIFY whitelistedNotifyRcNamesChanged) 0099 0100 /** 0101 * Whether to show notifications. 0102 * 0103 * Default is true. 0104 */ 0105 Q_PROPERTY(bool showNotifications READ showNotifications WRITE setShowNotifications NOTIFY showNotificationsChanged) 0106 0107 /** 0108 * Whether to show application jobs. 0109 * 0110 * Default is false. 0111 */ 0112 Q_PROPERTY(bool showJobs READ showJobs WRITE setShowJobs NOTIFY showJobsChanged) 0113 0114 /** 0115 * The notification urgency types the model should contain. 0116 * 0117 * Default is all urgencies: low, normal, critical. 0118 */ 0119 Q_PROPERTY(Urgencies urgencies READ urgencies WRITE setUrgencies NOTIFY urgenciesChanged) 0120 0121 /** 0122 * The sort mode for notifications. 0123 * 0124 * Default is strictly by date created/updated. 0125 */ 0126 Q_PROPERTY(SortMode sortMode READ sortMode WRITE setSortMode NOTIFY sortModeChanged) 0127 0128 /** 0129 * The sort order for notifications. 0130 * 0131 * This only affects the sort order by date. When @c sortMode is set to SortByTypeAndUrgency 0132 * the order of notification groups (e.g. high - jobs - normal - low) is unaffected, and only 0133 * notifications within the same group are either sorted ascending or descending by their 0134 * creation/update date. 0135 * 0136 * Default is DescendingOrder, i.e. newest notifications come first. 0137 * 0138 * @since 5.19 0139 */ 0140 Q_PROPERTY(Qt::SortOrder sortOrder READ sortOrder WRITE setSortOrder NOTIFY sortOrderChanged) 0141 0142 /** 0143 * The group mode for notifications. 0144 * 0145 * Default is ungrouped. 0146 */ 0147 Q_PROPERTY(GroupMode groupMode READ groupMode WRITE setGroupMode NOTIFY groupModeChanged) 0148 0149 /** 0150 * How many notifications are shown in each group. 0151 * 0152 * You can expand a group by setting the IsGroupExpandedRole to true. 0153 * 0154 * Default is 0, which means no limit. 0155 */ 0156 Q_PROPERTY(int groupLimit READ groupLimit WRITE setGroupLimit NOTIFY groupLimitChanged) 0157 0158 /** 0159 * Whether to automatically show notifications that are unread. 0160 * 0161 * This is any notification that was created or updated after the value of @c lastRead. 0162 */ 0163 Q_PROPERTY(bool expandUnread READ expandUnread WRITE setExpandUnread NOTIFY expandUnreadChanged) 0164 0165 /** 0166 * The number of notifications in the model 0167 */ 0168 Q_PROPERTY(int count READ count NOTIFY countChanged) 0169 0170 /** 0171 * The number of active, i.e. non-expired notifications 0172 */ 0173 Q_PROPERTY(int activeNotificationsCount READ activeNotificationsCount NOTIFY activeNotificationsCountChanged) 0174 0175 /** 0176 * The number of inactive, i.e. non-expired notifications 0177 */ 0178 Q_PROPERTY(int expiredNotificationsCount READ expiredNotificationsCount NOTIFY expiredNotificationsCountChanged) 0179 0180 /** 0181 * The time when the user last could read the notifications. 0182 * This is typically reset whenever the list of notifications is opened and is used to determine 0183 * the @c unreadNotificationsCount 0184 */ 0185 Q_PROPERTY(QDateTime lastRead READ lastRead WRITE setLastRead RESET resetLastRead NOTIFY lastReadChanged) 0186 0187 /** 0188 * The number of notifications added since lastRead 0189 * 0190 * This can be used to show a "n unread notifications" label 0191 */ 0192 Q_PROPERTY(int unreadNotificationsCount READ unreadNotificationsCount NOTIFY unreadNotificationsCountChanged) 0193 0194 /** 0195 * The number of active jobs 0196 */ 0197 Q_PROPERTY(int activeJobsCount READ activeJobsCount NOTIFY activeJobsCountChanged) 0198 /** 0199 * The combined percentage of all jobs. 0200 * 0201 * This is the average of all percentages and could can be used to show 0202 * a global progress bar. 0203 */ 0204 Q_PROPERTY(int jobsPercentage READ jobsPercentage NOTIFY jobsPercentageChanged) 0205 0206 /** 0207 * The window that will render the notifications 0208 * 0209 * This is used to tell the xdg_activation_v1 protocol who is requesting the activation. 0210 */ 0211 Q_PROPERTY(QWindow *window READ window WRITE setWindow NOTIFY windowChanged) 0212 public: 0213 explicit Notifications(QObject *parent = nullptr); 0214 ~Notifications() override; 0215 0216 enum Roles { 0217 IdRole = Qt::UserRole + 1, ///< A notification identifier. This can be uint notification ID or string application job source. 0218 SummaryRole = Qt::DisplayRole, ///< The notification summary. 0219 ImageRole = Qt::DecorationRole, ///< The notification main image, which is not the application icon. Only valid for pixmap icons. 0220 0221 IsGroupRole = Qt::UserRole + 2, ///< Whether the item is a group 0222 GroupChildrenCountRole, ///< The number of children in a group. 0223 ExpandedGroupChildrenCountRole, ///< The number of children in a group that are expanded. 0224 IsGroupExpandedRole, ///< Whether the group is expanded, this role is writable. 0225 0226 IsInGroupRole, ///< Whether the notification is currently inside a group. 0227 TypeRole, ///< The type of model entry, either NotificationType or JobType. 0228 CreatedRole, ///< When the notification was first created. 0229 UpdatedRole, ///< When the notification was last updated, invalid when it hasn't been updated. 0230 0231 BodyRole, ///< The notification body text. 0232 IconNameRole, ///< The notification main icon name, which is not the application icon. Only valid for icon names, if a URL supplied, it is loaded and 0233 ///< exposed as ImageRole instead. 0234 0235 DesktopEntryRole, ///< The desktop entry (without .desktop suffix, e.g. org.kde.spectacle) of the application that sent the notification. 0236 NotifyRcNameRole, ///< The notifyrc name (e.g. spectaclerc) of the application that sent the notification. 0237 0238 ApplicationNameRole, ///< The user-visible name of the application (e.g. Spectacle) 0239 ApplicationIconNameRole, ///< The icon name of the application 0240 OriginNameRole, ///< The name of the device or account the notification originally came from, e.g. "My Phone" (in case of device sync) or 0241 ///< "foo@example.com" (in case of an email notification) 0242 0243 // Jobs 0244 JobStateRole, ///< The state of the job, either JobStateJopped, JobStateSuspended, or JobStateRunning. 0245 PercentageRole, ///< The percentage of the job. Use @c jobsPercentage to get a global percentage for all jobs. 0246 JobErrorRole, ///< The error id of the job, zero in case of no error. 0247 SuspendableRole, ///< Whether the job can be suspended @sa suspendJob 0248 KillableRole, ///< Whether the job can be killed/canceled @sa killJob 0249 JobDetailsRole, ///< A pointer to a Job item itself containing more detailed information about the job 0250 0251 ActionNamesRole, ///< The IDs of the actions, excluding the default and settings action, e.g. [action1, action2] 0252 ActionLabelsRole, ///< The user-visible labels of the actions, excluding the default and settings action, e.g. ["Accept", "Reject"] 0253 HasDefaultActionRole, ///< Whether the notification has a default action, which is one that is invoked when the popup itself is clicked 0254 DefaultActionLabelRole, ///< The user-visible label of the default action, typically not shown as the popup itself becomes clickable 0255 0256 UrlsRole, ///< A list of URLs associated with the notification, e.g. a path to a screenshot that was just taken or image received 0257 0258 UrgencyRole, ///< The notification urgency, either LowUrgency, NormalUrgency, or CriticalUrgency. Jobs do not have an urgency. 0259 TimeoutRole, ///< The timeout for the notification in milliseconds. 0 means the notification should not timeout, -1 means a sensible default should be 0260 ///< applied. 0261 0262 ConfigurableRole, ///< Whether the notification can be configured because a desktopEntry or notifyRcName is known, or the notification has a setting 0263 ///< action. @sa configure 0264 ConfigureActionLabelRole, ///< The user-visible label for the settings action 0265 ClosableRole, ///< Whether the item can be closed. Notifications are always closable, jobs are only when in JobStateStopped. 0266 0267 ExpiredRole, ///< The notification timed out and closed. Actions on it cannot be invoked anymore. 0268 DismissedRole, ///< The notification got temporarily hidden by the user but could still be interacted with. 0269 ReadRole, ///< Whether the notification got read by the user. If true, the notification isn't considered unread even if created after lastRead. 0270 ///< @since 5.17 0271 0272 UserActionFeedbackRole, ///< Whether this notification is a response/confirmation to an explicit user action. @since 5.18 0273 0274 HasReplyActionRole, ///< Whether the notification has a reply action. @since 5.18 0275 ReplyActionLabelRole, ///< The user-visible label for the reply action. @since 5.18 0276 ReplyPlaceholderTextRole, ///< A custom placeholder text for the reply action, e.g. "Reply to Max...". @since 5.18 0277 ReplySubmitButtonTextRole, ///< A custom text for the reply submit button, e.g. "Submit Comment". @since 5.18 0278 ReplySubmitButtonIconNameRole, ///< A custom icon name for the reply submit button. @since 5.18 0279 CategoryRole, ///< The (optional) category of the notification. Notifications can optionally have a type indicator. Although neither client or nor 0280 ///< server must support this, some may choose to. Those servers implementing categories may use them to intelligently display the 0281 ///< notification in a certain way, or group notifications of similar types. @since 5.21 0282 ResidentRole, ///< Whether the notification should keep its actions even when they were invoked. @since 5.22 0283 TransientRole, ///< Whether the notification is transient and should not be kept in history. @since 5.22 0284 }; 0285 Q_ENUM(Roles) 0286 0287 /** 0288 * The type of model item. 0289 */ 0290 enum Type { 0291 NoType, 0292 NotificationType, ///< This item represents a notification. 0293 JobType, ///< This item represents an application job. 0294 }; 0295 Q_ENUM(Type) 0296 0297 /** 0298 * The notification urgency. 0299 * 0300 * @note jobs do not have an urgency, yet still might be above normal urgency notifications. 0301 */ 0302 enum Urgency { 0303 // these don't match the spec's value 0304 LowUrgency = 1 << 0, ///< The notification has low urgency, it is not important and may not be shown or added to a history. 0305 NormalUrgency = 1 << 1, ///< The notification has normal urgency. This is also the default if no urgecny is supplied. 0306 CriticalUrgency = 1 << 2, 0307 }; 0308 Q_ENUM(Urgency) 0309 Q_DECLARE_FLAGS(Urgencies, Urgency) 0310 Q_FLAG(Urgencies) 0311 0312 /** 0313 * Which items should be cleared in a call to @c clear 0314 */ 0315 enum ClearFlag { 0316 ClearExpired = 1 << 1, 0317 // TODO more 0318 }; 0319 Q_ENUM(ClearFlag) 0320 Q_DECLARE_FLAGS(ClearFlags, ClearFlag) 0321 Q_FLAG(ClearFlags) 0322 0323 /** 0324 * The state an application job is in. 0325 */ 0326 enum JobState { 0327 JobStateStopped, ///< The job is stopped. It has either finished (error is 0) or failed (error is not 0) 0328 JobStateRunning, ///< The job is currently running. 0329 JobStateSuspended, ///< The job is currentl paused 0330 }; 0331 Q_ENUM(JobState) 0332 0333 /** 0334 * The sort mode for the model. 0335 */ 0336 enum SortMode { 0337 SortByDate = 0, ///< Sort notifications strictly by the date they were updated or created. 0338 // should this be flags? SortJobsFirst | SortByUrgency | ...? 0339 SortByTypeAndUrgency, ///< Sort notifications taking into account their type and urgency. The order is (descending): Critical, jobs, Normal, Low. 0340 }; 0341 Q_ENUM(SortMode) 0342 0343 /** 0344 * The group mode for the model. 0345 */ 0346 enum GroupMode { 0347 GroupDisabled = 0, 0348 // GroupApplicationsTree, // TODO make actual tree 0349 GroupApplicationsFlat, 0350 }; 0351 Q_ENUM(GroupMode) 0352 0353 enum InvokeBehavior { 0354 None = 0, 0355 Close = 1, 0356 }; 0357 Q_ENUM(InvokeBehavior) 0358 Q_DECLARE_FLAGS(InvokeBehaviors, InvokeBehavior) 0359 Q_FLAG(InvokeBehaviors) 0360 0361 int limit() const; 0362 void setLimit(int limit); 0363 0364 bool showExpired() const; 0365 void setShowExpired(bool show); 0366 0367 bool showDismissed() const; 0368 void setShowDismissed(bool show); 0369 0370 QStringList blacklistedDesktopEntries() const; 0371 void setBlacklistedDesktopEntries(const QStringList &blacklist); 0372 0373 QStringList blacklistedNotifyRcNames() const; 0374 void setBlacklistedNotifyRcNames(const QStringList &blacklist); 0375 0376 QStringList whitelistedDesktopEntries() const; 0377 void setWhitelistedDesktopEntries(const QStringList &whitelist); 0378 0379 QStringList whitelistedNotifyRcNames() const; 0380 void setWhitelistedNotifyRcNames(const QStringList &whitelist); 0381 0382 bool showNotifications() const; 0383 void setShowNotifications(bool showNotifications); 0384 0385 bool showJobs() const; 0386 void setShowJobs(bool showJobs); 0387 0388 Urgencies urgencies() const; 0389 void setUrgencies(Urgencies urgencies); 0390 0391 SortMode sortMode() const; 0392 void setSortMode(SortMode sortMode); 0393 0394 Qt::SortOrder sortOrder() const; 0395 void setSortOrder(Qt::SortOrder sortOrder); 0396 0397 GroupMode groupMode() const; 0398 void setGroupMode(GroupMode groupMode); 0399 0400 int groupLimit() const; 0401 void setGroupLimit(int limit); 0402 0403 bool expandUnread() const; 0404 void setExpandUnread(bool expand); 0405 0406 QWindow *window() const; 0407 void setWindow(QWindow *window); 0408 0409 int count() const; 0410 0411 int activeNotificationsCount() const; 0412 int expiredNotificationsCount() const; 0413 0414 QDateTime lastRead() const; 0415 void setLastRead(const QDateTime &lastRead); 0416 void resetLastRead(); 0417 0418 int unreadNotificationsCount() const; 0419 0420 int activeJobsCount() const; 0421 int jobsPercentage() const; 0422 0423 /** 0424 * Convert the given QModelIndex into a QPersistentModelIndex 0425 */ 0426 Q_INVOKABLE QPersistentModelIndex makePersistentModelIndex(const QModelIndex &idx) const; 0427 0428 /** 0429 * @brief Expire a notification 0430 * 0431 * Closes the notification in response to its timeout running out. 0432 * 0433 * Call this if you have an implementation that handles the timeout itself 0434 * by having called @c stopTimeout 0435 * 0436 * @sa stopTimeout 0437 */ 0438 Q_INVOKABLE void expire(const QModelIndex &idx); 0439 /** 0440 * @brief Close a notification 0441 * 0442 * Closes the notification in response to the user explicitly closing it. 0443 * 0444 * When the model index belongs to a group, the entire group is closed. 0445 */ 0446 Q_INVOKABLE void close(const QModelIndex &idx); 0447 /** 0448 * @brief Configure a notification 0449 * 0450 * This will invoke the settings action, if available, otherwise open the 0451 * kcm_notifications KCM for configuring the respective application and event. 0452 */ 0453 Q_INVOKABLE void configure(const QModelIndex &idx); // TODO pass ctx for transient handling 0454 /** 0455 * @brief Invoke the default notification action 0456 * 0457 * Invokes the action that should be triggered when clicking 0458 * the notification bubble itself. 0459 */ 0460 Q_INVOKABLE void invokeDefaultAction(const QModelIndex &idx, InvokeBehavior behavior = None); 0461 /** 0462 * @brief Invoke a notification action 0463 * 0464 * Invokes the action with the given actionId on the notification. 0465 * For invoking the default action, i.e. the one that is triggered 0466 * when clicking the notification bubble, use invokeDefaultAction 0467 */ 0468 Q_INVOKABLE void invokeAction(const QModelIndex &idx, const QString &actionId, InvokeBehavior = None); 0469 0470 /** 0471 * @brief Reply to a notification 0472 * 0473 * Replies to the given notification with the given text. 0474 * @since 5.18 0475 */ 0476 Q_INVOKABLE void reply(const QModelIndex &idx, const QString &text, InvokeBehavior behavior); 0477 0478 /** 0479 * @brief Start automatic timeout of notifications 0480 * 0481 * Call this if you no longer handle the timeout yourself. 0482 * 0483 * @sa stopTimeout 0484 */ 0485 Q_INVOKABLE void startTimeout(const QModelIndex &idx); 0486 0487 Q_INVOKABLE void startTimeout(uint notificationId); 0488 /** 0489 * @brief Stop the automatic timeout of notifications 0490 * 0491 * Call this if you have an implementation that handles the timeout itself 0492 * taking into account e.g. whether the user is currently interacting with 0493 * the notification to not close it under their mouse. Call @c expire 0494 * once your custom timer has run out. 0495 * 0496 * @sa expire 0497 */ 0498 Q_INVOKABLE void stopTimeout(const QModelIndex &idx); 0499 0500 /** 0501 * @brief Suspend a job 0502 */ 0503 Q_INVOKABLE void suspendJob(const QModelIndex &idx); 0504 /** 0505 * @brief Resume a job 0506 */ 0507 Q_INVOKABLE void resumeJob(const QModelIndex &idx); 0508 /** 0509 * @brief Kill a job 0510 */ 0511 Q_INVOKABLE void killJob(const QModelIndex &idx); 0512 0513 /** 0514 * @brief Clear notifications 0515 * 0516 * Removes the notifications matching th ClearFlags from the model. 0517 * This can be used for e.g. a "Clear History" action. 0518 */ 0519 Q_INVOKABLE void clear(ClearFlags flags); 0520 0521 /** 0522 * Returns a model index pointing to the group of a notification. 0523 */ 0524 Q_INVOKABLE QModelIndex groupIndex(const QModelIndex &idx) const; 0525 0526 Q_INVOKABLE void collapseAllGroups(); 0527 0528 QVariant data(const QModelIndex &index, int role) const override; 0529 bool setData(const QModelIndex &index, const QVariant &value, int role) override; 0530 int rowCount(const QModelIndex &parent = QModelIndex()) const override; 0531 QHash<int, QByteArray> roleNames() const override; 0532 0533 bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override; 0534 bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override; 0535 0536 Q_SIGNALS: 0537 void limitChanged(); 0538 void showExpiredChanged(); 0539 void showDismissedChanged(); 0540 void blacklistedDesktopEntriesChanged(); 0541 void blacklistedNotifyRcNamesChanged(); 0542 void whitelistedDesktopEntriesChanged(); 0543 void whitelistedNotifyRcNamesChanged(); 0544 void showNotificationsChanged(); 0545 void showJobsChanged(); 0546 void urgenciesChanged(); 0547 void sortModeChanged(); 0548 void sortOrderChanged(); 0549 void groupModeChanged(); 0550 void groupLimitChanged(); 0551 void expandUnreadChanged(); 0552 void countChanged(); 0553 void activeNotificationsCountChanged(); 0554 void expiredNotificationsCountChanged(); 0555 void lastReadChanged(); 0556 void unreadNotificationsCountChanged(); 0557 void activeJobsCountChanged(); 0558 void jobsPercentageChanged(); 0559 void windowChanged(QWindow *window); 0560 0561 protected: 0562 void classBegin() override; 0563 void componentComplete() override; 0564 0565 private: 0566 class Private; 0567 QScopedPointer<Private> d; 0568 }; 0569 0570 } // namespace NotificationManager 0571 0572 Q_DECLARE_OPERATORS_FOR_FLAGS(NotificationManager::Notifications::Urgencies)