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